From a384490b102c72b262b716ec746e75dc27f89727 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 19 May 2023 09:31:36 +0100 Subject: [PATCH 01/88] mediatek: fix append-gl-metadata when running in buildbot Use same logic as in append-metadata so build doesn't fail in case of missing build-key (it was previously failing on the buildbot runners). Signed-off-by: Daniel Golle --- target/linux/mediatek/image/filogic.mk | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk index 5c8b47c662f..7159917ff45 100644 --- a/target/linux/mediatek/image/filogic.mk +++ b/target/linux/mediatek/image/filogic.mk @@ -58,9 +58,12 @@ metadata_gl_json = \ define Build/append-gl-metadata $(if $(SUPPORTED_DEVICES),-echo $(call metadata_gl_json,$(SUPPORTED_DEVICES)) | fwtool -I - $@) - [ ! -s "$(BUILD_KEY)" -o ! -s "$@" ] || { \ + sha256sum "$@" | cut -d" " -f1 > "$@.sha256sum" + [ ! -s "$(BUILD_KEY)" -o ! -s "$(BUILD_KEY).ucert" -o ! -s "$@" ] || { \ + cp "$(BUILD_KEY).ucert" "$@.ucert" ;\ usign -S -m "$@" -s "$(BUILD_KEY)" -x "$@.sig" ;\ - fwtool -S "$@.sig" "$@" ;\ + ucert -A -c "$@.ucert" -x "$@.sig" ;\ + fwtool -S "$@.ucert" "$@" ;\ } endef From a665c8e5bd31df6db232ceb4df8bc77481fc1413 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 May 2023 19:29:18 +0200 Subject: [PATCH 02/88] util-linux: Fix build on powerpc and arc This fixes the build of util-linux on powerpc and arc. Both CPU architectures were not supported here in addition to the missing MIPS support. Fixes: 628a410ed149 ("util-linux: update to 2.39") Signed-off-by: Hauke Mehrtens --- ...0001-test_enosys-add-support-for-mips.patch | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/package/utils/util-linux/patches/0001-test_enosys-add-support-for-mips.patch b/package/utils/util-linux/patches/0001-test_enosys-add-support-for-mips.patch index 602ffe67e7d..f8c8f851ec6 100644 --- a/package/utils/util-linux/patches/0001-test_enosys-add-support-for-mips.patch +++ b/package/utils/util-linux/patches/0001-test_enosys-add-support-for-mips.patch @@ -1,24 +1,36 @@ From 2558932c65524d953e4c86d7fda2282a582aa5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 17 May 2023 16:50:47 +0200 -Subject: [PATCH] test_enosys: add support for mips +Subject: [PATCH] test_enosys: add support for mips, powerpc and arc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Thomas Weißschuh --- - tests/helpers/test_enosys.c | 2 ++ + tests/helpers/test_enosys.c | 14 ++ 1 file changed, 2 insertions(+) --- a/tests/helpers/test_enosys.c +++ b/tests/helpers/test_enosys.c -@@ -53,6 +53,8 @@ +@@ -53,6 +53,20 @@ # else # define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PPC64LE # endif ++#elif __powerpc__ ++# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PPC +#elif __mips__ ++# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_MIPS ++# else ++# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_MIPSEL ++# endif ++#elif __arc__ ++# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_ARCV2BE ++# else ++# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_ARCV2 ++# endif #else # error Unknown target architecture #endif From 13656378e94a5f0e148a7726818fdaa4ccb231e0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 May 2023 16:17:58 +0200 Subject: [PATCH 03/88] ath25: Remove virt_to_phys() from Ethernet driver Instead of defining an own virt_to_phys() use the version from the generic MIPS arch code which does the same. This fixes a compile warning. Signed-off-by: Hauke Mehrtens --- .../ath25/patches-5.15/110-ar2313_ethernet.patch | 4 +--- .../patches-5.15/220-enet_micrel_workaround.patch | 14 +++++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/target/linux/ath25/patches-5.15/110-ar2313_ethernet.patch b/target/linux/ath25/patches-5.15/110-ar2313_ethernet.patch index bd998b14274..fcb6abff7d7 100644 --- a/target/linux/ath25/patches-5.15/110-ar2313_ethernet.patch +++ b/target/linux/ath25/patches-5.15/110-ar2313_ethernet.patch @@ -33,7 +33,7 @@ +obj-$(CONFIG_NET_AR231X) += ar231x.o --- /dev/null +++ b/drivers/net/ethernet/atheros/ar231x/ar231x.c -@@ -0,0 +1,1119 @@ +@@ -0,0 +1,1117 @@ +/* + * ar231x.c: Linux driver for the Atheros AR231x Ethernet device. + * @@ -156,8 +156,6 @@ +MODULE_DESCRIPTION("AR231x Ethernet driver"); +#endif + -+#define virt_to_phys(x) ((u32)(x) & 0x1fffffff) -+ +/* prototypes */ +static void ar231x_halt(struct net_device *dev); +static void rx_tasklet_func(unsigned long data); diff --git a/target/linux/ath25/patches-5.15/220-enet_micrel_workaround.patch b/target/linux/ath25/patches-5.15/220-enet_micrel_workaround.patch index 2bd08156317..b97cb3622fc 100644 --- a/target/linux/ath25/patches-5.15/220-enet_micrel_workaround.patch +++ b/target/linux/ath25/patches-5.15/220-enet_micrel_workaround.patch @@ -1,6 +1,6 @@ --- a/drivers/net/ethernet/atheros/ar231x/ar231x.c +++ b/drivers/net/ethernet/atheros/ar231x/ar231x.c -@@ -135,6 +135,7 @@ static int ar231x_mdiobus_write(struct m +@@ -133,6 +133,7 @@ static int ar231x_mdiobus_write(struct m static int ar231x_mdiobus_reset(struct mii_bus *bus); static int ar231x_mdiobus_probe(struct net_device *dev); static void ar231x_adjust_link(struct net_device *dev); @@ -8,7 +8,7 @@ #ifndef ERR #define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args) -@@ -166,6 +167,32 @@ static const struct net_device_ops ar231 +@@ -164,6 +165,32 @@ static const struct net_device_ops ar231 #endif }; @@ -41,7 +41,7 @@ static int ar231x_probe(struct platform_device *pdev) { struct net_device *dev; -@@ -273,6 +300,24 @@ static int ar231x_probe(struct platform_ +@@ -271,6 +298,24 @@ static int ar231x_probe(struct platform_ mdiobus_register(sp->mii_bus); @@ -66,7 +66,7 @@ if (ar231x_mdiobus_probe(dev) != 0) { printk(KERN_ERR "%s: mdiobus_probe failed\n", dev->name); rx_tasklet_cleanup(dev); -@@ -326,8 +371,10 @@ static int ar231x_remove(struct platform +@@ -324,8 +369,10 @@ static int ar231x_remove(struct platform rx_tasklet_cleanup(dev); ar231x_init_cleanup(dev); unregister_netdev(dev); @@ -79,7 +79,7 @@ kfree(dev); return 0; } -@@ -870,7 +917,8 @@ static int ar231x_open(struct net_device +@@ -868,7 +915,8 @@ static int ar231x_open(struct net_device sp->eth_regs->mac_control |= MAC_CONTROL_RE; @@ -89,7 +89,7 @@ return 0; } -@@ -951,7 +999,8 @@ static int ar231x_close(struct net_devic +@@ -949,7 +997,8 @@ static int ar231x_close(struct net_devic #endif @@ -99,7 +99,7 @@ return 0; } -@@ -995,6 +1044,9 @@ static int ar231x_ioctl(struct net_devic +@@ -993,6 +1042,9 @@ static int ar231x_ioctl(struct net_devic { struct ar231x_private *sp = netdev_priv(dev); From 53956dd2f673fa3aacb643f88b25bb0314905931 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 May 2023 16:19:47 +0200 Subject: [PATCH 04/88] ath25: Replace fall through comment with fallthrough; Replace the fall through comment with fallthrough; in the ar2315 flash driver. This fixes a compile warning. Signed-off-by: Hauke Mehrtens --- target/linux/ath25/patches-5.15/120-spiflash.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/linux/ath25/patches-5.15/120-spiflash.patch b/target/linux/ath25/patches-5.15/120-spiflash.patch index c0f4fa6204c..b7a9607ac9b 100644 --- a/target/linux/ath25/patches-5.15/120-spiflash.patch +++ b/target/linux/ath25/patches-5.15/120-spiflash.patch @@ -350,13 +350,13 @@ + switch (read_len) { + case 4: + spi_data |= buf[3] << 24; -+ /* fall through */ ++ fallthrough; + case 3: + spi_data |= buf[2] << 16; -+ /* fall through */ ++ fallthrough; + case 2: + spi_data |= buf[1] << 8; -+ /* fall through */ ++ fallthrough; + case 1: + spi_data |= buf[0] & 0xff; + break; From f18cb0ba637de53c39df675711656cd111c030a5 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Sun, 7 May 2023 17:58:26 +0200 Subject: [PATCH 05/88] f2fs-tools: update to 1.16.0 Remove upstramed patches: - 100-configure.ac-fix-AC_ARG_WITH.patch - 101-configure.ac-fix-cross-compilation.patch Remove deprecated f2fstat tool: https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git/commit/?id=77bf7ed29f1dd1341079913f3b36fc62f812c4f5 Changelog: 06c027a f2fs-tools: upgrade version 1.16.0 542cc57 fsck.f2fs: fix sanity check logic for cp_payload a7df89e mkfs.f2fs: remove indentation c82985a fsck.f2fs: don't call report_zone on normal partition 0ac168e f2fs-tools: relax zone size of power of 2 641be32 mkfs.f2fs: trim all the devices except the first one 3835fef f2fs-tools: fix # of total segments 5b08ca9 f2fs_io: support AES_256_HCTR2 ae3301c f2fs_io: Fix out of tree builds ddbde27 fsck.f2fs: relocate chksum verification step during f2fs_do_mount() 77bf7ed f2fs-tools: Remove deprecated f2fstat fb6575e Remove sg_write_buffer 1bb669e fsck.f2fs: avoid uncessary recalculation ccd2361 fsck.f2fs: fix potential overflow of copying i_name cd6b133 fsck.f2fs: add parentheses for SB_MASK 399600a dump.f2fs: remove unavailable option -g 3e6e178 f2fs-tools: define HAVE_CLOCK_GETTIME properly 907b972 f2fs-tools: support F2FS_IOC_START_ATOMIC_REPLACE 9ff70fb f2fs-tools: give less overprovisioning space 844f821 f2fs-tools: set host-aware zoned device similar to host-managed one 88ac76d fsck.f2fs: fix missing to assign c.zoned_model 8cbe34e fsck.f2fs: trigger repairing if filesystem has inconsistent errors 2f1dde2 fsck.f2fs: trigger repairing if filesystem was forced to stop 465159f fsck.f2fs: export valid image size 3486b62 mkfs.f2fs: update allocation policy for ro feature bdd51e5 fsck.f2fs: fix __end_block_addr() 5a5e419 Always use sparse/sparse.h when building for Android 19f77c6 f2fs-tools: fix build error on lz4-1.9.4 986c1f1 Fix format strings in log messages 0d6acbe fsck.f2fs: use elapsed_time in checkpoint for period check 9b7a4c5 mkfs.f2fs: catch total_zones=0 instead of crashing 6148db3 f2fs-tools: use F2FS_BLKSIZE instead of PAGE_*_SIZE f09c2b7 f2fs_io: support triggering filesystem GC via ioctl 32e7d27 configure.ac: fix cross compilation 65fe94e configure.ac: fix AC_ARG_WITH 6325cf7 Use F2FS_BLKSIZE as the size of struct f2fs_summary_block c89be7a Use F2FS_BLKSIZE for dev_read_block() buffers 5317d18 Improve compile-time type checking for f2fs_report_zone() 92e2e52 Fix f2fs_report_zone() 648a491 Fix the struct f2fs_dentry_block definition c964547 resize.f2fs: add option to manually specify new overprovision a741438 fsck.f2fs: drop compression bit if inline_data is set 406b1c9 f2fs-tools: fix cannot get bdev information 9d0cb9e f2fs_io: add dsync option for write a7b8b46 tools: fix file too large causing overflow bddca6f dump.f2fs: add -I nid to dump inode by scan full disk ebc3879 android_config: add time headers c1144bf Check fallthrough in mount.h for Mac bcb9929 avoid unnecessary function 7d902f4 Fix dependencies on linux/blkzoned.h when using Bionic. 274abbb Remove unnecessary config.h 8c97ab3 libzone: remove duplicate header adcec10 Support zoned device if libc exists efc2bc7 mkfs.f2fs: fix typo 3034a41 mkfs.f2fs: split unused parameter dd8d8e5 f2fs-tools: do not use SG_IO in Android 4f216e6 f2fs-tools: move android_config before defining them 48c5dbb f2fscrypt: adjust config file first 4b55459 android_config: add missing uuid library Signed-off-by: Nick Hainke --- package/utils/f2fs-tools/Makefile | 7 +- .../100-configure.ac-fix-AC_ARG_WITH.patch | 88 ------------------- ...1-configure.ac-fix-cross-compilation.patch | 80 ----------------- 3 files changed, 3 insertions(+), 172 deletions(-) delete mode 100644 package/utils/f2fs-tools/patches/100-configure.ac-fix-AC_ARG_WITH.patch delete mode 100644 package/utils/f2fs-tools/patches/101-configure.ac-fix-cross-compilation.patch diff --git a/package/utils/f2fs-tools/Makefile b/package/utils/f2fs-tools/Makefile index c4e3720dd8d..27a6fd2248e 100644 --- a/package/utils/f2fs-tools/Makefile +++ b/package/utils/f2fs-tools/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=f2fs-tools -PKG_VERSION:=1.15.0 -PKG_RELEASE:=2 +PKG_VERSION:=1.16.0 +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git/snapshot/ -PKG_HASH:=147d471040b44900283ce2c935f1d35d13d7f40008e7cb8fab2b69f54da01a4f +PKG_HASH:=208c7a07e95383fbd7b466b5681590789dcb41f41bf197369c41a95383b57c5e PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0-only @@ -143,7 +143,6 @@ Package/f2fsck-selinux/install = $(Package/f2fsck/install) define Package/f2fs-tools/install $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/f2fstat $(1)/usr/sbin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/fibmap.f2fs $(1)/usr/sbin $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/parse.f2fs $(1)/usr/sbin endef diff --git a/package/utils/f2fs-tools/patches/100-configure.ac-fix-AC_ARG_WITH.patch b/package/utils/f2fs-tools/patches/100-configure.ac-fix-AC_ARG_WITH.patch deleted file mode 100644 index a7fb50a63d1..00000000000 --- a/package/utils/f2fs-tools/patches/100-configure.ac-fix-AC_ARG_WITH.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 9af8ee5baceab59d46154c96da62b52935f363fe Mon Sep 17 00:00:00 2001 -From: Nick Hainke -Date: Mon, 27 Jun 2022 20:43:11 +0200 -Subject: [PATCH] configure.ac: fix AC_ARG_WITH - -In the new version the configuration no longer respects the ---without/--with blkid/selinux parameters. Add the tests for -"with_blkid" and "with_selinux" back to configure.ac as described -in the manual. - -Link: https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/External-Software.html - -Fixes: c48335416a09 ("configure.ac: Enable cross-compilation") - -Signed-off-by: Nick Hainke ---- - configure.ac | 44 ++++++++++++++++++++++++++++++-------------- - 1 file changed, 30 insertions(+), 14 deletions(-) - ---- a/configure.ac -+++ b/configure.ac -@@ -39,12 +39,16 @@ AM_INIT_AUTOMAKE([-Wall -Werror foreign - - # Test configure options. - AC_ARG_WITH([selinux], -- AS_HELP_STRING([--without-selinux], -- [Ignore presence of libselinux and disable selinux support])) -+ [AS_HELP_STRING([--without-selinux], -+ [Ignore presence of libselinux and disable selinux support])], -+ [], -+ [with_selinux=check]) - - AC_ARG_WITH([blkid], -- AS_HELP_STRING([--without-blkid], -- [Ignore presence of libblkid and disable blkid support])) -+ [AS_HELP_STRING([--without-blkid], -+ [Ignore presence of libblkid and disable blkid support])], -+ [], -+ [with_blkid=check]) - - # Checks for programs. - AC_PROG_CC -@@ -55,11 +59,17 @@ AC_PATH_PROG([LDCONFIG], [ldconfig], - [$PATH:/sbin]) - - # Checks for libraries. --AC_CHECK_LIB([blkid], [blkid_probe_all], -- [AC_SUBST([libblkid_LIBS], ["-lblkid"]) -- AC_DEFINE([HAVE_LIBBLKID], [1], -- [Define if you have libblkid]) -- ], [], []) -+AS_IF([test "x$with_blkid" != xno], -+ [AC_CHECK_LIB([blkid], [blkid_probe_all], -+ [AC_SUBST([libblkid_LIBS], ["-lblkid"]) -+ AC_DEFINE([HAVE_LIBBLKID], [1], -+ [Define if you have libblkid]) -+ ], -+ [if test "x$with_blkid" != xcheck; then -+ AC_MSG_FAILURE( -+ [--with-blkid was given, but test for blkid failed]) -+ fi -+ ], -lblkid)]) - - AC_CHECK_LIB([lzo2], [main], - [AC_SUBST([liblzo2_LIBS], ["-llzo2"]) -@@ -73,11 +83,17 @@ AC_CHECK_LIB([lz4], [main], - [Define if you have liblz4]) - ], [], []) - --AC_CHECK_LIB([selinux], [getcon], -- [AC_SUBST([libselinux_LIBS], ["-lselinux"]) -- AC_DEFINE([HAVE_LIBSELINUX], [1], -- [Define if you have libselinux]) -- ], [], []) -+AS_IF([test "x$with_selinux" != xno], -+ [AC_CHECK_LIB([selinux], [getcon], -+ [AC_SUBST([libselinux_LIBS], ["-lselinux"]) -+ AC_DEFINE([HAVE_LIBSELINUX], [1], -+ [Define if you have libselinux]) -+ ], -+ [if test "x$with_selinux" != xcheck; then -+ AC_MSG_FAILURE( -+ [--with-selinux was given, but test for selinux failed]) -+ fi -+ ], -lselinux)]) - - AC_CHECK_LIB([uuid], [uuid_clear], - [AC_SUBST([libuuid_LIBS], ["-luuid"]) diff --git a/package/utils/f2fs-tools/patches/101-configure.ac-fix-cross-compilation.patch b/package/utils/f2fs-tools/patches/101-configure.ac-fix-cross-compilation.patch deleted file mode 100644 index b9edd6634b8..00000000000 --- a/package/utils/f2fs-tools/patches/101-configure.ac-fix-cross-compilation.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 821a1d3fcce31c234512a8f4dc4fc97dfbd7ae32 Mon Sep 17 00:00:00 2001 -From: Nick Hainke -Date: Mon, 4 Jul 2022 09:46:10 +0200 -Subject: [PATCH] configure.ac: fix cross compilation - -AC_CHECK_LIB seems to not work correctly with OpenWrt. Add possibility -to disable lz4 and lzo2 manually. - -Fixes errors in the form of: - Package f2fsck is missing dependencies for the following libraries: - liblz4.so.1 - liblzo2.so.2 - -Signed-off-by: Nick Hainke ---- - configure.ac | 44 ++++++++++++++++++++++++++++++++++---------- - 1 file changed, 34 insertions(+), 10 deletions(-) - ---- a/configure.ac -+++ b/configure.ac -@@ -50,6 +50,18 @@ AC_ARG_WITH([blkid], - [], - [with_blkid=check]) - -+AC_ARG_WITH([lzo2], -+ [AS_HELP_STRING([--without-lzo2], -+ [Ignore presence of liblzo2 and disable lzo2 support])], -+ [], -+ [with_lzo2=check]) -+ -+AC_ARG_WITH([lz4], -+ [AS_HELP_STRING([--without-lz4], -+ [Ignore presence of liblz4 and disable lz4 support])], -+ [], -+ [with_lz4=check]) -+ - # Checks for programs. - AC_PROG_CC - AM_PROG_AR -@@ -71,17 +83,29 @@ AS_IF([test "x$with_blkid" != xno], - fi - ], -lblkid)]) - --AC_CHECK_LIB([lzo2], [main], -- [AC_SUBST([liblzo2_LIBS], ["-llzo2"]) -- AC_DEFINE([HAVE_LIBLZO2], [1], -- [Define if you have liblzo2]) -- ], [], []) -- --AC_CHECK_LIB([lz4], [main], -- [AC_SUBST([liblz4_LIBS], ["-llz4"]) -- AC_DEFINE([HAVE_LIBLZ4], [1], -- [Define if you have liblz4]) -- ], [], []) -+AS_IF([test "x$with_lzo2" != xno], -+ [AC_CHECK_LIB([lzo2], [main], -+ [AC_SUBST([liblzo2_LIBS], ["-llzo2"]) -+ AC_DEFINE([HAVE_LIBLZO2], [1], -+ [Define if you have liblzo2]) -+ ], -+ [if test "x$with_lzo2" != xcheck; then -+ AC_MSG_FAILURE( -+ [--with-lzo2 was given, but test for lzo2 failed]) -+ fi -+ ], -llzo2)]) -+ -+AS_IF([test "x$with_lz4" != xno], -+ [AC_CHECK_LIB([lz4], [main], -+ [AC_SUBST([liblz4_LIBS], ["-llz4"]) -+ AC_DEFINE([HAVE_LIBLZ4], [1], -+ [Define if you have liblz4]) -+ ], -+ [if test "x$with_lz4" != xcheck; then -+ AC_MSG_FAILURE( -+ [--with-lz4 was given, but test for lz4 failed]) -+ fi -+ ], -llz4)]) - - AS_IF([test "x$with_selinux" != xno], - [AC_CHECK_LIB([selinux], [getcon], From f73d011810790095d20f53f473926f5b0fc6284b Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Thu, 18 May 2023 13:07:23 +0200 Subject: [PATCH 06/88] libjson-c: import patch to fix compilation on macos Fixes errors in the form of: /Users/user/src/openwrt/openwrt/build_dir/hostpkg/json-c-0.16/json_util.c:63:35: error: a function declaration without a prototype is deprecated in all versions of C [-Werror,-Wstrict-prototypes] const char *json_util_get_last_err() ^ void 1 error generated. ninja: build stopped: subcommand failed. Reported-by: Paul Spooren Suggested-by: Paul Spooren Signed-off-by: Nick Hainke --- package/libs/libjson-c/Makefile | 2 +- .../patches/010-fix-build-with-clang-15.patch | 184 ++++++++++++++++++ 2 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 package/libs/libjson-c/patches/010-fix-build-with-clang-15.patch diff --git a/package/libs/libjson-c/Makefile b/package/libs/libjson-c/Makefile index 2c312f200ee..d925ac750d6 100644 --- a/package/libs/libjson-c/Makefile +++ b/package/libs/libjson-c/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=json-c PKG_VERSION:=0.16 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-nodoc.tar.gz PKG_SOURCE_URL:=https://s3.amazonaws.com/json-c_releases/releases/ diff --git a/package/libs/libjson-c/patches/010-fix-build-with-clang-15.patch b/package/libs/libjson-c/patches/010-fix-build-with-clang-15.patch new file mode 100644 index 00000000000..d6af772e06b --- /dev/null +++ b/package/libs/libjson-c/patches/010-fix-build-with-clang-15.patch @@ -0,0 +1,184 @@ +From 6eca65617aacd19f4928acd5766b8dd20eda0b34 Mon Sep 17 00:00:00 2001 +From: Khem Raj +Date: Sat, 13 Aug 2022 20:37:03 -0700 +Subject: [PATCH] Fix build with clang-15+ + +Fixes +json_util.c:63:35: error: a function declaration without a prototype is deprecated in all versions of C [-We +rror,-Wstrict-prototypes] +const char *json_util_get_last_err() + ^ + void + +Signed-off-by: Khem Raj +--- + json_util.c | 2 +- + tests/test1.c | 6 +++--- + tests/test4.c | 2 +- + tests/test_cast.c | 2 +- + tests/test_charcase.c | 2 +- + tests/test_parse.c | 8 ++++---- + tests/test_printbuf.c | 4 ++-- + tests/test_util_file.c | 6 +++--- + 8 files changed, 16 insertions(+), 16 deletions(-) + +--- a/json_util.c ++++ b/json_util.c +@@ -60,7 +60,7 @@ static int _json_object_to_fd(int fd, st + + static char _last_err[256] = ""; + +-const char *json_util_get_last_err() ++const char *json_util_get_last_err(void) + { + if (_last_err[0] == '\0') + return NULL; +--- a/tests/test1.c ++++ b/tests/test1.c +@@ -58,7 +58,7 @@ static const char *to_json_string(json_o + #endif + + json_object *make_array(void); +-json_object *make_array() ++json_object *make_array(void) + { + json_object *my_array; + +@@ -74,7 +74,7 @@ json_object *make_array() + } + + void test_array_del_idx(void); +-void test_array_del_idx() ++void test_array_del_idx(void) + { + int rc; + size_t ii; +@@ -140,7 +140,7 @@ void test_array_del_idx() + } + + void test_array_list_expand_internal(void); +-void test_array_list_expand_internal() ++void test_array_list_expand_internal(void) + { + int rc; + size_t ii; +--- a/tests/test4.c ++++ b/tests/test4.c +@@ -28,7 +28,7 @@ void print_hex(const char *s) + } + + static void test_lot_of_adds(void); +-static void test_lot_of_adds() ++static void test_lot_of_adds(void) + { + int ii; + char key[50]; +--- a/tests/test_cast.c ++++ b/tests/test_cast.c +@@ -94,7 +94,7 @@ static void getit(struct json_object *ne + printf("new_obj.%s json_object_get_double()=%f\n", field, json_object_get_double(o)); + } + +-static void checktype_header() ++static void checktype_header(void) + { + printf("json_object_is_type: %s,%s,%s,%s,%s,%s,%s\n", json_type_to_name(json_type_null), + json_type_to_name(json_type_boolean), json_type_to_name(json_type_double), +--- a/tests/test_charcase.c ++++ b/tests/test_charcase.c +@@ -19,7 +19,7 @@ int main(int argc, char **argv) + } + + /* make sure only lowercase forms are parsed in strict mode */ +-static void test_case_parse() ++static void test_case_parse(void) + { + struct json_tokener *tok; + json_object *new_obj; +--- a/tests/test_parse.c ++++ b/tests/test_parse.c +@@ -92,7 +92,7 @@ static void single_basic_parse(const cha + if (getenv("TEST_PARSE_CHUNKSIZE") != NULL) + single_incremental_parse(test_string, clear_serializer); + } +-static void test_basic_parse() ++static void test_basic_parse(void) + { + single_basic_parse("\"\003\"", 0); + single_basic_parse("/* hello */\"foo\"", 0); +@@ -195,7 +195,7 @@ static void test_basic_parse() + single_basic_parse("[18446744073709551616]", 1); + } + +-static void test_utf8_parse() ++static void test_utf8_parse(void) + { + // json_tokener_parse doesn't support checking for byte order marks. + // It's the responsibility of the caller to detect and skip a BOM. +@@ -222,7 +222,7 @@ static int clear_serializer(json_object + return JSON_C_VISIT_RETURN_CONTINUE; + } + +-static void test_verbose_parse() ++static void test_verbose_parse(void) + { + json_object *new_obj; + enum json_tokener_error error = json_tokener_success; +@@ -562,7 +562,7 @@ struct incremental_step + {NULL, -1, -1, json_tokener_success, 0}, + }; + +-static void test_incremental_parse() ++static void test_incremental_parse(void) + { + json_object *new_obj; + enum json_tokener_error jerr; +--- a/tests/test_printbuf.c ++++ b/tests/test_printbuf.c +@@ -16,7 +16,7 @@ static void test_printbuf_memset_length( + #define __func__ __FUNCTION__ + #endif + +-static void test_basic_printbuf_memset() ++static void test_basic_printbuf_memset(void) + { + struct printbuf *pb; + +@@ -29,7 +29,7 @@ static void test_basic_printbuf_memset() + printf("%s: end test\n", __func__); + } + +-static void test_printbuf_memset_length() ++static void test_printbuf_memset_length(void) + { + struct printbuf *pb; + +--- a/tests/test_util_file.c ++++ b/tests/test_util_file.c +@@ -35,7 +35,7 @@ static void test_read_fd_equal(const cha + #define PATH_MAX 256 + #endif + +-static void test_write_to_file() ++static void test_write_to_file(void) + { + json_object *jso; + +@@ -231,7 +231,7 @@ static void test_read_valid_nested_with_ + close(d); + } + +-static void test_read_nonexistant() ++static void test_read_nonexistant(void) + { + const char *filename = "./not_present.json"; + +@@ -249,7 +249,7 @@ static void test_read_nonexistant() + } + } + +-static void test_read_closed() ++static void test_read_closed(void) + { + // Test reading from a closed fd + int d = open("/dev/null", O_RDONLY, 0); From 45082d4e51935bb3e8eab255dd69c87f6f9310b0 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Fri, 19 May 2023 11:01:05 +0200 Subject: [PATCH 07/88] tools/cmake: update to 3.26.4 Changelog: https://www.kitware.com/cmake-3-26-4-available-for-download/ Signed-off-by: Nick Hainke --- tools/cmake/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cmake/Makefile b/tools/cmake/Makefile index 7fac8718ede..0c96b017e37 100644 --- a/tools/cmake/Makefile +++ b/tools/cmake/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=cmake -PKG_VERSION:=3.26.3 +PKG_VERSION:=3.26.4 PKG_VERSION_MAJOR:=$(word 1,$(subst ., ,$(PKG_VERSION))).$(word 2,$(subst ., ,$(PKG_VERSION))) PKG_RELEASE:=1 PKG_CPE_ID:=cpe:/a:kitware:cmake @@ -15,7 +15,7 @@ PKG_CPE_ID:=cpe:/a:kitware:cmake PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/Kitware/CMake/releases/download/v$(PKG_VERSION)/ \ https://cmake.org/files/v$(PKG_VERSION_MAJOR)/ -PKG_HASH:=bbd8d39217509d163cb544a40d6428ac666ddc83e22905d3e52c925781f0f659 +PKG_HASH:=313b6880c291bd4fe31c0aa51d6e62659282a521e695f30d5cc0d25abbd5c208 HOST_BUILD_PARALLEL:=1 HOST_CONFIGURE_PARALLEL:=1 From 2f11a89140030b51397199083b34b0e13ba9cbc6 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 May 2023 20:07:24 +0200 Subject: [PATCH 08/88] util-linux: Fix taskset conflict with busybox This fixes the following error: * check_data_file_clashes: Package taskset wants to install file build_dir/target-powerpc_8548_musl/root-mpc85xx/usr/bin/taskset But that file is already provided by package * busybox * opkg_install_cmd: Cannot install package taskset. Fixes: 3c3d797c4dad ("busybox: enable taskset by default") Signed-off-by: Hauke Mehrtens --- package/utils/util-linux/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package/utils/util-linux/Makefile b/package/utils/util-linux/Makefile index e14d816a42b..8dab6213906 100644 --- a/package/utils/util-linux/Makefile +++ b/package/utils/util-linux/Makefile @@ -485,6 +485,7 @@ endef define Package/taskset $(call Package/util-linux/Default) TITLE:=set or retrieve a process's CPU affinity + ALTERNATIVES:=200:/usr/bin/taskset:/usr/bin/util-linux-taskset endef define Package/taskset/description @@ -851,7 +852,7 @@ endef define Package/taskset/install $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/taskset $(1)/usr/bin/ + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/taskset $(1)/usr/bin/util-linux-taskset endef define Package/unshare/install From 3a935f7ea9214c831eccc585f0677c5132957dde Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Thu, 18 May 2023 17:12:36 +0200 Subject: [PATCH 09/88] util-linux: Use SYS_getrandom in randutils.c The getrandom syscall is not hanging at bootup any more if there is not enough entropy. This was fixed upstream in 2018 in commit: https://github.com/util-linux/util-linux/commit/a9cf659e0508c1f56813a7d74c64f67bbc962538 This OpenWrt patch is not needed any more. This reverts commit e64463ebde55 ("util-linux: avoid using the getrandom syscall") Signed-off-by: Hauke Mehrtens --- package/utils/util-linux/Makefile | 2 +- .../utils/util-linux/patches/210-use-urandom.patch | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 package/utils/util-linux/patches/210-use-urandom.patch diff --git a/package/utils/util-linux/Makefile b/package/utils/util-linux/Makefile index 8dab6213906..704d4f11ec4 100644 --- a/package/utils/util-linux/Makefile +++ b/package/utils/util-linux/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=util-linux PKG_VERSION:=2.39 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/$(PKG_NAME)/v2.39 diff --git a/package/utils/util-linux/patches/210-use-urandom.patch b/package/utils/util-linux/patches/210-use-urandom.patch deleted file mode 100644 index 5817209885f..00000000000 --- a/package/utils/util-linux/patches/210-use-urandom.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/lib/randutils.c -+++ b/lib/randutils.c -@@ -26,6 +26,11 @@ - #define THREAD_LOCAL static - #endif - -+/* force /dev/urandom to avoid hanging on early boot */ -+#undef HAVE_GETRANDOM -+#undef SYS_getrandom -+#undef __NR_getrandom -+ - #ifdef HAVE_GETRANDOM - # include - #elif defined (__linux__) From ab7e2513034fe0e33ec17c13c8bf81189b0ce742 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Fri, 19 May 2023 14:05:01 +0800 Subject: [PATCH 10/88] ramips: fix build error on Airlink AR670W The 'KERNEL' is not referenced by other objects, so double '$$' will cause shell unable to parse the variable 'BLOCKSIZE': dd ... bs=$(BLOCKSIZE) conv=sync bash: line 1: BLOCKSIZE: command not found Fixes: 09a0efbe83(ramips: set default BLOCKSIZE to 64k for nor flash devices) Signed-off-by: Shiji Yang --- target/linux/ramips/image/rt288x.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/linux/ramips/image/rt288x.mk b/target/linux/ramips/image/rt288x.mk index 3d2d0c7ae02..c93d7d78e51 100644 --- a/target/linux/ramips/image/rt288x.mk +++ b/target/linux/ramips/image/rt288x.mk @@ -15,7 +15,7 @@ define Device/airlink101_ar670w DEVICE_VENDOR := Airlink DEVICE_MODEL := AR670W IMAGE_SIZE := 3840k - KERNEL := $(KERNEL_DTB) | pad-to $$$$(BLOCKSIZE) + KERNEL := $(KERNEL_DTB) | pad-to $$(BLOCKSIZE) IMAGES += factory.bin IMAGE/factory.bin := $$(sysupgrade_bin) | check-size | \ wrg-header wrgn16a_airlink_ar670w From c0ef48814ea6dbd8c60b31af622c9ff4b163959f Mon Sep 17 00:00:00 2001 From: Linhui Liu Date: Fri, 19 May 2023 23:06:08 +0800 Subject: [PATCH 11/88] pcre2: switch to Github Releases and bump to 10.42 The mirror at SourceForge is an unofficial mirror and no longer maintained. ChangeLogs: https://github.com/PCRE2Project/pcre2/blob/pcre2-10.42/ChangeLog Signed-off-by: Linhui Liu --- package/libs/pcre2/Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package/libs/pcre2/Makefile b/package/libs/pcre2/Makefile index ca761cc36d8..d178e3cd04f 100644 --- a/package/libs/pcre2/Makefile +++ b/package/libs/pcre2/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=pcre2 -PKG_VERSION:=10.37 -PKG_RELEASE:=2 +PKG_VERSION:=10.42 +PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 -PKG_SOURCE_URL:=@SF/pcre/$(PKG_NAME)/$(PKG_VERSION) -PKG_HASH:=4d95a96e8b80529893b4562be12648d798b957b1ba1aae39606bbc2ab956d270 +PKG_SOURCE_URL:=https://github.com/PCRE2Project/pcre2/releases/download/$(PKG_NAME)-$(PKG_VERSION) +PKG_HASH:=8d36cd8cb6ea2a4c2bb358ff6411b0c788633a2a45dabbf1aeb4b701d1b5e840 PKG_MAINTAINER:=Shane Peelar PKG_LICENSE:=BSD-3-Clause From 7a29230752f232487107b2e0d54fe1f63e733b59 Mon Sep 17 00:00:00 2001 From: Jan Forman Date: Sat, 15 May 2021 20:48:12 +0200 Subject: [PATCH 12/88] ath79: Replace reset-button for DIR-859 gpio-export for the switch reset pin replaced with a reset pin definition for the driver, within the phy node. Signed-off-by: Jan Forman Tested-By: Sebastian Schaper --- target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts index 804f3434c37..140f0b65c60 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts +++ b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts @@ -56,17 +56,6 @@ debounce-interval = <60>; }; }; - - gpio-export { - compatible = "gpio-export"; - #size-cells = <0>; - - gpio_switch_reset { - gpio-export,name = "dir-859-a1:reset:switch"; - gpio-export,output = <1>; - gpios = <&gpio 11 GPIO_ACTIVE_HIGH>; - }; - }; }; &pcie { @@ -133,6 +122,8 @@ phy-mode = "sgmii"; qca,mib-poll-interval = <500>; + reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + qca,ar8327-initvals = < 0x04 0x00080080 /* PORT0 PAD MODE CTRL */ 0x10 0x81000080 /* POWER_ON_STRAP */ From 6ea910ab54ffc0640f4e7fc977c1e076f4e86323 Mon Sep 17 00:00:00 2001 From: Jan Forman Date: Sat, 15 May 2021 20:51:14 +0200 Subject: [PATCH 13/88] ath79: Create shared dtsi for DIR-859 Create a shared dtsi for the dir-859 and similarly device, it similarly as it done for the dir-842. Signed-off-by: Jan Forman --- .../ath79/dts/qca9563_dlink_dir-859-a1.dts | 113 +---------------- .../ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi | 118 ++++++++++++++++++ 2 files changed, 119 insertions(+), 112 deletions(-) create mode 100644 target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts index 140f0b65c60..a828f86cb16 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts +++ b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts @@ -1,9 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later OR MIT -#include "qca956x.dtsi" - +#include "qca9563_dlink_dir-8x9-a1.dtsi" #include -#include / { model = "D-Link DIR-859 A1"; @@ -40,113 +38,4 @@ linux,default-trigger = "phy0tpt"; }; }; - - keys { - compatible = "gpio-keys"; - - wps { - linux,code = ; - gpios = <&gpio 1 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; - - reset { - linux,code = ; - gpios = <&gpio 2 GPIO_ACTIVE_LOW>; - debounce-interval = <60>; - }; - }; -}; - -&pcie { - status = "okay"; -}; - -&spi { - status = "okay"; - - flash@0 { - compatible = "jedec,spi-nor"; - reg = <0>; - spi-max-frequency = <50000000>; - - partitions { - compatible = "fixed-partitions"; - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "bootloader"; - reg = <0x000000 0x40000>; - read-only; - }; - - partition@40000 { - label = "bdcfg"; - reg = <0x040000 0x10000>; - read-only; - }; - - partition@50000 { - label = "devdata"; - reg = <0x050000 0x10000>; - read-only; - }; - - partition@60000 { - label = "devconf"; - reg = <0x060000 0x10000>; - read-only; - }; - - partition@70000 { - compatible = "seama"; - label = "firmware"; - reg = <0x070000 0xf80000>; - }; - - art: partition@ff0000 { - label = "art"; - reg = <0xff0000 0x010000>; - read-only; - }; - }; - }; -}; - -&mdio0 { - status = "okay"; - - phy0: ethernet-phy@0 { - reg = <0>; - phy-mode = "sgmii"; - qca,mib-poll-interval = <500>; - - reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; - - qca,ar8327-initvals = < - 0x04 0x00080080 /* PORT0 PAD MODE CTRL */ - 0x10 0x81000080 /* POWER_ON_STRAP */ - 0x50 0xcc35cc35 /* LED_CTRL0 */ - 0x54 0xcb37cb37 /* LED_CTRL1 */ - 0x58 0x00000000 /* LED_CTRL2 */ - 0x5c 0x00f3cf00 /* LED_CTRL3 */ - 0x7c 0x0000007e /* PORT0_STATUS */ - >; - }; -}; - -ð0 { - status = "okay"; - - pll-data = <0x03000101 0x00000101 0x00001919>; - - phy-mode = "sgmii"; - phy-handle = <&phy0>; -}; - -&wmac { - status = "okay"; - - qca,no-eeprom; }; diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi new file mode 100644 index 00000000000..65948ecb222 --- /dev/null +++ b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca956x.dtsi" + +#include +#include + +/ { + + keys { + compatible = "gpio-keys"; + + wps { + linux,code = ; + gpios = <&gpio 1 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + + reset { + linux,code = ; + gpios = <&gpio 2 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; +}; + +&pcie { + status = "okay"; +}; + +&spi { + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bootloader"; + reg = <0x000000 0x40000>; + read-only; + }; + + partition@40000 { + label = "bdcfg"; + reg = <0x040000 0x10000>; + read-only; + }; + + partition@50000 { + label = "devdata"; + reg = <0x050000 0x10000>; + read-only; + }; + + partition@60000 { + label = "devconf"; + reg = <0x060000 0x10000>; + read-only; + }; + + partition@70000 { + compatible = "seama"; + label = "firmware"; + reg = <0x070000 0xf80000>; + }; + + art: partition@ff0000 { + label = "art"; + reg = <0xff0000 0x010000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + phy0: ethernet-phy@0 { + reg = <0>; + phy-mode = "sgmii"; + qca,mib-poll-interval = <500>; + + reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + + qca,ar8327-initvals = < + 0x04 0x00080080 /* PORT0 PAD MODE CTRL */ + 0x10 0x81000080 /* POWER_ON_STRAP */ + 0x50 0xcc35cc35 /* LED_CTRL0 */ + 0x54 0xcb37cb37 /* LED_CTRL1 */ + 0x58 0x00000000 /* LED_CTRL2 */ + 0x5c 0x00f3cf00 /* LED_CTRL3 */ + 0x7c 0x0000007e /* PORT0_STATUS */ + >; + }; +}; + +ð0 { + status = "okay"; + + pll-data = <0x03000101 0x00000101 0x00001919>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; +}; + +&wmac { + status = "okay"; + + qca,no-eeprom; +}; From 2f4b6d0f89f1e6874a6452962d165884fca3cf3b Mon Sep 17 00:00:00 2001 From: Jan Forman Date: Mon, 31 Oct 2022 22:15:56 +0100 Subject: [PATCH 14/88] ath79: Convert calibration data to nvmem For D-link DIR-859 and DIR-869 Replace the mtd-cal-data by an nvmem-cell. Add the PCIe node for the ath10k radio to the devicetree. Thanks to DragonBlue for this patch Signed-off-by: Jan Forman --- .../ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi | 37 ++++++++++++++++++- .../etc/hotplug.d/firmware/10-ath9k-eeprom | 1 - .../etc/hotplug.d/firmware/11-ath10k-caldata | 4 -- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi index 65948ecb222..556ba604a6b 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi +++ b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi @@ -26,6 +26,14 @@ &pcie { status = "okay"; + + wifi@0,0 { + compatible = "qcom,ath10k"; + reg = <0x0000 0 0 0 0>; + + nvmem-cells = <&calibration_ath10k>, <&macaddr_devdata_94>; + nvmem-cell-names = "calibration", "mac-address-ascii"; + }; }; &spi { @@ -57,6 +65,18 @@ label = "devdata"; reg = <0x050000 0x10000>; read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_devdata_94: macaddr@94 { + reg = <0x94 0x11>; + }; + + macaddr_devdata_b0: macaddr@b0 { + reg = <0xb0 0x11>; + }; }; partition@60000 { @@ -71,10 +91,22 @@ reg = <0x070000 0xf80000>; }; - art: partition@ff0000 { + partition@ff0000 { label = "art"; reg = <0xff0000 0x010000>; read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + calibration_ath9k: calibration@1000 { + reg = <0x1000 0x440>; + }; + + calibration_ath10k: calibration@5000 { + reg = <0x5000 0x844>; + }; }; }; }; @@ -114,5 +146,6 @@ &wmac { status = "okay"; - qca,no-eeprom; + nvmem-cells = <&calibration_ath9k>, <&macaddr_devdata_b0>; + nvmem-cell-names = "calibration", "mac-address-ascii"; }; diff --git a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom index 022f5e29477..a57479b87cf 100644 --- a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom +++ b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom @@ -30,7 +30,6 @@ case "$FIRMWARE" in dlink,dir-842-c1|\ dlink,dir-842-c2|\ dlink,dir-842-c3|\ - dlink,dir-859-a1|\ nec,wf1200cr|\ nec,wg1200cr|\ wd,mynet-n600|\ diff --git a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata index 4db311fde0a..f0a3755de91 100644 --- a/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata +++ b/target/linux/ath79/generic/base-files/etc/hotplug.d/firmware/11-ath10k-caldata @@ -68,10 +68,6 @@ case "$FIRMWARE" in caldata_extract "art" 0x5000 0x844 ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary art 0x0) -1) ;; - dlink,dir-859-a1) - caldata_extract "art" 0x5000 0x844 - ath10k_patch_mac $(mtd_get_mac_ascii devdata "wlan5mac") - ;; engenius,ecb1200|\ engenius,ecb1750) caldata_extract "art" 0x5000 0x844 From 8d618a3186e0979bcf4db407cb8dd232200919a8 Mon Sep 17 00:00:00 2001 From: Jan Forman Date: Fri, 28 May 2021 09:45:52 +0200 Subject: [PATCH 15/88] ath79: Add support for D-Link DIR-869-A1 Specifications The D-Link EXO AC1750 (DIR-869) router released in 2016. It is powered by Qualcomm Atheros QCA9563 @ 750 MHz chipset, 64 MB RAM and 16 MB flash. 10/100/1000 Gigabit Ethernet WAN port Four 10/100/1000 Gigabit Ethernet LAN ports Power Button, Reset Button, WPS Button, Mode Switch Flashing 1. Upload factory.bin via D-link web interface (Management/Upgrade). Revert to stock Upload original firmware via OpenWrt sysupgrade interface. Debricking D-Link Recovery GUI (192.168.0.1) Signed-off-by: Jan Forman --- .../ath79/dts/qca9563_dlink_dir-869-a1.dts | 31 +++++++++++++++++++ .../generic/base-files/etc/board.d/02_network | 5 +++ .../etc/uci-defaults/09_fix-checksum | 1 + target/linux/ath79/image/generic.mk | 15 ++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts b/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts new file mode 100644 index 00000000000..eab713ea66a --- /dev/null +++ b/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca9563_dlink_dir-8x9-a1.dtsi" +#include + +/ { + model = "D-Link DIR-869 A1"; + compatible = "dlink,dir-869-a1", "qca,qca9563"; + + aliases { + led-boot = &led_power_orange; + led-failsafe = &led_power_orange; + led-running = &led_power_white; + led-upgrade = &led_power_orange; + }; + + leds { + compatible = "gpio-leds"; + + led_power_orange: power_orange { + label = "orange:power"; + gpios = <&gpio 15 GPIO_ACTIVE_LOW>; + }; + + led_power_white: power_white { + label = "white:power"; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; + }; + }; +}; + diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 1d89f0b86c5..487467cd598 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -291,6 +291,7 @@ ath79_setup_interfaces() dlink,dir-842-c2|\ dlink,dir-842-c3|\ dlink,dir-859-a1|\ + dlink,dir-869-a1|\ engenius,epg5000|\ engenius,esr1200|\ engenius,esr1750|\ @@ -656,6 +657,10 @@ ath79_setup_macs() label_mac=$lan_mac ;; dlink,dir-859-a1|\ + dlink,dir-869-a1) + lan_mac=$(mtd_get_mac_text "devdata" 0xc9) + wan_mac=$(mtd_get_mac_text "devdata" 0x79) + ;; qihoo,c301|\ wd,mynet-n600|\ wd,mynet-n750) diff --git a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum index 4d961f26d29..7f4d6cf428c 100644 --- a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum +++ b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum @@ -22,6 +22,7 @@ dlink,dap-3662-a1) fixwrgg ;; dlink,dir-629-a1|\ +dlink,dir-869-a1|\ qihoo,c301) fix_seama_header ;; diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index fc9ffa6de96..d4a419501c0 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -1150,11 +1150,24 @@ define Device/dlink_dir-859-a1 DEVICE_MODEL := DIR-859 DEVICE_VARIANT := A1 IMAGE_SIZE := 15872k - DEVICE_PACKAGES := kmod-usb2 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct + DEVICE_PACKAGES := kmod-usb2 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct SEAMA_SIGNATURE := wrgac37_dlink.2013gui_dir859 endef TARGET_DEVICES += dlink_dir-859-a1 +define Device/dlink_dir-869-a1 + $(Device/seama) + SOC := qca9563 + DEVICE_VENDOR := D-Link + DEVICE_MODEL := DIR-869 + DEVICE_VARIANT := A1 + IMAGE_SIZE := 15872k + DEVICE_PACKAGES := kmod-usb2 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct + SEAMA_SIGNATURE := wrgac54_dlink.2015_dir869 + SUPPORTED_DEVICES += dir-869-a1 +endef +TARGET_DEVICES += dlink_dir-869-a1 + define Device/elecom_wrc-1750ghbk2-i SOC := qca9563 DEVICE_VENDOR := ELECOM From 25eead21c5ab3367317051fce4ebc3552c49f86f Mon Sep 17 00:00:00 2001 From: Lech Perczak Date: Tue, 13 Sep 2022 23:40:06 +0200 Subject: [PATCH 16/88] ath79: fix 5GHz on QCA9886 variant of ZTE MF286 Recently, a strange variant of ZTE MF286 was discovered, having QCA9886 radio instead of QCA9882 - like MF286A, but having MF286 flash layout and rest of hardware. To support both variants in one image, bind calibration data at offset 0x5000 both as "calibration" and "pre-calibration" nvmem-cells, so ath10k can load caldata for both at runtime. Signed-off-by: Lech Perczak --- target/linux/ath79/dts/qca9563_zte_mf286.dts | 4 ++-- target/linux/ath79/image/nand.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/linux/ath79/dts/qca9563_zte_mf286.dts b/target/linux/ath79/dts/qca9563_zte_mf286.dts index 2e528a6b971..877075c7699 100644 --- a/target/linux/ath79/dts/qca9563_zte_mf286.dts +++ b/target/linux/ath79/dts/qca9563_zte_mf286.dts @@ -119,8 +119,8 @@ }; &wifi_ath10k { - nvmem-cells = <&macaddr_mac_0>, <&cal_caldata_5000>; - nvmem-cell-names = "mac-address", "calibration"; + nvmem-cells = <&macaddr_mac_0>, <&cal_caldata_5000>, <&cal_caldata_5000>; + nvmem-cell-names = "mac-address", "calibration", "pre-calibration"; mac-address-increment = <1>; }; diff --git a/target/linux/ath79/image/nand.mk b/target/linux/ath79/image/nand.mk index d1bd4feb1fe..84a589809f0 100644 --- a/target/linux/ath79/image/nand.mk +++ b/target/linux/ath79/image/nand.mk @@ -426,8 +426,8 @@ TARGET_DEVICES += zte_mf282 define Device/zte_mf286 $(Device/zte_mf28x_common) DEVICE_MODEL := MF286 - DEVICE_PACKAGES += ath10k-firmware-qca988x-ct kmod-usb-net-qmi-wwan \ - kmod-usb-serial-option uqmi + DEVICE_PACKAGES += ath10k-firmware-qca988x-ct ath10k-firmware-qca9888-ct \ + kmod-usb-net-qmi-wwan kmod-usb-serial-option uqmi endef TARGET_DEVICES += zte_mf286 From eab9de0c9c05e1a057e4c9112c4802c7f8fe9a3d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Thu, 18 May 2023 22:51:08 +0200 Subject: [PATCH 17/88] ipq40xx: convert EZVIZ CS-W3-WD1200G-EUP to DSA Convert the repeater to DSA. Signed-off-by: Christian Lamparter --- .../ipq40xx/base-files/etc/board.d/02_network | 1 + .../dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts | 36 +++++++++++++++++++ target/linux/ipq40xx/image/generic.mk | 3 +- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/target/linux/ipq40xx/base-files/etc/board.d/02_network b/target/linux/ipq40xx/base-files/etc/board.d/02_network index cb318d36a30..28648c0db99 100644 --- a/target/linux/ipq40xx/base-files/etc/board.d/02_network +++ b/target/linux/ipq40xx/base-files/etc/board.d/02_network @@ -82,6 +82,7 @@ ipq40xx_setup_interfaces() ucidef_set_interface_lan "sw-eth1 sw-eth2" ;; aruba,ap-303h|\ + ezviz,cs-w3-wd1200g-eup|\ netgear,rbr50|\ netgear,rbs50|\ netgear,srr60|\ diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts index dea5c2dc36d..22a48c12c44 100644 --- a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts +++ b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4018-cs-w3-wd1200g-eup.dts @@ -239,6 +239,42 @@ status = "okay"; }; +&gmac { + status = "okay"; + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; +}; + +&switch { + status = "okay"; +}; + +&swport2 { + status = "okay"; + label = "lan3"; +}; + +&swport3 { + status = "okay"; + label = "lan2"; +}; + +&swport4 { + status = "okay"; + label = "lan1"; +}; + +&swport5 { + status = "okay"; + label = "wan"; + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; +}; + +ðphy0 { + status = "disabled"; +}; + &wifi0 { status = "okay"; qcom,ath10k-calibration-variant = "ezviz-cs-w3-wd1200g-eup"; diff --git a/target/linux/ipq40xx/image/generic.mk b/target/linux/ipq40xx/image/generic.mk index c8b8ec936b4..59bdd042962 100644 --- a/target/linux/ipq40xx/image/generic.mk +++ b/target/linux/ipq40xx/image/generic.mk @@ -555,8 +555,7 @@ define Device/ezviz_cs-w3-wd1200g-eup DEVICE_COMPAT_MESSAGE := uboot's bootcmd has to be updated (see wiki). \ Upgrade via sysupgrade mechanism is not possible. endef -# Missing DSA Setup -#TARGET_DEVICES += ezviz_cs-w3-wd1200g-eup +TARGET_DEVICES += ezviz_cs-w3-wd1200g-eup define Device/glinet_gl-a1300 $(call Device/FitImage) From 4071398b13aeee873cb5a48b00b6c90074763d5f Mon Sep 17 00:00:00 2001 From: Sven Roederer Date: Thu, 11 May 2023 12:42:12 +0200 Subject: [PATCH 18/88] build: escape whitespaces in VERSION_DIST for Netgear images Prevents subshell commands from failing to parse options when having defined a whitespace in the VERSION_DIST. As the called resulting images unlikely will handle whitespace correctly, we replace them by "-". Signed-off-by: Sven Roederer --- include/image-commands.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/image-commands.mk b/include/image-commands.mk index 0c13f30fef6..6c385b85e8c 100644 --- a/include/image-commands.mk +++ b/include/image-commands.mk @@ -410,7 +410,7 @@ endef define Build/netgear-dni $(STAGING_DIR_HOST)/bin/mkdniimg \ - -B $(NETGEAR_BOARD_ID) -v $(VERSION_DIST).$(firstword $(subst -, ,$(REVISION))) \ + -B $(NETGEAR_BOARD_ID) -v $(shell cat $(VERSION_DIST)| sed -e 's/[[:space:]]/-/g').$(firstword $(subst -, ,$(REVISION))) \ $(if $(NETGEAR_HW_ID),-H $(NETGEAR_HW_ID)) \ -r "$(1)" \ -i $@ -o $@.new @@ -423,7 +423,7 @@ define Build/netgear-encrypted-factory --output-file $@ \ --model $(NETGEAR_ENC_MODEL) \ --region $(NETGEAR_ENC_REGION) \ - --version V1.0.0.0.$(VERSION_DIST).$(firstword $(subst -, ,$(REVISION))) \ + --version V1.0.0.0.$(shell cat $(VERSION_DIST)| sed -e 's/[[:space:]]/-/g').$(firstword $(subst -, ,$(REVISION))) \ --encryption-block-size 0x20000 \ --openssl-bin "$(STAGING_DIR_HOST)/bin/openssl" \ --key 6865392d342b4d212964363d6d7e7765312c7132613364316e26322a5a5e2538 \ From 3f99b2b3f7e4567e331fce35c3d27b65c34ea651 Mon Sep 17 00:00:00 2001 From: Tiago Gaspar Date: Wed, 12 Apr 2023 13:53:33 +0100 Subject: [PATCH 19/88] kernel: net: add support for kernel tls Add ktls (Kernel TLS) kmods to enable TLS support in kernel (allowing TLS offload when the network card supports it) Signed-off-by: Tiago Gaspar (added disabled symbols) Signed-off-by: Christian Lamparter --- package/kernel/linux/modules/netsupport.mk | 19 +++++++++++++++++++ target/linux/generic/config-5.15 | 2 ++ 2 files changed, 21 insertions(+) diff --git a/package/kernel/linux/modules/netsupport.mk b/package/kernel/linux/modules/netsupport.mk index 4653b825650..b7392898092 100644 --- a/package/kernel/linux/modules/netsupport.mk +++ b/package/kernel/linux/modules/netsupport.mk @@ -46,6 +46,7 @@ define KernelPackage/bonding SUBMENU:=$(NETWORK_SUPPORT_MENU) TITLE:=Ethernet bonding driver KCONFIG:=CONFIG_BONDING + DEPENDS:=PACKAGE_kmod-tls:kmod-tls FILES:=$(LINUX_DIR)/drivers/net/bonding/bonding.ko AUTOLOAD:=$(call AutoLoad,40,bonding) MODPARAMS.bonding:=max_bonds=0 @@ -1042,6 +1043,24 @@ endef $(eval $(call KernelPackage,tcp-bbr)) +define KernelPackage/tls + SUBMENU:=$(NETWORK_SUPPORT_MENU) + TITLE:=In-kernel TLS Support with HW Offload + KCONFIG:=CONFIG_TLS \ + CONFIG_TLS_DEVICE=y + FILES:=$(LINUX_DIR)/net/tls/tls.ko + AUTOLOAD:=$(call AutoProbe,tls) +endef + +define KernelPackage/tls/description + Kernel module for in-kernel TLS protocol support and hw offload + (to supported interfaces). + This allows symmetric encryption handling of the TLS protocol to + be done in-kernel and it's HW offload when available. +endef + +$(eval $(call KernelPackage,tls)) + define KernelPackage/tcp-hybla SUBMENU:=$(NETWORK_SUPPORT_MENU) diff --git a/target/linux/generic/config-5.15 b/target/linux/generic/config-5.15 index 4c35281b540..f13af8ba268 100644 --- a/target/linux/generic/config-5.15 +++ b/target/linux/generic/config-5.15 @@ -6571,6 +6571,8 @@ CONFIG_TINY_RCU=y # CONFIG_TI_TSC2046 is not set # CONFIG_TLAN is not set # CONFIG_TLS is not set +# CONFIG_TLS_DEVICE is not set +# CONFIG_TLS_TOE is not set # CONFIG_TMD_HERMES is not set # CONFIG_TMP006 is not set # CONFIG_TMP007 is not set From 2afabe677922c5f3a3234985c5a2d7bd2140f6f5 Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 12 Apr 2023 11:17:01 +0200 Subject: [PATCH 20/88] ls-rcw: Bump to lf-6.1.1-1.0.0 and switch to github The default location of ls-rcw has been changed from codeuaurora to github. The reason is that the old codeaurora source no longer resolves. Also use the latest tag for Layerscape Linux Development POC from NXP. Tested on: * NXP FRWY-LS1012A * NXP LS1046A-RDB Signed-off-by: Wojciech Dubowik (reset PKG_RELEASE, Mention that previous codeaurora source is no longer available) Signed-off-by: Christian Lamparter --- package/firmware/layerscape/ls-rcw/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/firmware/layerscape/ls-rcw/Makefile b/package/firmware/layerscape/ls-rcw/Makefile index 10a6593835f..1569f1042e7 100644 --- a/package/firmware/layerscape/ls-rcw/Makefile +++ b/package/firmware/layerscape/ls-rcw/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ls-rcw -PKG_VERSION:=21.08 -PKG_RELEASE:=4 +PKG_VERSION:=lf-6.1.1-1.0.0 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/rcw -PKG_SOURCE_VERSION:=LSDK-21.08 -PKG_MIRROR_HASH:=5b6ae3937d8c64f24c2d09d21e892e60b9f60de3573ca64ef19fa71072e6e346 +PKG_SOURCE_URL:=https://github.com/nxp-qoriq/rcw +PKG_SOURCE_VERSION:=lf-6.1.1-1.0.0 +PKG_MIRROR_HASH:=3127285549a0a7dd3cded20c2fbfb67b06943faa8dab529f61936dc1bea177db PKG_FLAGS:=nonshared From 69c430aa2c6505772aa331f6c5c10362565af5e3 Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 12 Apr 2023 11:20:37 +0200 Subject: [PATCH 21/88] uboot-layerscape: Bump to lf-6.1.1-1.0.0 and switch to github The default location of uboot-layerscape has been changed from codeuaurora to github. Also use the latest tag for Layerscape Linux Development POC from NXP. Tested on: * NXP FRWY-LS1012A * NXP LS1028A-RDB * NXP LS1046A-RDB V2: Remove ls1028ardb specifix fixups not needed with new uboot Signed-off-by: Wojciech Dubowik (reset PKG_RELEASE) Signed-off-by: Christian Lamparter --- package/boot/uboot-layerscape/Makefile | 10 +++--- ...rmware-get-random-when-no-kaslr-seed.patch | 33 ------------------- ...le-gic-initialization-for-ls1028ardb.patch | 8 ----- 3 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 package/boot/uboot-layerscape/patches/0003-avoid-calling-sec-firmware-get-random-when-no-kaslr-seed.patch delete mode 100644 package/boot/uboot-layerscape/patches/0004-disable-gic-initialization-for-ls1028ardb.patch diff --git a/package/boot/uboot-layerscape/Makefile b/package/boot/uboot-layerscape/Makefile index 044a788d6ef..e255debfeb8 100644 --- a/package/boot/uboot-layerscape/Makefile +++ b/package/boot/uboot-layerscape/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=uboot-layerscape -PKG_VERSION:=21.08 -PKG_RELEASE:=7 +PKG_VERSION:=lf-6.1.1-1.0.0 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/u-boot -PKG_SOURCE_VERSION:=LSDK-21.08 -PKG_MIRROR_HASH:=54909a98bdcc26c7f9b35b35fcae09b977ecbf044be7bffa6dad9306c47cccf6 +PKG_SOURCE_URL:=https://github.com/nxp-qoriq/u-boot +PKG_SOURCE_VERSION:=lf-6.1.1-1.0.0 +PKG_MIRROR_HASH:=f4a3a262fd8923af72dede0348a512c05b756e3925279553eaf1c6667b186fb4 include $(INCLUDE_DIR)/u-boot.mk include $(INCLUDE_DIR)/package.mk diff --git a/package/boot/uboot-layerscape/patches/0003-avoid-calling-sec-firmware-get-random-when-no-kaslr-seed.patch b/package/boot/uboot-layerscape/patches/0003-avoid-calling-sec-firmware-get-random-when-no-kaslr-seed.patch deleted file mode 100644 index 681ec90f1ce..00000000000 --- a/package/boot/uboot-layerscape/patches/0003-avoid-calling-sec-firmware-get-random-when-no-kaslr-seed.patch +++ /dev/null @@ -1,33 +0,0 @@ -Index: uboot-layerscape-lf-6.1.1-1.0.0/arch/arm/cpu/armv8/sec_firmware.c -=================================================================== ---- uboot-layerscape-lf-6.1.1-1.0.0.orig/arch/arm/cpu/armv8/sec_firmware.c -+++ uboot-layerscape-lf-6.1.1-1.0.0/arch/arm/cpu/armv8/sec_firmware.c -@@ -473,12 +473,6 @@ int fdt_fixup_kaslr(void *fdt) - return 0; - } - -- ret = sec_firmware_get_random(rand, 8); -- if (ret < 0) { -- printf("WARNING: No random number to set kaslr-seed\n"); -- return 0; -- } -- - err = fdt_check_header(fdt); - if (err < 0) { - printf("fdt_chosen: %s\n", fdt_strerror(err)); -@@ -490,6 +484,15 @@ int fdt_fixup_kaslr(void *fdt) - if (nodeoffset < 0) - return 0; - -+ if (fdt_find_or_add_subnode(fdt, nodeoffset, "kaslr-seed")) -+ return 0; -+ -+ ret = sec_firmware_get_random(rand, 8); -+ if (ret < 0) { -+ printf("WARNING: No random number to set kaslr-seed\n"); -+ return 0; -+ } -+ - err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand, - sizeof(rand)); - if (err < 0) { diff --git a/package/boot/uboot-layerscape/patches/0004-disable-gic-initialization-for-ls1028ardb.patch b/package/boot/uboot-layerscape/patches/0004-disable-gic-initialization-for-ls1028ardb.patch deleted file mode 100644 index 72011ae3a9b..00000000000 --- a/package/boot/uboot-layerscape/patches/0004-disable-gic-initialization-for-ls1028ardb.patch +++ /dev/null @@ -1,8 +0,0 @@ ---- a/configs/ls1028ardb_tfa_defconfig -+++ b/configs/ls1028ardb_tfa_defconfig -@@ -1,5 +1,4 @@ - CONFIG_ARM=y --CONFIG_GIC_V3_ITS=y - CONFIG_TARGET_LS1028ARDB=y - CONFIG_TFABOOT=y - CONFIG_SYS_MALLOC_F_LEN=0x6000 From 6b5496aef1ad3cb79b0cf38122990fdc7d21cf27 Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 12 Apr 2023 11:22:05 +0200 Subject: [PATCH 22/88] fman-ucode: Bump to lf-6.1.1-1.0.0 and switch to github The default location of fman-ucode has been changed from codeuaurora to github. Also use the latest tag for Layerscape Linux Development POC from NXP. Tested on: * NXP LS1046A-RDB Signed-off-by: Wojciech Dubowik (reset PKG_RELEASE) Signed-off-by: Christian Lamparter --- package/firmware/layerscape/fman-ucode/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/firmware/layerscape/fman-ucode/Makefile b/package/firmware/layerscape/fman-ucode/Makefile index 83d9313ce55..fdd46598512 100644 --- a/package/firmware/layerscape/fman-ucode/Makefile +++ b/package/firmware/layerscape/fman-ucode/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=fman-ucode -PKG_VERSION:=21.08 -PKG_RELEASE:=3 +PKG_VERSION:=lf-6.1.1-1.0.0 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/NXP/qoriq-fm-ucode.git -PKG_SOURCE_VERSION:=LSDK-21.08 -PKG_MIRROR_HASH:=fc3c249c20b823e9554764f875c3d600b05f2e3659262d79f081e6765e891c96 +PKG_SOURCE_URL:=https://github.com/nxp-qoriq/qoriq-fm-ucode +PKG_SOURCE_VERSION:=lf-6.1.1-1.0.0 +PKG_MIRROR_HASH:=3614200837945460374570a48822a3efb96a64b93724e7f973e61008baeccf3a PKG_FLAGS:=nonshared From f6eae517aed833b4c9ae377a5b0e385f6d1330c0 Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 12 Apr 2023 11:33:37 +0200 Subject: [PATCH 23/88] ppfe-firmware: Bump to lf-6.1.1-1.0.0 and switch to github The default location of ppfe-firmware has been changed from codeuaurora to github. Also use the latest tag for Layerscape Linux Development POC from NXP. Tested on: * NXP FRWY-LS1012A Signed-off-by: Wojciech Dubowik (reset PKG_RELEASE) Signed-off-by: Christian Lamparter --- package/firmware/layerscape/ppfe-firmware/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/firmware/layerscape/ppfe-firmware/Makefile b/package/firmware/layerscape/ppfe-firmware/Makefile index 094d8fecc8d..86f6194125a 100644 --- a/package/firmware/layerscape/ppfe-firmware/Makefile +++ b/package/firmware/layerscape/ppfe-firmware/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ppfe -PKG_VERSION:=21.08 -PKG_RELEASE:=3 +PKG_VERSION:=lf-6.1.1-1.0.0 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://github.com/NXP/qoriq-engine-pfe-bin.git -PKG_SOURCE_VERSION:=LSDK-21.08 -PKG_MIRROR_HASH:=f2591b12bc02dbfcf113dcb79cce2fc703d8492b7309ad75b3c4915b76966c64 +PKG_SOURCE_URL:=https://github.com/nxp-qoriq/qoriq-engine-pfe-bin +PKG_SOURCE_VERSION:=lf-6.1.1-1.0.0 +PKG_MIRROR_HASH:=eb1e3efe08980e70594060c84c1620a1dde53e00e96bae63d15dceb236c0bfa8 PKG_FLAGS:=nonshared From 5e91b4507c0010970482099464b44a5404835caa Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 19 Apr 2023 08:41:18 +0200 Subject: [PATCH 24/88] tfa-layerscape: Change to github and use the latest tag The default location of tfa-layerscape has been changed from codeuaurora to github. Also use the latest tag for Layerscape Linux Development POC from NXP. v2: * restored ls1021a-afrdm board * added platform defines to fiptool so ls-ddr-phy can be built Signed-off-by: Wojciech Dubowik (reset PKG_RELEASE) Signed-off-by: Christian Lamparter --- package/boot/tfa-layerscape/Makefile | 17 +- .../patches/001-fiptool-hostbuild-fixes.patch | 37 ++- ...ix-create_pbl-and-byte_swap-host-bui.patch | 16 +- ...plat-nxp-restore-ls1012afrdm-support.patch | 232 ++++++++++++++++++ 4 files changed, 265 insertions(+), 37 deletions(-) create mode 100644 package/boot/tfa-layerscape/patches/004-plat-nxp-restore-ls1012afrdm-support.patch diff --git a/package/boot/tfa-layerscape/Makefile b/package/boot/tfa-layerscape/Makefile index 2deea4d83f6..c1ef217f479 100644 --- a/package/boot/tfa-layerscape/Makefile +++ b/package/boot/tfa-layerscape/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=tfa-layerscape -PKG_VERSION:=21.08 -PKG_RELEASE:=6 +PKG_VERSION:=lf-6.1.1-1.0.0 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/atf -PKG_SOURCE_VERSION:=LSDK-21.08 -PKG_MIRROR_HASH:=893f2d28a77dcc9d4413a619b4719ca5f1f4dc78dd824a8488e7d543e66bcf95 +PKG_SOURCE_URL:=https://github.com/nxp-qoriq/atf +PKG_SOURCE_VERSION:=lf-6.1.1-1.0.0 +PKG_MIRROR_HASH:=c0e3c7d0cc9ee5f9ae68cd705ce7f07f714c4fe3fd4a5a79de5699e7865b759f PKG_BUILD_DEPENDS:=tfa-layerscape/host include $(INCLUDE_DIR)/host-build.mk @@ -25,18 +25,19 @@ HOST_CFLAGS += -Wall -Werror -pedantic -std=c99 define Host/Compile $(MAKE) -C \ $(HOST_BUILD_DIR)/tools/fiptool \ + PLAT_FIPTOOL_HELPER_MK="$(HOST_BUILD_DIR)/tools/nxp/plat_fiptool/plat_fiptool.mk" CFLAGS="$(HOST_CFLAGS)" \ LDFLAGS="$(HOST_LDFLAGS)" \ HOSTCCFLAGS="$(HOST_CFLAGS)" $(MAKE) -C \ - $(HOST_BUILD_DIR)/tools/nxp \ + $(HOST_BUILD_DIR)/tools/nxp/create_pbl \ CFLAGS="$(HOST_CFLAGS)" endef define Host/Install $(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/fiptool/fiptool $(STAGING_DIR_HOST)/bin/fiptool-layerscape - $(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/nxp/create_pbl $(STAGING_DIR_HOST)/bin/tfa-create-pbl - $(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/nxp/byte_swap $(STAGING_DIR_HOST)/bin/tfa-byte-swap + $(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/nxp/create_pbl/create_pbl $(STAGING_DIR_HOST)/bin/tfa-create-pbl + $(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/nxp/create_pbl/byte_swap $(STAGING_DIR_HOST)/bin/tfa-byte-swap endef define Trusted-Firmware-A/Default diff --git a/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch index 4b74048754f..8e7375cfa22 100644 --- a/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch +++ b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch @@ -1,6 +1,6 @@ --- a/Makefile +++ b/Makefile -@@ -801,10 +801,6 @@ CRTTOOL ?= ${CRTTOOLPATH}/cert_create$ +@@ -914,10 +914,6 @@ CRTTOOL ?= ${CRTTOOLPATH}/cert_create$ ENCTOOLPATH ?= tools/encrypt_fw ENCTOOL ?= ${ENCTOOLPATH}/encrypt_fw${BIN_EXT} @@ -11,7 +11,7 @@ # Variables for use with sptool SPTOOLPATH ?= tools/sptool SPTOOL ?= ${SPTOOLPATH}/sptool${BIN_EXT} -@@ -1160,13 +1156,6 @@ endif +@@ -1322,13 +1318,6 @@ endif clean: @echo " CLEAN" $(call SHELL_REMOVE_DIR,${BUILD_PLAT}) @@ -25,7 +25,7 @@ ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} clean ${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean -@@ -1175,13 +1164,6 @@ realclean distclean: +@@ -1337,13 +1326,6 @@ realclean distclean: @echo " REALCLEAN" $(call SHELL_REMOVE_DIR,${BUILD_BASE}) $(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*) @@ -39,37 +39,33 @@ ${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean -@@ -1238,7 +1220,7 @@ certificates: ${CRT_DEPS} ${CRTTOOL} +@@ -1400,7 +1382,7 @@ certificates: ${CRT_DEPS} ${CRTTOOL} @${ECHO_BLANK_LINE} endif -${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL} +${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} - ${Q}${FIPTOOL} create ${FIP_ARGS} $@ - ${Q}${FIPTOOL} info $@ - @${ECHO_BLANK_LINE} -@@ -1254,7 +1236,7 @@ fwu_certificates: ${FWU_CRT_DEPS} ${CRTT + $(eval ${CHECK_FIP_CMD}) + ${Q}${FIPTOOL} create ${FIP_ARGS} $@ + ${Q}${FIPTOOL} info $@ +@@ -1417,7 +1399,7 @@ fwu_certificates: ${FWU_CRT_DEPS} ${CRTT @${ECHO_BLANK_LINE} endif -${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL} +${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} - ${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@ - ${Q}${FIPTOOL} info $@ - @${ECHO_BLANK_LINE} -@@ -1279,24 +1261,10 @@ ${BUILD_PLAT}/${DDR_FIP_NAME}: ${DDR_FIP + $(eval ${CHECK_FWU_FIP_CMD}) + ${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@ + ${Q}${FIPTOOL} info $@ +@@ -1425,19 +1407,9 @@ ${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP @echo "Built $@ successfully" @${ECHO_BLANK_LINE} -fiptool: ${FIPTOOL} fip: ${BUILD_PLAT}/${FIP_NAME} fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME} - fip_ddr: ${BUILD_PLAT}/${DDR_FIP_NAME} --.PHONY: ${FIPTOOL} --${FIPTOOL}: -- @${ECHO_BLANK_LINE} -- @echo "Building $@" +-${FIPTOOL}: FORCE -ifdef UNIX_MK - ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" FIPTOOL=${FIPTOOL} --no-print-directory -C ${FIPTOOLPATH} -else @@ -77,14 +73,13 @@ -# to pass the gnumake flags to nmake. - ${Q}set MAKEFLAGS= && ${MSVC_NMAKE} /nologo /f ${FIPTOOLPATH}/Makefile.msvc FIPTOOLPATH=$(subst /,\,$(FIPTOOLPATH)) FIPTOOL=$(subst /,\,$(FIPTOOL)) -endif -- @${ECHO_BLANK_LINE} - sptool: ${SPTOOL} - .PHONY: ${SPTOOL} - ${SPTOOL}: + ${SPTOOL}: FORCE + ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" SPTOOL=${SPTOOL} --no-print-directory -C ${SPTOOLPATH} --- a/tools/fiptool/Makefile +++ b/tools/fiptool/Makefile -@@ -38,7 +38,7 @@ all: ${PROJECT} +@@ -48,7 +48,7 @@ all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" diff --git a/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch b/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch index 167549d55b5..73c5c66cae1 100644 --- a/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch +++ b/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch @@ -11,14 +11,14 @@ Signed-off-by: Biwen Li tools/nxp/pbl_ch3.mk | 5 ----- 2 files changed, 8 deletions(-) ---- a/tools/nxp/pbl_ch2.mk -+++ b/tools/nxp/pbl_ch2.mk +--- a/tools/nxp/create_pbl/pbl_ch2.mk ++++ b/tools/nxp/create_pbl/pbl_ch2.mk @@ -19,8 +19,6 @@ ifeq ($(RCW),"") else # Generate header for bl2.bin $(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE} - # Compile create_pbl tool -- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};\ +- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};\ # Add bl2.bin to RCW ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ;\ @@ -26,18 +26,18 @@ Signed-off-by: Biwen Li ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}" else # -a option appends the image for Chassis 3 devices in case of non secure boot -- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH}; +- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH}; ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \ -o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ; # Swapping of RCW is required for QSPi Chassis 2 devices ---- a/tools/nxp/pbl_ch3.mk -+++ b/tools/nxp/pbl_ch3.mk +--- a/tools/nxp/create_pbl/pbl_ch3.mk ++++ b/tools/nxp/create_pbl/pbl_ch3.mk @@ -26,9 +26,6 @@ else # Generate header for bl2.bin $(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE} - # Compile create_pbl tool -- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};\ +- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH};\ - # Add Block Copy command for bl2.bin to RCW ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\ @@ -46,7 +46,7 @@ Signed-off-by: Biwen Li ifeq ($(RCW),"") ${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}" else -- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH}; +- ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${CREATE_PBL_TOOL_PATH}; - # Add Block Copy command and populate boot loc ptrfor bl2.bin to RCW ${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \ diff --git a/package/boot/tfa-layerscape/patches/004-plat-nxp-restore-ls1012afrdm-support.patch b/package/boot/tfa-layerscape/patches/004-plat-nxp-restore-ls1012afrdm-support.patch new file mode 100644 index 00000000000..fc9504f82fd --- /dev/null +++ b/package/boot/tfa-layerscape/patches/004-plat-nxp-restore-ls1012afrdm-support.patch @@ -0,0 +1,232 @@ +From 8c6a66feb721f18c930c7df03d1fbb7304107af6 Mon Sep 17 00:00:00 2001 +From: Wojciech Dubowik +Date: Thu, 20 Apr 2023 16:21:25 +0200 +Subject: [PATCH] tfa-layerscape: Restore ls1012afrdm support + +Signed-off-by: Wojciech Dubowik +--- + plat/nxp/soc-ls1012a/ls1012afrdm/ddr_init.c | 34 +++++++ + plat/nxp/soc-ls1012a/ls1012afrdm/plat_def.h | 92 +++++++++++++++++++ + plat/nxp/soc-ls1012a/ls1012afrdm/platform.mk | 25 +++++ + .../soc-ls1012a/ls1012afrdm/platform_def.h | 13 +++ + plat/nxp/soc-ls1012a/ls1012afrdm/policy.h | 16 ++++ + 5 files changed, 180 insertions(+) + create mode 100644 plat/nxp/soc-ls1012a/ls1012afrdm/ddr_init.c + create mode 100644 plat/nxp/soc-ls1012a/ls1012afrdm/plat_def.h + create mode 100644 plat/nxp/soc-ls1012a/ls1012afrdm/platform.mk + create mode 100644 plat/nxp/soc-ls1012a/ls1012afrdm/platform_def.h + create mode 100644 plat/nxp/soc-ls1012a/ls1012afrdm/policy.h + +diff --git a/plat/nxp/soc-ls1012a/ls1012afrdm/ddr_init.c b/plat/nxp/soc-ls1012a/ls1012afrdm/ddr_init.c +new file mode 100644 +index 000000000..8cb518540 +--- /dev/null ++++ b/plat/nxp/soc-ls1012a/ls1012afrdm/ddr_init.c +@@ -0,0 +1,34 @@ ++/* ++ * Copyright 2018-2022 NXP ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#include ++#include ++ ++#include ++ ++long long init_ddr(void) ++{ ++ static const struct fsl_mmdc_info mparam = { ++ .mdctl = U(0x04180000), ++ .mdpdc = U(0x00030035), ++ .mdotc = U(0x12554000), ++ .mdcfg0 = U(0xbabf7954), ++ .mdcfg1 = U(0xdb328f64), ++ .mdcfg2 = U(0x01ff00db), ++ .mdmisc = U(0x00001680), ++ .mdref = U(0x0f3c8000), ++ .mdrwd = U(0x00002000), ++ .mdor = U(0x00bf1023), ++ .mdasp = U(0x0000003f), ++ .mpodtctrl = U(0x0000022a), ++ .mpzqhwctrl = U(0xa1390003), ++ }; ++ ++ mmdc_init(&mparam, NXP_DDR_ADDR); ++ NOTICE("DDR Init Done\n"); ++ ++ return NXP_DRAM0_SIZE; ++} +diff --git a/plat/nxp/soc-ls1012a/ls1012afrdm/plat_def.h b/plat/nxp/soc-ls1012a/ls1012afrdm/plat_def.h +new file mode 100644 +index 000000000..eb745a0a3 +--- /dev/null ++++ b/plat/nxp/soc-ls1012a/ls1012afrdm/plat_def.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright 2022 NXP ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef PLAT_DEF_H ++#define PLAT_DEF_H ++ ++#include ++/* ++ * Required without TBBR. ++ * To include the defines for DDR PHY ++ * Images. ++ */ ++#include ++ ++#include ++#include ++ ++/* DDR Related definition */ ++#define PLAT_DEF_DRAM0_SIZE 0x20000000 /* 512 MB */ ++ ++#define NXP_SYSCLK_FREQ 125000000 ++#define NXP_DDRCLK_FREQ 100000000 ++ ++/* UART related definition */ ++#define NXP_CONSOLE_ADDR NXP_UART_ADDR ++#define NXP_CONSOLE_BAUDRATE 115200 ++ ++#define NXP_SPD_EEPROM0 0x51 ++ ++/* Size of cacheable stacks */ ++#if defined(IMAGE_BL2) ++#if defined(TRUSTED_BOARD_BOOT) ++#define PLATFORM_STACK_SIZE 0x2000 ++#else ++#define PLATFORM_STACK_SIZE 0x1000 ++#endif ++#elif defined(IMAGE_BL31) ++#define PLATFORM_STACK_SIZE 0x1000 ++#endif ++ ++/* SD block buffer */ ++#define NXP_SD_BLOCK_BUF_SIZE (0x00100000) ++#define NXP_SD_BLOCK_BUF_ADDR ULL(0x80000000) ++ ++#define BL2_LIMIT (NXP_OCRAM_ADDR + NXP_OCRAM_SIZE) ++ ++/* IO defines as needed by IO driver framework */ ++#define MAX_IO_DEVICES 3 ++#define MAX_IO_BLOCK_DEVICES 1 ++#define MAX_IO_HANDLES 4 ++ ++/* ++ * FIP image defines - Offset at which FIP Image would be present ++ * Image would include Bl31 , Bl33 and Bl32 (optional) ++ */ ++#ifdef POLICY_FUSE_PROVISION ++#define MAX_FIP_DEVICES 2 ++#endif ++ ++#ifndef MAX_FIP_DEVICES ++#define MAX_FIP_DEVICES 1 ++#endif ++ ++#ifdef PLAT_FIP_OFFSET ++#undef PLAT_FIP_OFFSET ++#endif ++#ifdef PLAT_FIP_MAX_SIZE ++#undef PLAT_FIP_MAX_SIZE ++#endif ++#define PLAT_FIP_OFFSET 0x60000 ++#define PLAT_FIP_MAX_SIZE 0x170000 ++ ++/* ++ * ID of the secure physical generic timer interrupt used by the BL32. ++ */ ++#define BL32_IRQ_SEC_PHY_TIMER 29 ++ ++/* ++ * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3 ++ * terminology. On a GICv2 system or mode, the lists will be merged and treated ++ * as Group 0 interrupts. ++ */ ++#define PLAT_LS_G1S_IRQ_PROPS(grp) \ ++ INTR_PROP_DESC(BL32_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ ++ GIC_INTR_CFG_LEVEL) ++ ++#define PLAT_LS_G0_IRQ_PROPS(grp) ++ ++#endif +diff --git a/plat/nxp/soc-ls1012a/ls1012afrdm/platform.mk b/plat/nxp/soc-ls1012a/ls1012afrdm/platform.mk +new file mode 100644 +index 000000000..270e92420 +--- /dev/null ++++ b/plat/nxp/soc-ls1012a/ls1012afrdm/platform.mk +@@ -0,0 +1,25 @@ ++# ++# Copyright 2018-2022 NXP ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++ ++# board-specific build parameters ++BOOT_MODE := qspi ++BOARD := ls1012afrdm ++ ++# DDR Compilation Configs ++DDRC_NUM_CS := 1 ++ ++# On-Board Flash Details ++QSPI_FLASH_SZ := 0x4000000 ++ ++BL2_SOURCES += ${BOARD_PATH}/ddr_init.c ++ ++SUPPORTED_BOOT_MODE := qspi ++ ++# Adding platform board build info ++include plat/nxp/common/plat_make_helper/plat_common_def.mk ++ ++# Adding SoC build info ++include plat/nxp/soc-ls1012a/soc.mk +diff --git a/plat/nxp/soc-ls1012a/ls1012afrdm/platform_def.h b/plat/nxp/soc-ls1012a/ls1012afrdm/platform_def.h +new file mode 100644 +index 000000000..7daf1c02c +--- /dev/null ++++ b/plat/nxp/soc-ls1012a/ls1012afrdm/platform_def.h +@@ -0,0 +1,13 @@ ++/* ++ * Copyright 2022 NXP ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef PLATFORM_DEF_H ++#define PLATFORM_DEF_H ++ ++#include ++#include ++ ++#endif /* PLATFORM_DEF_H */ +diff --git a/plat/nxp/soc-ls1012a/ls1012afrdm/policy.h b/plat/nxp/soc-ls1012a/ls1012afrdm/policy.h +new file mode 100644 +index 000000000..a782d01c7 +--- /dev/null ++++ b/plat/nxp/soc-ls1012a/ls1012afrdm/policy.h +@@ -0,0 +1,16 @@ ++/* ++ * Copyright 2018-2022 NXP ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++#ifndef POLICY_H ++#define POLICY_H ++ ++/* ++ * Set this to 0x0 to leave the default SMMU page size in sACR ++ * Set this to 0x1 to change the SMMU page size to 64K ++ */ ++#define POLICY_SMMU_PAGESZ_64K 0x0 ++ ++#endif /* POLICY_H */ +-- +2.34.1 + From 7365e6b00a7ab823467b7d92d4f3f0bdbe271f35 Mon Sep 17 00:00:00 2001 From: Aleksander Jan Bajkowski Date: Sun, 14 May 2023 11:43:57 +0200 Subject: [PATCH 25/88] kernel: remove obsolete kernel version switches This removes unneeded kernel version switches from the targets after kernel 5.10 has been dropped. Signed-off-by: Aleksander Jan Bajkowski --- .../ath25/files/drivers/net/phy/mvswitch.c | 8 --- .../net/ethernet/atheros/ag71xx/ag71xx_main.c | 4 -- .../generic/files/block/partitions/fit.c | 4 -- .../generic/files/drivers/net/phy/ar8216.c | 16 ----- .../files/drivers/net/phy/b53/b53_common.c | 6 -- .../files/drivers/net/dsa/qca/qca8k-ipq4019.c | 58 ------------------- .../ipq40xx/files/drivers/net/phy/qca807x.c | 19 ------ .../files/drivers/net/ethernet/ralink/mdio.c | 9 --- .../drivers/net/ethernet/ralink/mdio_rt2880.c | 8 --- .../drivers/net/ethernet/ralink/mtk_eth_soc.c | 4 -- .../drivers/net/ethernet/ralink/soc_mt7620.c | 8 --- .../files/drivers/pinctrl/pinctrl-aw9523.c | 10 ---- 12 files changed, 154 deletions(-) diff --git a/target/linux/ath25/files/drivers/net/phy/mvswitch.c b/target/linux/ath25/files/drivers/net/phy/mvswitch.c index e3550d55baf..29f2f9f0e82 100644 --- a/target/linux/ath25/files/drivers/net/phy/mvswitch.c +++ b/target/linux/ath25/files/drivers/net/phy/mvswitch.c @@ -312,11 +312,7 @@ mvswitch_config_init(struct phy_device *pdev) priv->orig_features = dev->features; #ifdef HEADER_MODE -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags |= IFF_NO_IP_ALIGN; -#else - dev->priv_flags |= IFF_NO_IP_ALIGN; -#endif dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; #else dev->features |= NETIF_F_HW_VLAN_CTAG_RX; @@ -376,11 +372,7 @@ mvswitch_detach(struct phy_device *pdev) dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; dev->features = priv->orig_features; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; -#else - dev->priv_flags &= ~IFF_NO_IP_ALIGN; -#endif } static void diff --git a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c index d553c62401a..06ebbd8ea38 100644 --- a/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c +++ b/target/linux/ath79/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c @@ -1352,11 +1352,7 @@ static int ag71xx_rx_packets(struct ag71xx *ag, int limit) dev->stats.rx_packets++; dev->stats.rx_bytes += pktlen; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - skb = build_skb(ring->buf[i].rx_buf, ag71xx_buffer_size(ag)); -#else skb = napi_build_skb(ring->buf[i].rx_buf, ag71xx_buffer_size(ag)); -#endif if (!skb) { skb_free_frag(ring->buf[i].rx_buf); goto next; diff --git a/target/linux/generic/files/block/partitions/fit.c b/target/linux/generic/files/block/partitions/fit.c index ce6a2b54115..13c03743f3d 100644 --- a/target/linux/generic/files/block/partitions/fit.c +++ b/target/linux/generic/files/block/partitions/fit.c @@ -73,11 +73,7 @@ int parse_fit_partitions(struct parsed_partitions *state, u64 fit_start_sector, u64 sectors, int *slot, int add_remain) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) struct block_device *bdev = state->disk->part0; -#else - struct block_device *bdev = state->bdev; -#endif struct address_space *mapping = bdev->bd_inode->i_mapping; struct page *page; void *fit, *init_fit; diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index bf98fd599ec..5e248f856ef 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -891,11 +891,7 @@ ar8216_phy_write(struct ar8xxx_priv *priv, int addr, int regnum, u16 val) static int ar8229_hw_init(struct ar8xxx_priv *priv) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) phy_interface_t phy_if_mode; -#else - int phy_if_mode; -#endif if (priv->initialized) return 0; @@ -903,11 +899,7 @@ ar8229_hw_init(struct ar8xxx_priv *priv) ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET); ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) of_get_phy_mode(priv->pdev->of_node, &phy_if_mode); -#else - phy_if_mode = of_get_phy_mode(priv->pdev->of_node); -#endif if (phy_if_mode == PHY_INTERFACE_MODE_GMII) { ar8xxx_write(priv, AR8229_REG_OPER_MODE0, @@ -2467,11 +2459,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev) /* VID fixup only needed on ar8216 */ if (chip_is_ar8216(priv)) { dev->phy_ptr = priv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags |= IFF_NO_IP_ALIGN; -#else - dev->priv_flags |= IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = ar8216_mangle_rx; dev->eth_mangle_tx = ar8216_mangle_tx; } @@ -2706,11 +2694,7 @@ ar8xxx_phy_detach(struct phy_device *phydev) #ifdef CONFIG_ETHERNET_PACKET_MANGLE dev->phy_ptr = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; -#else - dev->priv_flags &= ~IFF_NO_IP_ALIGN; -#endif dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; #endif diff --git a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c index 87d731ec3e2..215a369e63e 100644 --- a/target/linux/generic/files/drivers/net/phy/b53/b53_common.c +++ b/target/linux/generic/files/drivers/net/phy/b53/b53_common.c @@ -506,15 +506,9 @@ static int b53_configure_ports_of(struct b53_device *dev) if (fixed_link) { u32 spd; u8 po = GMII_PO_LINK; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) phy_interface_t mode; -#else - int mode = of_get_phy_mode(pn); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0) of_get_phy_mode(pn, &mode); -#endif if (!of_property_read_u32(fixed_link, "speed", &spd)) { switch (spd) { diff --git a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c index a8c3a20406a..202d1a582cb 100644 --- a/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c +++ b/target/linux/ipq40xx/files/drivers/net/dsa/qca/qca8k-ipq4019.c @@ -1435,23 +1435,12 @@ qca8k_port_fdb_dump(struct dsa_switch *ds, int port, return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) -static int -qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct switchdev_trans *trans) -#else static int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, struct netlink_ext_ack *extack) -#endif { struct qca8k_priv *priv = ds->priv; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - if (switchdev_trans_ph_prepare(trans)) - return 0; -#endif - if (vlan_filtering) { qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), QCA8K_PORT_LOOKUP_VLAN_MODE, @@ -1465,70 +1454,32 @@ qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) -static int -qca8k_port_vlan_prepare(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -{ - return 0; -} -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) -static void -qca8k_port_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan) -#else static int qca8k_port_vlan_add(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, struct netlink_ext_ack *extack) -#endif { bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; struct qca8k_priv *priv = ds->priv; int ret = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - u16 vid; - for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) - ret = qca8k_vlan_add(priv, port, vid, untagged); -#else ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - if (ret) - dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -#else if (ret) { dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); return ret; } -#endif if (pvid) { int shift = 16 * (port % 2); qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - 0xfff << shift, - vlan->vid_end << shift); -#else 0xfff << shift, vlan->vid << shift); -#endif qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - QCA8K_PORT_VLAN_CVID(vlan->vid_end) | - QCA8K_PORT_VLAN_SVID(vlan->vid_end)); -#else QCA8K_PORT_VLAN_CVID(vlan->vid) | QCA8K_PORT_VLAN_SVID(vlan->vid)); -#endif } -#if LINUX_VERSION_CODE > KERNEL_VERSION(5,12,0) return 0; -#endif } static int @@ -1537,14 +1488,8 @@ qca8k_port_vlan_del(struct dsa_switch *ds, int port, { struct qca8k_priv *priv = ds->priv; int ret = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - u16 vid; - for (vid = vlan->vid_begin; vid <= vlan->vid_end && !ret; ++vid) - ret = qca8k_vlan_del(priv, port, vid); -#else ret = qca8k_vlan_del(priv, port, vlan->vid); -#endif if (ret) dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); @@ -1577,9 +1522,6 @@ static const struct dsa_switch_ops qca8k_switch_ops = { .port_fdb_del = qca8k_port_fdb_del, .port_fdb_dump = qca8k_port_fdb_dump, .port_vlan_filtering = qca8k_port_vlan_filtering, -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - .port_vlan_prepare = qca8k_port_vlan_prepare, -#endif .port_vlan_add = qca8k_port_vlan_add, .port_vlan_del = qca8k_port_vlan_del, .phylink_validate = qca8k_phylink_validate, diff --git a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c index 28e0e6bc8e8..23b0ca74f71 100644 --- a/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c +++ b/target/linux/ipq40xx/files/drivers/net/phy/qca807x.c @@ -576,16 +576,6 @@ static int qca807x_config_intr(struct phy_device *phydev) return ret; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) -static int qca807x_ack_intr(struct phy_device *phydev) -{ - int ret; - - ret = phy_read(phydev, QCA807X_INTR_STATUS); - - return (ret < 0) ? ret : 0; -} -#else static irqreturn_t qca807x_handle_interrupt(struct phy_device *phydev) { int irq_status, int_enabled; @@ -611,7 +601,6 @@ static irqreturn_t qca807x_handle_interrupt(struct phy_device *phydev) return IRQ_HANDLED; } -#endif static int qca807x_led_config(struct phy_device *phydev) { @@ -802,11 +791,7 @@ static struct phy_driver qca807x_drivers[] = { .config_init = qca807x_config, .read_status = qca807x_read_status, .config_intr = qca807x_config_intr, -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - .ack_interrupt = qca807x_ack_intr, -#else .handle_interrupt = qca807x_handle_interrupt, -#endif .soft_reset = genphy_soft_reset, .get_tunable = qca807x_get_tunable, .set_tunable = qca807x_set_tunable, @@ -824,11 +809,7 @@ static struct phy_driver qca807x_drivers[] = { .config_init = qca807x_config, .read_status = qca807x_read_status, .config_intr = qca807x_config_intr, -#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) - .ack_interrupt = qca807x_ack_intr, -#else .handle_interrupt = qca807x_handle_interrupt, -#endif .soft_reset = genphy_soft_reset, .get_tunable = qca807x_get_tunable, .set_tunable = qca807x_set_tunable, diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c index b923b02af9f..a6448443c01 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio.c @@ -64,11 +64,7 @@ int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node, int { const __be32 *_phy_addr = NULL; struct phy_device *phydev; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - int phy_mode; -#else phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA; -#endif _phy_addr = of_get_property(phy_node, "reg", NULL); @@ -77,13 +73,8 @@ int fe_connect_phy_node(struct fe_priv *priv, struct device_node *phy_node, int return -EINVAL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - phy_mode = of_get_phy_mode(phy_node); - if (phy_mode < 0) { -#else of_get_phy_mode(phy_node, &phy_mode); if (phy_mode == PHY_INTERFACE_MODE_NA) { -#endif dev_err(priv->dev, "incorrect phy-mode %d\n", phy_mode); priv->phy->phy_node[port] = NULL; return -EINVAL; diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c index 6242cf9b423..0c47d118464 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mdio_rt2880.c @@ -156,11 +156,7 @@ void rt2880_port_init(struct fe_priv *priv, struct device_node *np) const __be32 *id = of_get_property(np, "reg", NULL); const __be32 *link; int size; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - int phy_mode; -#else phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA; -#endif if (!id || (be32_to_cpu(*id) != 0)) { pr_err("%s: invalid port id\n", np->name); @@ -176,11 +172,7 @@ void rt2880_port_init(struct fe_priv *priv, struct device_node *np) return; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - phy_mode = of_get_phy_mode(np); -#else of_get_phy_mode(np, &phy_mode); -#endif switch (phy_mode) { case PHY_INTERFACE_MODE_RGMII: break; diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c index 9876a247e3a..b79b3489380 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/mtk_eth_soc.c @@ -1096,11 +1096,7 @@ poll_again: return rx_done; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) -static void fe_tx_timeout(struct net_device *dev) -#else static void fe_tx_timeout(struct net_device *dev, unsigned int txqueue) -#endif { struct fe_priv *priv = netdev_priv(dev); struct fe_tx_ring *ring = &priv->tx_ring; diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c index 42685eebc33..a4b2908d59e 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/soc_mt7620.c @@ -144,11 +144,7 @@ static void mt7620_port_init(struct fe_priv *priv, struct device_node *np) struct mt7620_gsw *gsw = (struct mt7620_gsw *)priv->soc->swpriv; const __be32 *_id = of_get_property(np, "reg", NULL); const __be32 *phy_addr; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - int phy_mode; -#else phy_interface_t phy_mode = PHY_INTERFACE_MODE_NA; -#endif int size, id; int shift = 12; u32 val, mask = 0; @@ -178,11 +174,7 @@ static void mt7620_port_init(struct fe_priv *priv, struct device_node *np) priv->phy->phy_fixed[id] = NULL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) - phy_mode = of_get_phy_mode(np); -#else of_get_phy_mode(np, &phy_mode); -#endif switch (phy_mode) { case PHY_INTERFACE_MODE_RGMII: mask = 0; diff --git a/target/linux/ramips/files/drivers/pinctrl/pinctrl-aw9523.c b/target/linux/ramips/files/drivers/pinctrl/pinctrl-aw9523.c index 4e75c9bf079..4900c5a0c0e 100644 --- a/target/linux/ramips/files/drivers/pinctrl/pinctrl-aw9523.c +++ b/target/linux/ramips/files/drivers/pinctrl/pinctrl-aw9523.c @@ -386,11 +386,6 @@ static const struct pinconf_ops aw9523_pinconf_ops = { .is_generic = true, }; -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 0) -#define GPIO_LINE_DIRECTION_IN 1 -#define GPIO_LINE_DIRECTION_OUT 0 -#endif - /* * aw9523_get_pin_direction - Get pin direction * @regmap: Regmap structure @@ -437,11 +432,6 @@ static int aw9523_get_port_state(struct regmap *regmap, u8 pin, return regmap_read(regmap, reg, state); } -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 5, 0) -#undef GPIO_LINE_DIRECTION_IN -#undef GPIO_LINE_DIRECTION_OUT -#endif - static int aw9523_gpio_irq_type(struct irq_data *d, unsigned int type) { switch (type) { From 4642d8abdc699685db5d4eb251c71055a2bc43fa Mon Sep 17 00:00:00 2001 From: Sander van Deijck Date: Fri, 19 May 2023 00:59:25 +0200 Subject: [PATCH 26/88] kirkwood: add support for Iomega Storcenter ix4-200d Iomega Storcenter ix4-200d is a four-bay SATA NAS powered by a Marvell Kirkwood SoC clocked at 1.2GHz. It has 512MB of RAM and 32MB of flash memory, 3x USB 2.0 and 2x 1Gbit/s NIC Specification: - SoC: Marvell Kirkwood 88F6281 - CPU/Speed: 1200Mhz - Flash size: 32 MiB - RAM: 512MB - LAN: 2x 1Gbit/s - 3x USB 2.0 Notes: - The blue drive LED is triggered by HDD activity, it can not be controlled via GPIO. - The LCD screen requires proprietary code and does not function at this time. - Due to a kernel-related issue with the Marvell 88SE6121 SATA controller, currently only trays numbered #3 and #4 work, #1 and #2 do not. [1] Serial pinout: CN4 -------------- | 10 8 6 4 2 | | 9 7 5 3 1 | -------------- PIN 1 Mark (fat line) 1 = RXD 4 = TXD 6 = GND 9 = 3.3V (not necessary to connect) Installation instructions: 1. download initramfs-uImage and copy into tftp server 2. connect the tftp server to network port #1 3. access uboot environment with serial cable and run setenv mainlineLinux yes setenv arcNumber 1682 setenv console 'console=ttyS0,115200n8' setenv mtdparts 'mtdparts=orion_nand:0x100000@0x000000(u-boot)ro,0x20000@0xA0000(u-boot environment)ro,0x300000@0x100000(kernel),0x1C00000@0x400000(ubi)' setenv bootargs_root 'root=' setenv bootcmd 'setenv bootargs ${console} ${mtdparts} ${bootargs_root}; nand read.e 0x800000 0x100000 0x300000; bootm 0x00800000' saveenv setenv serverip 192.168.1.1 setenv ipaddr 192.168.1.2 tftpboot 0x00800000 [initramfs-uImage filename] bootm 0x00800000 4. connect to LAN on network port #2, log into openwrt and sysupgrade to install into flash [1] https://bugzilla.kernel.org/show_bug.cgi?id=216094 Signed-off-by: Sander van Deijck (aligned FROM from signed-off. LED+key rename, whitespace removal) Signed-off-by: Christian Lamparter --- .../base-files/etc/board.d/02_network | 3 + .../arch/arm/boot/dts/kirkwood-ix4-200d.dts | 202 ++++++++++++++++++ target/linux/kirkwood/image/Makefile | 18 ++ 3 files changed, 223 insertions(+) create mode 100644 target/linux/kirkwood/files/arch/arm/boot/dts/kirkwood-ix4-200d.dts diff --git a/target/linux/kirkwood/base-files/etc/board.d/02_network b/target/linux/kirkwood/base-files/etc/board.d/02_network index df38694f40c..15f75df6a81 100644 --- a/target/linux/kirkwood/base-files/etc/board.d/02_network +++ b/target/linux/kirkwood/base-files/etc/board.d/02_network @@ -37,6 +37,9 @@ kirkwood_setup_interfaces() endian,4i-edge-200) ucidef_set_interface_lan "port1 port2 port3 port4 eth1" ;; + iom,ix4-200d) + ucidef_set_interface_lan "eth0 eth1" "dhcp" + ;; linksys,e4200-v2|\ linksys,ea3500|\ linksys,ea4500) diff --git a/target/linux/kirkwood/files/arch/arm/boot/dts/kirkwood-ix4-200d.dts b/target/linux/kirkwood/files/arch/arm/boot/dts/kirkwood-ix4-200d.dts new file mode 100644 index 00000000000..c63742a1a88 --- /dev/null +++ b/target/linux/kirkwood/files/arch/arm/boot/dts/kirkwood-ix4-200d.dts @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/dts-v1/; + +#include "kirkwood.dtsi" +#include "kirkwood-6281.dtsi" +#include + +/ { + model = "Iomega ix4-200d"; + compatible = "iom,ix4-200d", "marvell,kirkwood-88f6281", "marvell,kirkwood"; + + aliases { + led-boot = &led_status_white; + led-failsafe = &led_status_red; + led-running = &led_power_white; + led-upgrade = &led_status_red; + }; + + chosen { + bootargs = "console=ttyS0,115200n8 earlyprintk"; + stdout-path = &uart0; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x20000000>; + }; + + ocp@f1000000 { + i2c@11000 { + status = "okay"; + + adt7473@2e { + compatible = "adi,adt7473"; + reg = <0x2e>; + }; + }; + + pinctrl: pin-controller@10000 { + pmx_spi: pmx-spi { + marvell,pins = "mpp12", "mpp13", "mpp14"; + marvell,function = "gpio"; + }; + + pmx_keys: pmx-keys { + marvell,pins = "mpp16", "mpp29", "mpp47", "mpp49"; + marvell,function = "gpio"; + }; + }; + + sata@80000 { + status = "okay"; + nr-ports = <2>; + }; + + serial@12000 { + status = "okay"; + }; + + spi3 { + compatible = "spi-gpio"; + #address-cells = <0x1>; + ranges; + status = "okay"; + sck-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + mosi-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>; + num-chipselects = <1>; + #size-cells = <0>; + + gpio_spi: gpio_spi@0 { + compatible = "fairchild,74hc595"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + registers-number = <1>; + spi-max-frequency = <100000>; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&pmx_keys>; + pinctrl-names = "default"; + + button-0 { + label = "Next Button"; + linux,code = ; + gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>; + }; + + button-1 { + label = "Reset Button"; + linux,code = ; + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + + button-2 { + label = "Cancel Button"; + linux,code = ; + gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; + }; + + button-3 { + label = "Power Button"; + linux,code = ; + gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led_status_white: led-0 { + label = "status:white"; + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio_spi 4 GPIO_ACTIVE_LOW>; + }; + + led_status_red: led-1 { + label = "status:red"; + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&gpio_spi 5 GPIO_ACTIVE_LOW>; + }; + + led_power_white: led-2 { + label = "power:white"; + function = LED_FUNCTION_POWER; + color = ; + gpios = <&gpio_spi 7 GPIO_ACTIVE_HIGH>; + }; + }; + }; +}; + +ð0 { + status = "okay"; + ethernet0-port@0 { + phy-handle = <ðphy0>; + }; +}; + +ð1 { + status = "okay"; + ethernet1-port@0 { + phy-handle = <ðphy1>; + }; +}; + +&mdio { + status = "okay"; + + ethphy0: ethernet-phy@8 { + reg = <8>; + }; + + ethphy1: ethernet-phy@9 { + reg = <9>; + }; +}; + +&nand { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "u-boot"; + reg = <0x0000000 0x100000>; + read-only; + }; + + partition@a0000 { + label = "u-boot environment"; + reg = <0xa0000 0x20000>; + read-only; + }; + + partition@100000 { + label = "kernel"; + reg = <0x100000 0x300000>; + }; + + partition@400000 { + label = "ubi"; + reg = <0x400000 0x1C00000>; + }; + }; +}; + +&pciec { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; diff --git a/target/linux/kirkwood/image/Makefile b/target/linux/kirkwood/image/Makefile index ea76e219706..0fa14b89f32 100644 --- a/target/linux/kirkwood/image/Makefile +++ b/target/linux/kirkwood/image/Makefile @@ -184,6 +184,24 @@ define Device/iom_ix2-200 endef TARGET_DEVICES += iom_ix2-200 +define Device/iom_ix4-200d + DEVICE_VENDOR := Iomega + DEVICE_MODEL := StorCenter ix4-200d + DEVICE_PACKAGES := kmod-ata-marvell-sata kmod-fs-ext4 \ + kmod-gpio-button-hotplug kmod-gpio-nxp-74hc164 \ + kmod-hwmon-adt7475 kmod-mvsdio kmod-spi-gpio + PAGESIZE := 512 + SUBPAGESIZE := 256 + BLOCKSIZE := 16k + KERNEL_SIZE := 3072k + KERNEL_IN_UBI := + UBINIZE_OPTS := -E 5 + IMAGE_SIZE := 31744k + IMAGE/factory.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-ubi | \ + check-size +endef +TARGET_DEVICES += iom_ix4-200d + define Device/iptime_nas1 DEVICE_VENDOR := ipTIME DEVICE_MODEL := NAS1 From aa28e91404ed7c4c3786a289fbf206c13adb9762 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Thu, 18 May 2023 14:49:51 +0200 Subject: [PATCH 27/88] nettle: update to 3.9 Changelog: https://git.lysator.liu.se/nettle/nettle/-/blob/26cd0222fd09b8f5dc0edba30d6908722c7e9b09/NEWS Refresh patch: - 100-portability.patch Signed-off-by: Nick Hainke --- package/libs/nettle/Makefile | 6 +++--- package/libs/nettle/patches/100-portability.patch | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package/libs/nettle/Makefile b/package/libs/nettle/Makefile index 0cec4a5d339..36410920b99 100644 --- a/package/libs/nettle/Makefile +++ b/package/libs/nettle/Makefile @@ -8,13 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nettle -PKG_VERSION:=3.8.1 -PKG_RELEASE:=3 +PKG_VERSION:=3.9 +PKG_RELEASE:=1 PKG_BUILD_FLAGS:=no-mips16 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=@GNU/nettle -PKG_HASH:=364f3e2b77cd7dcde83fd7c45219c834e54b0c75e428b6f894a23d12dd41cbfe +PKG_HASH:=0ee7adf5a7201610bb7fe0acbb7c9b3be83be44904dd35ebbcd965cd896bfeaa PKG_LICENSE:=GPL-2.0-or-later PKG_LICENSE_FILES:=COPYING diff --git a/package/libs/nettle/patches/100-portability.patch b/package/libs/nettle/patches/100-portability.patch index b4677ec0206..a44baa296d5 100644 --- a/package/libs/nettle/patches/100-portability.patch +++ b/package/libs/nettle/patches/100-portability.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -4704,6 +4704,7 @@ $as_echo_n "checking build system compil +@@ -4719,6 +4719,7 @@ $as_echo_n "checking build system compil # remove anything that might look like compiler output to our "||" expression rm -f conftest* a.out b.out a.exe a_out.exe cat >conftest.c <conftest.c <conftest.c <conftest.c < Date: Wed, 8 Feb 2023 09:59:27 +0800 Subject: [PATCH 28/88] build: Allow specifying uImage time Some U-Boot checks for a specified uImage time and refuses to boot if mismatched. This patch fixes it by recognizing UIMAGE_TIME parameter. Signed-off-by: David Yang --- include/image-commands.mk | 1 + include/image.mk | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/image-commands.mk b/include/image-commands.mk index 6c385b85e8c..ea602662a5b 100644 --- a/include/image-commands.mk +++ b/include/image-commands.mk @@ -581,6 +581,7 @@ define Build/tplink-v2-image endef define Build/uImage + $(if $(UIMAGE_TIME),SOURCE_DATE_EPOCH="$(UIMAGE_TIME)") \ mkimage \ -A $(LINUX_KARCH) \ -O linux \ diff --git a/include/image.mk b/include/image.mk index b801ef993c3..0eae216ded2 100644 --- a/include/image.mk +++ b/include/image.mk @@ -405,6 +405,7 @@ define Device/Init BOARD_NAME := UIMAGE_MAGIC := UIMAGE_NAME := + UIMAGE_TIME := DEVICE_COMPAT_VERSION := 1.0 DEVICE_COMPAT_MESSAGE := SUPPORTED_DEVICES := $(subst _,$(comma),$(1)) @@ -425,7 +426,7 @@ DEFAULT_DEVICE_VARS := \ DEVICE_DTS_CONFIG DEVICE_DTS_DELIMITER DEVICE_DTS_DIR DEVICE_DTS_OVERLAY \ DEVICE_DTS_LOADADDR \ DEVICE_FDT_NUM DEVICE_IMG_PREFIX SOC BOARD_NAME UIMAGE_MAGIC UIMAGE_NAME \ - SUPPORTED_DEVICES IMAGE_METADATA KERNEL_ENTRY KERNEL_LOADADDR \ + UIMAGE_TIME SUPPORTED_DEVICES IMAGE_METADATA KERNEL_ENTRY KERNEL_LOADADDR \ UBOOT_PATH IMAGE_SIZE \ FACTORY_IMG_NAME FACTORY_SIZE \ DEVICE_PACKAGES DEVICE_COMPAT_VERSION DEVICE_COMPAT_MESSAGE \ From 3f9526957b15e48f3b651bfcca377a9a6e8e1416 Mon Sep 17 00:00:00 2001 From: Linhui Liu Date: Sat, 20 May 2023 13:45:19 +0800 Subject: [PATCH 29/88] tools/ccache: update to 4.8.1 Release Notes: https://ccache.dev/releasenotes.html#_ccache_4_8_1 Signed-off-by: Linhui Liu --- tools/ccache/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ccache/Makefile b/tools/ccache/Makefile index 74b2ae3b44c..33255e92970 100644 --- a/tools/ccache/Makefile +++ b/tools/ccache/Makefile @@ -7,11 +7,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ccache -PKG_VERSION:=4.8 +PKG_VERSION:=4.8.1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ccache/ccache/releases/download/v$(PKG_VERSION) -PKG_HASH:=b963ee3bf88d7266b8a0565e4ba685d5666357f0a7e364ed98adb0dc1191fcbb +PKG_HASH:=87959b6819530b3dcaeb39992f585b9fc2c7120302809741378097774919fb6f include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/cmake.mk From 857345496bf1d4870320e856ae75104e166d78d1 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 20 May 2023 21:43:39 +0200 Subject: [PATCH 30/88] tfa-layerscape: fix fiptool's build A missing '\' caused the remaining parameters not to be passed to make. This fixes the following error: | gcc -c [...] fiptool.c -o fiptool.o | In file included from fiptool.h:16, | from fiptool.c:19: |fiptool_platform.h:19:11: fatal error: openssl/sha.h: No such file or directory | 19 | # include | | ^~~~~~~~~~~~~~~ |compilation terminated. |make[3]: *** [Makefile:58: fiptool.o] Error 1 as the HOST_CFLAGS are no longer passed. then, HOST_CFLAGS is specified as a command argument, this is a specific problem of our built since appending these needs the override directive. Fixes: df28bfe03247 ("tfa-layerscape: Change to github and use the latest tag") Signed-off-by: Christian Lamparter --- package/boot/tfa-layerscape/Makefile | 2 +- .../patches/001-fiptool-hostbuild-fixes.patch | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/package/boot/tfa-layerscape/Makefile b/package/boot/tfa-layerscape/Makefile index c1ef217f479..3509658869b 100644 --- a/package/boot/tfa-layerscape/Makefile +++ b/package/boot/tfa-layerscape/Makefile @@ -25,7 +25,7 @@ HOST_CFLAGS += -Wall -Werror -pedantic -std=c99 define Host/Compile $(MAKE) -C \ $(HOST_BUILD_DIR)/tools/fiptool \ - PLAT_FIPTOOL_HELPER_MK="$(HOST_BUILD_DIR)/tools/nxp/plat_fiptool/plat_fiptool.mk" + PLAT_FIPTOOL_HELPER_MK="$(HOST_BUILD_DIR)/tools/nxp/plat_fiptool/plat_fiptool.mk" \ CFLAGS="$(HOST_CFLAGS)" \ LDFLAGS="$(HOST_LDFLAGS)" \ HOSTCCFLAGS="$(HOST_CFLAGS)" diff --git a/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch index 8e7375cfa22..50ce6528d77 100644 --- a/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch +++ b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch @@ -88,3 +88,19 @@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} +--- a/tools/nxp/plat_fiptool/plat_fiptool.mk 2023-05-20 22:28:28.079945619 +0200 ++++ b/tools/nxp/plat_fiptool/plat_fiptool.mk 2023-05-20 22:26:59.443307771 +0200 +@@ -22,11 +22,11 @@ INCLUDE_PATHS += -I${PLAT_DEF_UUID_OID_C + $(shell rm ${PLAT_DEF_UUID_CONFIG_FILE_PATH}/${PLAT_DEF_UUID_CONFIG_FILE_NAME}.o) + + ifeq (${PLAT_DEF_OID},yes) +-HOSTCCFLAGS += -DPLAT_DEF_OID ++override HOSTCCFLAGS += -DPLAT_DEF_OID + endif + + ifeq (${PLAT_DEF_UUID},yes) +-HOSTCCFLAGS += -DPLAT_DEF_FIP_UUID ++override HOSTCCFLAGS += -DPLAT_DEF_FIP_UUID + PLAT_OBJECTS += ${PLAT_DEF_UUID_CONFIG_FILE_PATH}/${PLAT_DEF_UUID_CONFIG_FILE_NAME}.o + endif + From c191c2d46f0080b8c6e6aee76b30ae9cf50d6e3e Mon Sep 17 00:00:00 2001 From: Stan Grishin Date: Mon, 27 Feb 2023 00:04:33 +0000 Subject: [PATCH 31/88] x86: base-files add support for Sophos 135r3/135r3w The Sophos SG/XG-135 revision 3 has odd numbering of eth ports where the WAN port (as marked on the case) is: `eth6` and `eth0`, `eth1`, `eth2`, `eth3`, `eth5`, `eth7`, `eth8` are LAN ports. Port `eth4` seems to be the SFP port. Also add the missing LED definition for supported Sophos devices. Original discussion at: https://forum.openwrt.org/t/openwrt-on-revision-3-of-sophos-desktop-appliances/152912 Signed-off-by: Stan Grishin --- target/linux/x86/base-files/etc/board.d/01_leds | 7 +++++++ target/linux/x86/base-files/etc/board.d/02_network | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/target/linux/x86/base-files/etc/board.d/01_leds b/target/linux/x86/base-files/etc/board.d/01_leds index e639d108081..e41c78e62b2 100644 --- a/target/linux/x86/base-files/etc/board.d/01_leds +++ b/target/linux/x86/base-files/etc/board.d/01_leds @@ -16,6 +16,13 @@ pc-engines-apu1|pc-engines-apu2|pc-engines-apu3|pc-engines-apu4|pc-engines-apu5| ucidef_set_led_netdev "lan" "LAN" "apu:green:2" "br-lan" ucidef_set_led_default "diag" "DIAG" "apu:green:1" "1" ;; +sophos-sg-105wr1|sophos-sg-125wr1|sophos-sg-135wr1|sophos-xg-105wr1|sophos-xg-125wr1|sophos-xg-135wr1) + ucidef_set_led_netdev "wlan" "WiFi" "ath9k-phy0" "phy0tpt" + ;; +sophos-sg-105wr2|sophos-sg-125wr2|sophos-sg-135wr2|sophos-xg-105wr2|sophos-xg-125wr2|sophos-xg-135wr2| +sophos-sg-105wr3|sophos-sg-125wr3|sophos-sg-135wr3|sophos-xg-105wr3|sophos-xg-125wr3|sophos-xg-135wr3) + ucidef_set_led_netdev "wlan" "WiFi" "ath10k-phy0" "phy0tpt" + ;; traverse-technologies-geos) ucidef_set_led_netdev "lan" "LAN" "geos:1" "br-lan" "tx rx" ucidef_set_led_netdev "wlan" "WiFi" "geos:2" "phy0tpt" diff --git a/target/linux/x86/base-files/etc/board.d/02_network b/target/linux/x86/base-files/etc/board.d/02_network index 094a45f9148..e00e8c04dd2 100644 --- a/target/linux/x86/base-files/etc/board.d/02_network +++ b/target/linux/x86/base-files/etc/board.d/02_network @@ -64,6 +64,10 @@ sophos-sg-135r2|sophos-xg-135r2| \ sophos-sg-135wr2|sophos-xg-135wr2) ucidef_set_interfaces_lan_wan "eth0 eth2 eth3 eth4 eth5 eth6 eth7" "eth1" ;; +sophos-sg-135r3|sophos-xg-135r3| \ +sophos-sg-135wr3|sophos-xg-135wr3) + ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth5 eth7 eth8" "eth6" + ;; traverse-technologies-geos) ucidef_set_interface_lan "eth0 eth1" ucidef_add_atm_bridge "0" "35" "llc" "bridged" From d728d05c6cfe2c9071cc9fbe3edc5342ae8979a7 Mon Sep 17 00:00:00 2001 From: Nozomi Miyamori Date: Wed, 29 Mar 2023 21:15:13 +0900 Subject: [PATCH 32/88] dropbear: add ForceCommand uci option adds ForceCommand option. If the command is specified, it forces users to execute the command when they log in. Signed-off-by: Nozomi Miyamori Signed-off-by: Christian Lamparter --- package/network/services/dropbear/files/dropbear.init | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package/network/services/dropbear/files/dropbear.init b/package/network/services/dropbear/files/dropbear.init index ea4cad2a8d5..b82e967cbce 100755 --- a/package/network/services/dropbear/files/dropbear.init +++ b/package/network/services/dropbear/files/dropbear.init @@ -119,6 +119,7 @@ validate_section_dropbear() 'enable:bool:1' \ 'Interface:string' \ 'GatewayPorts:bool:0' \ + 'ForceCommand:string' \ 'RootPasswordAuth:bool:1' \ 'RootLogin:bool:1' \ 'rsakeyfile:file' \ @@ -158,6 +159,7 @@ dropbear_instance() procd_set_param command "$PROG" -F -P "$pid_file" [ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s [ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a + [ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}" [ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g [ "${RootLogin}" -eq 0 ] && procd_append_param command -w if [ -n "${rsakeyfile}" ]; then From 09d0643c188f0d08910e490b945f884dfdd866f2 Mon Sep 17 00:00:00 2001 From: DENG Qingfang Date: Thu, 13 Apr 2023 11:21:01 +0800 Subject: [PATCH 33/88] ramips: mt7621: fix Xiaomi Router 3G/Pro LEDs The PHY name has been changed to "mt7530-0" since IRQ support was added to MT7530 driver. Fixes: f9cfe7af1f1f ("kernel: backport MT7530 IRQ support") Signed-off-by: DENG Qingfang (node names, added color, function+function-enumerator properties) Signed-off-by: Christian Lamparter --- .../dts/mt7621_xiaomi_mi-router-3-pro.dts | 40 ++++++++++++++----- .../ramips/dts/mt7621_xiaomi_mi-router-3g.dts | 33 ++++++++++----- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3-pro.dts b/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3-pro.dts index 64f588dc501..34d0e4a0318 100644 --- a/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3-pro.dts +++ b/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3-pro.dts @@ -4,6 +4,7 @@ #include #include +#include / { compatible = "xiaomi,mi-router-3-pro", "mediatek,mt7621-soc"; @@ -24,43 +25,60 @@ leds { compatible = "gpio-leds"; - led_status_red: status_red { + led_status_red: led-0 { label = "red:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 6 GPIO_ACTIVE_LOW>; }; - led_status_blue: status_blue { + led_status_blue: led-1 { label = "blue:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 8 GPIO_ACTIVE_LOW>; }; - led_status_yellow: status_yellow { + led_status_yellow: led-2 { label = "yellow:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 10 GPIO_ACTIVE_LOW>; }; - wan_amber { + led-3 { label = "amber:wan"; + color = ; + function = LED_FUNCTION_WAN; gpios = <&gpio 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:04:1Gbps"; + linux,default-trigger = "mt7530-0:04:1Gbps"; }; - lan3_amber { + led-4 { label = "amber:lan3"; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <3>; gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:03:1Gbps"; + linux,default-trigger = "mt7530-0:03:1Gbps"; }; - lan2_amber { + led-5 { label = "amber:lan2"; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <2>; gpios = <&gpio 16 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:02:1Gbps"; + linux,default-trigger = "mt7530-0:02:1Gbps"; }; - lan1_amber { + led-6 { label = "amber:lan1"; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <1>; gpios = <&gpio 15 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:01:1Gbps"; + linux,default-trigger = "mt7530-0:01:1Gbps"; }; }; diff --git a/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3g.dts b/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3g.dts index 1a19579208b..c13c0c95709 100644 --- a/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3g.dts +++ b/target/linux/ramips/dts/mt7621_xiaomi_mi-router-3g.dts @@ -1,4 +1,5 @@ #include "mt7621_xiaomi_nand_128m.dtsi" +#include / { compatible = "xiaomi,mi-router-3g", "mediatek,mt7621-soc"; @@ -15,37 +16,51 @@ leds { compatible = "gpio-leds"; - led_status_red: status_red { + led_status_red: led-0 { label = "red:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 6 GPIO_ACTIVE_LOW>; }; - led_status_blue: status_blue { + led_status_blue: led-1 { label = "blue:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 8 GPIO_ACTIVE_LOW>; }; - led_status_yellow: status_yellow { + led_status_yellow: led-2 { label = "yellow:status"; + color = ; + function = LED_FUNCTION_STATUS; gpios = <&gpio 10 GPIO_ACTIVE_LOW>; }; - wan_amber { + led-3 { label = "amber:wan"; + color = ; + function = LED_FUNCTION_WAN; gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:01:1Gbps"; + linux,default-trigger = "mt7530-0:01:1Gbps"; }; - lan1_amber { + led-4 { label = "amber:lan1"; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <1>; gpios = <&gpio 14 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:03:1Gbps"; + linux,default-trigger = "mt7530-0:03:1Gbps"; }; - lan2_amber { + led-5 { label = "amber:lan2"; + color = ; + function = LED_FUNCTION_LAN; + function-enumerator = <2>; gpios = <&gpio 16 GPIO_ACTIVE_LOW>; - linux,default-trigger = "dsa-0.0:02:1Gbps"; + linux,default-trigger = "mt7530-0:02:1Gbps"; }; }; From 3f297be1ed49351282f26462a7aa6e03036a1ffc Mon Sep 17 00:00:00 2001 From: Felix Baumann Date: Fri, 19 May 2023 18:06:15 +0200 Subject: [PATCH 34/88] treewide: Disable building 16M RAM devices Following deprecation notice[1] in 21.02, disable targets with 16M of RAM [1] https://openwrt.org/supported_devices/864_warning Signed-off-by: Felix Baumann --- target/linux/bcm47xx/image/legacy.mk | 25 +++++++++++++++++++++++++ target/linux/bcm47xx/image/mips74k.mk | 4 ++++ 2 files changed, 29 insertions(+) diff --git a/target/linux/bcm47xx/image/legacy.mk b/target/linux/bcm47xx/image/legacy.mk index 448c5206f4f..4c37a4505cd 100644 --- a/target/linux/bcm47xx/image/legacy.mk +++ b/target/linux/bcm47xx/image/legacy.mk @@ -7,6 +7,7 @@ define Device/asus_wl-300g DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "WL300g " + DEFAULT := n endef TARGET_DEVICES += asus_wl-300g @@ -15,6 +16,7 @@ define Device/asus_wl-320gp DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "WL320gP " + DEFAULT := n endef TARGET_DEVICES += asus_wl-320gp @@ -23,6 +25,7 @@ define Device/asus_wl-330ge DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "WL-330gE " + DEFAULT := n endef TARGET_DEVICES += asus_wl-330ge @@ -31,6 +34,7 @@ define Device/asus_wl-500gd DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := "WL500gx " + DEFAULT := n endef TARGET_DEVICES += asus_wl-500gd @@ -40,6 +44,7 @@ define Device/asus_wl-500gp-v1 DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := "WL500gp " + DEFAULT := n endef TARGET_DEVICES += asus_wl-500gp-v1 @@ -49,6 +54,7 @@ define Device/asus_wl-500gp-v2 DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := "WL500gpv2 " + DEFAULT := n endef TARGET_DEVICES += asus_wl-500gp-v2 @@ -65,6 +71,7 @@ define Device/asus_wl-520gu DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := "WL520gu " + DEFAULT := n endef TARGET_DEVICES += asus_wl-520gu @@ -73,6 +80,7 @@ define Device/asus_wl-550ge DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "WL550gE " + DEFAULT := n endef TARGET_DEVICES += asus_wl-550ge @@ -81,6 +89,7 @@ define Device/asus_wl-hdd25 DEVICE_PACKAGES := kmod-b43 $(USB1_PACKAGES) $(Device/asus) PRODUCTID := "WLHDD " + DEFAULT := n endef TARGET_DEVICES += asus_wl-hdd25 @@ -99,6 +108,7 @@ define Device/edimax_ps1208-mfg DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) IMAGES := bin IMAGE/bin := append-rootfs | trx-with-loader | edimax-bin + DEFAULT := n endef TARGET_DEVICES += edimax_ps1208-mfg @@ -118,6 +128,7 @@ define Device/linksys_wrt54g3g $(Device/linksys) DEVICE_ID := W54F VERSION := 2.20.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54g3g @@ -126,6 +137,7 @@ define Device/linksys_wrt54g3g-em $(Device/linksys) DEVICE_ID := W3GN VERSION := 2.20.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54g3g-em @@ -140,6 +152,7 @@ define Device/linksys_wrt54g3gv2-vf DEVICE_ID := 3G2V VERSION := 3.00.24 SERIAL := 6 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54g3gv2-vf @@ -149,6 +162,7 @@ define Device/linksys_wrt54g $(Device/linksys) DEVICE_ID := W54G VERSION := 4.71.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54g @@ -163,6 +177,7 @@ define Device/linksys_wrt54gs FILESYSTEMS := $(FS_128K) DEVICE_ID := W54S VERSION := 4.80.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54gs @@ -173,6 +188,7 @@ define Device/linksys_wrt54gs-v4 $(Device/linksys) DEVICE_ID := W54s VERSION := 1.09.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt54gs-v4 @@ -183,6 +199,7 @@ define Device/linksys_wrtsl54gs FILESYSTEMS := $(FS_128K) DEVICE_ID := W54U VERSION := 2.08.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrtsl54gs @@ -192,6 +209,7 @@ define Device/linksys_wrt150n $(Device/linksys) DEVICE_ID := N150 VERSION := 1.51.3 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt150n @@ -221,6 +239,7 @@ define Device/motorola_wa840g DEVICE_PACKAGES := kmod-b43 $(Device/motorola) MOTOROLA_DEVICE := 2 + DEFAULT := n endef TARGET_DEVICES += motorola_wa840g @@ -229,6 +248,7 @@ define Device/motorola_we800g DEVICE_PACKAGES := kmod-b43 $(Device/motorola) MOTOROLA_DEVICE := 3 + DEFAULT := n endef TARGET_DEVICES += motorola_we800g @@ -237,6 +257,7 @@ define Device/motorola_wr850g DEVICE_PACKAGES := kmod-b43 $(Device/motorola) MOTOROLA_DEVICE := 1 + DEFAULT := n endef TARGET_DEVICES += motorola_wr850g @@ -247,6 +268,7 @@ define Device/netgear_wgr614-v8 $(Device/netgear) NETGEAR_BOARD_ID := U12H072T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wgr614-v8 @@ -257,6 +279,7 @@ define Device/netgear_wgt634u FILESYSTEMS := $(FS_128K) IMAGES := bin IMAGE/bin := append-rootfs | trx-with-loader | prepend-with-elf + DEFAULT := n endef TARGET_DEVICES += netgear_wgt634u @@ -267,6 +290,7 @@ define Device/netgear_wndr3300-v1 $(Device/netgear) NETGEAR_BOARD_ID := U12H093T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wndr3300-v1 @@ -277,6 +301,7 @@ define Device/netgear_wnr834b-v2 $(Device/netgear) NETGEAR_BOARD_ID := U12H081T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wnr834b-v2 diff --git a/target/linux/bcm47xx/image/mips74k.mk b/target/linux/bcm47xx/image/mips74k.mk index 7e65821a558..4478374f160 100644 --- a/target/linux/bcm47xx/image/mips74k.mk +++ b/target/linux/bcm47xx/image/mips74k.mk @@ -24,6 +24,7 @@ define Device/asus_rt-n10 DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "RT-N10 " + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10 @@ -323,6 +324,7 @@ define Device/netgear_wgr614-v10-na $(Device/netgear) NETGEAR_BOARD_ID := U12H139T01_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wgr614-v10-na @@ -332,6 +334,7 @@ define Device/netgear_wgr614-v10 $(Device/netgear) NETGEAR_BOARD_ID := U12H139T01_NETGEAR NETGEAR_REGION := 1 + DEFAULT := n endef TARGET_DEVICES += netgear_wgr614-v10 @@ -420,6 +423,7 @@ define Device/netgear_wnr1000-v3 $(Device/netgear) NETGEAR_BOARD_ID := U12H139T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wnr1000-v3 From f5cb556d4f70e7aac428857fe782b58ece0cf188 Mon Sep 17 00:00:00 2001 From: Felix Baumann Date: Sat, 20 May 2023 08:37:45 +0200 Subject: [PATCH 35/88] treewide: Disable building 32M RAM devices Following deprecation notice[1] in 21.02, disable targets with 32M of RAM [1] https://openwrt.org/supported_devices/864_warning Signed-off-by: Felix Baumann --- target/linux/ath79/image/generic-tp-link.mk | 6 +++ target/linux/ath79/image/generic.mk | 2 + target/linux/ath79/image/tiny-ubnt.mk | 7 +++ target/linux/ath79/image/tiny.mk | 1 + target/linux/bcm47xx/image/generic.mk | 3 ++ target/linux/bcm47xx/image/legacy.mk | 4 ++ target/linux/bcm47xx/image/mips74k.mk | 21 +++++++++ target/linux/bcm63xx/image/bcm63xx.mk | 18 ++++++++ target/linux/lantiq/image/ar9.mk | 1 + target/linux/lantiq/image/danube.mk | 2 + target/linux/lantiq/image/vr9.mk | 2 + target/linux/ramips/image/mt7620.mk | 5 +++ target/linux/ramips/image/mt76x8.mk | 2 + target/linux/ramips/image/rt288x.mk | 1 + target/linux/ramips/image/rt305x.mk | 48 +++++++++++++++++++++ target/linux/ramips/image/rt3883.mk | 1 + 16 files changed, 124 insertions(+) diff --git a/target/linux/ath79/image/generic-tp-link.mk b/target/linux/ath79/image/generic-tp-link.mk index 83361892937..cfabc89b8df 100644 --- a/target/linux/ath79/image/generic-tp-link.mk +++ b/target/linux/ath79/image/generic-tp-link.mk @@ -707,6 +707,7 @@ define Device/tplink_tl-wr1043nd-v1 DEVICE_PACKAGES := kmod-usb2 kmod-usb-ledtrig-usbport kmod-switch-rtl8366rb TPLINK_HWID := 0x10430001 SUPPORTED_DEVICES += tl-wr1043nd + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr1043nd-v1 @@ -789,6 +790,7 @@ define Device/tplink_tl-wr710n-v1 DEVICE_PACKAGES := kmod-usb-chipidea2 kmod-usb-ledtrig-usbport TPLINK_HWID := 0x07100001 SUPPORTED_DEVICES += tl-wr710n + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr710n-v1 @@ -801,6 +803,7 @@ define Device/tplink_tl-wr710n-v2.1 TPLINK_HWID := 0x07100002 TPLINK_HWREV := 0x2 SUPPORTED_DEVICES += tl-wr710n + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr710n-v2.1 @@ -822,6 +825,7 @@ define Device/tplink_tl-wr810n-v2 DEVICE_VARIANT := v2 TPLINK_HWID := 0x8100002 SUPPORTED_DEVICES += tl-wr810n-v2 + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr810n-v2 @@ -851,6 +855,7 @@ define Device/tplink_tl-wr842n-v1 DEVICE_PACKAGES := kmod-usb2 kmod-usb-ledtrig-usbport TPLINK_HWID := 0x8420001 SUPPORTED_DEVICES += tl-mr3420 + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr842n-v1 @@ -862,6 +867,7 @@ define Device/tplink_tl-wr842n-v2 DEVICE_PACKAGES := kmod-usb2 kmod-usb-ledtrig-usbport TPLINK_HWID := 0x8420002 SUPPORTED_DEVICES += tl-wr842n-v2 + DEFAULT := n endef TARGET_DEVICES += tplink_tl-wr842n-v2 diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index d4a419501c0..f8969a919c9 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -2924,6 +2924,7 @@ define Device/wd_mynet-wifi-rangeextender IMAGE/sysupgrade.bin := append-rootfs | pad-rootfs | cybertan-trx | \ addpattern | append-metadata SUPPORTED_DEVICES += mynet-rext + DEFAULT := n endef TARGET_DEVICES += wd_mynet-wifi-rangeextender @@ -3014,6 +3015,7 @@ define Device/ziking_cpe46b DEVICE_MODEL := CPE46B IMAGE_SIZE := 8000k DEVICE_PACKAGES := kmod-i2c-gpio + DEFAULT := n endef TARGET_DEVICES += ziking_cpe46b diff --git a/target/linux/ath79/image/tiny-ubnt.mk b/target/linux/ath79/image/tiny-ubnt.mk index 805d193d454..07333714418 100644 --- a/target/linux/ath79/image/tiny-ubnt.mk +++ b/target/linux/ath79/image/tiny-ubnt.mk @@ -5,6 +5,7 @@ define Device/ubnt_airrouter SOC := ar7241 DEVICE_MODEL := AirRouter SUPPORTED_DEVICES += airrouter + DEFAULT := n endef TARGET_DEVICES += ubnt_airrouter @@ -14,6 +15,7 @@ define Device/ubnt_nanobridge-m DEVICE_MODEL := NanoBridge M DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m + DEFAULT := n endef TARGET_DEVICES += ubnt_nanobridge-m @@ -24,6 +26,7 @@ define Device/ubnt_bullet-m-ar7240 DEVICE_VARIANT := XM (AR7240) DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m + DEFAULT := n endef TARGET_DEVICES += ubnt_bullet-m-ar7240 @@ -34,6 +37,7 @@ define Device/ubnt_bullet-m-ar7241 DEVICE_VARIANT := XM (AR7241) DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m ubnt,bullet-m + DEFAULT := n endef TARGET_DEVICES += ubnt_bullet-m-ar7241 @@ -43,6 +47,7 @@ define Device/ubnt_picostation-m DEVICE_MODEL := Picostation M DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m + DEFAULT := n endef TARGET_DEVICES += ubnt_picostation-m @@ -52,6 +57,7 @@ define Device/ubnt_nanostation-m DEVICE_MODEL := Nanostation M DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += nanostation-m + DEFAULT := n endef TARGET_DEVICES += ubnt_nanostation-m @@ -61,6 +67,7 @@ define Device/ubnt_nanostation-loco-m DEVICE_MODEL := Nanostation Loco M DEVICE_PACKAGES += rssileds SUPPORTED_DEVICES += bullet-m + DEFAULT := n endef TARGET_DEVICES += ubnt_nanostation-loco-m diff --git a/target/linux/ath79/image/tiny.mk b/target/linux/ath79/image/tiny.mk index 0f355ef9142..6baa3afff79 100644 --- a/target/linux/ath79/image/tiny.mk +++ b/target/linux/ath79/image/tiny.mk @@ -76,5 +76,6 @@ define Device/pqi_air-pen DEVICE_PACKAGES := kmod-usb-chipidea2 IMAGE_SIZE := 7680k SUPPORTED_DEVICES += pqi-air-pen + DEFAULT := n endef TARGET_DEVICES += pqi_air-pen diff --git a/target/linux/bcm47xx/image/generic.mk b/target/linux/bcm47xx/image/generic.mk index 94064cb7d13..5cab0fa9328 100644 --- a/target/linux/bcm47xx/image/generic.mk +++ b/target/linux/bcm47xx/image/generic.mk @@ -10,6 +10,7 @@ define Device/linksys_wrt300n-v1.1 $(Device/linksys) DEVICE_ID := EWC2 VERSION := 1.51.2 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt300n-v1.1 @@ -20,6 +21,7 @@ define Device/linksys_wrt310n-v1 $(Device/linksys) DEVICE_ID := 310N VERSION := 1.0.10 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt310n-v1 @@ -30,6 +32,7 @@ define Device/linksys_wrt350n-v1 $(Device/linksys) DEVICE_ID := EWCG VERSION := 1.04.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt350n-v1 diff --git a/target/linux/bcm47xx/image/legacy.mk b/target/linux/bcm47xx/image/legacy.mk index 4c37a4505cd..b21398deca2 100644 --- a/target/linux/bcm47xx/image/legacy.mk +++ b/target/linux/bcm47xx/image/legacy.mk @@ -63,6 +63,7 @@ define Device/asus_wl-500w DEVICE_PACKAGES := kmod-b43 kmod-usb-uhci kmod-usb2-pci $(Device/asus) PRODUCTID := "WL500W " + DEFAULT := n endef TARGET_DEVICES += asus_wl-500w @@ -119,6 +120,7 @@ define Device/huawei_e970 KERNEL_NAME = vmlinux.gz IMAGES := bin IMAGE/bin := append-rootfs | trx-without-loader | huawei-bin + DEFAULT := n endef TARGET_DEVICES += huawei_e970 @@ -220,6 +222,7 @@ define Device/linksys_wrt160n-v1 $(Device/linksys) DEVICE_ID := N150 VERSION := 1.50.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt160n-v1 @@ -231,6 +234,7 @@ define Device/linksys_wrt300n-v1 IMAGES := bin trx DEVICE_ID := EWCB VERSION := 1.03.6 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt300n-v1 diff --git a/target/linux/bcm47xx/image/mips74k.mk b/target/linux/bcm47xx/image/mips74k.mk index 4478374f160..0f7610f3ddc 100644 --- a/target/linux/bcm47xx/image/mips74k.mk +++ b/target/linux/bcm47xx/image/mips74k.mk @@ -34,6 +34,7 @@ define Device/asus_rt-n10p DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := RT-N10P + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10p @@ -42,6 +43,7 @@ define Device/asus_rt-n10p-v2 DEVICE_VARIANT := v2 $(Device/asus) PRODUCTID := RT-N10PV2 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10p-v2 @@ -51,6 +53,7 @@ define Device/asus_rt-n10u DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := RT-N10U + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10u @@ -60,6 +63,7 @@ define Device/asus_rt-n10u-b DEVICE_PACKAGES := kmod-b43 $(USB2_PACKAGES) $(Device/asus) PRODUCTID := RT-N10U + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10u-b @@ -69,6 +73,7 @@ define Device/asus_rt-n12 DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := "RT-N12 " + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12 @@ -77,6 +82,7 @@ define Device/asus_rt-n12-b1 DEVICE_VARIANT := B1 $(Device/asus) PRODUCTID := RT-N12B1 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12-b1 @@ -85,6 +91,7 @@ define Device/asus_rt-n12-c1 DEVICE_VARIANT := C1 $(Device/asus) PRODUCTID := RT-N12C1 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12-c1 @@ -93,6 +100,7 @@ define Device/asus_rt-n12-d1 DEVICE_VARIANT := D1 $(Device/asus) PRODUCTID := RT-N12D1 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12-d1 @@ -100,6 +108,7 @@ define Device/asus_rt-n12hp DEVICE_MODEL := RT-N12HP $(Device/asus) PRODUCTID := RT-N12HP + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12hp @@ -132,6 +141,7 @@ define Device/asus_rt-n53 DEVICE_PACKAGES := kmod-b43 $(Device/asus) PRODUCTID := RT-N53 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n53 @@ -169,6 +179,7 @@ define Device/linksys_wrt310n-v2 $(Device/linksys) DEVICE_ID := 310N VERSION := 2.0.1 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt310n-v2 @@ -179,6 +190,7 @@ define Device/linksys_wrt320n-v1 $(Device/linksys) DEVICE_ID := 320N VERSION := 1.0.5 + DEFAULT := n endef TARGET_DEVICES += linksys_wrt320n-v1 @@ -188,6 +200,7 @@ define Device/linksys_e900-v1 $(Device/linksys) DEVICE_ID := E900 VERSION := 1.0.4 + DEFAULT := n endef TARGET_DEVICES += linksys_e900-v1 @@ -198,6 +211,7 @@ define Device/linksys_e1000 $(Device/linksys) DEVICE_ID := E100 VERSION := 1.1.3 + DEFAULT := n endef TARGET_DEVICES += linksys_e1000 @@ -207,6 +221,7 @@ define Device/linksys_e1200-v1 $(Device/linksys) DEVICE_ID := E120 VERSION := 1.0.3 + DEFAULT := n endef TARGET_DEVICES += linksys_e1200-v1 @@ -216,6 +231,7 @@ define Device/linksys_e1200-v2 $(Device/linksys) DEVICE_ID := E122 VERSION := 1.0.4 + DEFAULT := n endef TARGET_DEVICES += linksys_e1200-v2 @@ -225,6 +241,7 @@ define Device/linksys_e1500-v1 $(Device/linksys) DEVICE_ID := E150 VERSION := 1.0.5 + DEFAULT := n endef TARGET_DEVICES += linksys_e1500-v1 @@ -245,6 +262,7 @@ define Device/linksys_e2000-v1 $(Device/linksys) DEVICE_ID := 32XN VERSION := 1.0.4 + DEFAULT := n endef TARGET_DEVICES += linksys_e2000-v1 @@ -353,6 +371,7 @@ define Device/netgear_wn3000rp $(Device/netgear) NETGEAR_BOARD_ID := U12H163T01_NETGEAR NETGEAR_REGION := 1 + DEFAULT := n endef TARGET_DEVICES += netgear_wn3000rp @@ -434,6 +453,7 @@ define Device/netgear_wnr2000v2 $(Device/netgear) NETGEAR_BOARD_ID := U12H114T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wnr2000v2 @@ -486,6 +506,7 @@ define Device/netgear_wnr3500-v2 $(Device/netgear) NETGEAR_BOARD_ID := U12H127T00_NETGEAR NETGEAR_REGION := 2 + DEFAULT := n endef TARGET_DEVICES += netgear_wnr3500-v2 diff --git a/target/linux/bcm63xx/image/bcm63xx.mk b/target/linux/bcm63xx/image/bcm63xx.mk index 97959d7819c..9c5cc9bce5b 100644 --- a/target/linux/bcm63xx/image/bcm63xx.mk +++ b/target/linux/bcm63xx/image/bcm63xx.mk @@ -210,6 +210,7 @@ define Device/adb_a4001n CHIP_ID := 6328 FLASH_MB := 8 DEVICE_PACKAGES := $(USB2_PACKAGES) $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += adb_a4001n @@ -222,6 +223,7 @@ define Device/adb_a4001n1 CHIP_ID := 6328 FLASH_MB := 16 DEVICE_PACKAGES := $(USB2_PACKAGES) $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += adb_a4001n1 @@ -234,6 +236,7 @@ define Device/adb_pdg-a4001n-a-000-1a1-ax CHIP_ID := 6328 FLASH_MB := 16 DEVICE_PACKAGES := $(USB2_PACKAGES) $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += adb_pdg-a4001n-a-000-1a1-ax @@ -269,6 +272,7 @@ define Device/alcatel_rg100a CHIP_ID := 6358 BLOCK_SIZE := 0x20000 DEVICE_PACKAGES := $(USB2_PACKAGES) $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += alcatel_rg100a @@ -448,6 +452,7 @@ define Device/comtrend_ct-6373 CFE_BOARD_ID := CT6373-1 CHIP_ID := 6358 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += comtrend_ct-6373 @@ -532,6 +537,7 @@ define Device/d-link_dsl-2650u CFE_BOARD_ID := 96358VW2 CHIP_ID := 6358 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += d-link_dsl-2650u @@ -593,6 +599,7 @@ define Device/d-link_dsl-2750u-c1 CHIP_ID := 6328 FLASH_MB := 8 DEVICE_PACKAGES := $(USB2_PACKAGES) $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += d-link_dsl-2750u-c1 @@ -618,6 +625,7 @@ define Device/d-link_dva-g3810bn-tl CFE_BOARD_ID := 96358VW CHIP_ID := 6358 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += d-link_dva-g3810bn-tl @@ -765,6 +773,7 @@ define Device/huawei_echolife-hg622 BLOCK_SIZE := 0x20000 FLASH_MB := 16 DEVICE_PACKAGES := $(RT28_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += huawei_echolife-hg622 @@ -825,6 +834,7 @@ define Device/netgear_cvg834g HCS_MAGIC_BYTES := 0xa020 HCS_REV_MIN := 0001 HCS_REV_MAJ := 0022 + DEFAULT := n endef TARGET_DEVICES += netgear_cvg834g @@ -930,6 +940,7 @@ define Device/pirelli_a226g CHIP_ID := 6358 CFE_EXTRAS += --signature2 IMAGE --tag-version 8 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += pirelli_a226g @@ -941,6 +952,7 @@ define Device/pirelli_a226m CHIP_ID := 6358 CFE_EXTRAS += --signature2 IMAGE --tag-version 8 DEVICE_PACKAGES := $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += pirelli_a226m @@ -965,6 +977,7 @@ define Device/pirelli_agpf-s0 CFE_EXTRAS += --signature2 IMAGE --tag-version 8 BLOCK_SIZE := 0x20000 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += pirelli_agpf-s0 @@ -1009,6 +1022,7 @@ define Device/sagem_fast-2704n CHIP_ID := 6318 FLASH_MB := 8 DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += sagem_fast-2704n @@ -1046,6 +1060,7 @@ define Device/sfr_neufbox-4-sercomm-r0 CHIP_ID := 6358 CFE_EXTRAS += --rsa-signature "$(VERSION_DIST)-$(firstword $(subst -,$(space),$(REVISION)))" DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += sfr_neufbox-4-sercomm-r0 @@ -1058,6 +1073,7 @@ define Device/sfr_neufbox-4-foxconn-r1 CHIP_ID := 6358 CFE_EXTRAS += --rsa-signature "$(VERSION_DIST)-$(firstword $(subst -,$(space),$(REVISION)))" DEVICE_PACKAGES := $(B43_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += sfr_neufbox-4-foxconn-r1 @@ -1096,6 +1112,7 @@ define Device/t-com_speedport-w-303v CFE_BOARD_ID := 96358-502V CHIP_ID := 6358 DEVICE_PACKAGES := $(B43_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += t-com_speedport-w-303v @@ -1182,6 +1199,7 @@ define Device/telsey_cpva642 CFE_EXTRAS += --signature "Telsey Tlc" --signature2 "99.99.999" --second-image-flag "0" FLASH_MB := 8 DEVICE_PACKAGES := $(RT63_PACKAGES) $(USB2_PACKAGES) + DEFAULT := n endef TARGET_DEVICES += telsey_cpva642 diff --git a/target/linux/lantiq/image/ar9.mk b/target/linux/lantiq/image/ar9.mk index 9a0d68433ce..3a301f3655b 100644 --- a/target/linux/lantiq/image/ar9.mk +++ b/target/linux/lantiq/image/ar9.mk @@ -154,6 +154,7 @@ define Device/zte_h201l kmod-usb-dwc2 kmod-usb-ledtrig-usbport \ kmod-ltq-tapi kmod-ltq-vmmc SUPPORTED_DEVICES += H201L + DEFAULT := n endef TARGET_DEVICES += zte_h201l diff --git a/target/linux/lantiq/image/danube.mk b/target/linux/lantiq/image/danube.mk index a54cb3117da..c2bf7e798bb 100644 --- a/target/linux/lantiq/image/danube.mk +++ b/target/linux/lantiq/image/danube.mk @@ -12,6 +12,7 @@ define Device/arcadyan_arv4510pw kmod-ltq-tapi kmod-ltq-vmmc \ kmod-rt2800-pci kmod-ath5k wpad-basic-mbedtls SUPPORTED_DEVICES += ARV4510PW + DEFAULT := n endef TARGET_DEVICES += arcadyan_arv4510pw @@ -219,5 +220,6 @@ define Device/siemens_gigaset-sx76x ltq-adsl-app ppp-mod-pppoe \ kmod-ath5k wpad-basic-mbedtls SUPPORTED_DEVICES += GIGASX76X + DEFAULT := n endef TARGET_DEVICES += siemens_gigaset-sx76x diff --git a/target/linux/lantiq/image/vr9.mk b/target/linux/lantiq/image/vr9.mk index f3149bf2c07..3c05636f563 100644 --- a/target/linux/lantiq/image/vr9.mk +++ b/target/linux/lantiq/image/vr9.mk @@ -12,6 +12,7 @@ define Device/alphanetworks_asl56026 DEVICE_ALT0_VENDOR := BT Openreach DEVICE_ALT0_MODEL := ECI VDSL Modem V-2FUb/I IMAGE_SIZE := 7488k + DEFAULT := n endef TARGET_DEVICES += alphanetworks_asl56026 @@ -38,6 +39,7 @@ define Device/arcadyan_vg3503j DEVICE_MODEL := ECI VDSL Modem V-2FUb/R IMAGE_SIZE := 8000k SUPPORTED_DEVICES += VG3503J + DEFAULT := n endef TARGET_DEVICES += arcadyan_vg3503j diff --git a/target/linux/ramips/image/mt7620.mk b/target/linux/ramips/image/mt7620.mk index 621162c9701..7c2ff740f05 100644 --- a/target/linux/ramips/image/mt7620.mk +++ b/target/linux/ramips/image/mt7620.mk @@ -124,6 +124,7 @@ define Device/asus_rt-n12p DEVICE_VENDOR := ASUS DEVICE_MODEL := RT-N11P/RT-N12+/RT-N12Eb1 SUPPORTED_DEVICES += rt-n12p + DEFAULT := n endef TARGET_DEVICES += asus_rt-n12p @@ -191,6 +192,7 @@ define Device/comfast_cf-wr800n DEVICE_VENDOR := Comfast DEVICE_MODEL := CF-WR800N SUPPORTED_DEVICES += cf-wr800n + DEFAULT := n endef TARGET_DEVICES += comfast_cf-wr800n @@ -241,6 +243,7 @@ define Device/dlink_dwr-116-a1 DLINK_ROM_ID := DLK6E3803001 DLINK_FAMILY_MEMBER := 0x6E38 DLINK_FIRMWARE_SIZE := 0x7E0000 + DEFAULT := n endef TARGET_DEVICES += dlink_dwr-116-a1 @@ -853,6 +856,7 @@ define Device/netgear_wn3000rp-v3 DEVICE_MODEL := WN3000RP DEVICE_VARIANT := v3 SUPPORTED_DEVICES += wn3000rpv3 + DEFAULT := n endef TARGET_DEVICES += netgear_wn3000rp-v3 @@ -1438,6 +1442,7 @@ define Device/zbtlink_zbt-wr8305rt DEVICE_MODEL := ZBT-WR8305RT DEVICE_PACKAGES := kmod-usb2 kmod-usb-ohci SUPPORTED_DEVICES += zbt-wr8305rt + DEFAULT := n endef TARGET_DEVICES += zbtlink_zbt-wr8305rt diff --git a/target/linux/ramips/image/mt76x8.mk b/target/linux/ramips/image/mt76x8.mk index 22db5c1382b..816009ac182 100644 --- a/target/linux/ramips/image/mt76x8.mk +++ b/target/linux/ramips/image/mt76x8.mk @@ -68,6 +68,7 @@ define Device/asus_rt-n10p-v3 DEVICE_VENDOR := ASUS DEVICE_MODEL := RT-N10P DEVICE_VARIANT := V3 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n10p-v3 @@ -82,6 +83,7 @@ define Device/asus_rt-n11p-b1 DEVICE_ALT1_VENDOR := ASUS DEVICE_ALT1_MODEL := RT-N300 DEVICE_ALT1_VARIANT := B1 + DEFAULT := n endef TARGET_DEVICES += asus_rt-n11p-b1 diff --git a/target/linux/ramips/image/rt288x.mk b/target/linux/ramips/image/rt288x.mk index c93d7d78e51..0fdb35d963b 100644 --- a/target/linux/ramips/image/rt288x.mk +++ b/target/linux/ramips/image/rt288x.mk @@ -54,6 +54,7 @@ define Device/belkin_f5d8235-v1 DEVICE_PACKAGES := kmod-switch-rtl8366s kmod-usb-ohci kmod-usb-ohci-pci \ kmod-usb2 kmod-usb2-pci kmod-usb-ledtrig-usbport SUPPORTED_DEVICES += f5d8235-v1 + DEFAULT := n endef TARGET_DEVICES += belkin_f5d8235-v1 diff --git a/target/linux/ramips/image/rt305x.mk b/target/linux/ramips/image/rt305x.mk index 83658cffa2d..815e03a8d44 100644 --- a/target/linux/ramips/image/rt305x.mk +++ b/target/linux/ramips/image/rt305x.mk @@ -43,6 +43,7 @@ define Device/7links_px-4885-8m DEVICE_PACKAGES := kmod-usb-dwc2 kmod-usb2 kmod-usb-ohci \ kmod-usb-ledtrig-usbport kmod-leds-gpio SUPPORTED_DEVICES += px-4885-8M + DEFAULT := n endef TARGET_DEVICES += 7links_px-4885-8m @@ -53,6 +54,7 @@ define Device/8devices_carambola DEVICE_MODEL := Carambola DEVICE_PACKAGES := SUPPORTED_DEVICES += carambola + DEFAULT := n endef TARGET_DEVICES += 8devices_carambola @@ -62,6 +64,7 @@ define Device/accton_wr6202 DEVICE_VENDOR := Accton DEVICE_MODEL := WR6202 SUPPORTED_DEVICES += wr6202 + DEFAULT := n endef TARGET_DEVICES += accton_wr6202 @@ -81,6 +84,7 @@ define Device/alfa-network_w502u DEVICE_VENDOR := ALFA DEVICE_MODEL := Networks W502U SUPPORTED_DEVICES += w502u + DEFAULT := n endef TARGET_DEVICES += alfa-network_w502u @@ -104,6 +108,7 @@ define Device/allnet_all0256n-8m DEVICE_VARIANT := 8M DEVICE_PACKAGES := rssileds SUPPORTED_DEVICES += all0256n-8M + DEFAULT := n endef TARGET_DEVICES += allnet_all0256n-8m @@ -127,6 +132,7 @@ define Device/allnet_all5003 DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-usb-ledtrig-usbport \ kmod-i2c-gpio kmod-hwmon-lm92 kmod-gpio-pcf857x SUPPORTED_DEVICES += all5003 + DEFAULT := n endef TARGET_DEVICES += allnet_all5003 @@ -138,6 +144,7 @@ define Device/alphanetworks_asl26555-16m DEVICE_VARIANT := 16M DEVICE_PACKAGES := kmod-usb-dwc2 kmod-usb-ledtrig-usbport SUPPORTED_DEVICES += asl26555 asl26555-16M + DEFAULT := n endef TARGET_DEVICES += alphanetworks_asl26555-16m @@ -148,6 +155,7 @@ define Device/alphanetworks_asl26555-8m DEVICE_MODEL := ASL26555 DEVICE_PACKAGES := kmod-usb-dwc2 kmod-usb-ledtrig-usbport SUPPORTED_DEVICES += asl26555 asl26555-8M + DEFAULT := n endef TARGET_DEVICES += alphanetworks_asl26555-8m @@ -159,6 +167,7 @@ define Device/arcwireless_freestation5 DEVICE_PACKAGES := kmod-usb-dwc2 kmod-rt2500-usb kmod-rt2800-usb \ kmod-rt2x00-usb SUPPORTED_DEVICES += freestation5 + DEFAULT := n endef TARGET_DEVICES += arcwireless_freestation5 @@ -201,6 +210,7 @@ define Device/asiarf_awm002-evb-8m DEVICE_VARIANT := 8M DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-gpio SUPPORTED_DEVICES += awm002-evb-8M + DEFAULT := n endef TARGET_DEVICES += asiarf_awm002-evb-8m @@ -232,6 +242,7 @@ define Device/asus_rt-n13u DEVICE_MODEL := RT-N13U DEVICE_PACKAGES := kmod-leds-gpio kmod-rt2800-pci kmod-usb-dwc2 SUPPORTED_DEVICES += rt-n13u + DEFAULT := n endef TARGET_DEVICES += asus_rt-n13u @@ -262,6 +273,7 @@ define Device/aximcom_mr-102n DEVICE_VENDOR := AXIMCom DEVICE_MODEL := MR-102N SUPPORTED_DEVICES += mr-102n + DEFAULT := n endef TARGET_DEVICES += aximcom_mr-102n @@ -274,6 +286,7 @@ define Device/aztech_hw550-3g DEVICE_ALT0_MODEL := ALL0239-3G DEVICE_PACKAGES := kmod-usb-dwc2 kmod-usb-ledtrig-usbport SUPPORTED_DEVICES += hw550-3g + DEFAULT := n endef TARGET_DEVICES += aztech_hw550-3g @@ -285,6 +298,7 @@ define Device/belkin_f5d8235-v2 DEVICE_VARIANT := v2 DEVICE_PACKAGES := kmod-switch-rtl8366rb SUPPORTED_DEVICES += f5d8235-v2 + DEFAULT := n endef TARGET_DEVICES += belkin_f5d8235-v2 @@ -294,6 +308,7 @@ define Device/belkin_f7c027 DEVICE_VENDOR := Belkin DEVICE_MODEL := F7C027 SUPPORTED_DEVICES += f7c027 + DEFAULT := n endef TARGET_DEVICES += belkin_f7c027 @@ -320,6 +335,7 @@ define Device/dlink_dap-1350 DEVICE_VENDOR := D-Link DEVICE_MODEL := DAP-1350 SUPPORTED_DEVICES += dap-1350 + DEFAULT := n endef TARGET_DEVICES += dlink_dap-1350 @@ -369,6 +385,7 @@ define Device/dlink_dir-300-b7 DEVICE_MODEL := DIR-300 DEVICE_VARIANT := B7 SUPPORTED_DEVICES += dir-300-b7 + DEFAULT := n endef TARGET_DEVICES += dlink_dir-300-b7 @@ -379,6 +396,7 @@ define Device/dlink_dir-320-b1 DEVICE_MODEL := DIR-320 DEVICE_VARIANT := B1 SUPPORTED_DEVICES += dir-320-b1 + DEFAULT := n endef TARGET_DEVICES += dlink_dir-320-b1 @@ -445,6 +463,7 @@ define Device/dlink_dir-620-a1 DEVICE_MODEL := DIR-620 DEVICE_VARIANT := A1 SUPPORTED_DEVICES += dir-620-a1 + DEFAULT := n endef TARGET_DEVICES += dlink_dir-620-a1 @@ -455,6 +474,7 @@ define Device/dlink_dir-620-d1 DEVICE_MODEL := DIR-620 DEVICE_VARIANT := D1 SUPPORTED_DEVICES += dir-620-d1 + DEFAULT := n endef TARGET_DEVICES += dlink_dir-620-d1 @@ -474,6 +494,7 @@ define Device/dlink_dwr-512-b IMAGE/sysupgrade.bin := mkdlinkfw | pad-rootfs | append-metadata IMAGE/factory.bin := mkdlinkfw | pad-rootfs | mkdlinkfw-factory SUPPORTED_DEVICES += dwr-512-b + DEFAULT := n endef TARGET_DEVICES += dlink_dwr-512-b @@ -484,6 +505,7 @@ define Device/easyacc_wizard-8800 DEVICE_VENDOR := EasyAcc DEVICE_MODEL := WIZARD 8800 SUPPORTED_DEVICES += wizard8800 + DEFAULT := n endef TARGET_DEVICES += easyacc_wizard-8800 @@ -558,6 +580,7 @@ define Device/hame_mpr-a2 DEVICE_VARIANT := A2 DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 SUPPORTED_DEVICES += mpr-a2 + DEFAULT := n endef TARGET_DEVICES += hame_mpr-a2 @@ -611,6 +634,7 @@ define Device/huawei_hg255d DEVICE_VENDOR := HuaWei DEVICE_MODEL := HG255D SUPPORTED_DEVICES += hg255d + DEFAULT := n endef TARGET_DEVICES += huawei_hg255d @@ -623,6 +647,7 @@ define Device/intenso_memory2move DEVICE_PACKAGES := kmod-usb2 kmod-usb-storage kmod-scsi-core kmod-fs-ext4 \ kmod-fs-vfat block-mount SUPPORTED_DEVICES += m2m + DEFAULT := n endef TARGET_DEVICES += intenso_memory2move @@ -668,6 +693,7 @@ define Device/mofinetwork_mofi3500-3gn DEVICE_VENDOR := MoFi Network DEVICE_MODEL := MOFI3500-3GN SUPPORTED_DEVICES += mofi3500-3gn + DEFAULT := n endef TARGET_DEVICES += mofinetwork_mofi3500-3gn @@ -730,6 +756,7 @@ define Device/nexx_wt1520-8m DEVICE_MODEL := WT1520 DEVICE_VARIANT := 8M SUPPORTED_DEVICES += wt1520-8M + DEFAULT := n endef TARGET_DEVICES += nexx_wt1520-8m @@ -741,6 +768,7 @@ define Device/nixcore_x1-16m DEVICE_VARIANT := 16M DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += nixcore-x1 nixcore-x1-16M + DEFAULT := n endef TARGET_DEVICES += nixcore_x1-16m @@ -752,6 +780,7 @@ define Device/nixcore_x1-8m DEVICE_VARIANT := 8M DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += nixcore-x1 nixcore-x1-8M + DEFAULT := n endef TARGET_DEVICES += nixcore_x1-8m @@ -763,6 +792,7 @@ define Device/olimex_rt5350f-olinuxino DEVICE_MODEL := RT5350F-OLinuXino DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += rt5350f-olinuxino + DEFAULT := n endef TARGET_DEVICES += olimex_rt5350f-olinuxino @@ -774,6 +804,7 @@ define Device/olimex_rt5350f-olinuxino-evb DEVICE_MODEL := RT5350F-OLinuXino-EVB DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += rt5350f-olinuxino-evb + DEFAULT := n endef TARGET_DEVICES += olimex_rt5350f-olinuxino-evb @@ -792,6 +823,7 @@ define Device/omnima_miniembwifi DEVICE_VENDOR := Omnima DEVICE_MODEL := MiniEMBWiFi SUPPORTED_DEVICES += miniembwifi + DEFAULT := n endef TARGET_DEVICES += omnima_miniembwifi @@ -835,6 +867,7 @@ define Device/planex_mzk-wdpr DEVICE_VENDOR := Planex DEVICE_MODEL := MZK-WDPR SUPPORTED_DEVICES += mzk-wdpr + DEFAULT := n endef TARGET_DEVICES += planex_mzk-wdpr @@ -887,6 +920,7 @@ define Device/poray_m4-8m DEVICE_VARIANT := 8M DEVICE_PACKAGES := kmod-usb2 SUPPORTED_DEVICES += m4-8M + DEFAULT := n endef TARGET_DEVICES += poray_m4-8m @@ -900,6 +934,7 @@ define Device/poray_x5 DEVICE_MODEL := X5/X6 DEVICE_PACKAGES := kmod-usb2 SUPPORTED_DEVICES += x5 + DEFAULT := n endef TARGET_DEVICES += poray_x5 @@ -913,6 +948,7 @@ define Device/poray_x8 DEVICE_MODEL := X8 DEVICE_PACKAGES := kmod-usb2 SUPPORTED_DEVICES += x8 + DEFAULT := n endef TARGET_DEVICES += poray_x8 @@ -923,6 +959,7 @@ define Device/prolink_pwh2004 DEVICE_MODEL := PWH2004 DEVICE_PACKAGES := SUPPORTED_DEVICES += pwh2004 + DEFAULT := n endef TARGET_DEVICES += prolink_pwh2004 @@ -973,6 +1010,7 @@ define Device/teltonika_rut5xx DEVICE_VENDOR := Teltonika DEVICE_MODEL := RUT5XX SUPPORTED_DEVICES += rut5xx + DEFAULT := n endef TARGET_DEVICES += teltonika_rut5xx @@ -1042,6 +1080,7 @@ define Device/trendnet_tew-714tru DEVICE_VENDOR := TRENDnet DEVICE_MODEL := TEW-714TRU SUPPORTED_DEVICES += tew-714tru + DEFAULT := n endef TARGET_DEVICES += trendnet_tew-714tru @@ -1077,6 +1116,7 @@ define Device/unbranded_wr512-3gn-8m DEVICE_MODEL := WR512-3GN DEVICE_VARIANT := 8M SUPPORTED_DEVICES += wr512-3gn-8M + DEFAULT := n endef TARGET_DEVICES += unbranded_wr512-3gn-8m @@ -1108,6 +1148,7 @@ define Device/upvel_ur-336un DEVICE_MODEL := UR-336UN DEVICE_PACKAGES := kmod-usb-dwc2 kmod-usb-ledtrig-usbport SUPPORTED_DEVICES += ur-336un + DEFAULT := n endef TARGET_DEVICES += upvel_ur-336un @@ -1119,6 +1160,7 @@ define Device/vocore_vocore-16m DEVICE_VARIANT := 16M DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += vocore vocore-16M + DEFAULT := n endef TARGET_DEVICES += vocore_vocore-16m @@ -1130,6 +1172,7 @@ define Device/vocore_vocore-8m DEVICE_VARIANT := 8M DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 kmod-i2c-ralink kmod-spi-dev SUPPORTED_DEVICES += vocore vocore-8M + DEFAULT := n endef TARGET_DEVICES += vocore_vocore-8m @@ -1149,6 +1192,7 @@ define Device/wiznet_wizfi630a DEVICE_VENDOR := WIZnet DEVICE_MODEL := WizFi630A SUPPORTED_DEVICES += wizfi630a + DEFAULT := n endef TARGET_DEVICES += wiznet_wizfi630a @@ -1158,6 +1202,7 @@ define Device/zorlik_zl5900v2 DEVICE_VENDOR := Zorlik DEVICE_MODEL := ZL5900V2 DEVICE_PACKAGES := kmod-usb-ohci kmod-usb2 + DEFAULT := n endef TARGET_DEVICES += zorlik_zl5900v2 @@ -1180,6 +1225,7 @@ define Device/zyxel_keenetic DEVICE_PACKAGES := kmod-usb2 kmod-usb-ehci kmod-usb-ledtrig-usbport \ kmod-usb-dwc2 SUPPORTED_DEVICES += kn + DEFAULT := n endef TARGET_DEVICES += zyxel_keenetic @@ -1190,6 +1236,7 @@ define Device/zyxel_keenetic-4g-b DEVICE_VENDOR := ZyXEL DEVICE_MODEL := Keenetic 4G DEVICE_VARIANT := B + DEFAULT := n endef TARGET_DEVICES += zyxel_keenetic-4g-b @@ -1200,6 +1247,7 @@ define Device/zyxel_keenetic-lite-b DEVICE_VENDOR := ZyXEL DEVICE_MODEL := Keenetic Lite DEVICE_VARIANT := B + DEFAULT := n endef TARGET_DEVICES += zyxel_keenetic-lite-b diff --git a/target/linux/ramips/image/rt3883.mk b/target/linux/ramips/image/rt3883.mk index 0d12aa0a402..04300992965 100644 --- a/target/linux/ramips/image/rt3883.mk +++ b/target/linux/ramips/image/rt3883.mk @@ -72,6 +72,7 @@ define Device/loewe_wmdr-143n DEVICE_VENDOR := Loewe DEVICE_MODEL := WMDR-143N SUPPORTED_DEVICES += wmdr-143n + DEFAULT := n endef TARGET_DEVICES += loewe_wmdr-143n From 066441b5e4919ab6a59a41f00209b8c8d19dc8a5 Mon Sep 17 00:00:00 2001 From: Felix Baumann Date: Sat, 20 May 2023 09:07:44 +0200 Subject: [PATCH 36/88] treewide: Disable building 8M RAM devices Following deprecation notice[1] in 21.02, disable target with 8M of RAM [1] https://openwrt.org/supported_devices/864_warning Signed-off-by: Felix Baumann --- target/linux/bcm47xx/image/legacy.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/bcm47xx/image/legacy.mk b/target/linux/bcm47xx/image/legacy.mk index b21398deca2..3c682d37e7e 100644 --- a/target/linux/bcm47xx/image/legacy.mk +++ b/target/linux/bcm47xx/image/legacy.mk @@ -315,6 +315,7 @@ define Device/usrobotics_usr5461 DEVICE_PACKAGES := kmod-b43 $(USB1_PACKAGES) IMAGES := bin IMAGE/bin := append-rootfs | trx-with-loader | usrobotics-bin + DEFAULT := n endef TARGET_DEVICES += usrobotics_usr5461 From 3b2337b467b7bb39746a244e82506ffbbfae4897 Mon Sep 17 00:00:00 2001 From: Philip Prindeville Date: Wed, 17 May 2023 09:38:48 -0600 Subject: [PATCH 37/88] kernel: disable IGD (video DRM) support IGD is only useful when accelerating a VM guest that wants to direct render to memory in the host's framebuffer, but since OpenWrt typically runs on headless hardware, this serves no purpose. Also build vfio with VFIO_NOIOMMU undefined (to get all of the code enabled), but allow it to be enabled via boot-time modparams settings (or at run-time via sysfs writes to "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode". Signed-off-by: Philip Prindeville --- package/kernel/linux/modules/virt.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package/kernel/linux/modules/virt.mk b/package/kernel/linux/modules/virt.mk index 85f47aacbf9..90226b48063 100644 --- a/package/kernel/linux/modules/virt.mk +++ b/package/kernel/linux/modules/virt.mk @@ -82,6 +82,8 @@ define KernelPackage/vfio CONFIG_VFIO \ CONFIG_VFIO_NOIOMMU=n \ CONFIG_VFIO_MDEV=n + MODPARAMS.vfio:=\ + enable_unsafe_noiommu_mode=n FILES:= \ $(LINUX_DIR)/drivers/vfio/vfio.ko \ $(LINUX_DIR)/drivers/vfio/vfio_virqfd.ko \ @@ -102,7 +104,7 @@ define KernelPackage/vfio-pci DEPENDS:=@TARGET_x86_64 @PCI_SUPPORT +kmod-vfio +kmod-irqbypass KCONFIG:= \ CONFIG_VFIO_PCI \ - CONFIG_VFIO_PCI_IGD=y + CONFIG_VFIO_PCI_IGD=n FILES:= \ $(LINUX_DIR)/drivers/vfio/pci/vfio-pci-core.ko \ $(LINUX_DIR)/drivers/vfio/pci/vfio-pci.ko From 8182c7edcbe397fe87737d876c8529f42bc7bdd1 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 21 May 2023 13:11:14 +0200 Subject: [PATCH 38/88] firmware: intel-microcode: update to 20230512 Debian changelog: intel-microcode (3.20230512.1) unstable; urgency=medium * New upstream microcode datafile 20230512 (closes: #1036013) * Includes fixes or mitigations for an undisclosed security issue * New microcodes: sig 0x000906a4, pf_mask 0x40, 2022-10-12, rev 0x0004, size 115712 sig 0x000b06e0, pf_mask 0x01, 2022-12-19, rev 0x0010, size 134144 * Updated microcodes: sig 0x00050653, pf_mask 0x97, 2022-12-21, rev 0x1000171, size 36864 sig 0x00050654, pf_mask 0xb7, 2022-12-21, rev 0x2006f05, size 44032 sig 0x00050656, pf_mask 0xbf, 2022-12-21, rev 0x4003501, size 37888 sig 0x00050657, pf_mask 0xbf, 2022-12-21, rev 0x5003501, size 37888 sig 0x0005065b, pf_mask 0xbf, 2022-12-21, rev 0x7002601, size 29696 sig 0x000606a6, pf_mask 0x87, 2022-12-28, rev 0xd000390, size 296960 sig 0x000706e5, pf_mask 0x80, 2022-12-25, rev 0x00ba, size 113664 sig 0x000806a1, pf_mask 0x10, 2023-01-13, rev 0x0033, size 34816 sig 0x000806c1, pf_mask 0x80, 2022-12-28, rev 0x00aa, size 110592 sig 0x000806c2, pf_mask 0xc2, 2022-12-28, rev 0x002a, size 97280 sig 0x000806d1, pf_mask 0xc2, 2022-12-28, rev 0x0044, size 102400 sig 0x000806e9, pf_mask 0xc0, 2022-12-26, rev 0x00f2, size 105472 sig 0x000806e9, pf_mask 0x10, 2023-01-02, rev 0x00f2, size 105472 sig 0x000806ea, pf_mask 0xc0, 2022-12-26, rev 0x00f2, size 105472 sig 0x000806eb, pf_mask 0xd0, 2022-12-26, rev 0x00f2, size 105472 sig 0x000806ec, pf_mask 0x94, 2022-12-26, rev 0x00f6, size 105472 sig 0x000806f8, pf_mask 0x87, 2023-03-13, rev 0x2b000461, size 564224 sig 0x000806f7, pf_mask 0x87, 2023-03-13, rev 0x2b000461 sig 0x000806f6, pf_mask 0x87, 2023-03-13, rev 0x2b000461 sig 0x000806f5, pf_mask 0x87, 2023-03-13, rev 0x2b000461 sig 0x000806f4, pf_mask 0x87, 2023-03-13, rev 0x2b000461 sig 0x000806f8, pf_mask 0x10, 2023-02-14, rev 0x2c0001d1, size 595968 sig 0x000806f6, pf_mask 0x10, 2023-02-14, rev 0x2c0001d1 sig 0x000806f5, pf_mask 0x10, 2023-02-14, rev 0x2c0001d1 sig 0x000806f4, pf_mask 0x10, 2023-02-14, rev 0x2c0001d1 sig 0x000906a3, pf_mask 0x80, 2023-02-14, rev 0x042a, size 218112 sig 0x000906a4, pf_mask 0x80, 2023-02-14, rev 0x042a sig 0x000906e9, pf_mask 0x2a, 2022-12-26, rev 0x00f2, size 108544 sig 0x000906ea, pf_mask 0x22, 2023-01-12, rev 0x00f2, size 104448 sig 0x000906eb, pf_mask 0x02, 2022-12-26, rev 0x00f2, size 105472 sig 0x000906ec, pf_mask 0x22, 2023-01-12, rev 0x00f2, size 104448 sig 0x000906ed, pf_mask 0x22, 2023-02-05, rev 0x00f8, size 104448 sig 0x000a0652, pf_mask 0x20, 2022-12-27, rev 0x00f6, size 96256 sig 0x000a0653, pf_mask 0x22, 2023-01-01, rev 0x00f6, size 97280 sig 0x000a0655, pf_mask 0x22, 2022-12-26, rev 0x00f6, size 96256 sig 0x000a0660, pf_mask 0x80, 2022-12-26, rev 0x00f6, size 97280 sig 0x000a0661, pf_mask 0x80, 2022-12-26, rev 0x00f6, size 96256 sig 0x000a0671, pf_mask 0x02, 2022-12-25, rev 0x0058, size 103424 sig 0x000b0671, pf_mask 0x32, 2023-02-06, rev 0x0113, size 207872 sig 0x000b06a2, pf_mask 0xc0, 2023-02-22, rev 0x4112, size 212992 sig 0x000b06a3, pf_mask 0xc0, 2023-02-22, rev 0x4112 * source: update symlinks to reflect id of the latest release, 20230512 -- Henrique de Moraes Holschuh Tue, 16 May 2023 00:13:02 -0300 intel-microcode (3.20230214.1) unstable; urgency=medium * Non-maintainer upload. * New upstream microcode datafile 20230214 - Includes Fixes for: (Closes: #1031334) - INTEL-SA-00700: CVE-2022-21216 - INTEL-SA-00730: CVE-2022-33972 - INTEL-SA-00738: CVE-2022-33196 - INTEL-SA-00767: CVE-2022-38090 * New Microcodes: sig 0x000806f4, pf_mask 0x10, 2022-12-19, rev 0x2c000170 sig 0x000806f4, pf_mask 0x87, 2022-12-27, rev 0x2b000181 sig 0x000806f5, pf_mask 0x10, 2022-12-19, rev 0x2c000170 sig 0x000806f5, pf_mask 0x87, 2022-12-27, rev 0x2b000181 sig 0x000806f6, pf_mask 0x10, 2022-12-19, rev 0x2c000170 sig 0x000806f6, pf_mask 0x87, 2022-12-27, rev 0x2b000181 sig 0x000806f7, pf_mask 0x87, 2022-12-27, rev 0x2b000181 sig 0x000806f8, pf_mask 0x10, 2022-12-19, rev 0x2c000170 sig 0x000806f8, pf_mask 0x10, 2022-12-19, rev 0x2c000170, size 600064 sig 0x000806f8, pf_mask 0x87, 2022-12-27, rev 0x2b000181 sig 0x000806f8, pf_mask 0x87, 2022-12-27, rev 0x2b000181, size 561152 sig 0x000b06a2, pf_mask 0xc0, 2022-12-08, rev 0x410e sig 0x000b06a2, pf_mask 0xc0, 2022-12-08, rev 0x410e, size 212992 sig 0x000b06a3, pf_mask 0xc0, 2022-12-08, rev 0x410e * Updated Microcodes: sig 0x00050653, pf_mask 0x97, 2022-08-30, rev 0x1000161, size 36864 sig 0x00050656, pf_mask 0xbf, 2022-08-26, rev 0x4003303, size 37888 sig 0x00050657, pf_mask 0xbf, 2022-08-26, rev 0x5003303, size 37888 sig 0x0005065b, pf_mask 0xbf, 2022-08-26, rev 0x7002503, size 29696 sig 0x000606a6, pf_mask 0x87, 2022-10-09, rev 0xd000389, size 296960 sig 0x000606c1, pf_mask 0x10, 2022-09-23, rev 0x1000211, size 289792 sig 0x000706a1, pf_mask 0x01, 2022-09-16, rev 0x003e, size 75776 sig 0x000706a8, pf_mask 0x01, 2022-09-20, rev 0x0022, size 76800 sig 0x000706e5, pf_mask 0x80, 2022-08-31, rev 0x00b8, size 113664 sig 0x000806a1, pf_mask 0x10, 2022-09-07, rev 0x0032, size 34816 sig 0x00090672, pf_mask 0x07, 2023-01-04, rev 0x002c sig 0x00090672, pf_mask 0x07, 2023-01-04, rev 0x002c, size 219136 sig 0x00090675, pf_mask 0x07, 2023-01-04, rev 0x002c sig 0x000906a3, pf_mask 0x80, 2023-01-11, rev 0x0429 sig 0x000906a3, pf_mask 0x80, 2023-01-11, rev 0x0429, size 218112 sig 0x000906a4, pf_mask 0x80, 2023-01-11, rev 0x0429 sig 0x000906c0, pf_mask 0x01, 2022-09-02, rev 0x24000024, size 20480 sig 0x000a0671, pf_mask 0x02, 2022-08-31, rev 0x0057, size 103424 sig 0x000b0671, pf_mask 0x32, 2022-12-19, rev 0x0112, size 207872 sig 0x000b06f2, pf_mask 0x07, 2023-01-04, rev 0x002c sig 0x000b06f5, pf_mask 0x07, 2023-01-04, rev 0x002c -- Tobias Frost Sun, 12 Mar 2023 18:16:50 +0100 Signed-off-by: Christian Lamparter --- package/firmware/intel-microcode/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/firmware/intel-microcode/Makefile b/package/firmware/intel-microcode/Makefile index 58ae7ee74be..4c234ddc846 100644 --- a/package/firmware/intel-microcode/Makefile +++ b/package/firmware/intel-microcode/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=intel-microcode -PKG_VERSION:=20221108 +PKG_VERSION:=20230512 PKG_RELEASE:=1 PKG_SOURCE:=intel-microcode_3.$(PKG_VERSION).1.tar.xz -PKG_SOURCE_URL:=@DEBIAN/pool/non-free/i/intel-microcode/ -PKG_HASH:=9c40fc5cbb386a4e1154f8f316422b28fccc9eaabdea707a80643f9bed3f9064 +PKG_SOURCE_URL:=@DEBIAN/pool/non-free-firmware/i/intel-microcode/ +PKG_HASH:=e6717a42d7b6e92280565fbb180cd0d11bc5d14874ef06ff1bed2b7a11d17c67 PKG_BUILD_DIR:=$(BUILD_DIR)/intel-microcode-3.$(PKG_VERSION).1 PKG_BUILD_DEPENDS:=iucode-tool/host From 38c150612cc9be488527e342db92d5c74093213f Mon Sep 17 00:00:00 2001 From: Sebastian Kemper Date: Wed, 17 Aug 2022 22:13:56 +0200 Subject: [PATCH 39/88] build: revert 54070a1 (all kernels are >= 5.10) Commit 54070a1 was added to allow building proper SDKs with kernels < 5.10. Now that all targets use at least kernel 5.10 it can be reverted. Signed-off-by: Sebastian Kemper --- include/kernel-defaults.mk | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk index 4029dad7387..6a341c32255 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk @@ -153,17 +153,12 @@ define Kernel/CopyImage } endef -# Always add "modules" so a proper Module.symvers file is written that -# also contains symbols from the kernel modules. Without these symbols -# external packages that depend on exported symbols from kernel modules -# will fail to build. define Kernel/CompileImage/Default rm -f $(TARGET_DIR)/init - +$(KERNEL_MAKE) $(KERNEL_MAKEOPTS_IMAGE) $(if $(KERNELNAME),$(KERNELNAME),all) modules + +$(KERNEL_MAKE) $(KERNEL_MAKEOPTS_IMAGE) $(if $(KERNELNAME),$(KERNELNAME),all) $(call Kernel/CopyImage) endef -# Here as well, always add "modules", see comment above. ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) define Kernel/CompileImage/Initramfs $(call Kernel/Configure/Initramfs) @@ -185,7 +180,7 @@ endif $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_XZ),$(STAGING_DIR_HOST)/bin/xz -T$(if $(filter 1,$(NPROC)),2,0) -9 -fz --check=crc32 $(KERNEL_BUILD_DIR)/initrd.cpio) $(if $(CONFIG_TARGET_INITRAMFS_COMPRESSION_ZSTD),$(STAGING_DIR_HOST)/bin/zstd -T0 -f -o $(KERNEL_BUILD_DIR)/initrd.cpio.zstd $(KERNEL_BUILD_DIR)/initrd.cpio) endif - +$(KERNEL_MAKE) $(KERNEL_MAKEOPTS_IMAGE) $(if $(KERNELNAME),$(KERNELNAME),all) modules + +$(KERNEL_MAKE) $(KERNEL_MAKEOPTS_IMAGE) $(if $(KERNELNAME),$(KERNELNAME),all) $(call Kernel/CopyImage,-initramfs) endef else From f75204036ccc56700df18258602cc65726dd653b Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Sun, 22 May 2022 06:10:56 -0400 Subject: [PATCH 40/88] prereq-build: allow host command symlinks to update This makes the prereq stage update the symlinks installed into staging_dir/host/bin by rearrainging the way they are verified. Before, seeing or installing a symlink would result in a successful exit code, and not installing a symlink would result is a failed exit code. However, that is not able to account for the difference between existing good and bad links, or whether the link would be the same if it was reinstalled, because the check can match the program to a different path. Instead, let a success exit code represent identifying an existing symlink as exactly the same as what would be installed if it did not exist, and let a fail exit code represent needing to install the symlink or not having a match to the check criteria. The failing exit code is caught by a new second attempt for all of the check-* targets which will then indicate to the user that there was an update by having a success exit code when the check is run again and the link is the same. When there is nothing to update, the checks will run only once. This relies on the ls command to be POSIX-conformant with long format: "path/to/link -> target/of/link" Also, make sure the symlink is executable, not just a file, and the directory only needs to be created once. Fixes: #12610 Signed-off-by: Michael Pratt --- include/prereq.mk | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/include/prereq.mk b/include/prereq.mk index d34539ec304..89660d323d9 100644 --- a/include/prereq.mk +++ b/include/prereq.mk @@ -30,6 +30,8 @@ define Require printf "Checking '$(1)'... " if $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) >/dev/null 2>/dev/null; then \ echo 'ok.'; \ + elif $(NO_TRACE_MAKE) -f $(firstword $(MAKEFILE_LIST)) check-$(1) >/dev/null 2>/dev/null; then \ + echo 'updated.'; \ else \ echo 'failed.'; \ echo "$(PKG_NAME): $(strip $(2))" >> $(TMP_DIR)/.prereq-error; \ @@ -107,7 +109,7 @@ endef # 3+: candidates define SetupHostCommand define Require/$(1) - [ -f "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0; \ + mkdir -p "$(STAGING_DIR_HOST)/bin"; \ for cmd in $(call QuoteHostCommand,$(3)) $(call QuoteHostCommand,$(4)) \ $(call QuoteHostCommand,$(5)) $(call QuoteHostCommand,$(6)) \ $(call QuoteHostCommand,$(7)) $(call QuoteHostCommand,$(8)) \ @@ -117,9 +119,13 @@ define SetupHostCommand bin="$$$$$$$$(PATH="$(subst $(space),:,$(filter-out $(STAGING_DIR_HOST)/%,$(subst :,$(space),$(PATH))))" \ command -v "$$$$$$$${cmd%% *}")"; \ if [ -x "$$$$$$$$bin" ] && eval "$$$$$$$$cmd" >/dev/null 2>/dev/null; then \ - mkdir -p "$(STAGING_DIR_HOST)/bin"; \ + case "$$$$$$$$(ls -dl -- $(STAGING_DIR_HOST)/bin/$(strip $(1)))" in \ + *" -> $$$$$$$$bin"*) \ + [ -x "$(STAGING_DIR_HOST)/bin/$(strip $(1))" ] && exit 0 \ + ;; \ + esac; \ ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \ - exit 0; \ + exit 1; \ fi; \ fi; \ done; \ From e2f9fa42044a2660f702a9b51b14cbde24a13702 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Tue, 16 May 2023 03:22:09 -0400 Subject: [PATCH 41/88] prereq-build: remove python 2 cleanup recipe This reverts commit 3b68fb57c938af3948ae4c2da61501183fbef649. After refactoring build checks to update old symlinks, and after a long time of no python 2 support, this is no longer needed. Signed-off-by: Michael Pratt --- include/prereq-build.mk | 2 -- include/prereq.mk | 12 ------------ 2 files changed, 14 deletions(-) diff --git a/include/prereq-build.mk b/include/prereq-build.mk index 14a22108805..52988fbda92 100644 --- a/include/prereq-build.mk +++ b/include/prereq-build.mk @@ -175,8 +175,6 @@ $(eval $(call SetupHostCommand,install,Please install GNU 'install', \ $(eval $(call SetupHostCommand,perl,Please install Perl 5.x, \ perl --version | grep "perl.*v5")) -$(eval $(call CleanupPython2)) - $(eval $(call SetupHostCommand,python,Please install Python >= 3.6, \ python3.11 -V 2>&1 | grep 'Python 3', \ python3.10 -V 2>&1 | grep 'Python 3', \ diff --git a/include/prereq.mk b/include/prereq.mk index 89660d323d9..5646b24efaa 100644 --- a/include/prereq.mk +++ b/include/prereq.mk @@ -77,18 +77,6 @@ define RequireCHeader $$(eval $$(call Require,$(1),$(2))) endef -define CleanupPython2 - define Require/python2-cleanup - if [ -f "$(STAGING_DIR_HOST)/bin/python" ] && \ - $(STAGING_DIR_HOST)/bin/python -V 2>&1 | \ - grep -q 'Python 2'; then \ - rm $(STAGING_DIR_HOST)/bin/python; \ - fi - endef - - $$(eval $$(call Require,python2-cleanup)) -endef - define QuoteHostCommand '$(subst ','"'"',$(strip $(1)))' endef From bd262663142e90f64f1c256b3e6b2b979c1022c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 17 May 2023 11:58:16 +0200 Subject: [PATCH 42/88] mac80211: brcm: drop brcmfmac patch waiting for register_wiphy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That was a workaround for OpenWrt generation of config files. This patch was used to postpone returning from probe function until loading firmware and calling register_wiphy(). All of that is not needed anymore thanks to the ieee80211 hotplug.d script introduced in the commit 5f8f8a366136 ("base-files, mac80211, broadcom-wl: wifi detection and configuration"). That takes care of generating /etc/config/wireless entries even if wireless device appears late in the booting process. Signed-off-by: Rafał Miłecki --- package/kernel/mac80211/Makefile | 2 +- ...-register-wiphy-s-during-module_init.patch | 64 ------------------- 2 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index 225649d67b2..248b48c3c15 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 PKG_VERSION:=6.1.24 -PKG_RELEASE:=2 +PKG_RELEASE:=3 # PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.58/ PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/ PKG_HASH:=5d39aca7e34c33cb9b3e366117b2e86841b7bdd37933679d6b1e61be6b150648 diff --git a/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch b/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch deleted file mode 100644 index 9d0f3e20b1d..00000000000 --- a/package/kernel/mac80211/patches/brcm/860-brcmfmac-register-wiphy-s-during-module_init.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Mon, 8 Jun 2015 16:11:40 +0200 -Subject: [PATCH] brcmfmac: register wiphy(s) during module_init -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This is needed by OpenWrt which expects all PHYs to be created after -module loads successfully. - -Signed-off-by: Rafał Miłecki ---- - ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c -@@ -459,6 +459,7 @@ struct brcmf_fw { - u32 curpos; - unsigned int board_index; - void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); -+ struct completion *completion; - }; - - #ifdef CONFIG_EFI -@@ -686,6 +687,8 @@ static void brcmf_fw_request_done(const - fwctx->req = NULL; - } - fwctx->done(fwctx->dev, ret, fwctx->req); -+ if (fwctx->completion) -+ complete(fwctx->completion); - kfree(fwctx); - } - -@@ -751,6 +754,8 @@ int brcmf_fw_get_firmwares(struct device - { - struct brcmf_fw_item *first = &req->items[0]; - struct brcmf_fw *fwctx; -+ struct completion completion; -+ unsigned long time_left; - char *alt_path = NULL; - int ret; - -@@ -768,6 +773,9 @@ int brcmf_fw_get_firmwares(struct device - fwctx->dev = dev; - fwctx->req = req; - fwctx->done = fw_cb; -+ -+ init_completion(&completion); -+ fwctx->completion = &completion; - - /* First try alternative board-specific path if any */ - if (fwctx->req->board_types[0]) -@@ -787,6 +795,12 @@ int brcmf_fw_get_firmwares(struct device - if (ret < 0) - brcmf_fw_request_done(NULL, fwctx); - -+ -+ time_left = wait_for_completion_timeout(&completion, -+ msecs_to_jiffies(5000)); -+ if (!time_left && fwctx) -+ fwctx->completion = NULL; -+ - return 0; - } - From 7d0fb2cc34cb7aaa2b6eaca4f14f2c20778d3e40 Mon Sep 17 00:00:00 2001 From: Doug Kerr Date: Thu, 8 Sep 2022 19:07:18 -0400 Subject: [PATCH 43/88] build: drop support for python 3.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python 3.6 EOL was Dec. 2021 buildbot is running debian 10 which ships with 3.7 meson 0.62+ requires 3.7 Signed-off-by: Doug Kerr Signed-off-by: Petr Štetiar [rebased] --- README.md | 2 +- include/prereq-build.mk | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 29ff89f90c2..8bca0ee7b08 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ documentation. ``` binutils bzip2 diff find flex gawk gcc-6+ getopt grep install libc-dev libz-dev -make4.1+ perl python3.6+ rsync subversion unzip which +make4.1+ perl python3.7+ rsync subversion unzip which ``` ### Quickstart diff --git a/include/prereq-build.mk b/include/prereq-build.mk index 52988fbda92..9096e379bb0 100644 --- a/include/prereq-build.mk +++ b/include/prereq-build.mk @@ -175,23 +175,21 @@ $(eval $(call SetupHostCommand,install,Please install GNU 'install', \ $(eval $(call SetupHostCommand,perl,Please install Perl 5.x, \ perl --version | grep "perl.*v5")) -$(eval $(call SetupHostCommand,python,Please install Python >= 3.6, \ +$(eval $(call SetupHostCommand,python,Please install Python >= 3.7, \ python3.11 -V 2>&1 | grep 'Python 3', \ python3.10 -V 2>&1 | grep 'Python 3', \ python3.9 -V 2>&1 | grep 'Python 3', \ python3.8 -V 2>&1 | grep 'Python 3', \ python3.7 -V 2>&1 | grep 'Python 3', \ - python3.6 -V 2>&1 | grep 'Python 3', \ - python3 -V 2>&1 | grep -E 'Python 3\.([6-9]|[0-9][0-9])\.?')) + python3 -V 2>&1 | grep -E 'Python 3\.([7-9]|[0-9][0-9])\.?')) -$(eval $(call SetupHostCommand,python3,Please install Python >= 3.6, \ +$(eval $(call SetupHostCommand,python3,Please install Python >= 3.7, \ python3.11 -V 2>&1 | grep 'Python 3', \ python3.10 -V 2>&1 | grep 'Python 3', \ python3.9 -V 2>&1 | grep 'Python 3', \ python3.8 -V 2>&1 | grep 'Python 3', \ python3.7 -V 2>&1 | grep 'Python 3', \ - python3.6 -V 2>&1 | grep 'Python 3', \ - python3 -V 2>&1 | grep -E 'Python 3\.([6-9]|[0-9][0-9])\.?')) + python3 -V 2>&1 | grep -E 'Python 3\.([7-9]|[0-9][0-9])\.?')) $(eval $(call TestHostCommand,python3-distutils, \ Please install the Python3 distutils module, \ From aed2569d3780cab1a1a2d75c9f9e3fe413a9844d Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 21 May 2023 18:30:14 +0200 Subject: [PATCH 44/88] uml: fix build error due to frame size > 1024 the UML build fails during the kernel build: | arch/um/drivers/net_kern.c: In function 'compute_hash': | arch/um/drivers/net_kern.c:322:1: error: the frame size of 1072 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] | 322 | } | | ^ |cc1: all warnings being treated as errors The compute_hash() function is added by our patch: 102-pseudo-random-mac.patch Instead of allocating a 1024 byte buffer on the stack for the SHA1 digest input, let's allocate the data on the heap. We should be able to do that since crypto_alloc_ahash and ahash_request_alloc also need to allocate structures on the heap. Signed-off-by: Christian Lamparter --- .../patches-5.15/102-pseudo-random-mac.patch | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/target/linux/uml/patches-5.15/102-pseudo-random-mac.patch b/target/linux/uml/patches-5.15/102-pseudo-random-mac.patch index 925b9d77101..045d2d0dbd9 100644 --- a/target/linux/uml/patches-5.15/102-pseudo-random-mac.patch +++ b/target/linux/uml/patches-5.15/102-pseudo-random-mac.patch @@ -49,7 +49,7 @@ Applies to vanilla kernel 3.9.4. #define DRIVER_NAME "uml-netdev" static DEFINE_SPINLOCK(opened_lock); -@@ -274,9 +282,51 @@ static const struct ethtool_ops uml_net_ +@@ -274,9 +282,55 @@ static const struct ethtool_ops uml_net_ .get_ts_info = ethtool_op_get_ts_info, }; @@ -59,24 +59,26 @@ Applies to vanilla kernel 3.9.4. + * * an interface name. */ +static int compute_hash(const char *umid, const char *ifname, char *hash) +{ -+ struct ahash_request *desc; -+ struct crypto_ahash *tfm; ++ struct ahash_request *desc = NULL; ++ struct crypto_ahash *tfm = NULL; + struct scatterlist sg; -+ char vmif[1024]; -+ int ret; ++ char *vmif = NULL; ++ int ret = -ENOMEM; ++ ++ vmif = kmalloc(1024, GFP_KERNEL); ++ if (!vmif) ++ goto out; + + strcpy (vmif, umid); + strcat (vmif, ifname); + + tfm = crypto_alloc_ahash("sha1", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) -+ return -ENOMEM; ++ goto out; + + desc = ahash_request_alloc(tfm, GFP_KERNEL); -+ if (!desc) { -+ ret = -ENOMEM; ++ if (!desc) + goto out; -+ } + + crypto_ahash_clear_flags(tfm, ~0); + @@ -88,6 +90,8 @@ Applies to vanilla kernel 3.9.4. + ret = crypto_ahash_digest(desc); +out: + crypto_free_ahash(tfm); ++ ahash_request_free(desc); ++ kfree(vmif); + + return ret; +} @@ -101,7 +105,7 @@ Applies to vanilla kernel 3.9.4. char *end; int i; -@@ -319,9 +369,26 @@ void uml_net_setup_etheraddr(struct net_ +@@ -319,9 +373,26 @@ void uml_net_setup_etheraddr(struct net_ return; random: From 959563fb813890e478bf0a51523cd84d54b9af91 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sun, 21 May 2023 19:05:03 +0200 Subject: [PATCH 45/88] uml: exclude some /arch/x86 optimizations The x86_64 UML target wants to include SSSE3 optimized crypto code which lives under /arch/x86/crypto. However, these are not built and this causes an error. | ERROR: module '[...]/arch/x86/crypto/sha512-ssse3.ko' is missing. | make[3]: *** [modules/crypto.mk:990: [...]/kmod-crypto-sha512_5.15.112-1_x86_64.ipk] Error 1 Signed-off-by: Christian Lamparter --- package/kernel/linux/modules/crypto.mk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package/kernel/linux/modules/crypto.mk b/package/kernel/linux/modules/crypto.mk index a3785d26fd0..248b4d68f9e 100644 --- a/package/kernel/linux/modules/crypto.mk +++ b/package/kernel/linux/modules/crypto.mk @@ -897,10 +897,12 @@ define KernelPackage/crypto-sha1/mpc85xx AUTOLOAD+=$(call AutoLoad,09,sha1-ppc-spe) endef +ifndef CONFIG_TARGET_uml define KernelPackage/crypto-sha1/x86_64 FILES+=$(LINUX_DIR)/arch/x86/crypto/sha1-ssse3.ko AUTOLOAD+=$(call AutoLoad,09,sha1-ssse3) endef +endif ifdef KernelPackage/crypto-sha1/$(ARCH) KernelPackage/crypto-sha1/$(CRYPTO_TARGET)=\ @@ -935,10 +937,12 @@ define KernelPackage/crypto-sha256/mpc85xx AUTOLOAD+=$(call AutoLoad,09,sha256-ppc-spe) endef +ifndef CONFIG_TARGET_uml define KernelPackage/crypto-sha256/x86_64 FILES+=$(LINUX_DIR)/arch/x86/crypto/sha256-ssse3.ko AUTOLOAD+=$(call AutoLoad,09,sha256-ssse3) endef +endif ifdef KernelPackage/crypto-sha256/$(ARCH) KernelPackage/crypto-sha256/$(CRYPTO_TARGET)=\ @@ -977,10 +981,12 @@ endef KernelPackage/crypto-sha512/tegra=$(KernelPackage/crypto-sha512/arm) +ifndef CONFIG_TARGET_uml define KernelPackage/crypto-sha512/x86_64 FILES+=$(LINUX_DIR)/arch/x86/crypto/sha512-ssse3.ko AUTOLOAD+=$(call AutoLoad,09,sha512-ssse3) endef +endif ifdef KernelPackage/crypto-sha512/$(ARCH) KernelPackage/crypto-sha512/$(CRYPTO_TARGET)=\ From 2fbb91d73ffecc7d033e5bb0b550d664ef9e0f91 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sun, 21 May 2023 22:51:16 +0800 Subject: [PATCH 46/88] ramips: correct page read return value of the mt7621 nand driver read_page() need to return maximum number of bitflips instead of the accumulated number. Change takes from upstream mt7621 u-boot [1]. * @read_page: function to read a page according to the ECC generator * requirements; returns maximum number of bitflips * corrected in any single ECC step, -EIO hw error [1] https://lore.kernel.org/all/cover.1653015383.git.weijie.gao@mediatek.com/ Signed-off-by: Shiji Yang --- .../files/drivers/mtd/nand/raw/mt7621_nand.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c b/target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c index f3a81ee4e24..89cc7e2624a 100644 --- a/target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c +++ b/target/linux/ramips/files/drivers/mtd/nand/raw/mt7621_nand.c @@ -1006,7 +1006,7 @@ static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf, { struct mt7621_nfc *nfc = nand_get_controller_data(nand); struct mtd_info *mtd = nand_to_mtd(nand); - int bitflips = 0; + int bitflips = 0, ret = 0; int rc, i; nand_read_page_op(nand, page, 0, NULL, 0); @@ -1031,7 +1031,7 @@ static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf, mt7621_nfc_read_sector_fdm(nfc, i); if (rc < 0) { - bitflips = -EIO; + ret = -EIO; continue; } @@ -1043,10 +1043,11 @@ static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf, dev_dbg(nfc->dev, "Uncorrectable ECC error at page %d.%d\n", page, i); - bitflips = -EBADMSG; + bitflips = nand->ecc.strength + 1; mtd->ecc_stats.failed++; - } else if (bitflips >= 0) { - bitflips += rc; + } else { + if (rc > bitflips) + bitflips = rc; mtd->ecc_stats.corrected += rc; } } @@ -1055,6 +1056,9 @@ static int mt7621_nfc_read_page_hwecc(struct nand_chip *nand, uint8_t *buf, nfi_write16(nfc, NFI_CON, 0); + if (ret < 0) + return ret; + return bitflips; } From e8f7957450e2dcbeb90492c711a973d2cf0ebbfc Mon Sep 17 00:00:00 2001 From: INAGAKI Hiroshi Date: Thu, 13 Oct 2022 11:20:10 +0900 Subject: [PATCH 47/88] ath79: enable NVMEM u-boot-env driver on generic subtarget This patch enables NVMEM u-boot-env driver (COFNIG_NVMEM_U_BOOT_ENV) on generic subtarget to use from devices, for MAC address and etc. Signed-off-by: INAGAKI Hiroshi --- target/linux/ath79/generic/config-default | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/linux/ath79/generic/config-default b/target/linux/ath79/generic/config-default index dd59a354900..06f264b626a 100644 --- a/target/linux/ath79/generic/config-default +++ b/target/linux/ath79/generic/config-default @@ -15,6 +15,8 @@ CONFIG_MARVELL_PHY=y CONFIG_MICREL_PHY=y CONFIG_MTD_REDBOOT_PARTS=y CONFIG_MTD_SPLIT_EVA_FW=y +CONFIG_NVMEM_SYSFS=y +CONFIG_NVMEM_U_BOOT_ENV=y CONFIG_PHY_AR7100_USB=y CONFIG_PHY_AR7200_USB=y CONFIG_REALTEK_PHY=y From e5d8739aa846db621b6368ba83db17c353a35dea Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Sat, 20 May 2023 20:35:51 +0800 Subject: [PATCH 48/88] ath79: improve support for D-Link DIR-8x9 A1 series 1. Remove unnecessary new lines in the dts. 2. Remove duplicate included file "gpio.h" in the device dts. 3. Add missing button labels "reset" and "wps". 4. Unify the format of the reg properties. 5. Add u-boot environment support. 6. Reduce spi clock frequency since the max value suggested by the chip datasheet is only 25 MHz. 7. Add seama header fixup for DIR-859 A1. Without this header fixup, u-boot checksum for kernel will fail after the first boot. Signed-off-by: Shiji Yang --- package/boot/uboot-envtools/files/ath79 | 2 ++ .../linux/ath79/dts/qca9563_dlink_dir-859-a1.dts | 1 - .../linux/ath79/dts/qca9563_dlink_dir-869-a1.dts | 2 -- .../linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi | 15 ++++++++------- .../base-files/etc/uci-defaults/09_fix-checksum | 1 + 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79 index 47271453f69..38fc663e709 100644 --- a/package/boot/uboot-envtools/files/ath79 +++ b/package/boot/uboot-envtools/files/ath79 @@ -27,6 +27,8 @@ araknis,an-700-ap-i-ac|\ arduino,yun|\ buffalo,bhr-4grv2|\ devolo,magic-2-wifi|\ +dlink,dir-859-a1|\ +dlink,dir-869-a1|\ engenius,eap1200h|\ engenius,eap1750h|\ engenius,eap300-v2|\ diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts index a828f86cb16..93bd8e363e8 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts +++ b/target/linux/ath79/dts/qca9563_dlink_dir-859-a1.dts @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qca9563_dlink_dir-8x9-a1.dtsi" -#include / { model = "D-Link DIR-859 A1"; diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts b/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts index eab713ea66a..5afe683613b 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts +++ b/target/linux/ath79/dts/qca9563_dlink_dir-869-a1.dts @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later OR MIT #include "qca9563_dlink_dir-8x9-a1.dtsi" -#include / { model = "D-Link DIR-869 A1"; @@ -28,4 +27,3 @@ }; }; }; - diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi index 556ba604a6b..754fcd415d9 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi +++ b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi @@ -6,17 +6,18 @@ #include / { - keys { compatible = "gpio-keys"; wps { + label = "wps"; linux,code = ; gpios = <&gpio 1 GPIO_ACTIVE_LOW>; debounce-interval = <60>; }; reset { + label = "reset"; linux,code = ; gpios = <&gpio 2 GPIO_ACTIVE_LOW>; debounce-interval = <60>; @@ -42,7 +43,7 @@ flash@0 { compatible = "jedec,spi-nor"; reg = <0>; - spi-max-frequency = <50000000>; + spi-max-frequency = <25000000>; partitions { compatible = "fixed-partitions"; @@ -51,19 +52,19 @@ partition@0 { label = "bootloader"; - reg = <0x000000 0x40000>; + reg = <0x000000 0x040000>; read-only; }; partition@40000 { + compatible = "u-boot,env"; label = "bdcfg"; - reg = <0x040000 0x10000>; - read-only; + reg = <0x040000 0x010000>; }; partition@50000 { label = "devdata"; - reg = <0x050000 0x10000>; + reg = <0x050000 0x010000>; read-only; compatible = "nvmem-cells"; @@ -81,7 +82,7 @@ partition@60000 { label = "devconf"; - reg = <0x060000 0x10000>; + reg = <0x060000 0x010000>; read-only; }; diff --git a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum index 7f4d6cf428c..ad3db95a0c6 100644 --- a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum +++ b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum @@ -22,6 +22,7 @@ dlink,dap-3662-a1) fixwrgg ;; dlink,dir-629-a1|\ +dlink,dir-859-a1|\ dlink,dir-869-a1|\ qihoo,c301) fix_seama_header From 0ffbef9317a1dc049ad259c1ec1530355efc0552 Mon Sep 17 00:00:00 2001 From: Shiji Yang Date: Fri, 5 May 2023 01:50:36 +0000 Subject: [PATCH 49/88] ath79: add support for D-Link DIR-859 A3 Specifications: SOC: QCA9563 775 MHz + QCA9880 Switch: QCA8337N-AL3C RAM: Winbond W9751G6KB-25 64 MiB Flash: Winbond W25Q128FVSG 16 MiB WLAN: Wi-Fi4 2.4 GHz 3*3 + 5 GHz 3*3 LAN: LAN ports *4 WAN: WAN port *1 Buttons: reset *1 + wps *1 LEDs: ethernet *5, power, wlan, wps MAC Address: use address source1 source2 label 40:9b:xx:xx:xx:3c lan && wlan u-boot,env@ethaddr lan 40:9b:xx:xx:xx:3c devdata@0x3f $label wan 40:9b:xx:xx:xx:3f devdata@0x8f $label + 3 wlan2g 40:9b:xx:xx:xx:3c devdata@0x5b $label wlan5g 40:9b:xx:xx:xx:3e devdata@0x76 $label + 2 Install via Web UI: Apply factory image in the stock firmware's Web UI. Install via Emergency Room Mode: DIR-859 A1 will enter recovery mode when the system fails to boot or press reset button for about 10 seconds. First, set computer IP to 192.168.0.5 and Gateway to 192.168.0.1. Then we can open http://192.168.0.1 in the web browser to upload OpenWrt factory image or stock firmware. Some modern browsers may need to turn on compatibility mode. Signed-off-by: Shiji Yang --- package/boot/uboot-envtools/files/ath79 | 1 + .../ath79/dts/qca9563_dlink_dir-859-a3.dts | 64 +++++++++++++++++++ .../ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi | 4 +- .../generic/base-files/etc/board.d/01_leds | 3 + .../generic/base-files/etc/board.d/02_network | 5 ++ .../etc/uci-defaults/09_fix-checksum | 1 + target/linux/ath79/image/generic.mk | 14 +++- 7 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 target/linux/ath79/dts/qca9563_dlink_dir-859-a3.dts diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79 index 38fc663e709..7c30aa052a6 100644 --- a/package/boot/uboot-envtools/files/ath79 +++ b/package/boot/uboot-envtools/files/ath79 @@ -28,6 +28,7 @@ arduino,yun|\ buffalo,bhr-4grv2|\ devolo,magic-2-wifi|\ dlink,dir-859-a1|\ +dlink,dir-859-a3|\ dlink,dir-869-a1|\ engenius,eap1200h|\ engenius,eap1750h|\ diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-859-a3.dts b/target/linux/ath79/dts/qca9563_dlink_dir-859-a3.dts new file mode 100644 index 00000000000..164e0802f9f --- /dev/null +++ b/target/linux/ath79/dts/qca9563_dlink_dir-859-a3.dts @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qca9563_dlink_dir-8x9-a1.dtsi" + +#include + +/ { + compatible = "dlink,dir-859-a3", "qca,qca9563"; + model = "D-Link DIR-859 A3"; + + aliases { + label-mac-device = &wmac; + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + leds { + compatible = "gpio-leds"; + + led_power: power { + label = "green:power"; + color = ; + function = LED_FUNCTION_POWER; + gpios = <&gpio 15 GPIO_ACTIVE_LOW>; + }; + + wan { + color = ; + function = LED_FUNCTION_WAN; + gpios = <&gpio 16 GPIO_ACTIVE_LOW>; + }; + + wlan { + color = ; + function = LED_FUNCTION_WLAN; + gpios = <&gpio 19 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tpt"; + }; + + wps { + color = ; + function = LED_FUNCTION_WPS; + gpios = <&gpio 8 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&ath10k { + nvmem-cells = <&calibration_ath10k>, <&macaddr_bdcfg_ethaddr 2>; + nvmem-cell-names = "calibration", "mac-address"; +}; + +&bdcfg { + macaddr_bdcfg_ethaddr: ethaddr { + #nvmem-cell-cells = <1>; + }; +}; + +&wmac { + nvmem-cells = <&calibration_ath9k>, <&macaddr_bdcfg_ethaddr 0>; + nvmem-cell-names = "calibration", "mac-address"; +}; diff --git a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi index 754fcd415d9..3fd9790c4a2 100644 --- a/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi +++ b/target/linux/ath79/dts/qca9563_dlink_dir-8x9-a1.dtsi @@ -28,7 +28,7 @@ &pcie { status = "okay"; - wifi@0,0 { + ath10k: wifi@0,0 { compatible = "qcom,ath10k"; reg = <0x0000 0 0 0 0>; @@ -56,7 +56,7 @@ read-only; }; - partition@40000 { + bdcfg: partition@40000 { compatible = "u-boot,env"; label = "bdcfg"; reg = <0x040000 0x010000>; diff --git a/target/linux/ath79/generic/base-files/etc/board.d/01_leds b/target/linux/ath79/generic/base-files/etc/board.d/01_leds index d3508049baa..2ee4ed2544d 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/01_leds +++ b/target/linux/ath79/generic/base-files/etc/board.d/01_leds @@ -234,6 +234,9 @@ dlink,dap-1365-a1) dlink,dir-859-a1) ucidef_set_led_switch "internet" "WAN" "green:internet" "switch0" "0x20" ;; +dlink,dir-859-a3) + ucidef_set_led_switch "wan" "WAN" "green:wan" "switch0" "0x20" + ;; engenius,ens202ext-v1|\ engenius,enstationac-v1) ucidef_set_rssimon "wlan0" "200000" "1" diff --git a/target/linux/ath79/generic/base-files/etc/board.d/02_network b/target/linux/ath79/generic/base-files/etc/board.d/02_network index 487467cd598..4f535f8a648 100644 --- a/target/linux/ath79/generic/base-files/etc/board.d/02_network +++ b/target/linux/ath79/generic/base-files/etc/board.d/02_network @@ -291,6 +291,7 @@ ath79_setup_interfaces() dlink,dir-842-c2|\ dlink,dir-842-c3|\ dlink,dir-859-a1|\ + dlink,dir-859-a3|\ dlink,dir-869-a1|\ engenius,epg5000|\ engenius,esr1200|\ @@ -661,6 +662,10 @@ ath79_setup_macs() lan_mac=$(mtd_get_mac_text "devdata" 0xc9) wan_mac=$(mtd_get_mac_text "devdata" 0x79) ;; + dlink,dir-859-a3) + lan_mac=$(get_mac_label) + wan_mac=$(macaddr_add "$lan_mac" 3) + ;; qihoo,c301|\ wd,mynet-n600|\ wd,mynet-n750) diff --git a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum index ad3db95a0c6..0ea81a8dc3a 100644 --- a/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum +++ b/target/linux/ath79/generic/base-files/etc/uci-defaults/09_fix-checksum @@ -23,6 +23,7 @@ dlink,dap-3662-a1) ;; dlink,dir-629-a1|\ dlink,dir-859-a1|\ +dlink,dir-859-a3|\ dlink,dir-869-a1|\ qihoo,c301) fix_seama_header diff --git a/target/linux/ath79/image/generic.mk b/target/linux/ath79/image/generic.mk index f8969a919c9..788520120de 100644 --- a/target/linux/ath79/image/generic.mk +++ b/target/linux/ath79/image/generic.mk @@ -1143,18 +1143,28 @@ define Device/dlink_dir-842-c3 endef TARGET_DEVICES += dlink_dir-842-c3 -define Device/dlink_dir-859-a1 +define Device/dlink_dir-859-ax $(Device/seama) SOC := qca9563 DEVICE_VENDOR := D-Link DEVICE_MODEL := DIR-859 - DEVICE_VARIANT := A1 IMAGE_SIZE := 15872k DEVICE_PACKAGES := kmod-usb2 kmod-ath10k-ct-smallbuffers ath10k-firmware-qca988x-ct SEAMA_SIGNATURE := wrgac37_dlink.2013gui_dir859 endef + +define Device/dlink_dir-859-a1 + $(Device/dlink_dir-859-ax) + DEVICE_VARIANT := A1 +endef TARGET_DEVICES += dlink_dir-859-a1 +define Device/dlink_dir-859-a3 + $(Device/dlink_dir-859-ax) + DEVICE_VARIANT := A3 +endef +TARGET_DEVICES += dlink_dir-859-a3 + define Device/dlink_dir-869-a1 $(Device/seama) SOC := qca9563 From 6c80a578a4428c81fd92e0a2abe95dacfa20c008 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 15:27:48 +0200 Subject: [PATCH 50/88] CI: check-kernel-patches: use buildbot user on git diff check Use buildbot user on git diff check instead of using git config safe directory. This should accomplish the same result but should be a better approach following safe practice enforced by git. Fixes: a7747e8670cb ("ci: fix check kernel patches job") Signed-off-by: Christian Marangi --- .github/workflows/check-kernel-patches.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/check-kernel-patches.yml b/.github/workflows/check-kernel-patches.yml index 4ad35e62507..274bae367de 100644 --- a/.github/workflows/check-kernel-patches.yml +++ b/.github/workflows/check-kernel-patches.yml @@ -85,10 +85,6 @@ jobs: run: | chown -R buildbot:buildbot openwrt - - name: Opt-out from Git stricter repository ownership checks - run: | - git config --global --add safe.directory '*' - - name: Initialization environment run: | TARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 1) @@ -138,6 +134,7 @@ jobs: run: make target/linux/refresh V=s - name: Validate Refreshed Kernel Patches + shell: su buildbot -c "sh -e {0}" working-directory: openwrt run: | . .github/workflows/scripts/ci_helpers.sh From eecc6e48117be26c2eefd9257cceb9d9b1e842f2 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 16:47:08 +0200 Subject: [PATCH 51/88] CI: rework build workflow to have split target and subtarget directly Instead of referring to a redundant job and ENV variables, rework build workflow to accept and require split target and subtarget and use them directly from inputs. Rework each user and pass a JSON of tuple to matrix include with each target/subtarget combination to test. Special notice this doesn't use the github actions matrix combination feature but reference each specific tuple of target and subtarget to test. Just a cleanup no behaviour change intended. Signed-off-by: Christian Marangi --- .github/workflows/build.yml | 32 ++++++++++------------ .github/workflows/check-kernel-patches.yml | 26 ++++++++---------- .github/workflows/coverity.yml | 3 +- .github/workflows/kernel.yml | 12 +++++--- .github/workflows/packages.yml | 7 +++-- .github/workflows/toolchain.yml | 6 ++-- 6 files changed, 44 insertions(+), 42 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8744bc7737a..52fba8e1063 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,9 @@ on: target: required: true type: string + subtarget: + required: true + type: string testing: type: boolean build_toolchain: @@ -50,7 +53,7 @@ permissions: jobs: setup_build: - name: Setup build ${{ inputs.target }} + name: Setup build ${{ inputs.target }}/${{ inputs.subtarget }} runs-on: ubuntu-latest outputs: owner_lc: ${{ steps.lower_owner.outputs.owner_lc }} @@ -109,7 +112,7 @@ jobs: echo "container_tag=$CONTAINER_TAG" >> $GITHUB_OUTPUT build: - name: Build ${{ inputs.target }} + name: Build ${{ inputs.target }}/${{ inputs.subtarget }} needs: setup_build runs-on: ubuntu-latest @@ -157,13 +160,6 @@ jobs: run: | chown -R buildbot:buildbot openwrt - - name: Initialization environment - run: | - TARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 1) - SUBTARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 2) - echo "TARGET=$TARGET" >> "$GITHUB_ENV" - echo "SUBTARGET=$SUBTARGET" >> "$GITHUB_ENV" - - name: Prepare prebuilt tools shell: su buildbot -c "sh -e {0}" working-directory: openwrt @@ -213,7 +209,7 @@ jobs: fi fi - SUMS_FILE="https://downloads.cdn.openwrt.org/$TOOLCHAIN_PATH/targets/${{ env.TARGET }}/${{ env.SUBTARGET }}/sha256sums" + SUMS_FILE="https://downloads.cdn.openwrt.org/$TOOLCHAIN_PATH/targets/${{ inputs.target }}/${{ inputs.subtarget }}/sha256sums" if curl $SUMS_FILE | grep -q ".*openwrt-toolchain.*tar.xz"; then TOOLCHAIN_STRING="$( curl $SUMS_FILE | grep ".*openwrt-toolchain.*tar.xz")" TOOLCHAIN_FILE=$(echo "$TOOLCHAIN_STRING" | sed -n -e 's/.*\(openwrt-toolchain.*\).tar.xz/\1/p') @@ -235,16 +231,16 @@ jobs: uses: actions/cache@v3 with: path: openwrt/.ccache - key: ccache-kernel-${{ env.TARGET }}/${{ env.SUBTARGET }}-${{ needs.setup_build.outputs.ccache_hash }} + key: ccache-kernel-${{ inputs.target }}/${{ inputs.subtarget }}-${{ needs.setup_build.outputs.ccache_hash }} restore-keys: | - ccache-kernel-${{ env.TARGET }}/${{ env.SUBTARGET }}- + ccache-kernel-${{ inputs.target }}/${{ inputs.subtarget }}- - name: Download external toolchain/sdk if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type != 'internal' shell: su buildbot -c "sh -e {0}" working-directory: openwrt run: | - wget -O - https://downloads.cdn.openwrt.org/${{ env.TOOLCHAIN_PATH }}/targets/${{ env.TARGET }}/${{ env.SUBTARGET }}/${{ env.TOOLCHAIN_FILE }}.tar.xz \ + wget -O - https://downloads.cdn.openwrt.org/${{ env.TOOLCHAIN_PATH }}/targets/${{ inputs.target }}/${{ inputs.subtarget }}/${{ env.TOOLCHAIN_FILE }}.tar.xz \ | tar --xz -xf - - name: Configure testing kernel @@ -289,7 +285,7 @@ jobs: ./scripts/ext-toolchain.sh \ --toolchain ${{ env.TOOLCHAIN_FILE }}/toolchain-* \ --overwrite-config \ - --config ${{ env.TARGET }}/${{ env.SUBTARGET }} + --config ${{ inputs.target }}/${{ inputs.subtarget }} - name: Adapt external sdk to external toolchain format if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_sdk' @@ -331,7 +327,7 @@ jobs: ./scripts/ext-toolchain.sh \ --toolchain ${{ env.TOOLCHAIN_FILE }}/staging_dir/toolchain-* \ --overwrite-config \ - --config ${{ env.TARGET }}/${{ env.SUBTARGET }} + --config ${{ inputs.target }}/${{ inputs.subtarget }} - name: Configure internal toolchain if: inputs.build_toolchain == true || steps.parse-toolchain.outputs.toolchain-type == 'internal' @@ -342,8 +338,8 @@ jobs: echo CONFIG_AUTOREMOVE=y >> .config echo CONFIG_CCACHE=y >> .config - echo "CONFIG_TARGET_${{ env.TARGET }}=y" >> .config - echo "CONFIG_TARGET_${{ env.TARGET }}_${{ env.SUBTARGET }}=y" >> .config + echo "CONFIG_TARGET_${{ inputs.target }}=y" >> .config + echo "CONFIG_TARGET_${{ inputs.target }}_${{ inputs.subtarget }}=y" >> .config make defconfig @@ -435,5 +431,5 @@ jobs: if: failure() uses: actions/upload-artifact@v3 with: - name: ${{ env.TARGET }}-${{ env.SUBTARGET }}-logs + name: ${{ inputs.target }}-${{ inputs.subtarget }}-logs path: "openwrt/logs" diff --git a/.github/workflows/check-kernel-patches.yml b/.github/workflows/check-kernel-patches.yml index 274bae367de..1ab4a361f53 100644 --- a/.github/workflows/check-kernel-patches.yml +++ b/.github/workflows/check-kernel-patches.yml @@ -6,6 +6,9 @@ on: target: required: true type: string + subtarget: + required: true + type: string testing: type: boolean use_openwrt_container: @@ -85,13 +88,6 @@ jobs: run: | chown -R buildbot:buildbot openwrt - - name: Initialization environment - run: | - TARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 1) - SUBTARGET=$(echo ${{ inputs.target }} | cut -d "/" -f 2) - echo "TARGET=$TARGET" >> "$GITHUB_ENV" - echo "SUBTARGET=$SUBTARGET" >> "$GITHUB_ENV" - - name: Prepare prebuilt tools shell: su buildbot -c "sh -e {0}" working-directory: openwrt @@ -118,8 +114,8 @@ jobs: echo CONFIG_AUTOREMOVE=y >> .config echo CONFIG_CCACHE=y >> .config - echo "CONFIG_TARGET_${{ env.TARGET }}=y" >> .config - echo "CONFIG_TARGET_${{ env.TARGET }}_${{ env.SUBTARGET }}=y" >> .config + echo "CONFIG_TARGET_${{ inputs.target }}=y" >> .config + echo "CONFIG_TARGET_${{ inputs.target }}_${{ inputs.subtarget }}=y" >> .config make defconfig @@ -140,13 +136,13 @@ jobs: . .github/workflows/scripts/ci_helpers.sh if git diff --name-only --exit-code; then - success "Kernel patches for ${{ env.TARGET }}/${{ env.SUBTARGET }} seems ok" + success "Kernel patches for ${{ inputs.target }}/${{ inputs.subtarget }} seems ok" else - err "Kernel patches for ${{ env.TARGET }}/${{ env.SUBTARGET }} require refresh. (run 'make target/linux/refresh' and force push this pr)" + err "Kernel patches for ${{ inputs.target }}/${{ inputs.subtarget }} require refresh. (run 'make target/linux/refresh' and force push this pr)" err "You can also check the provided artifacts with the refreshed patch from this CI run." - mkdir ${{ env.TARGET }}-${{ env.SUBTARGET }}-refreshed + mkdir ${{ inputs.target }}-${{ inputs.subtarget }}-refreshed for f in $(git diff --name-only); do - cp --parents $f ${{ env.TARGET }}-${{ env.SUBTARGET }}-refreshed/ + cp --parents $f ${{ inputs.target }}-${{ inputs.subtarget }}-refreshed/ done exit 1 fi @@ -155,5 +151,5 @@ jobs: if: failure() uses: actions/upload-artifact@v3 with: - name: ${{ env.TARGET }}-${{ env.SUBTARGET }}-refreshed - path: openwrt/${{ env.TARGET }}-${{ env.SUBTARGET }}-refreshed + name: ${{ inputs.target }}-${{ inputs.subtarget }}-refreshed + path: openwrt/${{ inputs.target }}-${{ inputs.subtarget }}-refreshed diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index db628d05eec..db59ef8ca68 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,7 +17,8 @@ jobs: packages: read uses: ./.github/workflows/build.yml with: - target: x86/64 + target: x86 + subtarget: 64 build_full: true include_feeds: true coverity_compiler_template_list: >- diff --git a/.github/workflows/kernel.yml b/.github/workflows/kernel.yml index a25829a4c0e..02aee8b27cc 100644 --- a/.github/workflows/kernel.yml +++ b/.github/workflows/kernel.yml @@ -64,8 +64,9 @@ jobs: if echo "$CHANGED_FILES" | grep -v -q target/linux || echo "$CHANGED_FILES" | grep -q target/linux/generic || echo "$CHANGED_FILES" | grep -q $(echo $TARGET | cut -d "/" -f 1); then + TUPLE='{"target":"'"$(echo $TARGET | cut -d "/" -f 1)"'","subtarget":"'"$(echo $TARGET | cut -d "/" -f 2)"'"}' [[ $FIRST -ne 1 ]] && JSON_TARGETS_SUBTARGETS="$JSON_TARGETS_SUBTARGETS"',' - JSON_TARGETS_SUBTARGETS="$JSON_TARGETS_SUBTARGETS"'"'"${TARGET}"'"' + JSON_TARGETS_SUBTARGETS="$JSON_TARGETS_SUBTARGETS""$TUPLE" FIRST=0 fi done @@ -77,8 +78,9 @@ jobs: if echo "$CHANGED_FILES" | grep -v -q target/linux || echo "$CHANGED_FILES" | grep -q target/linux/generic || echo "$CHANGED_FILES" | grep -q $(echo $TARGET | cut -d "/" -f 1); then + TUPLE='{"target":"'"$(echo $TARGET | cut -d "/" -f 1)"'","subtarget":"'"$(echo $TARGET | cut -d "/" -f 2)"'"}' [[ $FIRST -ne 1 ]] && JSON_TARGETS="$JSON_TARGETS"',' - JSON_TARGETS="$JSON_TARGETS"'"'"${TARGET}"'"' + JSON_TARGETS="$JSON_TARGETS""$TUPLE" FIRST=0 fi done @@ -104,10 +106,11 @@ jobs: strategy: fail-fast: False matrix: - target: ${{fromJson(needs.determine_targets.outputs.targets_subtargets)}} + include: ${{fromJson(needs.determine_targets.outputs.targets_subtargets)}} uses: ./.github/workflows/build.yml with: target: ${{ matrix.target }} + subtarget: ${{ matrix.subtarget }} build_kernel: true build_all_kmods: true @@ -120,8 +123,9 @@ jobs: strategy: fail-fast: False matrix: - target: ${{fromJson(needs.determine_targets.outputs.targets)}} + include: ${{fromJson(needs.determine_targets.outputs.targets)}} uses: ./.github/workflows/check-kernel-patches.yml with: target: ${{ matrix.target }} + subtarget: ${{ matrix.subtarget }} diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 340ee0c2044..e2f932b1ba3 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -37,11 +37,14 @@ jobs: fail-fast: False matrix: include: - - target: malta/be - - target: x86/64 + - target: malta + subtarget: be + - target: x86 + subtarget: 64 uses: ./.github/workflows/build.yml with: target: ${{ matrix.target }} + subtarget: ${{ matrix.subtarget }} build_kernel: true build_all_kmods: true build_all_modules: true diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index 2a24d82e30f..5755ca25b9d 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -40,8 +40,9 @@ jobs: JSON='[' FIRST=1 for TARGET in $TARGETS; do + TUPLE='{"target":"'"$(echo $TARGET | cut -d "/" -f 1)"'","subtarget":"'"$(echo $TARGET | cut -d "/" -f 2)"'"}' [[ $FIRST -ne 1 ]] && JSON="$JSON"',' - JSON="$JSON"'"'"${TARGET}"'"' + JSON="$JSON""$TUPLE" FIRST=0 done JSON="$JSON"']' @@ -61,8 +62,9 @@ jobs: strategy: fail-fast: False matrix: - target: ${{fromJson(needs.determine_targets.outputs.target)}} + include: ${{fromJson(needs.determine_targets.outputs.target)}} uses: ./.github/workflows/build.yml with: target: ${{ matrix.target }} + subtarget: ${{ matrix.subtarget }} build_toolchain: true From 1c05388ab04c934ec240e8362321908f91381a90 Mon Sep 17 00:00:00 2001 From: Pietro Ameruoso Date: Mon, 22 May 2023 09:52:47 +0200 Subject: [PATCH 52/88] mediatek: add support for Zyxel EX5601-T0 router Zyxel EX5601-T0 specifics -------------- The operator specific firmware running on the Zyxel branded EX5601-T0 includes U-Boot modifications affecting the OpenWrt installation. Partition Table | dev | size | erasesize | name | | ---- | -------- | --------- | ------------- | | mtd0 | 20000000 | 00040000 | "spi0.1" | | mtd1 | 00100000 | 00040000 | "BL2" | | mtd2 | 00080000 | 00040000 | "u-boot-env" | | mtd3 | 00200000 | 00040000 | "Factory" | | mtd4 | 001c0000 | 00040000 | "FIP" | | mtd5 | 00040000 | 00040000 | "zloader" | | mtd6 | 04000000 | 00040000 | "ubi" | | mtd7 | 04000000 | 00040000 | "ubi2" | | mtd8 | 15a80000 | 00040000 | "zyubi" | The router boots BL2 which than loads FIP (u-boot). U-boot has hardcoded a command to always launch Zloader "mtd read zloader 0x46000000" and than "bootm". Bootargs are deactivated. Zloader is the zyxel booloader which allow to dual-boot ubi or ubi2, by default access to zloader is blocked. Too zloader checks that the firmware contains a particolar file called zyfwinfo. Additional details regarding Zloader can be found here: https://hack-gpon.github.io/zyxel/ https://forum.openwrt.org/t/adding-openwrt-support-for-zyxel-ex5601-t0/155914 Hardware -------- SOC: MediaTek MT7986a CPU: 4 core cortex-a53 (2000MHz) RAM: 1GB DDR4 FLASH: 512MB SPI-NAND (Micron xxx) WIFI: Wifi6 Mediatek MT7976 802.11ax 5 GHz 4x4 + 2.4GHZ 4x4 ETH: MediaTek MT7531 Switch + SoC 3 x builtin 1G phy (lan1, lan2, lan3) 1 x MaxLinear GPY211B 2.5 N-Base-T phy5 (lan4) 1 x MaxLinear GPY211B 2.5Gbit xor SFP/N-Base-T phy6 (wan) USB: 1 x USB 3.2 Enhanced SuperSpeed port UART: 3V3 115200 8N1 (Pinout: GND KEY RX TX VCC) VOIP: 2 FXS ports for analog phones MAC Address Table ----------------- eth0/lan Factory 0x002a eth1/wan Factory 0x0024 wifi 2.4Ghz Factory 0x0004 wifi 5Ghz Factory 0x0004 + 1 Serial console (UART) --------------------- +-------+-------+-------+-------+-------+ | +3.3V | RX | TX | KEY | GND | +---+---+-------+-------+-------+-------+ | +--- Don't connect Installation ------------ Keep in mind that openwrt can only run on the UBI partition, the openwrt firmware is not able to understand the zloader bootargs. The procedure allows restoring the UBI partition with the Zyxel firmware and retains all the OEM functionalities. 1. Unlock Zloader (this will allow to swap manually between partitions UBI and UBI2): - Attach a usb-ttl adapter to your computer and boot the router. - While the router is booting at some point you will read the following: `Please press Enter to activate this console.` - As soon as you read that press enter, type root and than press enter again (just do it, don't care about the logs scrolling). - Most likely the router is still printing the boot log, leave it boot until it stops. - If everything went ok you should have full root access "root@EX5601-T0:/#". - Type the following command and press enter: "fw_setenv EngDebugFlag 0x1". - Reboot the router. - As soon as you read `Hit any key to stop autoboot:` press Enter. - If everything went ok you should have the following prompt: "ZHAL>". - You have successfully unlocked zloader access, this procedure must be done only once. 2. Check the current active partition: - Boot the router and repeat the steps above to gain root access. - Type the following command to check the current active image: "cat /proc/cmdline". - If `rootubi=ubi` it means that the active partition is `mtd6` - If `rootubi=ubi2` it means that the active partition is `mtd7` - As mentioned earlier we need to flash openwrt into ubi/mtd6 and never overwrite ubi2/mtd7 to be able to fully roll-back. - To activate and boot from mtd7 (ubi2) enter into ZHAL> command prompt and type the following commands: atbt 1 # unlock write atsw # swap boot partition atsr # reboot the router - After rebooting check again with "cat /proc/cmdline" that you are correctly booting from mtd7/ubi2 - If yes proceed with the installation guide. If not probably you don't have a firmware into ubi2 or you did something wrong. 3. Flashing: - Download the sysupgrade file for the router from openwrt, than we need to add the zyfwinfo file into the sysupgrade tar. Zloader only checks for the magic (which is a fixed value 'EXYZ') and the crc of the file itself (256bytes). I created a script to create a valid zyfwinfo file but you can use anything that does exactly the same: https://raw.githubusercontent.com/pameruoso/OpenWRT-Zyxel-EX5601-T0/main/gen_zyfwinfo.sh - Add the zyfwinfo file into the sysupgrade tar. - Enter via telnet or ssh into the router with admin credentials - Enter the following commands to disable the firmware and model checks "zycli fwidcheck off" and "zycli modelcheck off" - Open the router web interface and in the update firmware page select the "restore default settings option" - Select the sysupgrade file and click on upload. - The router will flash and reboot itself into openwrt from UBI 4. Restoring and going back to Zyxel firmware. - Use the ZHAL> command line to manually swap the boot parition to UBI2 with the following: atbt 1 # unlock write atsw # swap boot partition atsr # reboot the router - You will boot again the Zyxel firmware you have into UBI2 and you can flash the zyxel firmware to overwrite the UBI partition and openwrt. Working features ---------------- 3 gbit lan ports Wifi Zyxel partitioning for coexistance with Zloader and dual boot. WAN SFP port (only after exporting pins 57 and 10. gpiobase411) leds reset button serial interface usb port lan ethernet 2.5 gbit port (autosense) wan ethernet 2.5 gbit port (autosense) Not working ---------------- voip (missing drivers or proper zyxel platform software) Swapping the wan ethernet/sfp xor port ---------------- The way to swap the wan port between sfp and ethernet is the following: export the pins 57 and 10. Pin 57 is used to probe if an sfp is present. If pin 57 value is 0 it means that an sfp is present into the cage (cat /sys/class/gpio/gpio468/value). If pin 57 value is 1 it means that no sfp is inserted into the cage. In conclusion by default both 57 an 10 pins are by default 1, which means that the active port is the ethernet one. After inserting an SFP pin 57 will become 0 and you have to manually change the value of pin 10 to 0 too. This is totally scriptable of course. Leds description ------------ All the leds are working out of the box but the leds managed by the 2 maxlinear phy (phy 5 lan, phy6 wan). To activate the phy5 led (rj45 ethernet port led on the back of the router) you have to use mdio-tools. To activate the phy6 led (led on the front of the router for 2.5gbit link) you have to use mdio-tools. Example: Set lan5 led to fast blink on 2500/1000, slow blink on 10/100: mdio mdio-bus mmd 5:30 raw 0x0001 0x33FC Set wan 2.5gbit led to constant on when wan is 2.5gbit: mdio mdio-bus mmd 6:30 raw 0x0001 0x0080 Signed-off-by: Pietro Ameruoso --- .../uboot-envtools/files/mediatek_filogic | 4 + .../dts/mt7986a-zyxel-ex5601-t0-stock.dts | 560 ++++++++++++++++++ .../etc/hotplug.d/ieee80211/11_fix_wifi_mac | 4 + target/linux/mediatek/image/filogic.mk | 23 + 4 files changed, 591 insertions(+) create mode 100644 target/linux/mediatek/dts/mt7986a-zyxel-ex5601-t0-stock.dts diff --git a/package/boot/uboot-envtools/files/mediatek_filogic b/package/boot/uboot-envtools/files/mediatek_filogic index a685b046536..50b9cd0e463 100644 --- a/package/boot/uboot-envtools/files/mediatek_filogic +++ b/package/boot/uboot-envtools/files/mediatek_filogic @@ -52,6 +52,10 @@ xiaomi,redmi-router-ax6000-ubootmod) ubootenv_add_uci_config "$envdev" "0x0" "0x1f000" "0x20000" "1" ubootenv_add_uci_config "$envdev2" "0x0" "0x1f000" "0x20000" "1" ;; +zyxel,ex5601-t0) + local envdev=/dev/mtd$(find_mtd_index "u-boot-env") + ubootenv_add_uci_config "$envdev" "0x0" "0x20000" "0x40000" "2" + ;; esac config_load ubootenv diff --git a/target/linux/mediatek/dts/mt7986a-zyxel-ex5601-t0-stock.dts b/target/linux/mediatek/dts/mt7986a-zyxel-ex5601-t0-stock.dts new file mode 100644 index 00000000000..07a3e8d3ee9 --- /dev/null +++ b/target/linux/mediatek/dts/mt7986a-zyxel-ex5601-t0-stock.dts @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2021 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7986a.dtsi" +#include +#include + +/ { + model = "Zyxel EX5601-T0"; + compatible = "zyxel,ex5601-t0", "mediatek,mt7986a-rfb-snand"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0 0x40000000 0 0x40000000>; + }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_5v: regulator-5v { + compatible = "regulator-fixed"; + regulator-name = "fixed-5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-boot-on; + regulator-always-on; + }; + + gpio-keys { + compatible = "gpio-keys"; + poll-interval = <20>; + + reset-button { + label = "reset"; + gpios = <&pio 21 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wlan-button { + label = "wlan"; + gpios = <&pio 11 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + wps-button { + label = "wps"; + gpios = <&pio 56 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + zyleds { + compatible = "gpio-leds"; + + led_green_wifi24g { + label = "zyled-green-wifi24g"; + gpios = <&pio 1 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_green_wifi5g { + label = "zyled-green-wifi5g"; + gpios = <&pio 2 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_green_inet { + label = "zyled-green-inet"; + gpios = <&pio 14 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_red_inet { + label = "zyled-red-inet"; + gpios = <&pio 15 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_green_pwr { + label = "zyled-green-pwr"; + gpios = <&pio 13 GPIO_ACTIVE_LOW>; + linux,default-trigger = "timer"; /* Default blinking */ + led-pattern = <125 125>; /* Fast blink is 4 HZ */ + }; + + led_red_pwr { + label = "zyled-red-pwr"; + gpios = <&pio 12 GPIO_ACTIVE_LOW>; + default-state = "off"; + }; + + led_green_fxs { + label = "zyled-green-fxs"; + gpios = <&pio 16 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led_amber_fxs { + label = "zyled-amber-fxs"; + gpios = <&pio 17 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led_amber_wps24g { + label = "zyled-amber-wps24g"; + gpios = <&pio 18 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led_amber_wps5g { + label = "zyled-amber-wps5g"; + gpios = <&pio 19 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led_green_lan { + label = "zyled-green-lan"; + gpios = <&pio 20 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led_green_sfp { + label = "zyled-green-sfp"; + gpios = <&pio 24 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + }; + +}; + +ð { + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "2500base-x"; + + nvmem-cells = <&macaddr_factory_002a>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "2500base-x"; + phy = <&phy6>; + + nvmem-cells = <&macaddr_factory_0024>; + nvmem-cell-names = "mac-address"; + }; + + mdio: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + reset-gpios = <&pio 6 GPIO_ACTIVE_LOW>; + reset-delay-us = <1500000>; + reset-post-delay-us = <1000000>; + + phy5: phy@5 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <5>; + }; + + phy6: phy@6 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <6>; + }; + + switch@0 { + compatible = "mediatek,mt7531"; + reg = <31>; + reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@5 { + reg = <5>; + label = "lan4"; + phy-mode = "2500base-x"; + phy = <&phy5>; + }; + + port@6 { + reg = <6>; + ethernet = <&gmac0>; + phy-mode = "2500base-x"; + + fixed-link { + speed = <2500>; + full-duplex; + pause; + }; + }; + }; + }; + }; +}; + +&wmac { + status = "okay"; + pinctrl-names = "default", "dbdc"; + pinctrl-0 = <&wf_2g_5g_pins>; + pinctrl-1 = <&wf_dbdc_pins>; + mediatek,mtd-eeprom = <&factory 0x0>; + nvmem-cells = <&macaddr_factory_0004>; + nvmem-cell-names = "mac-address"; +}; + +&crypto { + status = "okay"; +}; + +&mmc0 { + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_pins_default>; + pinctrl-1 = <&mmc0_pins_uhs>; + bus-width = <8>; + max-frequency = <200000000>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + hs400-ds-delay = <0x14014>; + vmmc-supply = <®_3p3v>; + vqmmc-supply = <®_1p8v>; + non-removable; + no-sd; + no-sdio; + status = "disabled"; +}; + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pcie_pins>; + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +&pio { + mmc0_pins_default: mmc0-pins { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; /* pull-up 10K */ + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = <6>; + mediatek,pull-down-adv = <2>; /* pull-down 50K */ + }; + conf-ds { + pins = "EMMC_DSL"; + mediatek,pull-down-adv = <2>; /* pull-down 50K */ + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; /* pull-up 10K */ + }; + }; + + mmc0_pins_uhs: mmc0-uhs-pins { + mux { + function = "emmc"; + groups = "emmc_51"; + }; + conf-cmd-dat { + pins = "EMMC_DATA_0", "EMMC_DATA_1", "EMMC_DATA_2", + "EMMC_DATA_3", "EMMC_DATA_4", "EMMC_DATA_5", + "EMMC_DATA_6", "EMMC_DATA_7", "EMMC_CMD"; + input-enable; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; /* pull-up 10K */ + }; + conf-clk { + pins = "EMMC_CK"; + drive-strength = <6>; + mediatek,pull-down-adv = <2>; /* pull-down 50K */ + }; + conf-ds { + pins = "EMMC_DSL"; + mediatek,pull-down-adv = <2>; /* pull-down 50K */ + }; + conf-rst { + pins = "EMMC_RSTB"; + drive-strength = <4>; + mediatek,pull-up-adv = <1>; /* pull-up 10K */ + }; + }; + + pcie_pins: pcie-pins { + mux { + function = "pcie"; + groups = "pcie_clk", "pcie_wake", "pcie_pereset"; + }; + }; + + spic_pins_g2: spic-pins-29-to-32 { + mux { + function = "spi"; + groups = "spi1_2"; + }; + }; + + spi_flash_pins: spi-flash-pins-33-to-38 { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + conf-pu { + pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP"; + drive-strength = <8>; + mediatek,pull-up-adv = <0>; /* bias-disable */ + }; + conf-pd { + pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO"; + drive-strength = <8>; + mediatek,pull-down-adv = <0>; /* bias-disable */ + }; + }; + + uart1_pins: uart1-pins { + mux { + function = "uart"; + groups = "uart1"; + }; + }; + + uart2_pins: uart2-pins { + mux { + function = "uart"; + groups = "uart2"; + }; + }; + + wf_2g_5g_pins: wf_2g_5g-pins { + mux { + function = "wifi"; + groups = "wf_2g", "wf_5g"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = <4>; + }; + }; + + wf_dbdc_pins: wf_dbdc-pins { + mux { + function = "wifi"; + groups = "wf_dbdc"; + }; + conf { + pins = "WF0_HB1", "WF0_HB2", "WF0_HB3", "WF0_HB4", + "WF0_HB0", "WF0_HB0_B", "WF0_HB5", "WF0_HB6", + "WF0_HB7", "WF0_HB8", "WF0_HB9", "WF0_HB10", + "WF0_TOP_CLK", "WF0_TOP_DATA", "WF1_HB1", + "WF1_HB2", "WF1_HB3", "WF1_HB4", "WF1_HB0", + "WF1_HB5", "WF1_HB6", "WF1_HB7", "WF1_HB8", + "WF1_TOP_CLK", "WF1_TOP_DATA"; + drive-strength = <4>; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi_flash_pins>; + cs-gpios = <0>, <0>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + spi_nand: spi_nand@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-nand"; + reg = <1>; + spi-max-frequency = <10000000>; + spi-tx-buswidth = <4>; + spi-rx-buswidth = <4>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x00000 0x0100000>; + read-only; + }; + + partition@100000 { + label = "u-boot-env"; + reg = <0x0100000 0x0080000>; + }; + + factory: partition@180000 { + label = "Factory"; + reg = <0x180000 0x0200000>; + read-only; + }; + + partition@380000 { + label = "FIP"; + reg = <0x380000 0x01C0000>; + read-only; + }; + + partition@540000 { + label = "zloader"; + reg = <0x540000 0x0040000>; + read-only; + }; + + partition@580000 { + label = "ubi"; + reg = <0x580000 0x4000000>; + }; + + partition@4580000 { + label = "ubi2"; + reg = <0x4580000 0x4000000>; + read-only; + }; + + partition@8580000 { + label = "zyubi"; + reg = <0x8580000 0x15A80000>; + }; + }; + }; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spic_pins_g2>; + status = "okay"; + + proslic_spi: proslic_spi@0 { + compatible = "silabs,proslic_spi"; + reg = <0>; + spi-max-frequency = <10000000>; + spi-cpha = <1>; + spi-cpol = <1>; + channel_count = <1>; + debug_level = <4>; /* 1 = TRC, 2 = DBG, 4 = ERR */ + reset_gpio = <&pio 7 GPIO_ACTIVE_HIGH>; + ig,enable-spi = <1>; /* 1: Enable, 0: Disable */ + }; +}; + +&ssusb { + vusb33-supply = <®_3p3v>; + vbus-supply = <®_5v>; + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + status = "okay"; +}; + +&uart2 { + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + status = "okay"; +}; + +&usb_phy { + status = "okay"; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_0004: macaddr@0004 { + reg = <0x0004 0x6>; + }; + + macaddr_factory_0024: macaddr@0024 { + reg = <0x0024 0x6>; + }; + + macaddr_factory_002a: macaddr@002a { + reg = <0x002a 0x6>; + }; +}; diff --git a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac index 8088b98eb6e..a56e5bc6893 100644 --- a/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac +++ b/target/linux/mediatek/filogic/base-files/etc/hotplug.d/ieee80211/11_fix_wifi_mac @@ -37,4 +37,8 @@ case "$board" in tplink,tl-xdr6088) [ "$PHYNBR" = "0" ] && get_mac_label > /sys${DEVPATH}/macaddress ;; + zyxel,ex5601-t0) + addr=$(mtd_get_mac_binary "Factory" 0x4) + [ "$PHYNBR" = "1" ] && macaddr_add $addr 1 > /sys${DEVPATH}/macaddress + ;; esac diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk index 7159917ff45..92d1dcfad24 100644 --- a/target/linux/mediatek/image/filogic.mk +++ b/target/linux/mediatek/image/filogic.mk @@ -294,3 +294,26 @@ ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),) endif endef TARGET_DEVICES += xiaomi_redmi-router-ax6000-ubootmod + +define Device/zyxel_ex5601-t0-stock + DEVICE_VENDOR := Zyxel + DEVICE_MODEL := EX5601-T0 (stock layout) + DEVICE_DTS := mt7986a-zyxel-ex5601-t0-stock + DEVICE_DTS_DIR := ../dts + DEVICE_PACKAGES := kmod-mt7986-firmware mt7986-wo-firmware + SUPPORTED_DEVICES := mediatek,mt7986a-rfb-snand + UBINIZE_OPTS := -E 5 + BLOCKSIZE := 256k + PAGESIZE := 4096 + IMAGE_SIZE := 65536k + KERNEL_IN_UBI := 1 + IMAGES += factory.bin + IMAGE/factory.bin := append-ubi | check-size $$$$(IMAGE_SIZE) + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata + KERNEL = kernel-bin | lzma | \ + fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb + KERNEL_INITRAMFS = kernel-bin | lzma | \ + fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd + DTC_FLAGS += -@ --space 32768 +endef +TARGET_DEVICES += zyxel_ex5601-t0-stock From 17fbbafdcbc55d6ab3d357012f336941fa27d43e Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Sun, 21 May 2023 23:36:01 +0200 Subject: [PATCH 53/88] lldpd: update to 1.0.17 Release Notes: https://github.com/lldpd/lldpd/releases/tag/1.0.17 Signed-off-by: Nick Hainke --- package/network/services/lldpd/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/network/services/lldpd/Makefile b/package/network/services/lldpd/Makefile index c3753534a68..289adc55c94 100644 --- a/package/network/services/lldpd/Makefile +++ b/package/network/services/lldpd/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=lldpd -PKG_VERSION:=1.0.16 +PKG_VERSION:=1.0.17 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/lldpd/lldpd/releases/download/$(PKG_VERSION)/ -PKG_HASH:=7753c6e31e938923185f4e10c4ab328929729e22ee4a9687d08881fb82c092ee +PKG_HASH:=89ae691a4917ac9e0ec3b8b2c1e634cc402d43b804f98850c73bd1c7df380882 PKG_MAINTAINER:=Stijn Tintel PKG_LICENSE:=ISC From 78c45c1e591ce5aeff9fb7eeae049662c4ac4ef2 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Sun, 21 May 2023 23:25:52 +0200 Subject: [PATCH 54/88] libcap: update to 2.69 Release Notes: https://sites.google.com/site/fullycapable/release-notes-for-libcap#h.iuvg7sbjg8pe Fixes: CVE-2023-2602 CVE-2023-2603 Signed-off-by: Nick Hainke --- package/libs/libcap/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/libs/libcap/Makefile b/package/libs/libcap/Makefile index 6f51b5d5edd..989209302a4 100644 --- a/package/libs/libcap/Makefile +++ b/package/libs/libcap/Makefile @@ -6,12 +6,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libcap -PKG_VERSION:=2.68 +PKG_VERSION:=2.69 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/libs/security/linux-privs/libcap2 -PKG_HASH:=90be3b6d41be5f81ae4b03ec76012b0d27c829293684f6c05b65d5f9cce724b2 +PKG_HASH:=f311f8f3dad84699d0566d1d6f7ec943a9298b28f714cae3c931dfd57492d7eb PKG_MAINTAINER:=Paul Wassi PKG_LICENSE:=GPL-2.0-only From c520d682f02890afb38e43b862ca856e2b933507 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Sun, 21 May 2023 23:21:14 +0200 Subject: [PATCH 55/88] libxml2: update to 2.11.4 Release Notes: https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.11.4 Signed-off-by: Nick Hainke --- package/libs/libxml2/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/libs/libxml2/Makefile b/package/libs/libxml2/Makefile index 5a7de0d8a1e..ed1965c0195 100644 --- a/package/libs/libxml2/Makefile +++ b/package/libs/libxml2/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=libxml2 -PKG_VERSION:=2.11.3 +PKG_VERSION:=2.11.4 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@GNOME/libxml2/$(basename $(PKG_VERSION)) -PKG_HASH:=f1acae1664bda006cd81bfc238238217043d586d06659d5c0e3d1bcebe040870 +PKG_HASH:=737e1d7f8ab3f139729ca13a2494fd17bf30ddb4b7a427cf336252cab57f57f7 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=COPYING From 3b76f6eee430a107a0970583c1aa215b35f7e3e4 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Sun, 21 May 2023 23:54:31 +0200 Subject: [PATCH 56/88] busybox: update to 1.36.1 Release Notes: http://lists.busybox.net/pipermail/busybox-cvs/2023-May/041510.html Refresh commands, run after busybox is first built once (nothing changed compared to 1.36.0): cd package/utils/busybox/config/ ../convert_menuconfig.pl ../../../../build_dir/target-mipsel_24kc_musl/busybox-default/busybox-1.36.1 cd .. ./convert_defaults.pl ../../../build_dir/target-mipsel_24kc_musl/busybox-default/busybox-1.36.1/.config > Config-defaults.in Manual edits needed afterward: * Config-defaults.in: OpenWrt config symbol IPV6 logic applied to BUSYBOX_DEFAULT_FEATURE_IPV6 * Config-defaults.in: OpenWrt config TARGET_bcm53xx logic applied to BUSYBOX_DEFAULT_TRUNCATE (commit 547f1ec) * Config-defaults.in: OpenWrt logic applied to BUSYBOX_DEFAULT_LOGIN_SESSION_AS_CHILD (commit dc92917) * Config-defaults.in: correct the default ports that get reset BUSYBOX_DEFAULT_FEATURE_HTTPD_PORT_DEFAULT 80 BUSYBOX_DEFAULT_FEATURE_TELNETD_PORT_DEFAULT 23 * config/editors/Config.in: Add USE_GLIBC dependency to BUSYBOX_CONFIG_FEATURE_VI_REGEX_SEARCH (commit f141090) * config/shell/Config.in: change at "Options common to all shells" the conditional symbol SHELL_ASH --> BUSYBOX_CONFIG_SHELL_ASH (discussion in http://lists.openwrt.org/pipermail/openwrt-devel/2021-January/033140.html Apparently our script does not see the hidden option while prepending config options with "BUSYBOX_CONFIG_" which leads to a missed dependency when the options are later evaluated.) * Edit a few Config.in files by adding quotes to sourced items in config/Config.in, config/networking/Config.in and config/util-linux/Config.in (commit 1da014f) Tested-by: Hannu Nyman Signed-off-by: Nick Hainke --- package/utils/busybox/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile index d7ad8ca8fa2..4bddd5201d8 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile @@ -5,14 +5,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=busybox -PKG_VERSION:=1.36.0 +PKG_VERSION:=1.36.1 PKG_RELEASE:=1 PKG_FLAGS:=essential PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=https://www.busybox.net/downloads \ http://sources.buildroot.net -PKG_HASH:=542750c8af7cb2630e201780b4f99f3dcceeb06f505b479ec68241c1e6af61a5 +PKG_HASH:=b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314 PKG_BUILD_DEPENDS:=BUSYBOX_CONFIG_PAM:libpam PKG_BUILD_PARALLEL:=1 From 8fb9bbcf659ac6205554ed1680c57f3c4e0e0f54 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 22:24:40 +0200 Subject: [PATCH 57/88] kernel: add define for kernel 6.1 Add define for kernel 6.1. Signed-off-by: Christian Marangi --- include/kernel-6.1 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 include/kernel-6.1 diff --git a/include/kernel-6.1 b/include/kernel-6.1 new file mode 100644 index 00000000000..34e916622a7 --- /dev/null +++ b/include/kernel-6.1 @@ -0,0 +1,2 @@ +LINUX_VERSION-6.1 = .29 +LINUX_KERNEL_HASH-6.1.29 = 1e736cc9bd6036379a1d915e518abd4c2c94ad0fd1ea0da961c3489308b8fcfb \ No newline at end of file From fa79baf4a6e2306d60ac4968fdd8935e64c358ab Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 22:26:34 +0200 Subject: [PATCH 58/88] generic: copy backport, hack, pending patch and config from 5.15 to 6.1 Copy backport, hack, pending patch and config from 5.15 to 6.1. Signed-off-by: Christian Marangi --- ...ild-use-Wdeclaration-after-statement.patch | 73 + ...05-v5.17-02-Kbuild-move-to-std-gnu11.patch | 60 + ...-use-std-gnu11-for-KBUILD_USERCFLAGS.patch | 43 + ...-x86-arm64-add-arch_has_hw_pte_young.patch | 425 + ...dd-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch | 153 + ...-03-mm-vmscan.c-refactor-shrink_node.patch | 275 + ...inux-mm_inline.h-fold-__update_lru_s.patch | 82 + ...-v6.1-05-mm-multi-gen-LRU-groundwork.patch | 807 ++ ...multi-gen-LRU-minimal-implementation.patch | 1447 ++++ ...lti-gen-LRU-exploit-locality-in-rmap.patch | 491 ++ ...lti-gen-LRU-support-page-table-walks.patch | 1687 ++++ ...lti-gen-LRU-optimize-multiple-memcgs.patch | 315 + ...v6.1-10-mm-multi-gen-LRU-kill-switch.patch | 498 ++ ...m-multi-gen-LRU-thrashing-prevention.patch | 226 + ...2-mm-multi-gen-LRU-debugfs-interface.patch | 579 ++ ...don-t-sync-disk-for-each-aging-cycle.patch | 32 + ...-retry-pages-written-back-while-isol.patch | 124 + ...-move-lru_gen_add_mm-out-of-IRQ-off-.patch | 49 + ..._young-for-architectures-not-having-.patch | 96 + ...roduce-arch_has_hw_nonleaf_pmd_young.patch | 113 + ...RU-fix-crash-during-cgroup-migration.patch | 56 + .../020-v6.3-19-mm-add-vma_has_recency.patch | 196 + ...6.3-20-mm-support-POSIX_FADV_NOREUSE.patch | 125 + ...-rename-lru_gen_struct-to-lru_gen_pa.patch | 348 + ...-rename-lrugen-lists-to-lrugen-pages.patch | 162 + ...U-remove-eviction-fairness-safeguard.patch | 188 + ...-LRU-remove-aging-fairness-safeguard.patch | 287 + ...lti-gen-LRU-shuffle-should_run_aging.patch | 161 + ...-gen-LRU-per-node-lru_gen_page-lists.patch | 868 ++ ...i-gen-LRU-clarify-scan_control-flags.patch | 196 + ...-simplify-arch_has_hw_pte_young-chec.patch | 34 + ...m-multi-gen-LRU-avoid-futile-retries.patch | 88 + ...-uasm-Enable-muhu-opcode-for-MIPS-R6.patch | 65 + ...rkaround-for-Loongson-2F-nop-CPU-err.patch | 31 + ...ips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch | 3078 +++++++ ...bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch | 1005 +++ ...f-Add-JIT-workarounds-for-CPU-errata.patch | 120 + ...0-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch | 61 + ...f-Remove-old-BPF-JIT-implementations.patch | 387 + ...k-gate-Add-devm_clk_hw_register_gate.patch | 105 + ...to-define-reg_update_bits-for-no-bus.patch | 52 + ...63xx-use-more-precise-Kconfig-symbol.patch | 37 + ...resolve_btfids-Build-with-host-flags.patch | 49 + ...te-to-upstream-version-v1.6.1-19-g0a.patch | 997 +++ ...or-setting-affinity-if-no-IRQ-parent.patch | 48 + ...-Support-reserved-memory-description.patch | 166 + ...-bcm63xx_wdt-fix-fallthrough-warning.patch | 33 + ...kernel-proc-add-CPU-option-reporting.patch | 162 + ...mp_processor_id-in-preemptible-in-sh.patch | 62 + ...spinand-Add-support-for-XTX-XT26G0xA.patch | 186 + ...mvebu-a3700-comphy-Remove-port-from-.patch | 219 + ...mvebu-a3700-comphy-Add-native-kernel.patch | 1552 ++++ ...l-armada-37xx-Add-xtal-clock-to-comp.patch | 32 + ...mvebu-Make-SATA-PHY-optional-for-Arm.patch | 64 + ...xhci-mvebu-make-USB-3.0-PHY-optional.patch | 166 + ...ark-Fix-initialization-with-old-Marv.patch | 39 + ...mvebu-a3700-comphy-Remove-broken-res.patch | 194 + ...configurable-downshift-for-addresses.patch | 90 + ...efined-reg_base-to-be-added-to-every.patch | 95 + ..._base-and-reg_downshift-for-single-r.patch | 57 + ...platform_populate-for-MTD-partitions.patch | 72 + ...s-add-support-for-Sercomm-partitions.patch | 302 + ...ce-of-support-for-dynamic-partitions.patch | 106 + ...g-MTD-device-associated-with-a-speci.patch | 72 + ...e-check-partition-before-dereference.patch | 30 + ...sing-of_node_get-in-dynamic-partitio.patch | 101 + ...y-a-bit-code-find-partition-matching.patch | 65 + ...find-OF-node-for-every-MTD-partition.patch | 84 + ...-Don-t-print-error-message-on-EPROBE.patch | 32 + ...T_DEV-for-partitions-marked-as-rootf.patch | 47 + ...x-allow-to-use-on-MediaTek-MIPS-SoCs.patch | 33 + ...device-add-support-for-GD5FxGQ4xExxG.patch | 58 + ...device-add-support-for-GD5F1GQ5RExxG.patch | 33 + ...device-add-support-for-GD5F-2-4-GQ5x.patch | 84 + ...device-add-support-for-GD5FxGM7xExxG.patch | 91 + ...TP-Link-SafeLoader-partitions-table-.patch | 229 + ...9-mtd-spi-nor-support-eon-en25qh256a.patch | 49 + ...m-number-of-bitflips-for-each-read-r.patch | 73 + ...itialize-stats-in-struct-mtd_oob_ops.patch | 325 + ...ror-accounting-for-each-read-request.patch | 172 + ...-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch | 321 + ...onix-use-scratch-buffer-for-DMA-oper.patch | 35 + ...-mtd_otp_nvmem_add-to-handle-EPROBE_.patch | 47 + ...v5.18-page_pool-Add-allocation-stats.patch | 165 + ...01-v5.18-page_pool-Add-recycle-stats.patch | 140 + ...d-function-to-batch-and-return-stats.patch | 77 + ...cycle-stats-to-page_pool_put_page_bu.patch | 55 + ...et-page_pool-introduce-ethtool-stats.patch | 147 + ...ce-flags-field-in-xdp_buff-xdp_frame.patch | 99 + ...gs-support-to-xdp_return_-buff-frame.patch | 137 + ...ize-metadata-to-skb_shared_info-for-.patch | 31 + ...-total-xdp_frame-len-running-ndo_xdp.patch | 65 + ...-veth-Allow-jumbo-frames-in-xdp-mode.patch | 40 + ...net-page_pool-use-in_softirq-instead.patch | 56 + ...611-v6.3-net-add-helper-eth_addr_add.patch | 41 + ...uce-tagger-owned-storage-for-private.patch | 279 + ...ocols-connect-to-individual-switches.patch | 274 + ..._eth_soc-add-support-for-coherent-DM.patch | 327 + ...ek-mt7622-add-support-for-coherent-D.patch | 30 + ..._eth_soc-add-support-for-Wireless-Et.patch | 1679 ++++ ..._eth_soc-implement-flow-offloading-t.patch | 269 + ...ek-mt7622-introduce-nodes-for-Wirele.patch | 62 + ..._eth_soc-add-ipv6-flow-offload-suppo.patch | 79 + ..._eth_soc-support-TC_SETUP_BLOCK-for-.patch | 29 + ..._eth_soc-allocate-struct-mtk_ppe-sep.patch | 159 + ..._eth_soc-rework-hardware-flow-table-.patch | 424 + ..._eth_soc-remove-bridge-flow-offload-.patch | 44 + ..._eth_soc-support-creating-mac-addres.patch | 553 ++ ..._eth_soc-wed-fix-sparse-endian-warni.patch | 56 + ..._eth_soc-fix-return-value-check-in-m.patch | 25 + ..._eth_soc-use-standard-property-for-c.patch | 35 + ..._eth_soc-use-after-free-in-__mtk_ppe.patch | 33 + ..._eth_soc-add-check-for-allocation-fa.patch | 22 + ...silence-the-GCC-12-array-bounds-warn.patch | 26 + ..._eth_soc-rely-on-GFP_KERNEL-for-dma_.patch | 52 + ..._eth_soc-move-tx-dma-desc-configurat.patch | 206 + ..._eth_soc-add-txd_size-to-mtk_soc_dat.patch | 167 + ..._eth_soc-rely-on-txd_size-in-mtk_tx_.patch | 78 + ..._eth_soc-rely-on-txd_size-in-mtk_des.patch | 109 + ..._eth_soc-rely-on-txd_size-in-txd_to_.patch | 39 + ..._eth_soc-add-rxd_size-to-mtk_soc_dat.patch | 102 + ..._eth_soc-rely-on-txd_size-field-in-m.patch | 46 + ..._eth_soc-rely-on-rxd_size-field-in-m.patch | 68 + ..._eth_soc-introduce-device-register-m.patch | 814 ++ ..._eth_soc-introduce-MTK_NETSYS_V2-sup.patch | 917 ++ ..._eth_soc-convert-ring-dma-pointer-to.patch | 135 + ..._eth_soc-convert-scratch_ring-pointe.patch | 33 + ..._eth_soc-introduce-support-for-mt798.patch | 138 + ..._eth_soc-fix-error-code-in-mtk_flow_.patch | 25 + ..._eth_soc-enable-rx-cksum-offload-for.patch | 47 + ...19-34-eth-mtk_ppe-fix-up-after-merge.patch | 28 + ...-users-of-bitmap_foo-to-linkmode_foo.patch | 948 ++ ...ylink-add-MAC-phy_interface_t-bitmap.patch | 24 + ...supported_interfaces-for-phylink-val.patch | 98 + ...populate-supported_interfaces-member.patch | 63 + ...net-dsa-consolidate-phylink-creation.patch | 149 + ...phylink_get_interfaces-with-phylink_.patch | 51 + ...d-support-for-phylink-mac_select_pcs.patch | 59 + ...y-add-phy_interface_t-bitmap-support.patch | 61 + ...mac_select_pcs-method-to-phylink_mac.patch | 197 + ...-add-generic-validate-implementation.patch | 341 + ...e-helpers-for-iterating-through-port.patch | 68 + ...-net-phylink-add-pcs_validate-method.patch | 106 + ...k-add-legacy_pre_march2020-indicator.patch | 43 + ...-DSA-phylink-as-legacy_pre_march2020.patch | 36 + ...net-phylink-use-legacy_pre_march2020.patch | 115 + ...-fix-DSA-mac_select_pcs-introduction.patch | 88 + ...populate-supported_interfaces-member.patch | 48 + ...e-interface-checks-in-mvneta_validat.patch | 35 + ...op-use-of-phylink_helper_basex_speed.patch | 55 + ...-mvneta-use-phylink_generic_validate.patch | 72 + ...ark-as-a-legacy_pre_march2020-driver.patch | 29 + ...populate-supported_interfaces-member.patch | 43 + ...remove-interface-checks-in-mtk_valid.patch | 75 + ...drop-use-of-phylink_helper_basex_spe.patch | 42 + ...eth_soc-use-phylink_generic_validate.patch | 84 + ...mark-as-a-legacy_pre_march2020-drive.patch | 29 + ...remove-a-copy-of-the-NAPI_POLL_WEIGH.patch | 40 + ...9-mtk_eth_soc-remove-unused-mac-mode.patch | 35 + ...tk_eth_soc-remove-unused-sgmii-flags.patch | 40 + ...add-mask-and-update-PCS-speed-defini.patch | 40 + ...eth_soc-correct-802.3z-speed-setting.patch | 60 + ...th_soc-correct-802.3z-duplex-setting.patch | 101 + ...stop-passing-phylink-state-to-sgmii-.patch | 60 + ...mtk_eth_soc-provide-mtk_sgmii_config.patch | 89 + ...add-fixme-comment-for-state-speed-us.patch | 38 + ...c-move-MAC_MCR-setting-to-mac_finish.patch | 79 + ...move-restoration-of-SYSCFG0-to-mac_f.patch | 57 + ...convert-code-structure-to-suit-split.patch | 254 + ...soc-partially-convert-to-phylink_pcs.patch | 262 + ...terate-using-dsa_switch_for_each_use.patch | 106 + ...opulate-supported_interfaces-and-mac.patch | 166 + ...t-dsa-mt7530-remove-interface-checks.patch | 172 + ...rop-use-of-phylink_helper_basex_spee.patch | 34 + ...nly-indicate-linkmodes-that-can-be-s.patch | 86 + ...-switch-to-use-phylink_get_linkmodes.patch | 131 + ...530-partially-convert-to-phylink_pcs.patch | 385 + ...ove-autoneg-handling-to-PCS-validati.patch | 80 + ...19-net-dsa-mt7530-mark-as-non-legacy.patch | 34 + ...mt753x-fix-pcs-conversion-regression.patch | 116 + ...t7530-rework-mt7530_hw_vlan_-add-del.patch | 87 + ...et-dsa-mt7530-rework-mt753-01-_setup.patch | 75 + ...et-cpu-port-via-dp-cpu_dp-instead-of.patch | 117 + ..._eth_soc-rely-on-page_pool-for-singl.patch | 330 + ...et-mtk_eth_soc-add-basic-XDP-support.patch | 291 + ..._eth_soc-introduce-xdp-ethtool-count.patch | 110 + ...net-mtk_eth_soc-add-xmit-XDP-support.patch | 340 + ..._eth_soc-add-support-for-page_pool_g.patch | 95 + ..._eth_soc-introduce-mtk_xdp_frame_map.patch | 113 + ..._eth_soc-introduce-xdp-multi-frag-su.patch | 218 + ...cs-add-driver-for-MediaTek-SGMII-PCS.patch | 394 + ..._eth_soc-fix-hw-hash-reporting-for-M.patch | 74 + ..._eth_soc-fix-off-by-one-check-of-ARR.patch | 31 + ..._ppe-fix-possible-NULL-pointer-deref.patch | 27 + ...-ppe-fix-traffic-offload-with-bridge.patch | 64 + ..._eth_soc-remove-mtk_foe_entry_timest.patch | 33 + ..._eth_soc-enable-XDP-support-just-for.patch | 35 + ..._eth_soc-move-gdma_to_ppe-and-ppe_ba.patch | 127 + ..._eth_soc-move-ppe-table-hash-offset-.patch | 199 + ..._eth_soc-add-the-capability-to-run-m.patch | 318 + ..._eth_soc-move-wdma_base-definitions-.patch | 80 + ..._eth_soc-add-foe_entry_size-to-mtk_e.patch | 251 + ..._eth_soc-fix-typo-in-__mtk_foe_entry.patch | 27 + ..._eth_soc-check-max-allowed-value-in-.patch | 28 + ..._eth_wed-add-mtk_wed_configure_irq-a.patch | 189 + ..._eth_wed-add-wed-support-for-mt7986-.patch | 942 ++ ...rnet-mtk_eth_wed-add-axi-bus-support.patch | 237 + ..._eth_soc-introduce-flow-offloading-s.patch | 882 ++ ..._eth_soc-enable-flow-offloading-supp.patch | 26 + ..._eth_soc-fix-wrong-use-of-new-helper.patch | 46 + ..._eth_soc-fix-usage-of-foe_entry_size.patch | 49 + ..._eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch | 32 + ..._eth_soc-fix-state-in-__mtk_foe_entr.patch | 37 + ..._eth_soc-fix-possible-memory-leak-in.patch | 73 + ..._eth_wed-add-missing-put_device-in-m.patch | 47 + ...-mtk_eth_wed-add-missing-of_node_put.patch | 43 + ...et-mtk_wed-introduce-wed-mcu-support.patch | 591 ++ ...net-mtk_wed-introduce-wed-wo-support.patch | 737 ++ ..._wed-rename-tx_wdma-array-in-rx_wdma.patch | 79 + ...mtk_wed-add-configure-wed-wo-support.patch | 1521 ++++ ...ethernet-mtk_wed-add-rx-mib-counters.patch | 149 + ..._eth_soc-do-not-overwrite-mtu-config.patch | 98 + ..._eth_soc-remove-cpu_relax-in-mtk_pen.patch | 36 + ..._eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch | 63 + ..._wed-add-wcid-overwritten-support-fo.patch | 80 + ..._wed-return-status-value-in-mtk_wdma.patch | 85 + ..._wed-move-MTK_WDMA_RESET_IDX_TX-conf.patch | 52 + ...ethernet-mtk_wed-update-mtk_wed_stop.patch | 98 + ...mtk_wed-add-mtk_wed_rx_reset-routine.patch | 309 + ..._wed-add-reset-to-tx_ring_setup-call.patch | 103 + ..._wed-fix-sleep-while-atomic-in-mtk_w.patch | 103 + ..._wed-get-rid-of-queue-lock-for-rx-qu.patch | 52 + ..._wed-get-rid-of-queue-lock-for-tx-qu.patch | 75 + ..._eth_soc-introduce-mtk_hw_reset-util.patch | 70 + ..._eth_soc-introduce-mtk_hw_warm_reset.patch | 107 + ..._eth_soc-align-reset-procedure-to-ve.patch | 262 + ..._eth_soc-add-dma-checks-to-mtk_hw_re.patch | 249 + ..._wed-add-reset-reset_complete-callba.patch | 124 + ..._wed-add-reset-to-rx_ring_setup-call.patch | 106 + ..._eth_soc-account-for-vlan-in-rx-head.patch | 22 + ..._eth_soc-increase-tx-ring-side-for-Q.patch | 143 + ..._eth_soc-avoid-port_mg-assignment-on.patch | 52 + ..._eth_soc-implement-multi-queue-suppo.patch | 654 ++ ...t-dsa-tag_mtk-assign-per-port-queues.patch | 20 + ...iatek-ppe-assign-per-port-queues-for.patch | 93 + ..._eth_soc-compile-out-netsys-v2-code-.patch | 28 + ...ort-for-DSA-rx-offloading-via-metada.patch | 72 + ..._eth_soc-fix-VLAN-rx-hardware-accele.patch | 192 + ..._eth_soc-drop-packets-to-WDMA-if-the.patch | 37 + ..._eth_soc-disable-hardware-DSA-untagg.patch | 42 + ..._eth_soc-enable-special-tag-when-any.patch | 54 + ..._eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch | 129 + ..._wed-No-need-to-clear-memory-after-a.patch | 26 + ..._wed-fix-some-possible-NULL-pointer-.patch | 61 + ..._wed-fix-possible-deadlock-if-mtk_we.patch | 58 + ..._eth_soc-fix-tx-throughput-regressio.patch | 31 + ..._eth_soc-Avoid-truncating-allocation.patch | 60 + ...-mtk_eth_soc-add-definitions-for-PCS.patch | 55 + ...eliminate-unnecessary-error-handling.patch | 74 + ...soc-add-pcs_get_state-implementation.patch | 46 + ...convert-mtk_sgmii-to-use-regmap_upda.patch | 130 + ...add-out-of-band-forcing-of-speed-and.patch | 52 + ...07-net-mtk_eth_soc-move-PHY-power-up.patch | 48 + ...h_soc-move-interface-speed-selection.patch | 48 + ...th_soc-add-advertisement-programming.patch | 52 + ...move-and-correct-link-timer-programm.patch | 63 + ...add-support-for-in-band-802.3z-negot.patch | 132 + ...ii-ensure-the-SGMII-PHY-is-powered-d.patch | 119 + ...iatek-sgmii-fix-duplex-configuration.patch | 52 + ...enable-PCS-polling-to-allow-SFP-work.patch | 33 + ...ethernet-mtk_eth_soc-reset-PCS-state.patch | 48 + ..._eth_soc-only-write-values-if-needed.patch | 103 + ...t-mtk_eth_soc-add-support-for-MT7981.patch | 200 + ..._eth_soc-set-MDIO-bus-clock-frequenc.patch | 76 + ..._eth_soc-switch-to-external-PCS-driv.patch | 512 ++ ...k_eth_soc-use-WO-firmware-for-MT7981.patch | 46 + ..._eth_soc-fix-NULL-pointer-dereferenc.patch | 28 + ...-0001-net-bgmac-improve-handling-PHY.patch | 84 + ...t-bgmac-support-MDIO-described-in-DT.patch | 54 + ...dd-support-for-qca-8327-internal-phy.patch | 48 + ...3-Include-all-ports-in-enabled_ports.patch | 131 + ...-BCM5301x-workaround-for-a-wrong-CPU.patch | 42 + ...prove-flow-control-setup-on-BCM5301x.patch | 32 + ...t-dsa-b53-Drop-unused-cpu_port-field.patch | 205 + ...x-add-support-for-qca-8327-A-variant.patch | 65 + ...dd-resume-suspend-function-to-qca83x.patch | 45 + ...ix-spacing-and-improve-name-for-83xx.patch | 95 + ...hy-at803x-fix-resume-for-QCA8327-phy.patch | 131 + ...x-add-DAC-amplitude-fix-for-8327-phy.patch | 91 + ...nable-prefer-master-for-83xx-interna.patch | 27 + ...hy-at803x-better-describe-debug-regs.patch | 127 + ...-dsa-qca8k-add-mac-power-sel-support.patch | 80 + ...dsa-qca8k-Add-SGMII-clock-phase-prop.patch | 30 + ...k-add-support-for-sgmii-falling-edge.patch | 127 + ...dsa-qca8k-Document-support-for-CPU-p.patch | 29 + ...dsa-qca8k-add-support-for-cpu-port-6.patch | 153 + ...work-rgmii-delay-logic-and-scan-for-.patch | 295 + ...dsa-qca8k-Document-qca-sgmii-enable-.patch | 33 + ...-qca8k-add-explicit-SGMII-PLL-enable.patch | 65 + ...dsa-qca8k-Document-qca-led-open-drai.patch | 37 + ...qca8k-add-support-for-pws-config-reg.patch | 92 + ...dsa-qca8k-document-support-for-qca83.patch | 32 + ...et-dsa-qca8k-add-support-for-QCA8328.patch | 78 + ...8k-set-internal-delay-also-for-sgmii.patch | 159 + ...move-port-config-to-dedicated-struct.patch | 124 + ...ipq8064-mdio-fix-warning-with-new-qc.patch | 26 + ...net-dsa-qca8k-convert-to-YAML-schema.patch | 631 ++ ...elay-applied-to-wrong-cpu-in-parse-p.patch | 28 + ...for-loop-in-setup-and-add-cpu-port-c.patch | 151 + ...sure-pad0-mac06-exchange-is-disabled.patch | 47 + ...ernal-delay-applied-to-the-wrong-PAD.patch | 48 + ...16-net-dsa-qca8k-fix-MTU-calculation.patch | 46 + ...redundant-check-in-parse_port_config.patch | 29 + ...vert-to-GENMASK_FIELD_PREP_FIELD_GET.patch | 507 ++ ...move-extra-mutex_init-in-qca8k_setup.patch | 25 + ...move-regmap-init-in-probe-and-set-it.patch | 46 + ...k-initial-conversion-to-regmap-heper.patch | 249 + ...ca8k-add-additional-MIB-counter-and-.patch | 120 + ...ca8k-add-support-for-port-fast-aging.patch | 53 + ...sa-qca8k-add-set_ageing_time-support.patch | 78 + ...sa-qca8k-add-support-for-mdb_add-del.patch | 142 + ...sa-qca8k-add-support-for-mirror-mode.patch | 155 + ...t-next-net-dsa-qca8k-add-LAG-support.patch | 288 + ...dsa-qca8k-fix-warning-in-LAG-feature.patch | 40 + ...PHY-initialization-with-MTU-setup-in.patch | 52 + ...nl_lock-sections-in-dsa_slave_create.patch | 34 + ...op-updating-master-MTU-from-master.c.patch | 91 + ...l_mutex-when-calling-dsa_master_-set.patch | 78 + ...t-up-shared-ports-then-non-shared-po.patch | 118 + ...xt-net-dsa-setup-master-before-ports.patch | 115 + ...switch-operations-for-tracking-the-m.patch | 254 + ...aster-state-events-in-dsa_tree_-setu.patch | 89 + ...t-dsa-tag_qca-convert-to-FIELD-macro.patch | 86 + ...qca-move-define-to-include-linux-dsa.patch | 71 + ...ag_qca-enable-promisc_on_master-flag.patch | 27 + ...add-define-for-handling-mgmt-Etherne.patch | 110 + ...a-add-define-for-handling-MIB-packet.patch | 45 + ...add-support-for-handling-mgmt-and-MI.patch | 116 + ...8k-add-tracking-state-of-master-port.patch | 67 + ...d-support-for-mgmt-read-write-in-Eth.patch | 363 + ...d-support-for-mib-autocast-in-Ethern.patch | 226 + ...d-support-for-phy-read-write-with-mg.patch | 287 + ...qca8k-move-page-cache-to-driver-priv.patch | 208 + ...qca8k-cache-lo-and-hi-for-mdio-write.patch | 164 + ...d-support-for-larger-read-write-size.patch | 206 + ...troduce-qca8k_bulk_read-write-functi.patch | 104 + ...eck-correct-variable-in-qca8k_phy_et.patch | 28 + ...dsa-qca8k-fix-noderef.cocci-warnings.patch | 34 + ...8k-drop-MTU-tracking-from-qca8k_priv.patch | 79 + ...-qca8k-drop-port_sts-from-qca8k_priv.patch | 116 + ...8k-rework-and-simplify-mdiobus-logic.patch | 173 + ...-drop-dsa_switch_ops-from-qca8k_priv.patch | 39 + ...a8k-correctly-handle-mdio-read-error.patch | 33 + ...ify-bus-id-naming-with-legacy-and-OF.patch | 44 + ...net-dsa-qca8k-move-driver-to-qca-dir.patch | 7389 ++++++++++++++++ ...-cache-match-data-to-speed-up-access.patch | 157 + ...k-make-mib-autocast-feature-optional.patch | 77 + ...qca8k-move-mib-struct-to-common-code.patch | 6532 ++++++++++++++ ...ve-qca8k-read-write-rmw-and-reg-tabl.patch | 135 + ...ve-qca8k-bulk-read-write-helper-to-c.patch | 145 + ...ove-mib-init-function-to-common-code.patch | 137 + ...ve-port-set-status-eee-ethtool-stats.patch | 281 + ...move-bridge-functions-to-common-code.patch | 237 + ...ve-set-age-MTU-port-enable-disable-f.patch | 227 + ...ve-port-FDB-MDB-function-to-common-c.patch | 704 ++ ...ve-port-mirror-functions-to-common-c.patch | 232 + ...ve-port-VLAN-functions-to-common-cod.patch | 448 + ...ve-port-LAG-functions-to-common-code.patch | 384 + ...ve-read_switch_id-function-to-common.patch | 102 + ...x-NULL-pointer-dereference-for-of_de.patch | 29 + ...N-filtering-syncing-out-of-dsa_switc.patch | 77 + ...cross-chip-syncing-of-VLAN-filtering.patch | 52 + ...-rtl8366rb-Support-bridge-offloading.patch | 141 + ...-dsa-rtl8366-Drop-custom-VLAN-set-up.patch | 118 + ...b-Rewrite-weird-VLAN-filering-enable.patch | 270 + ...-Drop-and-depromote-pointless-prints.patch | 51 + ...tl8366rb-Use-core-filtering-tracking.patch | 61 + ...rtl8366rb-Support-disabling-learning.patch | 115 + ...net-dsa-rtl8366rb-Support-fast-aging.patch | 57 + ...-rtl8366rb-Support-setting-STP-state.patch | 107 + ...icro-stmmac-move-queue-reset-to-dedi.patch | 142 + ...icro-stmmac-first-disable-all-queues.patch | 37 + ...icro-stmmac-move-dma-conf-to-dedicat.patch | 1289 +++ ...icro-stmmac-generate-stmmac-dma-conf.patch | 1161 +++ ...icro-stmmac-permit-MTU-change-with-i.patch | 73 + ...x-inband-mgmt-for-big-endian-systems.patch | 156 + ...x-ethtool-autocast-mib-for-big-endia.patch | 81 + ...x-wrong-length-value-for-mgmt-eth-pa.patch | 102 + ...sa-tag_qca-fix-wrong-MGMT_DATA2-size.patch | 34 + ...qca8k-cache-lo-and-hi-for-mdio-write.patch | 172 + ...ntroduce-single-mii-read-write-lo-hi.patch | 150 + ...prove-mdio-master-read-write-by-usin.patch | 73 + ...-01-net-phy-at803x-add-fiber-support.patch | 193 + ...y-at803x-support-downstream-SFP-cage.patch | 95 + ...LL-pointer-dereference-on-AR9331-PHY.patch | 56 + ...ix-error-return-code-in-at803x_probe.patch | 31 + ...eric-Introduce-Sierra-EM919X-support.patch | 80 + ...ost-always-print-detected-modem-name.patch | 37 + ...-add-support-for-in-band-link-status.patch | 130 + ...e-implement-soft-state-polling-setup.patch | 98 + ...t-sfp-move-quirk-handling-into-sfp.c.patch | 291 + ...move-Alcatel-Lucent-3FE46541AA-fixup.patch | 69 + ....1-net-sfp-move-Huawei-MA5671A-fixup.patch | 48 + ...t-sfp-add-support-for-HALNy-GPON-SFP.patch | 79 + ...t-dsa-mt7530-use-external-PCS-driver.patch | 514 ++ ...k-enabling-2500Base-x-for-HG-MXPD-48.patch | 37 + ....0-net-mii-add-mii_bmcr_encode_fixed.patch | 55 + ...or-Motorcomm-yt8521-gigabit-ethernet.patch | 1724 ++++ ...fix-yt8521-duplicated-argument-to-or.patch | 49 + ...net-phy-add-Motorcomm-YT8531S-phy-id.patch | 140 + ...fix-the-spelling-problem-of-Sentinel.patch | 26 + ...nge-the-phy-id-of-yt8521-and-yt8531s.patch | 29 + ...-for-Motorcomm-yt8521-yt8531-gigabit.patch | 107 + ...support-for-Motorcomm-yt8521-gigabit.patch | 343 + ...upport-for-Motorcomm-yt8531s-gigabit.patch | 100 + ...or-Motorcomm-yt8531-gigabit-ethernet.patch | 302 + ...motorcomm-uninitialized-variables-in.patch | 34 + ...net-usb-ax88179_178a-add-TSO-feature.patch | 68 + ...s-add-Broadcom-s-BCM63138-controller.patch | 125 + ...-add-support-for-BCM63138-controller.patch | 356 + ...-leds-bcm63138-unify-full-stops-in-d.patch | 30 + ...help-info-about-BCM63138-module-name.patch | 28 + ...eds-leds-bcm63138-get-rid-of-LED_OFF.patch | 30 + ...-rework-nvmem-cell-instance-creation.patch | 456 + ...-nvmem-cell-post-processing-callback.patch | 82 + ...cotp-add-support-for-post-processing.patch | 92 + ...support-minimum-one-byte-access-stri.patch | 47 + ...-Remove-unused-devm_nvmem_unregister.patch | 72 + ...em-core-Use-devm_add_action_or_reset.patch | 58 + ...-input-parameter-for-NULL-in-nvmem_u.patch | 30 + ...4-nvmem-qfprom-fix-kerneldoc-warning.patch | 29 + ...sunxi_sid-Add-support-for-D1-variant.patch | 38 + ...fuse-replace-unnecessary-devm_kstrdu.patch | 28 + ...-for-Layerscape-SFP-Security-Fuse-Pr.patch | 139 + ...rease-fuse-blow-timeout-to-prevent-w.patch | 32 + ...d-driver-for-OCOTP-in-Sunplus-SP7021.patch | 291 + ...-parse-NVRAM-content-into-NVMEM-cell.patch | 146 + ...mark-ACPI-device-ID-table-as-maybe-u.patch | 32 + ...em-sunplus-ocotp-staticize-sp_otp_v0.patch | 30 + ...cotp-drop-useless-probe-confirmation.patch | 27 + ...support-passing-DT-node-in-cell-info.patch | 41 + ...-find-Device-Tree-nodes-for-NVMEM-ce.patch | 38 + ...19-0006-nvmem-Add-Apple-eFuse-driver.patch | 130 + ...ng-pm_runtime_resume_and_get-instead.patch | 31 + .../805-v5.19-0008-nvmem-sfp-Use-regmap.patch | 109 + ...m-sfp-Add-support-for-TA-2.1-devices.patch | 38 + ...001-nvmem-microchip-otpc-add-support.patch | 389 + ...Simplify-with-devm_platform_get_and_.patch | 32 + ...-handling-U-Boot-environment-variabl.patch | 286 + ...-Use-kzalloc-for-allocating-only-one.patch | 29 + ...nvmem-prefix-all-symbols-with-NVMEM_.patch | 281 + ...m-sort-config-symbols-alphabetically.patch | 535 ++ ...-find-Device-Tree-nodes-for-NVMEM-ce.patch | 31 + ...1-0008-nvmem-lan9662-otp-add-support.patch | 274 + ...em-u-boot-env-fix-crc32-casting-type.patch | 32 + ...em-lan9662-otp-Fix-compatible-string.patch | 34 + ...-fix-crc32_data_offset-on-redundant-.patch | 59 + ...p-Change-return-type-of-lan9662_otp_.patch | 35 + ...e-STM32MP15_BSEC_NUM_LOWER-in-config.patch | 82 + ...-warning-when-upper-OTPs-are-updated.patch | 34 + ...nvmem-stm32-add-nvmem-type-attribute.patch | 26 + ...m-stm32-fix-spelling-typo-in-comment.patch | 27 + ...x-spelling-mistake-controlls-control.patch | 27 + ...boot-env-add-Broadcom-format-support.patch | 67 + ...mem-brcm_nvram-Add-check-for-kzalloc.patch | 30 + ...nxi_sid-Always-use-32-bit-MMIO-reads.patch | 55 + ...mem-core-fix-device-node-refcounting.patch | 48 + ...mem-core-remove-spurious-white-space.patch | 26 + ...e-add-an-index-parameter-to-the-cell.patch | 180 + ...struct-nvmem_cell_info-to-nvmem-prov.patch | 78 + ...the-removal-of-the-cells-in-nvmem_ad.patch | 65 + ...05-nvmem-core-add-nvmem_add_one_cell.patch | 122 + ...vmem_add_one_cell-in-nvmem_add_cells.patch | 93 + ...32-add-OP-TEE-support-for-STM32MP13x.patch | 562 ++ ...ect-bsec-pta-presence-for-STM32MP15x.patch | 85 + ...eprm-fix-kernel-doc-bad-line-warning.patch | 32 + ...mi-sdam-register-at-device-init-time.patch | 43 + ...011-nvmem-stm32-fix-OPTEE-dependency.patch | 46 + ..._wwan-add-ZTE-MF286D-modem-19d2-1485.patch | 59 + ...001-nvmem-xilinx-zynqmp-make-modular.patch | 35 + ...2-nvmem-core-introduce-NVMEM-layouts.patch | 387 + ...ndle-the-absence-of-expected-layouts.patch | 61 + ...-core-request-layout-modules-loading.patch | 52 + ...em-core-add-per-cell-post-processing.patch | 86 + ...ow-to-modify-a-cell-before-adding-it.patch | 59 + ...replace-global-post-processing-with-.patch | 81 + ...m-cell-drop-global-cell_post_process.patch | 68 + ...de-own-priv-pointer-in-post-process-.patch | 76 + ...ayouts-sl28vpd-Add-new-layout-driver.patch | 215 + ...youts-onie-tlv-Add-new-layout-driver.patch | 306 + ...m-mark-OF-related-data-as-maybe-unus.patch | 32 + ...Support-postprocessing-for-GPU-speed.patch | 120 + ...p-Use-devm_platform_ioremap_resource.patch | 39 + ...tp-Use-devm_platform_ioremap_resourc.patch | 39 + ...p-Use-devm_platform_get_and_ioremap_.patch | 32 + ...rt-specifying-both-cell-raw-data-pos.patch | 115 + ...nv-post-process-ethaddr-env-variable.patch | 81 + ...cro-to-register-nvmem-layout-drivers.patch | 42 + ...28vpd-Use-module_nvmem_layout_driver.patch | 39 + ...ie-tlv-Use-module_nvmem_layout_drive.patch | 39 + ...uts-onie-tlv-Drop-wrong-module-alias.patch | 24 + ...28vpd-set-varaiable-sl28vpd_layout-s.patch | 31 + ...-bcm47xx-support-init-from-IO-memory.patch | 100 + ...vram-add-.read_post_process-for-MACs.patch | 77 + ...Support-public-address-configuration.patch | 51 + ...Fix-application-of-sizeof-to-pointer.patch | 29 + ...Add-a-new-PID-VID-13d3-3567-for-MT79.patch | 70 + ...Add-a-new-PID-VID-0489-e0c8-for-MT79.patch | 68 + ...Add-a-new-VID-PID-0e8d-0608-for-MT79.patch | 66 + ...ll-of_parse_phandle-variants-static-.patch | 359 + ...-of_parse_phandle_with_optional_args.patch | 58 + ...ke-.-cells-optional-for-simple-props.patch | 34 + ...operty-add-nvmem-cell-cells-property.patch | 30 + ...vice-Ignore-modalias-of-reused-nodes.patch | 37 + ...-ignore-error-code-in-of_device_ueve.patch | 29 + ...002-of-Update-of_device_get_modalias.patch | 103 + ...v6.4-0003-of-Rename-of_modalias_node.patch | 173 + ...0004-of-Move-of_modalias-to-module.c.patch | 160 + ...uest-module-helper-logic-to-module.c.patch | 131 + ...a-ahci-fix-enum-constants-for-gcc-13.patch | 348 + ...PS-ath79-drop-_machine_restart-again.patch | 49 + ....18-hwmon-lm70-Add-ti-tmp125-support.patch | 71 + ...ether-export-usbnet_cdc_zte_rx_fixup.patch | 58 + ...e-the-bogus-MAC-fixup-for-ZTE-device.patch | 118 + ...-scope-of-bogus-MAC-address-detectio.patch | 63 + ...-spinand-winbond-fix-flash-detection.patch | 40 + ...6.1-mtd-spinand-winbond-add-W25N02KV.patch | 106 + target/linux/generic/config-6.1 | 7591 +++++++++++++++++ .../generic/hack-6.1/204-module_strip.patch | 212 + ...-abort-configuration-on-unset-symbol.patch | 41 + .../hack-6.1/210-darwin_scripts_include.patch | 3053 +++++++ .../211-darwin-uuid-typedef-clash.patch | 22 + .../hack-6.1/212-tools_portability.patch | 110 + .../hack-6.1/214-spidev_h_portability.patch | 24 + .../hack-6.1/220-arm-gc_sections.patch | 123 + .../generic/hack-6.1/221-module_exports.patch | 126 + .../hack-6.1/230-openwrt_lzma_options.patch | 34 + .../hack-6.1/250-netfilter_depends.patch | 27 + .../linux/generic/hack-6.1/251-kconfig.patch | 210 + .../generic/hack-6.1/253-ksmbd-config.patch | 32 + .../generic/hack-6.1/259-regmap_dynamic.patch | 144 + .../260-crypto_test_dependencies.patch | 52 + .../hack-6.1/261-lib-arc4-unhide.patch | 24 + .../generic/hack-6.1/280-rfkill-stubs.patch | 84 + ...cache-use-more-efficient-cache-blast.patch | 64 + .../321-powerpc_crtsavres_prereq.patch | 38 + ...rans-call-add-disks-after-mtd-device.patch | 98 + .../410-block-fit-partition-parser.patch | 214 + ...upport-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch | 24 + ...ers-add-nvmem-support-to-cmdlinepart.patch | 120 + .../hack-6.1/430-mtk-bmt-support.patch | 33 + .../generic/hack-6.1/600-bridge_offload.patch | 846 ++ ...of_net-add-mac-address-ascii-support.patch | 116 + ...lter-connmark-introduce-set-dscpmark.patch | 214 + ...-netfilter-add-xt_FLOWOFFLOAD-target.patch | 861 ++ .../hack-6.1/651-wireless_mesh_header.patch | 24 + .../hack-6.1/660-fq_codel_defaults.patch | 27 + ...t-size-the-hashtable-more-adequately.patch | 25 + .../700-swconfig_switch_drivers.patch | 131 + ...-dsa-mv88e6xxx-disable-ATU-violation.patch | 21 + .../hack-6.1/720-net-phy-add-aqr-phys.patch | 142 + .../721-net-add-packet-mangeling.patch | 178 + ...hy-aquantia-enable-AQR112-and-AQR412.patch | 154 + ...aquantia-fix-system-side-protocol-mi.patch | 34 + ...y-aquantia-Add-AQR113-driver-support.patch | 43 + ...ntia-add-PHY_IDs-for-AQR112-variants.patch | 63 + ...mtk-lynxi-workaround-2500BaseX-no-an.patch | 53 + ...-r8152-add-LED-configuration-from-OF.patch | 74 + ...et-add-RTL8152-binding-documentation.patch | 54 + .../765-mxl-gpy-control-LED-reg-from-DT.patch | 101 + ...k-ge-add-LED-configuration-interface.patch | 72 + .../hack-6.1/773-bgmac-add-srab-switch.patch | 98 + .../780-usb-net-MeigLink_modem_support.patch | 43 + .../790-SFP-GE-T-ignore-TX_FAULT.patch | 65 + .../795-backport-phylink_pcs-helpers.patch | 167 + .../800-GPIO-add-named-gpio-exports.patch | 162 + .../810-bcma-ssb-fallback-sprom.patch | 187 + .../hack-6.1/901-debloat_sock_diag.patch | 162 + .../generic/hack-6.1/902-debloat_proc.patch | 408 + .../hack-6.1/904-debloat_dma_buf.patch | 92 + .../generic/hack-6.1/910-kobject_uevent.patch | 32 + .../911-kobject_add_broadcast_uevent.patch | 76 + .../hack-6.1/920-device_tree_cmdline.patch | 21 + ...vert-driver-core-Set-fw_devlink-on-b.patch | 30 + ...include-asm-rwonce.h-for-kernel-code.patch | 29 + ...s-negative-stack-offsets-on-stack-tr.patch | 57 + .../103-kbuild-export-SUBARCH.patch | 21 + ...ilicon-Labs-EM3581-device-compatible.patch | 32 + ...ilicon-Labs-SI3210-device-compatible.patch | 32 + ..._wdt-Add-support-for-specifying-WDI-.patch | 75 + ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch | 82 + ...ically-allocate-note.data-in-parse_e.patch | 94 + ...ame2-and-add-RENAME_WHITEOUT-support.patch | 81 + ...41-jffs2-add-RENAME_EXCHANGE-support.patch | 73 + .../142-jffs2-add-splice-ops.patch | 20 + ...ck-usage-in-jffs2_build_xattr_subsys.patch | 121 + ...ge_allow_receiption_on_disabled_port.patch | 45 + ...-rs5c372-support_alarms_up_to_1_week.patch | 94 + ...he_alarm_to_be_used_as_wakeup_source.patch | 70 + .../203-kallsyms_uncompressed.patch | 119 + .../205-backtrace_module_info.patch | 41 + ...e-filenames-from-deps_initramfs-list.patch | 30 + ...able_wilink_platform_without_drivers.patch | 20 + .../270-platform-mikrotik-build-bits.patch | 31 + .../300-mips_expose_boot_raw.patch | 40 + ...rriers-between-dcache-icache-flushes.patch | 71 + .../302-mips_no_branch_likely.patch | 22 + .../pending-6.1/305-mips_module_reloc.patch | 370 + .../pending-6.1/307-mips_highmem_offset.patch | 19 + .../pending-6.1/308-mips32r2_tune.patch | 22 + .../310-arm_module_unresolved_weak_sym.patch | 22 + ...t-command-line-parameters-from-users.patch | 282 + .../332-arc-add-OWRTDTB-section.patch | 84 + ...able-unaligned-access-in-kernel-mode.patch | 24 + ...ernel-XZ-compression-option-on-PPC_8.patch | 25 + ...ip-bcm-6345-l1-request-memory-region.patch | 113 + .../400-mtd-mtdsplit-support.patch | 328 + ...support-for-minor-aligned-partitions.patch | 245 + .../pending-6.1/420-mtd-redboot_space.patch | 41 + ...30-mtd-add-myloader-partition-parser.patch | 229 + ...check-for-bad-blocks-when-calculatin.patch | 68 + ...bcm47xxpart-detect-T_Meter-partition.patch | 37 + ...mtd-add-routerbootpart-parser-config.patch | 38 + ...mtd-cfi_cmdset_0002-no-erase_suspend.patch | 25 + ...et_0002-add-buffer-write-cmd-timeout.patch | 17 + ...25p80-mx-disable-software-protection.patch | 18 + .../476-mtd-spi-nor-add-eon-en25q128.patch | 18 + .../477-mtd-spi-nor-add-eon-en25qx128a.patch | 21 + .../479-mtd-spi-nor-add-xtx-xt25f128b.patch | 79 + ...r-add-support-for-Gigadevice-GD25D05.patch | 22 + .../482-mtd-spi-nor-add-gd25q512.patch | 21 + .../484-mtd-spi-nor-add-esmt-f25l16pa.patch | 23 + .../485-mtd-spi-nor-add-xmc-xm25qh128c.patch | 24 + ...nand-add-support-for-ESMT-F50x1G41LB.patch | 143 + ...nd-Add-support-for-Etron-EM73D044VCx.patch | 168 + .../488-mtd-spi-nor-add-xmc-xm25qh64c.patch | 22 + ...mtd-device-named-ubi-or-data-on-boot.patch | 97 + ...to-create-ubiblock-device-for-rootfs.patch | 69 + ...ting-ubi0-rootfs-in-init-do_mounts.c.patch | 53 + ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 34 + .../494-mtd-ubi-add-EOF-marker-support.patch | 60 + ...-add-bindings-for-mtd-concat-devices.patch | 52 + ...cat-add-dt-driver-for-concat-devices.patch | 216 + ...i-nor-locking-support-for-MX25L6405D.patch | 34 + ...i-nor-disable-16-bit-sr-for-macronix.patch | 30 + .../500-fs_cdrom_dependencies.patch | 52 + .../530-jffs2_make_lzma_available.patch | 4581 ++++++++++ .../pending-6.1/532-jffs2_eofdetect.patch | 65 + .../600-netfilter_conntrack_flush.patch | 88 + ...etfilter_match_bypass_default_checks.patch | 110 + ...netfilter_match_bypass_default_table.patch | 106 + ...netfilter_match_reduce_memory_access.patch | 22 + ...del-do-not-defer-queue-length-update.patch | 86 + .../pending-6.1/630-packet_socket_type.patch | 138 + .../pending-6.1/655-increase_skb_pad.patch | 20 + ...Add-support-for-MAP-E-FMRs-mesh-mode.patch | 511 ++ ...ng-with-source-address-failed-policy.patch | 263 + ...nes-for-_POLICY_FAILED-until-all-cod.patch | 50 + ...T-skip-GRO-for-foreign-MAC-addresses.patch | 149 + ...et-add-mac-address-increment-support.patch | 89 + ...83-of_net-add-mac-address-to-of-tree.patch | 55 + ...t-do-mac-address-increment-only-once.patch | 31 + ...ow_offload-handle-netdevice-events-f.patch | 106 + ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 41 + ...detach-callback-to-struct-phy_driver.patch | 38 + ...a-tag_mtk-add-padding-for-tx-packets.patch | 28 + ...d-knob-for-filtering-rx-tx-BPDU-pack.patch | 174 + ...rtl8221-allow-to-configure-SERDES-mo.patch | 106 + ...support-switching-between-SGMII-and-.patch | 61 + ...e-all-MACs-are-powered-down-before-r.patch | 28 + ...-use-genphy_soft_reset-for-2.5G-PHYs.patch | 65 + ...sable-SGMII-in-band-AN-for-2-5G-PHYs.patch | 43 + ...make-sure-paged-read-is-protected-by.patch | 35 + ...use-inline-functions-for-10GbE-adver.patch | 60 + ...check-validity-of-10GbE-link-partner.patch | 28 + ...-phy-realtek-introduce-rtl822x_probe.patch | 100 + ...tek-detect-early-version-of-RTL8221B.patch | 63 + ...iatek-ppe-add-support-for-flow-accou.patch | 428 + ..._eth_soc-drop-generic-vlan-rx-offloa.patch | 201 + ..._eth_soc-work-around-issue-with-send.patch | 94 + ...rnet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch | 21 + ..._eth_soc-fix-remaining-throughput-re.patch | 42 + ..._eth_soc-ppe-fix-L2-offloading-with-.patch | 33 + ..._eth_soc-add-code-for-offloading-flo.patch | 266 + ...iatek-mtk_ppe-prefer-newly-added-l2-.patch | 37 + ..._eth_soc-improve-keeping-track-of-of.patch | 331 + ...iatek-fix-ppe-flow-accounting-for-L2.patch | 333 + ..._eth_soc-add-missing-ppe-cache-flush.patch | 21 + ...iatek-fix-ppe-flow-accounting-for-v1.patch | 51 + ...pool-and-page-referenced-frags-in-GR.patch | 35 + ...ional-threading-for-backlog-processi.patch | 232 + ...equest-assisted-learning-on-CPU-port.patch | 27 + ...a-b53-add-support-for-BCM63xx-RGMIIs.patch | 174 + ...-net-dsa-b53-mmap-add-more-63xx-SoCs.patch | 108 + ...dsa-b53-mmap-allow-passing-a-chip-ID.patch | 195 + ...b53-add-BCM63268-RGMII-configuration.patch | 123 + ...sa-b53-mdio-add-support-for-BCM53134.patch | 189 + ...-missing-linux-if_ether.h-for-ETH_AL.patch | 61 + ...-bus-mhi-core-add-SBL-state-callback.patch | 48 + ...gister-OF-node-for-internal-MDIO-bus.patch | 43 + ...ice-struct-copy-its-DMA-params-to-th.patch | 73 + ...pio-cascade-add-generic-GPIO-cascade.patch | 222 + ...env-align-endianness-of-crc32-values.patch | 47 + .../810-pci_disable_common_quirks.patch | 62 + .../811-pci_disable_usb_common_quirks.patch | 115 + ...problem-with-platfom-data-in-w1-gpio.patch | 26 + .../pending-6.1/834-ledtrig-libata.patch | 149 + ...40-hwrng-bcm2835-set-quality-to-1000.patch | 26 + ...e-main-irq_chip-structure-a-static-d.patch | 102 + ...add-BCM63268-timer-clock-definitions.patch | 114 + ...add-BCM63268-timer-reset-definitions.patch | 107 + ...CM63268-timer-clock-and-reset-driver.patch | 345 + .../pending-6.1/920-mangle_bootargs.patch | 71 + 713 files changed, 130426 insertions(+) create mode 100644 target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch create mode 100644 target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch create mode 100644 target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch create mode 100644 target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch create mode 100644 target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch create mode 100644 target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch create mode 100644 target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch create mode 100644 target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch create mode 100644 target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch create mode 100644 target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch create mode 100644 target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch create mode 100644 target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch create mode 100644 target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch create mode 100644 target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch create mode 100644 target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch create mode 100644 target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch create mode 100644 target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch create mode 100644 target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch create mode 100644 target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch create mode 100644 target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch create mode 100644 target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch create mode 100644 target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch create mode 100644 target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch create mode 100644 target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch create mode 100644 target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch create mode 100644 target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch create mode 100644 target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch create mode 100644 target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch create mode 100644 target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch create mode 100644 target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch create mode 100644 target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch create mode 100644 target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch create mode 100644 target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch create mode 100644 target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch create mode 100644 target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch create mode 100644 target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch create mode 100644 target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch create mode 100644 target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch create mode 100644 target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch create mode 100644 target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch create mode 100644 target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch create mode 100644 target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch create mode 100644 target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch create mode 100644 target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch create mode 100644 target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch create mode 100644 target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch create mode 100644 target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch create mode 100644 target/linux/generic/backport-6.1/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch create mode 100644 target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch create mode 100644 target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch create mode 100644 target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch create mode 100644 target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch create mode 100644 target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch create mode 100644 target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch create mode 100644 target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch create mode 100644 target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch create mode 100644 target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch create mode 100644 target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch create mode 100644 target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch create mode 100644 target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch create mode 100644 target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch create mode 100644 target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch create mode 100644 target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch create mode 100644 target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch create mode 100644 target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch create mode 100644 target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch create mode 100644 target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch create mode 100644 target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch create mode 100644 target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch create mode 100644 target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch create mode 100644 target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch create mode 100644 target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch create mode 100644 target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch create mode 100644 target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch create mode 100644 target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch create mode 100644 target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch create mode 100644 target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch create mode 100644 target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch create mode 100644 target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch create mode 100644 target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch create mode 100644 target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch create mode 100644 target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch create mode 100644 target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch create mode 100644 target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch create mode 100644 target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch create mode 100644 target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch create mode 100644 target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch create mode 100644 target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch create mode 100644 target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch create mode 100644 target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch create mode 100644 target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch create mode 100644 target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch create mode 100644 target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch create mode 100644 target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch create mode 100644 target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch create mode 100644 target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch create mode 100644 target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch create mode 100644 target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch create mode 100644 target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch create mode 100644 target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch create mode 100644 target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch create mode 100644 target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch create mode 100644 target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch create mode 100644 target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch create mode 100644 target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch create mode 100644 target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch create mode 100644 target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch create mode 100644 target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch create mode 100644 target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch create mode 100644 target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch create mode 100644 target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch create mode 100644 target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch create mode 100644 target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch create mode 100644 target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch create mode 100644 target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch create mode 100644 target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch create mode 100644 target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch create mode 100644 target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch create mode 100644 target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch create mode 100644 target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch create mode 100644 target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch create mode 100644 target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch create mode 100644 target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch create mode 100644 target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch create mode 100644 target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch create mode 100644 target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch create mode 100644 target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch create mode 100644 target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch create mode 100644 target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch create mode 100644 target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch create mode 100644 target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch create mode 100644 target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch create mode 100644 target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch create mode 100644 target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch create mode 100644 target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch create mode 100644 target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch create mode 100644 target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch create mode 100644 target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch create mode 100644 target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch create mode 100644 target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch create mode 100644 target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch create mode 100644 target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch create mode 100644 target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch create mode 100644 target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch create mode 100644 target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch create mode 100644 target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch create mode 100644 target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch create mode 100644 target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch create mode 100644 target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch create mode 100644 target/linux/generic/backport-6.1/729-01-v6.1-net-ethernet-mtk_wed-introduce-wed-mcu-support.patch create mode 100644 target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch create mode 100644 target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch create mode 100644 target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch create mode 100644 target/linux/generic/backport-6.1/729-05-v6.1-net-ethernet-mtk_wed-add-rx-mib-counters.patch create mode 100644 target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch create mode 100644 target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch create mode 100644 target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch create mode 100644 target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch create mode 100644 target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch create mode 100644 target/linux/generic/backport-6.1/729-11-v6.2-net-ethernet-mtk_wed-move-MTK_WDMA_RESET_IDX_TX-conf.patch create mode 100644 target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch create mode 100644 target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch create mode 100644 target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch create mode 100644 target/linux/generic/backport-6.1/729-15-v6.2-net-ethernet-mtk_wed-fix-sleep-while-atomic-in-mtk_w.patch create mode 100644 target/linux/generic/backport-6.1/729-16-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-rx-qu.patch create mode 100644 target/linux/generic/backport-6.1/729-17-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-tx-qu.patch create mode 100644 target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch create mode 100644 target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch create mode 100644 target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch create mode 100644 target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch create mode 100644 target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch create mode 100644 target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch create mode 100644 target/linux/generic/backport-6.1/730-01-v6.3-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch create mode 100644 target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch create mode 100644 target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch create mode 100644 target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch create mode 100644 target/linux/generic/backport-6.1/730-05-v6.3-net-dsa-tag_mtk-assign-per-port-queues.patch create mode 100644 target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch create mode 100644 target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch create mode 100644 target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch create mode 100644 target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch create mode 100644 target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch create mode 100644 target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch create mode 100644 target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch create mode 100644 target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch create mode 100644 target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch create mode 100644 target/linux/generic/backport-6.1/730-16-v6.3-net-ethernet-mtk_wed-fix-some-possible-NULL-pointer-.patch create mode 100644 target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch create mode 100644 target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.4-21-net-mtk_eth_soc-use-WO-firmware-for-MT7981.patch create mode 100644 target/linux/generic/backport-6.1/733-v6.4-22-net-ethernet-mtk_eth_soc-fix-NULL-pointer-dereferenc.patch create mode 100644 target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch create mode 100644 target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch create mode 100644 target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch create mode 100644 target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch create mode 100644 target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch create mode 100644 target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch create mode 100644 target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch create mode 100644 target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch create mode 100644 target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch create mode 100644 target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch create mode 100644 target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch create mode 100644 target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch create mode 100644 target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch create mode 100644 target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch create mode 100644 target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch create mode 100644 target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch create mode 100644 target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch create mode 100644 target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch create mode 100644 target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch create mode 100644 target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch create mode 100644 target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch create mode 100644 target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch create mode 100644 target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch create mode 100644 target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch create mode 100644 target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch create mode 100644 target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch create mode 100644 target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch create mode 100644 target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch create mode 100644 target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch create mode 100644 target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch create mode 100644 target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch create mode 100644 target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch create mode 100644 target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch create mode 100644 target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch create mode 100644 target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch create mode 100644 target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch create mode 100644 target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch create mode 100644 target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch create mode 100644 target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch create mode 100644 target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch create mode 100644 target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch create mode 100644 target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch create mode 100644 target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch create mode 100644 target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch create mode 100644 target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch create mode 100644 target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch create mode 100644 target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch create mode 100644 target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch create mode 100644 target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch create mode 100644 target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch create mode 100644 target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch create mode 100644 target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch create mode 100644 target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch create mode 100644 target/linux/generic/backport-6.1/777-v6.2-04-net-dsa-qca8k-introduce-single-mii-read-write-lo-hi.patch create mode 100644 target/linux/generic/backport-6.1/777-v6.2-05-net-dsa-qca8k-improve-mdio-master-read-write-by-usin.patch create mode 100644 target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch create mode 100644 target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch create mode 100644 target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch create mode 100644 target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch create mode 100644 target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch create mode 100644 target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch create mode 100644 target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch create mode 100644 target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch create mode 100644 target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch create mode 100644 target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch create mode 100644 target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch create mode 100644 target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch create mode 100644 target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch create mode 100644 target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch create mode 100644 target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.2-02-net-phy-fix-yt8521-duplicated-argument-to-or.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-04-net-phy-fix-the-spelling-problem-of-Sentinel.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-05-net-phy-motorcomm-change-the-phy-id-of-yt8521-and-yt8531s.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-06-net-phy-Add-BIT-macro-for-Motorcomm-yt8521-yt8531-gigabit.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-07-net-phy-Add-dts-support-for-Motorcomm-yt8521-gigabit.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-08-net-phy-Add-dts-support-for-Motorcomm-yt8531s-gigabit.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch create mode 100644 target/linux/generic/backport-6.1/791-v6.3-10-net-phy-motorcomm-uninitialized-variables-in.patch create mode 100644 target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch create mode 100644 target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch create mode 100644 target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch create mode 100644 target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch create mode 100644 target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch create mode 100644 target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch create mode 100644 target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch create mode 100644 target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch create mode 100644 target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch create mode 100644 target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch create mode 100644 target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch create mode 100644 target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch create mode 100644 target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch create mode 100644 target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch create mode 100644 target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0001-nvmem-stm32-move-STM32MP15_BSEC_NUM_LOWER-in-config.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0002-nvmem-stm32-add-warning-when-upper-OTPs-are-updated.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0003-nvmem-stm32-add-nvmem-type-attribute.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0004-nvmem-stm32-fix-spelling-typo-in-comment.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0005-nvmem-Kconfig-Fix-spelling-mistake-controlls-control.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0006-nvmem-u-boot-env-add-Broadcom-format-support.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch create mode 100644 target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0001-nvmem-core-remove-spurious-white-space.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0002-nvmem-core-add-an-index-parameter-to-the-cell.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0003-nvmem-core-move-struct-nvmem_cell_info-to-nvmem-prov.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0004-nvmem-core-drop-the-removal-of-the-cells-in-nvmem_ad.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0005-nvmem-core-add-nvmem_add_one_cell.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0006-nvmem-core-use-nvmem_add_one_cell-in-nvmem_add_cells.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0007-nvmem-stm32-add-OP-TEE-support-for-STM32MP13x.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0008-nvmem-stm32-detect-bsec-pta-presence-for-STM32MP15x.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0009-nvmem-rave-sp-eeprm-fix-kernel-doc-bad-line-warning.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0010-nvmem-qcom-spmi-sdam-register-at-device-init-time.patch create mode 100644 target/linux/generic/backport-6.1/809-v6.3-0011-nvmem-stm32-fix-OPTEE-dependency.patch create mode 100644 target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0001-nvmem-xilinx-zynqmp-make-modular.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0003-nvmem-core-handle-the-absence-of-expected-layouts.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0004-nvmem-core-request-layout-modules-loading.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0005-nvmem-core-add-per-cell-post-processing.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0006-nvmem-core-allow-to-modify-a-cell-before-adding-it.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0007-nvmem-imx-ocotp-replace-global-post-processing-with-.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0008-nvmem-cell-drop-global-cell_post_process.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0009-nvmem-core-provide-own-priv-pointer-in-post-process-.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0010-nvmem-layouts-sl28vpd-Add-new-layout-driver.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0011-nvmem-layouts-onie-tlv-Add-new-layout-driver.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0012-nvmem-stm32-romem-mark-OF-related-data-as-maybe-unus.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0013-nvmem-mtk-efuse-Support-postprocessing-for-GPU-speed.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0015-nvmem-nintendo-otp-Use-devm_platform_ioremap_resourc.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0016-nvmem-vf610-ocotp-Use-devm_platform_get_and_ioremap_.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0017-nvmem-core-support-specifying-both-cell-raw-data-pos.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0018-nvmem-u-boot-env-post-process-ethaddr-env-variable.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0019-nvmem-Add-macro-to-register-nvmem-layout-drivers.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0020-nvmem-layouts-sl28vpd-Use-module_nvmem_layout_driver.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0021-nvmem-layouts-onie-tlv-Use-module_nvmem_layout_drive.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0022-nvmem-layouts-onie-tlv-Drop-wrong-module-alias.patch create mode 100644 target/linux/generic/backport-6.1/811-v6.4-0023-nvmem-layouts-sl28vpd-set-varaiable-sl28vpd_layout-s.patch create mode 100644 target/linux/generic/backport-6.1/812-v6.2-firmware-nvram-bcm47xx-support-init-from-IO-memory.patch create mode 100644 target/linux/generic/backport-6.1/813-v6.5-nvmem-brcm_nvram-add-.read_post_process-for-MACs.patch create mode 100644 target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch create mode 100644 target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch create mode 100644 target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch create mode 100644 target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch create mode 100644 target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch create mode 100644 target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch create mode 100644 target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch create mode 100644 target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch create mode 100644 target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch create mode 100644 target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch create mode 100644 target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch create mode 100644 target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch create mode 100644 target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch create mode 100644 target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch create mode 100644 target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch create mode 100644 target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch create mode 100644 target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch create mode 100644 target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch create mode 100644 target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch create mode 100644 target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch create mode 100644 target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch create mode 100644 target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch create mode 100644 target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch create mode 100644 target/linux/generic/config-6.1 create mode 100644 target/linux/generic/hack-6.1/204-module_strip.patch create mode 100644 target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch create mode 100644 target/linux/generic/hack-6.1/210-darwin_scripts_include.patch create mode 100644 target/linux/generic/hack-6.1/211-darwin-uuid-typedef-clash.patch create mode 100644 target/linux/generic/hack-6.1/212-tools_portability.patch create mode 100644 target/linux/generic/hack-6.1/214-spidev_h_portability.patch create mode 100644 target/linux/generic/hack-6.1/220-arm-gc_sections.patch create mode 100644 target/linux/generic/hack-6.1/221-module_exports.patch create mode 100644 target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch create mode 100644 target/linux/generic/hack-6.1/250-netfilter_depends.patch create mode 100644 target/linux/generic/hack-6.1/251-kconfig.patch create mode 100644 target/linux/generic/hack-6.1/253-ksmbd-config.patch create mode 100644 target/linux/generic/hack-6.1/259-regmap_dynamic.patch create mode 100644 target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch create mode 100644 target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch create mode 100644 target/linux/generic/hack-6.1/280-rfkill-stubs.patch create mode 100644 target/linux/generic/hack-6.1/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch create mode 100644 target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch create mode 100644 target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch create mode 100644 target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch create mode 100644 target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch create mode 100644 target/linux/generic/hack-6.1/421-drivers-mtd-parsers-add-nvmem-support-to-cmdlinepart.patch create mode 100644 target/linux/generic/hack-6.1/430-mtk-bmt-support.patch create mode 100644 target/linux/generic/hack-6.1/600-bridge_offload.patch create mode 100644 target/linux/generic/hack-6.1/601-of_net-add-mac-address-ascii-support.patch create mode 100644 target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch create mode 100644 target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch create mode 100644 target/linux/generic/hack-6.1/651-wireless_mesh_header.patch create mode 100644 target/linux/generic/hack-6.1/660-fq_codel_defaults.patch create mode 100644 target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch create mode 100644 target/linux/generic/hack-6.1/700-swconfig_switch_drivers.patch create mode 100644 target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch create mode 100644 target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch create mode 100644 target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch create mode 100644 target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch create mode 100644 target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch create mode 100644 target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch create mode 100644 target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch create mode 100644 target/linux/generic/hack-6.1/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch create mode 100644 target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch create mode 100644 target/linux/generic/hack-6.1/761-dt-bindings-net-add-RTL8152-binding-documentation.patch create mode 100644 target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch create mode 100644 target/linux/generic/hack-6.1/766-net-phy-mediatek-ge-add-LED-configuration-interface.patch create mode 100644 target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch create mode 100644 target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch create mode 100644 target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch create mode 100644 target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch create mode 100644 target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch create mode 100644 target/linux/generic/hack-6.1/810-bcma-ssb-fallback-sprom.patch create mode 100644 target/linux/generic/hack-6.1/901-debloat_sock_diag.patch create mode 100644 target/linux/generic/hack-6.1/902-debloat_proc.patch create mode 100644 target/linux/generic/hack-6.1/904-debloat_dma_buf.patch create mode 100644 target/linux/generic/hack-6.1/910-kobject_uevent.patch create mode 100644 target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch create mode 100644 target/linux/generic/hack-6.1/920-device_tree_cmdline.patch create mode 100644 target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch create mode 100644 target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch create mode 100644 target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch create mode 100644 target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch create mode 100644 target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch create mode 100644 target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch create mode 100644 target/linux/generic/pending-6.1/111-watchdog-max63xx_wdt-Add-support-for-specifying-WDI-.patch create mode 100644 target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch create mode 100644 target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch create mode 100644 target/linux/generic/pending-6.1/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch create mode 100644 target/linux/generic/pending-6.1/141-jffs2-add-RENAME_EXCHANGE-support.patch create mode 100644 target/linux/generic/pending-6.1/142-jffs2-add-splice-ops.patch create mode 100644 target/linux/generic/pending-6.1/143-jffs2-reduce-stack-usage-in-jffs2_build_xattr_subsys.patch create mode 100644 target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch create mode 100644 target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch create mode 100644 target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch create mode 100644 target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch create mode 100644 target/linux/generic/pending-6.1/205-backtrace_module_info.patch create mode 100644 target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch create mode 100644 target/linux/generic/pending-6.1/261-enable_wilink_platform_without_drivers.patch create mode 100644 target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch create mode 100644 target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch create mode 100644 target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch create mode 100644 target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch create mode 100644 target/linux/generic/pending-6.1/305-mips_module_reloc.patch create mode 100644 target/linux/generic/pending-6.1/307-mips_highmem_offset.patch create mode 100644 target/linux/generic/pending-6.1/308-mips32r2_tune.patch create mode 100644 target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch create mode 100644 target/linux/generic/pending-6.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch create mode 100644 target/linux/generic/pending-6.1/332-arc-add-OWRTDTB-section.patch create mode 100644 target/linux/generic/pending-6.1/333-arc-enable-unaligned-access-in-kernel-mode.patch create mode 100644 target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch create mode 100644 target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch create mode 100644 target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch create mode 100644 target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch create mode 100644 target/linux/generic/pending-6.1/420-mtd-redboot_space.patch create mode 100644 target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch create mode 100644 target/linux/generic/pending-6.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch create mode 100644 target/linux/generic/pending-6.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch create mode 100644 target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch create mode 100644 target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch create mode 100644 target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch create mode 100644 target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch create mode 100644 target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch create mode 100644 target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch create mode 100644 target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch create mode 100644 target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch create mode 100644 target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch create mode 100644 target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch create mode 100644 target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch create mode 100644 target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch create mode 100644 target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch create mode 100644 target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch create mode 100644 target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch create mode 100644 target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch create mode 100644 target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch create mode 100644 target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch create mode 100644 target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch create mode 100644 target/linux/generic/pending-6.1/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch create mode 100644 target/linux/generic/pending-6.1/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch create mode 100644 target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch create mode 100644 target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch create mode 100644 target/linux/generic/pending-6.1/500-fs_cdrom_dependencies.patch create mode 100644 target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch create mode 100644 target/linux/generic/pending-6.1/532-jffs2_eofdetect.patch create mode 100644 target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch create mode 100644 target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch create mode 100644 target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch create mode 100644 target/linux/generic/pending-6.1/612-netfilter_match_reduce_memory_access.patch create mode 100644 target/linux/generic/pending-6.1/620-net_sched-codel-do-not-defer-queue-length-update.patch create mode 100644 target/linux/generic/pending-6.1/630-packet_socket_type.patch create mode 100644 target/linux/generic/pending-6.1/655-increase_skb_pad.patch create mode 100644 target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch create mode 100644 target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch create mode 100644 target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch create mode 100644 target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch create mode 100644 target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch create mode 100644 target/linux/generic/pending-6.1/683-of_net-add-mac-address-to-of-tree.patch create mode 100644 target/linux/generic/pending-6.1/684-of_net-do-mac-address-increment-only-once.patch create mode 100644 target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch create mode 100644 target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch create mode 100644 target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch create mode 100644 target/linux/generic/pending-6.1/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch create mode 100644 target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch create mode 100644 target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch create mode 100644 target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch create mode 100644 target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch create mode 100644 target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch create mode 100644 target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch create mode 100644 target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch create mode 100644 target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch create mode 100644 target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch create mode 100644 target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch create mode 100644 target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch create mode 100644 target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch create mode 100644 target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch create mode 100644 target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch create mode 100644 target/linux/generic/pending-6.1/732-02-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch create mode 100644 target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch create mode 100644 target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch create mode 100644 target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch create mode 100644 target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch create mode 100644 target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch create mode 100644 target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch create mode 100644 target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch create mode 100644 target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch create mode 100644 target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch create mode 100644 target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch create mode 100644 target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch create mode 100644 target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch create mode 100644 target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch create mode 100644 target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch create mode 100644 target/linux/generic/pending-6.1/775-net-dsa-b53-add-BCM63268-RGMII-configuration.patch create mode 100644 target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch create mode 100644 target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch create mode 100644 target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch create mode 100644 target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch create mode 100644 target/linux/generic/pending-6.1/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch create mode 100644 target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch create mode 100644 target/linux/generic/pending-6.1/802-nvmem-u-boot-env-align-endianness-of-crc32-values.patch create mode 100644 target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch create mode 100644 target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch create mode 100644 target/linux/generic/pending-6.1/820-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch create mode 100644 target/linux/generic/pending-6.1/834-ledtrig-libata.patch create mode 100644 target/linux/generic/pending-6.1/840-hwrng-bcm2835-set-quality-to-1000.patch create mode 100644 target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch create mode 100644 target/linux/generic/pending-6.1/850-dt-bindings-clk-add-BCM63268-timer-clock-definitions.patch create mode 100644 target/linux/generic/pending-6.1/851-dt-bindings-reset-add-BCM63268-timer-reset-definitions.patch create mode 100644 target/linux/generic/pending-6.1/852-clk-bcm-Add-BCM63268-timer-clock-and-reset-driver.patch create mode 100644 target/linux/generic/pending-6.1/920-mangle_bootargs.patch diff --git a/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch b/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch new file mode 100644 index 00000000000..b481dd30617 --- /dev/null +++ b/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch @@ -0,0 +1,73 @@ +From 2fd7e7f9317d3048a14026816d081b08ba98ea8e Mon Sep 17 00:00:00 2001 +From: Mark Rutland +Date: Tue, 8 Mar 2022 22:56:13 +0100 +Subject: [PATCH 1/3] Kbuild: use -Wdeclaration-after-statement + +The kernel is moving from using `-std=gnu89` to `-std=gnu11`, permitting +the use of additional C11 features such as for-loop initial declarations. + +One contentious aspect of C99 is that it permits mixed declarations and +code, and for now at least, it seems preferable to enforce that +declarations must come first. + +These warnings were already enabled in the kernel itself, but not +for KBUILD_USERCFLAGS or the compat VDSO on arch/arm64, which uses +a separate set of CFLAGS. + +This patch fixes an existing violation in modpost.c, which is not +reported because of the missing flag in KBUILD_USERCFLAGS: + +| scripts/mod/modpost.c: In function ‘match’: +| scripts/mod/modpost.c:837:3: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] +| 837 | const char *endp = p + strlen(p) - 1; +| | ^~~~~ + +Signed-off-by: Mark Rutland +[arnd: don't add a duplicate flag to the default set, update changelog] +Signed-off-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nick Desaulniers +Tested-by: Sedat Dilek # LLVM/Clang v13.0.0 (x86-64) +Signed-off-by: Masahiro Yamada +--- + Makefile | 3 ++- + arch/arm64/kernel/vdso32/Makefile | 1 + + scripts/mod/modpost.c | 4 +++- + 3 files changed, 6 insertions(+), 2 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -440,7 +440,8 @@ endif + HOSTPKG_CONFIG = pkg-config + + export KBUILD_USERCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \ +- -O2 -fomit-frame-pointer -std=gnu89 ++ -O2 -fomit-frame-pointer -std=gnu89 \ ++ -Wdeclaration-after-statement + export KBUILD_USERLDFLAGS := + + KBUILD_HOSTCFLAGS := $(KBUILD_USERCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS) +--- a/arch/arm64/kernel/vdso32/Makefile ++++ b/arch/arm64/kernel/vdso32/Makefile +@@ -76,6 +76,7 @@ VDSO_CFLAGS += -Wall -Wundef -Wstrict-pr + -fno-strict-aliasing -fno-common \ + -Werror-implicit-function-declaration \ + -Wno-format-security \ ++ -Wdeclaration-after-statement \ + -std=gnu89 + VDSO_CFLAGS += -O2 + # Some useful compiler-dependent flags from top-level Makefile +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -833,8 +833,10 @@ static int match(const char *sym, const + { + const char *p; + while (*pat) { ++ const char *endp; ++ + p = *pat++; +- const char *endp = p + strlen(p) - 1; ++ endp = p + strlen(p) - 1; + + /* "*foo*" */ + if (*p == '*' && *endp == '*') { diff --git a/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch b/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch new file mode 100644 index 00000000000..94fc52fd8e0 --- /dev/null +++ b/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch @@ -0,0 +1,60 @@ +From b810c8e719ea082e47c7a8f7cf878bc84fa2455d Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Tue, 8 Mar 2022 22:56:14 +0100 +Subject: [PATCH 2/3] Kbuild: move to -std=gnu11 + +During a patch discussion, Linus brought up the option of changing +the C standard version from gnu89 to gnu99, which allows using variable +declaration inside of a for() loop. While the C99, C11 and later standards +introduce many other features, most of these are already available in +gnu89 as GNU extensions as well. + +An earlier attempt to do this when gcc-5 started defaulting to +-std=gnu11 failed because at the time that caused warnings about +designated initializers with older compilers. Now that gcc-5.1 is +the minimum compiler version used for building kernels, that is no +longer a concern. Similarly, the behavior of 'inline' functions changes +between gnu89 using gnu_inline behavior and gnu11 using standard c99+ +behavior, but this was taken care of by defining 'inline' to include +__attribute__((gnu_inline)) in order to allow building with clang a +while ago. + +Nathan Chancellor reported a new -Wdeclaration-after-statement +warning that appears in a system header on arm, this still needs a +workaround. + +The differences between gnu99, gnu11, gnu1x and gnu17 are fairly +minimal and mainly impact warnings at the -Wpedantic level that the +kernel never enables. Between these, gnu11 is the newest version +that is supported by all supported compiler versions, though it is +only the default on gcc-5, while all other supported versions of +gcc or clang default to gnu1x/gnu17. + +Link: https://lore.kernel.org/lkml/CAHk-=wiyCH7xeHcmiFJ-YgXUy2Jaj7pnkdKpcovt8fYbVFW3TA@mail.gmail.com/ +Link: https://github.com/ClangBuiltLinux/linux/issues/1603 +Suggested-by: Linus Torvalds +Acked-by: Marco Elver +Acked-by: Jani Nikula +Acked-by: David Sterba +Tested-by: Sedat Dilek +Reviewed-by: Alex Shi +Reviewed-by: Nick Desaulniers +Reviewed-by: Miguel Ojeda +Signed-off-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Signed-off-by: Masahiro Yamada +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -524,7 +524,7 @@ KBUILD_CFLAGS := -Wall -Wundef -Werror + -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE \ + -Werror=implicit-function-declaration -Werror=implicit-int \ + -Werror=return-type -Wno-format-security \ +- -std=gnu89 ++ -std=gnu11 + KBUILD_CPPFLAGS := -D__KERNEL__ + KBUILD_AFLAGS_KERNEL := + KBUILD_CFLAGS_KERNEL := diff --git a/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch b/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch new file mode 100644 index 00000000000..e34acbba171 --- /dev/null +++ b/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch @@ -0,0 +1,43 @@ +From 40337d6f3d677aee7ad3052ae662d3f53dd4d5cb Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Tue, 8 Mar 2022 22:56:15 +0100 +Subject: [PATCH 3/3] Kbuild: use -std=gnu11 for KBUILD_USERCFLAGS + +As we change the C language standard for the kernel from gnu89 to +gnu11, it makes sense to also update the version for user space +compilation. + +Some users have older native compilers than what they use for +kernel builds, so I considered using gnu99 as the default version +for wider compatibility with gcc-4.6 and earlier. + +However, testing with older compilers showed that we already require +HOSTCC version 5.1 as well because a lot of host tools include +linux/compiler.h that uses __has_attribute(): + + CC tools/objtool/exec-cmd.o +In file included from tools/include/linux/compiler_types.h:36:0, + from tools/include/linux/compiler.h:5, + from exec-cmd.c:2: +tools/include/linux/compiler-gcc.h:19:5: error: "__has_attribute" is not defined [-Werror=undef] + +Signed-off-by: Arnd Bergmann +Reviewed-by: Nathan Chancellor +Reviewed-by: Nick Desaulniers +Tested-by: Sedat Dilek +Signed-off-by: Masahiro Yamada +--- + Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Makefile ++++ b/Makefile +@@ -440,7 +440,7 @@ endif + HOSTPKG_CONFIG = pkg-config + + export KBUILD_USERCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \ +- -O2 -fomit-frame-pointer -std=gnu89 \ ++ -O2 -fomit-frame-pointer -std=gnu11 \ + -Wdeclaration-after-statement + export KBUILD_USERLDFLAGS := + diff --git a/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch b/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch new file mode 100644 index 00000000000..df854ffd3d8 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch @@ -0,0 +1,425 @@ +From a4103262b01a1b8704b37c01c7c813df91b7b119 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 01:59:58 -0600 +Subject: [PATCH 01/29] mm: x86, arm64: add arch_has_hw_pte_young() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Patch series "Multi-Gen LRU Framework", v14. + +What's new +========== +1. OpenWrt, in addition to Android, Arch Linux Zen, Armbian, ChromeOS, + Liquorix, post-factum and XanMod, is now shipping MGLRU on 5.15. +2. Fixed long-tailed direct reclaim latency seen on high-memory (TBs) + machines. The old direct reclaim backoff, which tries to enforce a + minimum fairness among all eligible memcgs, over-swapped by about + (total_mem>>DEF_PRIORITY)-nr_to_reclaim. The new backoff, which + pulls the plug on swapping once the target is met, trades some + fairness for curtailed latency: + https://lore.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com/ +3. Fixed minior build warnings and conflicts. More comments and nits. + +TLDR +==== +The current page reclaim is too expensive in terms of CPU usage and it +often makes poor choices about what to evict. This patchset offers an +alternative solution that is performant, versatile and +straightforward. + +Patchset overview +================= +The design and implementation overview is in patch 14: +https://lore.kernel.org/r/20220918080010.2920238-15-yuzhao@google.com/ + +01. mm: x86, arm64: add arch_has_hw_pte_young() +02. mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +Take advantage of hardware features when trying to clear the accessed +bit in many PTEs. + +03. mm/vmscan.c: refactor shrink_node() +04. Revert "include/linux/mm_inline.h: fold __update_lru_size() into + its sole caller" +Minor refactors to improve readability for the following patches. + +05. mm: multi-gen LRU: groundwork +Adds the basic data structure and the functions that insert pages to +and remove pages from the multi-gen LRU (MGLRU) lists. + +06. mm: multi-gen LRU: minimal implementation +A minimal implementation without optimizations. + +07. mm: multi-gen LRU: exploit locality in rmap +Exploits spatial locality to improve efficiency when using the rmap. + +08. mm: multi-gen LRU: support page table walks +Further exploits spatial locality by optionally scanning page tables. + +09. mm: multi-gen LRU: optimize multiple memcgs +Optimizes the overall performance for multiple memcgs running mixed +types of workloads. + +10. mm: multi-gen LRU: kill switch +Adds a kill switch to enable or disable MGLRU at runtime. + +11. mm: multi-gen LRU: thrashing prevention +12. mm: multi-gen LRU: debugfs interface +Provide userspace with features like thrashing prevention, working set +estimation and proactive reclaim. + +13. mm: multi-gen LRU: admin guide +14. mm: multi-gen LRU: design doc +Add an admin guide and a design doc. + +Benchmark results +================= +Independent lab results +----------------------- +Based on the popularity of searches [01] and the memory usage in +Google's public cloud, the most popular open-source memory-hungry +applications, in alphabetical order, are: + Apache Cassandra Memcached + Apache Hadoop MongoDB + Apache Spark PostgreSQL + MariaDB (MySQL) Redis + +An independent lab evaluated MGLRU with the most widely used benchmark +suites for the above applications. They posted 960 data points along +with kernel metrics and perf profiles collected over more than 500 +hours of total benchmark time. Their final reports show that, with 95% +confidence intervals (CIs), the above applications all performed +significantly better for at least part of their benchmark matrices. + +On 5.14: +1. Apache Spark [02] took 95% CIs [9.28, 11.19]% and [12.20, 14.93]% + less wall time to sort three billion random integers, respectively, + under the medium- and the high-concurrency conditions, when + overcommitting memory. There were no statistically significant + changes in wall time for the rest of the benchmark matrix. +2. MariaDB [03] achieved 95% CIs [5.24, 10.71]% and [20.22, 25.97]% + more transactions per minute (TPM), respectively, under the medium- + and the high-concurrency conditions, when overcommitting memory. + There were no statistically significant changes in TPM for the rest + of the benchmark matrix. +3. Memcached [04] achieved 95% CIs [23.54, 32.25]%, [20.76, 41.61]% + and [21.59, 30.02]% more operations per second (OPS), respectively, + for sequential access, random access and Gaussian (distribution) + access, when THP=always; 95% CIs [13.85, 15.97]% and + [23.94, 29.92]% more OPS, respectively, for random access and + Gaussian access, when THP=never. There were no statistically + significant changes in OPS for the rest of the benchmark matrix. +4. MongoDB [05] achieved 95% CIs [2.23, 3.44]%, [6.97, 9.73]% and + [2.16, 3.55]% more operations per second (OPS), respectively, for + exponential (distribution) access, random access and Zipfian + (distribution) access, when underutilizing memory; 95% CIs + [8.83, 10.03]%, [21.12, 23.14]% and [5.53, 6.46]% more OPS, + respectively, for exponential access, random access and Zipfian + access, when overcommitting memory. + +On 5.15: +5. Apache Cassandra [06] achieved 95% CIs [1.06, 4.10]%, [1.94, 5.43]% + and [4.11, 7.50]% more operations per second (OPS), respectively, + for exponential (distribution) access, random access and Zipfian + (distribution) access, when swap was off; 95% CIs [0.50, 2.60]%, + [6.51, 8.77]% and [3.29, 6.75]% more OPS, respectively, for + exponential access, random access and Zipfian access, when swap was + on. +6. Apache Hadoop [07] took 95% CIs [5.31, 9.69]% and [2.02, 7.86]% + less average wall time to finish twelve parallel TeraSort jobs, + respectively, under the medium- and the high-concurrency + conditions, when swap was on. There were no statistically + significant changes in average wall time for the rest of the + benchmark matrix. +7. PostgreSQL [08] achieved 95% CI [1.75, 6.42]% more transactions per + minute (TPM) under the high-concurrency condition, when swap was + off; 95% CIs [12.82, 18.69]% and [22.70, 46.86]% more TPM, + respectively, under the medium- and the high-concurrency + conditions, when swap was on. There were no statistically + significant changes in TPM for the rest of the benchmark matrix. +8. Redis [09] achieved 95% CIs [0.58, 5.94]%, [6.55, 14.58]% and + [11.47, 19.36]% more total operations per second (OPS), + respectively, for sequential access, random access and Gaussian + (distribution) access, when THP=always; 95% CIs [1.27, 3.54]%, + [10.11, 14.81]% and [8.75, 13.64]% more total OPS, respectively, + for sequential access, random access and Gaussian access, when + THP=never. + +Our lab results +--------------- +To supplement the above results, we ran the following benchmark suites +on 5.16-rc7 and found no regressions [10]. + fs_fio_bench_hdd_mq pft + fs_lmbench pgsql-hammerdb + fs_parallelio redis + fs_postmark stream + hackbench sysbenchthread + kernbench tpcc_spark + memcached unixbench + multichase vm-scalability + mutilate will-it-scale + nginx + +[01] https://trends.google.com +[02] https://lore.kernel.org/r/20211102002002.92051-1-bot@edi.works/ +[03] https://lore.kernel.org/r/20211009054315.47073-1-bot@edi.works/ +[04] https://lore.kernel.org/r/20211021194103.65648-1-bot@edi.works/ +[05] https://lore.kernel.org/r/20211109021346.50266-1-bot@edi.works/ +[06] https://lore.kernel.org/r/20211202062806.80365-1-bot@edi.works/ +[07] https://lore.kernel.org/r/20211209072416.33606-1-bot@edi.works/ +[08] https://lore.kernel.org/r/20211218071041.24077-1-bot@edi.works/ +[09] https://lore.kernel.org/r/20211122053248.57311-1-bot@edi.works/ +[10] https://lore.kernel.org/r/20220104202247.2903702-1-yuzhao@google.com/ + +Read-world applications +======================= +Third-party testimonials +------------------------ +Konstantin reported [11]: + I have Archlinux with 8G RAM + zswap + swap. While developing, I + have lots of apps opened such as multiple LSP-servers for different + langs, chats, two browsers, etc... Usually, my system gets quickly + to a point of SWAP-storms, where I have to kill LSP-servers, + restart browsers to free memory, etc, otherwise the system lags + heavily and is barely usable. + + 1.5 day ago I migrated from 5.11.15 kernel to 5.12 + the LRU + patchset, and I started up by opening lots of apps to create memory + pressure, and worked for a day like this. Till now I had not a + single SWAP-storm, and mind you I got 3.4G in SWAP. I was never + getting to the point of 3G in SWAP before without a single + SWAP-storm. + +Vaibhav from IBM reported [12]: + In a synthetic MongoDB Benchmark, seeing an average of ~19% + throughput improvement on POWER10(Radix MMU + 64K Page Size) with + MGLRU patches on top of 5.16 kernel for MongoDB + YCSB across + three different request distributions, namely, Exponential, Uniform + and Zipfan. + +Shuang from U of Rochester reported [13]: + With the MGLRU, fio achieved 95% CIs [38.95, 40.26]%, [4.12, 6.64]% + and [9.26, 10.36]% higher throughput, respectively, for random + access, Zipfian (distribution) access and Gaussian (distribution) + access, when the average number of jobs per CPU is 1; 95% CIs + [42.32, 49.15]%, [9.44, 9.89]% and [20.99, 22.86]% higher + throughput, respectively, for random access, Zipfian access and + Gaussian access, when the average number of jobs per CPU is 2. + +Daniel from Michigan Tech reported [14]: + With Memcached allocating ~100GB of byte-addressable Optante, + performance improvement in terms of throughput (measured as queries + per second) was about 10% for a series of workloads. + +Large-scale deployments +----------------------- +We've rolled out MGLRU to tens of millions of ChromeOS users and +about a million Android users. Google's fleetwide profiling [15] shows +an overall 40% decrease in kswapd CPU usage, in addition to +improvements in other UX metrics, e.g., an 85% decrease in the number +of low-memory kills at the 75th percentile and an 18% decrease in +app launch time at the 50th percentile. + +The downstream kernels that have been using MGLRU include: +1. Android [16] +2. Arch Linux Zen [17] +3. Armbian [18] +4. ChromeOS [19] +5. Liquorix [20] +6. OpenWrt [21] +7. post-factum [22] +8. XanMod [23] + +[11] https://lore.kernel.org/r/140226722f2032c86301fbd326d91baefe3d7d23.camel@yandex.ru/ +[12] https://lore.kernel.org/r/87czj3mux0.fsf@vajain21.in.ibm.com/ +[13] https://lore.kernel.org/r/20220105024423.26409-1-szhai2@cs.rochester.edu/ +[14] https://lore.kernel.org/r/CA+4-3vksGvKd18FgRinxhqHetBS1hQekJE2gwco8Ja-bJWKtFw@mail.gmail.com/ +[15] https://dl.acm.org/doi/10.1145/2749469.2750392 +[16] https://android.com +[17] https://archlinux.org +[18] https://armbian.com +[19] https://chromium.org +[20] https://liquorix.net +[21] https://openwrt.org +[22] https://codeberg.org/pf-kernel +[23] https://xanmod.org + +Summary +======= +The facts are: +1. The independent lab results and the real-world applications + indicate substantial improvements; there are no known regressions. +2. Thrashing prevention, working set estimation and proactive reclaim + work out of the box; there are no equivalent solutions. +3. There is a lot of new code; no smaller changes have been + demonstrated similar effects. + +Our options, accordingly, are: +1. Given the amount of evidence, the reported improvements will likely + materialize for a wide range of workloads. +2. Gauging the interest from the past discussions, the new features + will likely be put to use for both personal computers and data + centers. +3. Based on Google's track record, the new code will likely be well + maintained in the long term. It'd be more difficult if not + impossible to achieve similar effects with other approaches. + +This patch (of 14): + +Some architectures automatically set the accessed bit in PTEs, e.g., x86 +and arm64 v8.2. On architectures that do not have this capability, +clearing the accessed bit in a PTE usually triggers a page fault following +the TLB miss of this PTE (to emulate the accessed bit). + +Being aware of this capability can help make better decisions, e.g., +whether to spread the work out over a period of time to reduce bursty page +faults when trying to clear the accessed bit in many PTEs. + +Note that theoretically this capability can be unreliable, e.g., +hotplugged CPUs might be different from builtin ones. Therefore it should +not be used in architecture-independent code that involves correctness, +e.g., to determine whether TLB flushes are required (in combination with +the accessed bit). + +Link: https://lkml.kernel.org/r/20220918080010.2920238-1-yuzhao@google.com +Link: https://lkml.kernel.org/r/20220918080010.2920238-2-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Acked-by: Will Deacon +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: linux-arm-kernel@lists.infradead.org +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Miaohe Lin +Cc: Mike Rapoport +Cc: Qi Zheng +Signed-off-by: Andrew Morton +--- + arch/arm64/include/asm/pgtable.h | 14 ++------------ + arch/x86/include/asm/pgtable.h | 6 +++--- + include/linux/pgtable.h | 13 +++++++++++++ + mm/memory.c | 14 +------------- + 4 files changed, 19 insertions(+), 28 deletions(-) + +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -999,23 +999,13 @@ static inline void update_mmu_cache(stru + * page after fork() + CoW for pfn mappings. We don't always have a + * hardware-managed access flag on arm64. + */ +-static inline bool arch_faults_on_old_pte(void) +-{ +- WARN_ON(preemptible()); +- +- return !cpu_has_hw_af(); +-} +-#define arch_faults_on_old_pte arch_faults_on_old_pte ++#define arch_has_hw_pte_young cpu_has_hw_af + + /* + * Experimentally, it's cheap to set the access flag in hardware and we + * benefit from prefaulting mappings as 'old' to start with. + */ +-static inline bool arch_wants_old_prefaulted_pte(void) +-{ +- return !arch_faults_on_old_pte(); +-} +-#define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte ++#define arch_wants_old_prefaulted_pte cpu_has_hw_af + + #endif /* !__ASSEMBLY__ */ + +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_c + return boot_cpu_has_bug(X86_BUG_L1TF); + } + +-#define arch_faults_on_old_pte arch_faults_on_old_pte +-static inline bool arch_faults_on_old_pte(void) ++#define arch_has_hw_pte_young arch_has_hw_pte_young ++static inline bool arch_has_hw_pte_young(void) + { +- return false; ++ return true; + } + + #endif /* __ASSEMBLY__ */ +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + #endif + ++#ifndef arch_has_hw_pte_young ++/* ++ * Return whether the accessed bit is supported on the local CPU. ++ * ++ * This stub assumes accessing through an old PTE triggers a page fault. ++ * Architectures that automatically set the access bit should overwrite it. ++ */ ++static inline bool arch_has_hw_pte_young(void) ++{ ++ return false; ++} ++#endif ++ + #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR + static inline pte_t ptep_get_and_clear(struct mm_struct *mm, + unsigned long address, +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -121,18 +121,6 @@ int randomize_va_space __read_mostly = + 2; + #endif + +-#ifndef arch_faults_on_old_pte +-static inline bool arch_faults_on_old_pte(void) +-{ +- /* +- * Those arches which don't have hw access flag feature need to +- * implement their own helper. By default, "true" means pagefault +- * will be hit on old pte. +- */ +- return true; +-} +-#endif +- + #ifndef arch_wants_old_prefaulted_pte + static inline bool arch_wants_old_prefaulted_pte(void) + { +@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct + * On architectures with software "accessed" bits, we would + * take a double page fault, so mark it accessed here. + */ +- if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) { ++ if (!arch_has_hw_pte_young() && !pte_young(vmf->orig_pte)) { + pte_t entry; + + vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); diff --git a/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch b/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch new file mode 100644 index 00000000000..9e0430ea2aa --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch @@ -0,0 +1,153 @@ +From 493de1c4b0f2cd909169401da8c445f6c8a7e29d Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 01:59:59 -0600 +Subject: [PATCH 02/29] mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some architectures support the accessed bit in non-leaf PMD entries, e.g., +x86 sets the accessed bit in a non-leaf PMD entry when using it as part of +linear address translation [1]. Page table walkers that clear the +accessed bit may use this capability to reduce their search space. + +Note that: +1. Although an inline function is preferable, this capability is added + as a configuration option for consistency with the existing macros. +2. Due to the little interest in other varieties, this capability was + only tested on Intel and AMD CPUs. + +Thanks to the following developers for their efforts [2][3]. + Randy Dunlap + Stephen Rothwell + +[1]: Intel 64 and IA-32 Architectures Software Developer's Manual + Volume 3 (June 2021), section 4.8 +[2] https://lore.kernel.org/r/bfdcc7c8-922f-61a9-aa15-7e7250f04af7@infradead.org/ +[3] https://lore.kernel.org/r/20220413151513.5a0d7a7e@canb.auug.org.au/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-3-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + arch/Kconfig | 8 ++++++++ + arch/x86/Kconfig | 1 + + arch/x86/include/asm/pgtable.h | 3 ++- + arch/x86/mm/pgtable.c | 5 ++++- + include/linux/pgtable.h | 4 ++-- + 5 files changed, 17 insertions(+), 4 deletions(-) + +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -1295,6 +1295,14 @@ config ARCH_HAS_ELFCORE_COMPAT + config ARCH_HAS_PARANOID_L1D_FLUSH + bool + ++config ARCH_HAS_NONLEAF_PMD_YOUNG ++ bool ++ help ++ Architectures that select this option are capable of setting the ++ accessed bit in non-leaf PMD entries when using them as part of linear ++ address translations. Page table walkers that clear the accessed bit ++ may use this capability to reduce their search space. ++ + source "kernel/gcov/Kconfig" + + source "scripts/gcc-plugins/Kconfig" +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -84,6 +84,7 @@ config X86 + select ARCH_HAS_PMEM_API if X86_64 + select ARCH_HAS_PTE_DEVMAP if X86_64 + select ARCH_HAS_PTE_SPECIAL ++ select ARCH_HAS_NONLEAF_PMD_YOUNG if PGTABLE_LEVELS > 2 + select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 + select ARCH_HAS_COPY_MC if X86_64 + select ARCH_HAS_SET_MEMORY +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vad + + static inline int pmd_bad(pmd_t pmd) + { +- return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE; ++ return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) != ++ (_KERNPG_TABLE & ~_PAGE_ACCESSED); + } + + static inline unsigned long pages_to_mb(unsigned long npg) +--- a/arch/x86/mm/pgtable.c ++++ b/arch/x86/mm/pgtable.c +@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_ + return ret; + } + +-#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) + int pmdp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long addr, pmd_t *pmdp) + { +@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_ + + return ret; + } ++#endif ++ ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE + int pudp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long addr, pud_t *pudp) + { +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_yo + #endif + + #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG +-#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) + static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pmd_t *pmdp) +@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_yo + BUILD_BUG(); + return 0; + } +-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ ++#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ + #endif + + #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH diff --git a/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch b/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch new file mode 100644 index 00000000000..b8d2917d26c --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch @@ -0,0 +1,275 @@ +From 9e17efd11450d3d2069adaa3c58db9ac8ebd1c66 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:00 -0600 +Subject: [PATCH 03/29] mm/vmscan.c: refactor shrink_node() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch refactors shrink_node() to improve readability for the upcoming +changes to mm/vmscan.c. + +Link: https://lkml.kernel.org/r/20220918080010.2920238-4-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Barry Song +Reviewed-by: Miaohe Lin +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 198 +++++++++++++++++++++++++++------------------------- + 1 file changed, 104 insertions(+), 94 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2497,6 +2497,109 @@ enum scan_balance { + SCAN_FILE, + }; + ++static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) ++{ ++ unsigned long file; ++ struct lruvec *target_lruvec; ++ ++ target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); ++ ++ /* ++ * Flush the memory cgroup stats, so that we read accurate per-memcg ++ * lruvec stats for heuristics. ++ */ ++ mem_cgroup_flush_stats(); ++ ++ /* ++ * Determine the scan balance between anon and file LRUs. ++ */ ++ spin_lock_irq(&target_lruvec->lru_lock); ++ sc->anon_cost = target_lruvec->anon_cost; ++ sc->file_cost = target_lruvec->file_cost; ++ spin_unlock_irq(&target_lruvec->lru_lock); ++ ++ /* ++ * Target desirable inactive:active list ratios for the anon ++ * and file LRU lists. ++ */ ++ if (!sc->force_deactivate) { ++ unsigned long refaults; ++ ++ refaults = lruvec_page_state(target_lruvec, ++ WORKINGSET_ACTIVATE_ANON); ++ if (refaults != target_lruvec->refaults[0] || ++ inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) ++ sc->may_deactivate |= DEACTIVATE_ANON; ++ else ++ sc->may_deactivate &= ~DEACTIVATE_ANON; ++ ++ /* ++ * When refaults are being observed, it means a new ++ * workingset is being established. Deactivate to get ++ * rid of any stale active pages quickly. ++ */ ++ refaults = lruvec_page_state(target_lruvec, ++ WORKINGSET_ACTIVATE_FILE); ++ if (refaults != target_lruvec->refaults[1] || ++ inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) ++ sc->may_deactivate |= DEACTIVATE_FILE; ++ else ++ sc->may_deactivate &= ~DEACTIVATE_FILE; ++ } else ++ sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; ++ ++ /* ++ * If we have plenty of inactive file pages that aren't ++ * thrashing, try to reclaim those first before touching ++ * anonymous pages. ++ */ ++ file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); ++ if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) ++ sc->cache_trim_mode = 1; ++ else ++ sc->cache_trim_mode = 0; ++ ++ /* ++ * Prevent the reclaimer from falling into the cache trap: as ++ * cache pages start out inactive, every cache fault will tip ++ * the scan balance towards the file LRU. And as the file LRU ++ * shrinks, so does the window for rotation from references. ++ * This means we have a runaway feedback loop where a tiny ++ * thrashing file LRU becomes infinitely more attractive than ++ * anon pages. Try to detect this based on file LRU size. ++ */ ++ if (!cgroup_reclaim(sc)) { ++ unsigned long total_high_wmark = 0; ++ unsigned long free, anon; ++ int z; ++ ++ free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); ++ file = node_page_state(pgdat, NR_ACTIVE_FILE) + ++ node_page_state(pgdat, NR_INACTIVE_FILE); ++ ++ for (z = 0; z < MAX_NR_ZONES; z++) { ++ struct zone *zone = &pgdat->node_zones[z]; ++ ++ if (!managed_zone(zone)) ++ continue; ++ ++ total_high_wmark += high_wmark_pages(zone); ++ } ++ ++ /* ++ * Consider anon: if that's low too, this isn't a ++ * runaway file reclaim problem, but rather just ++ * extreme pressure. Reclaim as per usual then. ++ */ ++ anon = node_page_state(pgdat, NR_INACTIVE_ANON); ++ ++ sc->file_is_tiny = ++ file + free <= total_high_wmark && ++ !(sc->may_deactivate & DEACTIVATE_ANON) && ++ anon >> sc->priority; ++ } ++} ++ + /* + * Determine how aggressively the anon and file LRU lists should be + * scanned. The relative value of each set of LRU lists is determined +@@ -2965,109 +3068,16 @@ static void shrink_node(pg_data_t *pgdat + unsigned long nr_reclaimed, nr_scanned; + struct lruvec *target_lruvec; + bool reclaimable = false; +- unsigned long file; + + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + again: +- /* +- * Flush the memory cgroup stats, so that we read accurate per-memcg +- * lruvec stats for heuristics. +- */ +- mem_cgroup_flush_stats(); +- + memset(&sc->nr, 0, sizeof(sc->nr)); + + nr_reclaimed = sc->nr_reclaimed; + nr_scanned = sc->nr_scanned; + +- /* +- * Determine the scan balance between anon and file LRUs. +- */ +- spin_lock_irq(&target_lruvec->lru_lock); +- sc->anon_cost = target_lruvec->anon_cost; +- sc->file_cost = target_lruvec->file_cost; +- spin_unlock_irq(&target_lruvec->lru_lock); +- +- /* +- * Target desirable inactive:active list ratios for the anon +- * and file LRU lists. +- */ +- if (!sc->force_deactivate) { +- unsigned long refaults; +- +- refaults = lruvec_page_state(target_lruvec, +- WORKINGSET_ACTIVATE_ANON); +- if (refaults != target_lruvec->refaults[0] || +- inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) +- sc->may_deactivate |= DEACTIVATE_ANON; +- else +- sc->may_deactivate &= ~DEACTIVATE_ANON; +- +- /* +- * When refaults are being observed, it means a new +- * workingset is being established. Deactivate to get +- * rid of any stale active pages quickly. +- */ +- refaults = lruvec_page_state(target_lruvec, +- WORKINGSET_ACTIVATE_FILE); +- if (refaults != target_lruvec->refaults[1] || +- inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) +- sc->may_deactivate |= DEACTIVATE_FILE; +- else +- sc->may_deactivate &= ~DEACTIVATE_FILE; +- } else +- sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; +- +- /* +- * If we have plenty of inactive file pages that aren't +- * thrashing, try to reclaim those first before touching +- * anonymous pages. +- */ +- file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); +- if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) +- sc->cache_trim_mode = 1; +- else +- sc->cache_trim_mode = 0; +- +- /* +- * Prevent the reclaimer from falling into the cache trap: as +- * cache pages start out inactive, every cache fault will tip +- * the scan balance towards the file LRU. And as the file LRU +- * shrinks, so does the window for rotation from references. +- * This means we have a runaway feedback loop where a tiny +- * thrashing file LRU becomes infinitely more attractive than +- * anon pages. Try to detect this based on file LRU size. +- */ +- if (!cgroup_reclaim(sc)) { +- unsigned long total_high_wmark = 0; +- unsigned long free, anon; +- int z; +- +- free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); +- file = node_page_state(pgdat, NR_ACTIVE_FILE) + +- node_page_state(pgdat, NR_INACTIVE_FILE); +- +- for (z = 0; z < MAX_NR_ZONES; z++) { +- struct zone *zone = &pgdat->node_zones[z]; +- if (!managed_zone(zone)) +- continue; +- +- total_high_wmark += high_wmark_pages(zone); +- } +- +- /* +- * Consider anon: if that's low too, this isn't a +- * runaway file reclaim problem, but rather just +- * extreme pressure. Reclaim as per usual then. +- */ +- anon = node_page_state(pgdat, NR_INACTIVE_ANON); +- +- sc->file_is_tiny = +- file + free <= total_high_wmark && +- !(sc->may_deactivate & DEACTIVATE_ANON) && +- anon >> sc->priority; +- } ++ prepare_scan_count(pgdat, sc); + + shrink_node_memcgs(pgdat, sc); + diff --git a/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch b/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch new file mode 100644 index 00000000000..2f277a56e1c --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch @@ -0,0 +1,82 @@ +From 03705be42114db7cc5bd6eb7bf7e8703c94d4880 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:01 -0600 +Subject: [PATCH 04/29] Revert "include/linux/mm_inline.h: fold + __update_lru_size() into its sole caller" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch undoes the following refactor: commit 289ccba18af4 +("include/linux/mm_inline.h: fold __update_lru_size() into its sole +caller") + +The upcoming changes to include/linux/mm_inline.h will reuse +__update_lru_size(). + +Link: https://lkml.kernel.org/r/20220918080010.2920238-5-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Miaohe Lin +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -24,7 +24,7 @@ static inline int page_is_file_lru(struc + return !PageSwapBacked(page); + } + +-static __always_inline void update_lru_size(struct lruvec *lruvec, ++static __always_inline void __update_lru_size(struct lruvec *lruvec, + enum lru_list lru, enum zone_type zid, + int nr_pages) + { +@@ -33,6 +33,13 @@ static __always_inline void update_lru_s + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); + __mod_zone_page_state(&pgdat->node_zones[zid], + NR_ZONE_LRU_BASE + lru, nr_pages); ++} ++ ++static __always_inline void update_lru_size(struct lruvec *lruvec, ++ enum lru_list lru, enum zone_type zid, ++ long nr_pages) ++{ ++ __update_lru_size(lruvec, lru, zid, nr_pages); + #ifdef CONFIG_MEMCG + mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages); + #endif diff --git a/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch b/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch new file mode 100644 index 00000000000..237bd84875d --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch @@ -0,0 +1,807 @@ +From a9b328add8422921a0dbbef162730800e16e8cfd Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:02 -0600 +Subject: [PATCH 05/29] mm: multi-gen LRU: groundwork +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Evictable pages are divided into multiple generations for each lruvec. +The youngest generation number is stored in lrugen->max_seq for both +anon and file types as they are aged on an equal footing. The oldest +generation numbers are stored in lrugen->min_seq[] separately for anon +and file types as clean file pages can be evicted regardless of swap +constraints. These three variables are monotonically increasing. + +Generation numbers are truncated into order_base_2(MAX_NR_GENS+1) bits +in order to fit into the gen counter in page->flags. Each truncated +generation number is an index to lrugen->lists[]. The sliding window +technique is used to track at least MIN_NR_GENS and at most +MAX_NR_GENS generations. The gen counter stores a value within [1, +MAX_NR_GENS] while a page is on one of lrugen->lists[]. Otherwise it +stores 0. + +There are two conceptually independent procedures: "the aging", which +produces young generations, and "the eviction", which consumes old +generations. They form a closed-loop system, i.e., "the page reclaim". +Both procedures can be invoked from userspace for the purposes of working +set estimation and proactive reclaim. These techniques are commonly used +to optimize job scheduling (bin packing) in data centers [1][2]. + +To avoid confusion, the terms "hot" and "cold" will be applied to the +multi-gen LRU, as a new convention; the terms "active" and "inactive" will +be applied to the active/inactive LRU, as usual. + +The protection of hot pages and the selection of cold pages are based +on page access channels and patterns. There are two access channels: +one through page tables and the other through file descriptors. The +protection of the former channel is by design stronger because: +1. The uncertainty in determining the access patterns of the former + channel is higher due to the approximation of the accessed bit. +2. The cost of evicting the former channel is higher due to the TLB + flushes required and the likelihood of encountering the dirty bit. +3. The penalty of underprotecting the former channel is higher because + applications usually do not prepare themselves for major page + faults like they do for blocked I/O. E.g., GUI applications + commonly use dedicated I/O threads to avoid blocking rendering + threads. + +There are also two access patterns: one with temporal locality and the +other without. For the reasons listed above, the former channel is +assumed to follow the former pattern unless VM_SEQ_READ or VM_RAND_READ is +present; the latter channel is assumed to follow the latter pattern unless +outlying refaults have been observed [3][4]. + +The next patch will address the "outlying refaults". Three macros, i.e., +LRU_REFS_WIDTH, LRU_REFS_PGOFF and LRU_REFS_MASK, used later are added in +this patch to make the entire patchset less diffy. + +A page is added to the youngest generation on faulting. The aging needs +to check the accessed bit at least twice before handing this page over to +the eviction. The first check takes care of the accessed bit set on the +initial fault; the second check makes sure this page has not been used +since then. This protocol, AKA second chance, requires a minimum of two +generations, hence MIN_NR_GENS. + +[1] https://dl.acm.org/doi/10.1145/3297858.3304053 +[2] https://dl.acm.org/doi/10.1145/3503222.3507731 +[3] https://lwn.net/Articles/495543/ +[4] https://lwn.net/Articles/815342/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-6-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + fs/fuse/dev.c | 3 +- + include/linux/mm.h | 2 + + include/linux/mm_inline.h | 177 +++++++++++++++++++++++++++++- + include/linux/mmzone.h | 100 +++++++++++++++++ + include/linux/page-flags-layout.h | 13 ++- + include/linux/page-flags.h | 4 +- + include/linux/sched.h | 4 + + kernel/bounds.c | 5 + + mm/Kconfig | 8 ++ + mm/huge_memory.c | 3 +- + mm/memcontrol.c | 2 + + mm/memory.c | 25 +++++ + mm/mm_init.c | 6 +- + mm/mmzone.c | 2 + + mm/swap.c | 10 +- + mm/vmscan.c | 75 +++++++++++++ + 16 files changed, 425 insertions(+), 14 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -785,7 +785,8 @@ static int fuse_check_page(struct page * + 1 << PG_active | + 1 << PG_workingset | + 1 << PG_reclaim | +- 1 << PG_waiters))) { ++ 1 << PG_waiters | ++ LRU_GEN_MASK | LRU_REFS_MASK))) { + dump_page(page, "fuse: trying to steal weird page"); + return 1; + } +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct v + #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) + #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) + #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) ++#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) ++#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) + + /* + * Define the bit shifts to access each section. For non-existent +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -26,10 +26,13 @@ static inline int page_is_file_lru(struc + + static __always_inline void __update_lru_size(struct lruvec *lruvec, + enum lru_list lru, enum zone_type zid, +- int nr_pages) ++ long nr_pages) + { + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + ++ lockdep_assert_held(&lruvec->lru_lock); ++ WARN_ON_ONCE(nr_pages != (int)nr_pages); ++ + __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); + __mod_zone_page_state(&pgdat->node_zones[zid], + NR_ZONE_LRU_BASE + lru, nr_pages); +@@ -86,11 +89,177 @@ static __always_inline enum lru_list pag + return lru; + } + ++#ifdef CONFIG_LRU_GEN ++ ++static inline bool lru_gen_enabled(void) ++{ ++ return true; ++} ++ ++static inline bool lru_gen_in_fault(void) ++{ ++ return current->in_lru_fault; ++} ++ ++static inline int lru_gen_from_seq(unsigned long seq) ++{ ++ return seq % MAX_NR_GENS; ++} ++ ++static inline int page_lru_gen(struct page *page) ++{ ++ unsigned long flags = READ_ONCE(page->flags); ++ ++ return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++} ++ ++static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) ++{ ++ unsigned long max_seq = lruvec->lrugen.max_seq; ++ ++ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); ++ ++ /* see the comment on MIN_NR_GENS */ ++ return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); ++} ++ ++static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, ++ int old_gen, int new_gen) ++{ ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(old_gen == -1 && new_gen == -1); ++ ++ if (old_gen >= 0) ++ WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], ++ lrugen->nr_pages[old_gen][type][zone] - delta); ++ if (new_gen >= 0) ++ WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], ++ lrugen->nr_pages[new_gen][type][zone] + delta); ++ ++ /* addition */ ++ if (old_gen < 0) { ++ if (lru_gen_is_active(lruvec, new_gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, delta); ++ return; ++ } ++ ++ /* deletion */ ++ if (new_gen < 0) { ++ if (lru_gen_is_active(lruvec, old_gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, -delta); ++ return; ++ } ++} ++ ++static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ unsigned long seq; ++ unsigned long flags; ++ int gen = page_lru_gen(page); ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE_PAGE(gen != -1, page); ++ ++ if (PageUnevictable(page)) ++ return false; ++ /* ++ * There are three common cases for this page: ++ * 1. If it's hot, e.g., freshly faulted in or previously hot and ++ * migrated, add it to the youngest generation. ++ * 2. If it's cold but can't be evicted immediately, i.e., an anon page ++ * not in swapcache or a dirty page pending writeback, add it to the ++ * second oldest generation. ++ * 3. Everything else (clean, cold) is added to the oldest generation. ++ */ ++ if (PageActive(page)) ++ seq = lrugen->max_seq; ++ else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || ++ (PageReclaim(page) && ++ (PageDirty(page) || PageWriteback(page)))) ++ seq = lrugen->min_seq[type] + 1; ++ else ++ seq = lrugen->min_seq[type]; ++ ++ gen = lru_gen_from_seq(seq); ++ flags = (gen + 1UL) << LRU_GEN_PGOFF; ++ /* see the comment on MIN_NR_GENS about PG_active */ ++ set_mask_bits(&page->flags, LRU_GEN_MASK | BIT(PG_active), flags); ++ ++ lru_gen_update_size(lruvec, page, -1, gen); ++ /* for rotate_reclaimable_page() */ ++ if (reclaiming) ++ list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ else ++ list_add(&page->lru, &lrugen->lists[gen][type][zone]); ++ ++ return true; ++} ++ ++static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ unsigned long flags; ++ int gen = page_lru_gen(page); ++ ++ if (gen < 0) ++ return false; ++ ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ ++ /* for migrate_page_states() */ ++ flags = !reclaiming && lru_gen_is_active(lruvec, gen) ? BIT(PG_active) : 0; ++ flags = set_mask_bits(&page->flags, LRU_GEN_MASK, flags); ++ gen = ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++ ++ lru_gen_update_size(lruvec, page, gen, -1); ++ list_del(&page->lru); ++ ++ return true; ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline bool lru_gen_enabled(void) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_in_fault(void) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ return false; ++} ++ ++static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ return false; ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + static __always_inline void add_page_to_lru_list(struct page *page, + struct lruvec *lruvec) + { + enum lru_list lru = page_lru(page); + ++ if (lru_gen_add_page(lruvec, page, false)) ++ return; ++ + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); + list_add(&page->lru, &lruvec->lists[lru]); + } +@@ -100,6 +269,9 @@ static __always_inline void add_page_to_ + { + enum lru_list lru = page_lru(page); + ++ if (lru_gen_add_page(lruvec, page, true)) ++ return; ++ + update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); + list_add_tail(&page->lru, &lruvec->lists[lru]); + } +@@ -107,6 +279,9 @@ static __always_inline void add_page_to_ + static __always_inline void del_page_from_lru_list(struct page *page, + struct lruvec *lruvec) + { ++ if (lru_gen_del_page(lruvec, page, false)) ++ return; ++ + list_del(&page->lru); + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -294,6 +294,102 @@ enum lruvec_flags { + */ + }; + ++#endif /* !__GENERATING_BOUNDS_H */ ++ ++/* ++ * Evictable pages are divided into multiple generations. The youngest and the ++ * oldest generation numbers, max_seq and min_seq, are monotonically increasing. ++ * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An ++ * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the ++ * corresponding generation. The gen counter in page->flags stores gen+1 while ++ * a page is on one of lrugen->lists[]. Otherwise it stores 0. ++ * ++ * A page is added to the youngest generation on faulting. The aging needs to ++ * check the accessed bit at least twice before handing this page over to the ++ * eviction. The first check takes care of the accessed bit set on the initial ++ * fault; the second check makes sure this page hasn't been used since then. ++ * This process, AKA second chance, requires a minimum of two generations, ++ * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive ++ * LRU, e.g., /proc/vmstat, these two generations are considered active; the ++ * rest of generations, if they exist, are considered inactive. See ++ * lru_gen_is_active(). ++ * ++ * PG_active is always cleared while a page is on one of lrugen->lists[] so that ++ * the aging needs not to worry about it. And it's set again when a page ++ * considered active is isolated for non-reclaiming purposes, e.g., migration. ++ * See lru_gen_add_page() and lru_gen_del_page(). ++ * ++ * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice the ++ * number of categories of the active/inactive LRU when keeping track of ++ * accesses through page tables. This requires order_base_2(MAX_NR_GENS+1) bits ++ * in page->flags. ++ */ ++#define MIN_NR_GENS 2U ++#define MAX_NR_GENS 4U ++ ++#ifndef __GENERATING_BOUNDS_H ++ ++struct lruvec; ++ ++#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) ++#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) ++ ++#ifdef CONFIG_LRU_GEN ++ ++enum { ++ LRU_GEN_ANON, ++ LRU_GEN_FILE, ++}; ++ ++/* ++ * The youngest generation number is stored in max_seq for both anon and file ++ * types as they are aged on an equal footing. The oldest generation numbers are ++ * stored in min_seq[] separately for anon and file types as clean file pages ++ * can be evicted regardless of swap constraints. ++ * ++ * Normally anon and file min_seq are in sync. But if swapping is constrained, ++ * e.g., out of swap space, file min_seq is allowed to advance and leave anon ++ * min_seq behind. ++ * ++ * The number of pages in each generation is eventually consistent and therefore ++ * can be transiently negative. ++ */ ++struct lru_gen_struct { ++ /* the aging increments the youngest generation number */ ++ unsigned long max_seq; ++ /* the eviction increments the oldest generation numbers */ ++ unsigned long min_seq[ANON_AND_FILE]; ++ /* the multi-gen LRU lists, lazily sorted on eviction */ ++ struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* the multi-gen LRU sizes, eventually consistent */ ++ long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++}; ++ ++void lru_gen_init_lruvec(struct lruvec *lruvec); ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_init_memcg(struct mem_cgroup *memcg); ++void lru_gen_exit_memcg(struct mem_cgroup *memcg); ++#endif ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline void lru_gen_init_lruvec(struct lruvec *lruvec) ++{ ++} ++ ++#ifdef CONFIG_MEMCG ++static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) ++{ ++} ++#endif ++ ++#endif /* CONFIG_LRU_GEN */ ++ + struct lruvec { + struct list_head lists[NR_LRU_LISTS]; + /* per lruvec lru_lock for memcg */ +@@ -311,6 +407,10 @@ struct lruvec { + unsigned long refaults[ANON_AND_FILE]; + /* Various lruvec state flags (enum lruvec_flags) */ + unsigned long flags; ++#ifdef CONFIG_LRU_GEN ++ /* evictable pages divided into generations */ ++ struct lru_gen_struct lrugen; ++#endif + #ifdef CONFIG_MEMCG + struct pglist_data *pgdat; + #endif +--- a/include/linux/page-flags-layout.h ++++ b/include/linux/page-flags-layout.h +@@ -55,7 +55,8 @@ + #define SECTIONS_WIDTH 0 + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ ++ <= BITS_PER_LONG - NR_PAGEFLAGS + #define NODES_WIDTH NODES_SHIFT + #elif defined(CONFIG_SPARSEMEM_VMEMMAP) + #error "Vmemmap: No space for nodes field in page flags" +@@ -89,8 +90,8 @@ + #define LAST_CPUPID_SHIFT 0 + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT \ +- <= BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ ++ KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS + #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT + #else + #define LAST_CPUPID_WIDTH 0 +@@ -100,10 +101,12 @@ + #define LAST_CPUPID_NOT_IN_PAGE_FLAGS + #endif + +-#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH \ +- > BITS_PER_LONG - NR_PAGEFLAGS ++#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ ++ KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS + #error "Not enough bits in page flags" + #endif + ++#define LRU_REFS_WIDTH 0 ++ + #endif + #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemall + 1UL << PG_private | 1UL << PG_private_2 | \ + 1UL << PG_writeback | 1UL << PG_reserved | \ + 1UL << PG_slab | 1UL << PG_active | \ +- 1UL << PG_unevictable | __PG_MLOCKED) ++ 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) + + /* + * Flags checked when a page is prepped for return by the page allocator. +@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemall + * alloc-free cycle to prevent from reusing the page. + */ + #define PAGE_FLAGS_CHECK_AT_PREP \ +- (PAGEFLAGS_MASK & ~__PG_HWPOISON) ++ ((PAGEFLAGS_MASK & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) + + #define PAGE_FLAGS_PRIVATE \ + (1UL << PG_private | 1UL << PG_private_2) +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -911,6 +911,10 @@ struct task_struct { + #ifdef CONFIG_MEMCG + unsigned in_user_fault:1; + #endif ++#ifdef CONFIG_LRU_GEN ++ /* whether the LRU algorithm may apply to this access */ ++ unsigned in_lru_fault:1; ++#endif + #ifdef CONFIG_COMPAT_BRK + unsigned brk_randomized:1; + #endif +--- a/kernel/bounds.c ++++ b/kernel/bounds.c +@@ -22,6 +22,11 @@ int main(void) + DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); + #endif + DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); ++#ifdef CONFIG_LRU_GEN ++ DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); ++#else ++ DEFINE(LRU_GEN_WIDTH, 0); ++#endif + /* End of constants */ + + return 0; +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -897,6 +897,14 @@ config IO_MAPPING + config SECRETMEM + def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED + ++config LRU_GEN ++ bool "Multi-Gen LRU" ++ depends on MMU ++ # make sure page->flags has enough spare bits ++ depends on 64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP ++ help ++ A high performance LRU implementation to overcommit memory. ++ + source "mm/damon/Kconfig" + + endmenu +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struc + #ifdef CONFIG_64BIT + (1L << PG_arch_2) | + #endif +- (1L << PG_dirty))); ++ (1L << PG_dirty) | ++ LRU_GEN_MASK | LRU_REFS_MASK)); + + /* ->mapping in first tail page is compound_mapcount */ + VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem + + static void mem_cgroup_free(struct mem_cgroup *memcg) + { ++ lru_gen_exit_memcg(memcg); + memcg_wb_domain_exit(memcg); + __mem_cgroup_free(memcg); + } +@@ -5241,6 +5242,7 @@ static struct mem_cgroup *mem_cgroup_all + memcg->deferred_split_queue.split_queue_len = 0; + #endif + idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); ++ lru_gen_init_memcg(memcg); + return memcg; + fail: + mem_cgroup_id_remove(memcg); +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -4792,6 +4792,27 @@ static inline void mm_account_fault(stru + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); + } + ++#ifdef CONFIG_LRU_GEN ++static void lru_gen_enter_fault(struct vm_area_struct *vma) ++{ ++ /* the LRU algorithm doesn't apply to sequential or random reads */ ++ current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); ++} ++ ++static void lru_gen_exit_fault(void) ++{ ++ current->in_lru_fault = false; ++} ++#else ++static void lru_gen_enter_fault(struct vm_area_struct *vma) ++{ ++} ++ ++static void lru_gen_exit_fault(void) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + /* + * By the time we get here, we already hold the mm semaphore + * +@@ -4823,11 +4844,15 @@ vm_fault_t handle_mm_fault(struct vm_are + if (flags & FAULT_FLAG_USER) + mem_cgroup_enter_user_fault(); + ++ lru_gen_enter_fault(vma); ++ + if (unlikely(is_vm_hugetlb_page(vma))) + ret = hugetlb_fault(vma->vm_mm, vma, address, flags); + else + ret = __handle_mm_fault(vma, address, flags); + ++ lru_gen_exit_fault(); ++ + if (flags & FAULT_FLAG_USER) { + mem_cgroup_exit_user_fault(); + /* +--- a/mm/mm_init.c ++++ b/mm/mm_init.c +@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layo + + shift = 8 * sizeof(unsigned long); + width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH +- - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; ++ - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", +- "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", ++ "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", + SECTIONS_WIDTH, + NODES_WIDTH, + ZONES_WIDTH, + LAST_CPUPID_WIDTH, + KASAN_TAG_WIDTH, ++ LRU_GEN_WIDTH, ++ LRU_REFS_WIDTH, + NR_PAGEFLAGS); + mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", + "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", +--- a/mm/mmzone.c ++++ b/mm/mmzone.c +@@ -81,6 +81,8 @@ void lruvec_init(struct lruvec *lruvec) + + for_each_lru(lru) + INIT_LIST_HEAD(&lruvec->lists[lru]); ++ ++ lru_gen_init_lruvec(lruvec); + } + + #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -446,6 +446,11 @@ void lru_cache_add(struct page *page) + VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); + VM_BUG_ON_PAGE(PageLRU(page), page); + ++ /* see the comment in lru_gen_add_page() */ ++ if (lru_gen_enabled() && !PageUnevictable(page) && ++ lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) ++ SetPageActive(page); ++ + get_page(page); + local_lock(&lru_pvecs.lock); + pvec = this_cpu_ptr(&lru_pvecs.lru_add); +@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struc + + static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec) + { +- if (PageActive(page) && !PageUnevictable(page)) { ++ if (!PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { + int nr_pages = thp_nr_pages(page); + + del_page_from_lru_list(page, lruvec); +@@ -661,7 +666,8 @@ void deactivate_file_page(struct page *p + */ + void deactivate_page(struct page *page) + { +- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { ++ if (PageLRU(page) && !PageUnevictable(page) && ++ (PageActive(page) || lru_gen_enabled())) { + struct pagevec *pvec; + + local_lock(&lru_pvecs.lock); +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2821,6 +2821,81 @@ static bool can_age_anon_pages(struct pg + return can_demote(pgdat->node_id, sc); + } + ++#ifdef CONFIG_LRU_GEN ++ ++/****************************************************************************** ++ * shorthand helpers ++ ******************************************************************************/ ++ ++#define for_each_gen_type_zone(gen, type, zone) \ ++ for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ ++ for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ ++ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) ++ ++static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) ++{ ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) { ++ struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; ++ ++ /* for hotadd_new_pgdat() */ ++ if (!lruvec->pgdat) ++ lruvec->pgdat = pgdat; ++ ++ return lruvec; ++ } ++#endif ++ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); ++ ++ return pgdat ? &pgdat->__lruvec : NULL; ++} ++ ++/****************************************************************************** ++ * initialization ++ ******************************************************************************/ ++ ++void lru_gen_init_lruvec(struct lruvec *lruvec) ++{ ++ int gen, type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ lrugen->max_seq = MIN_NR_GENS + 1; ++ ++ for_each_gen_type_zone(gen, type, zone) ++ INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++} ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_init_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++void lru_gen_exit_memcg(struct mem_cgroup *memcg) ++{ ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, ++ sizeof(lruvec->lrugen.nr_pages))); ++ } ++} ++#endif ++ ++static int __init init_lru_gen(void) ++{ ++ BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); ++ BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); ++ ++ return 0; ++}; ++late_initcall(init_lru_gen); ++ ++#endif /* CONFIG_LRU_GEN */ ++ + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + unsigned long nr[NR_LRU_LISTS]; diff --git a/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch b/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch new file mode 100644 index 00000000000..f8a7d9bd7f6 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch @@ -0,0 +1,1447 @@ +From b564b9471cd60ef1ee3961a224898ce4a9620d84 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:03 -0600 +Subject: [PATCH 06/29] mm: multi-gen LRU: minimal implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To avoid confusion, the terms "promotion" and "demotion" will be applied +to the multi-gen LRU, as a new convention; the terms "activation" and +"deactivation" will be applied to the active/inactive LRU, as usual. + +The aging produces young generations. Given an lruvec, it increments +max_seq when max_seq-min_seq+1 approaches MIN_NR_GENS. The aging promotes +hot pages to the youngest generation when it finds them accessed through +page tables; the demotion of cold pages happens consequently when it +increments max_seq. Promotion in the aging path does not involve any LRU +list operations, only the updates of the gen counter and +lrugen->nr_pages[]; demotion, unless as the result of the increment of +max_seq, requires LRU list operations, e.g., lru_deactivate_fn(). The +aging has the complexity O(nr_hot_pages), since it is only interested in +hot pages. + +The eviction consumes old generations. Given an lruvec, it increments +min_seq when lrugen->lists[] indexed by min_seq%MAX_NR_GENS becomes empty. +A feedback loop modeled after the PID controller monitors refaults over +anon and file types and decides which type to evict when both types are +available from the same generation. + +The protection of pages accessed multiple times through file descriptors +takes place in the eviction path. Each generation is divided into +multiple tiers. A page accessed N times through file descriptors is in +tier order_base_2(N). Tiers do not have dedicated lrugen->lists[], only +bits in page->flags. The aforementioned feedback loop also monitors +refaults over all tiers and decides when to protect pages in which tiers +(N>1), using the first tier (N=0,1) as a baseline. The first tier +contains single-use unmapped clean pages, which are most likely the best +choices. In contrast to promotion in the aging path, the protection of a +page in the eviction path is achieved by moving this page to the next +generation, i.e., min_seq+1, if the feedback loop decides so. This +approach has the following advantages: + +1. It removes the cost of activation in the buffered access path by + inferring whether pages accessed multiple times through file + descriptors are statistically hot and thus worth protecting in the + eviction path. +2. It takes pages accessed through page tables into account and avoids + overprotecting pages accessed multiple times through file + descriptors. (Pages accessed through page tables are in the first + tier, since N=0.) +3. More tiers provide better protection for pages accessed more than + twice through file descriptors, when under heavy buffered I/O + workloads. + +Server benchmark results: + Single workload: + fio (buffered I/O): +[30, 32]% + IOPS BW + 5.19-rc1: 2673k 10.2GiB/s + patch1-6: 3491k 13.3GiB/s + + Single workload: + memcached (anon): -[4, 6]% + Ops/sec KB/sec + 5.19-rc1: 1161501.04 45177.25 + patch1-6: 1106168.46 43025.04 + + Configurations: + CPU: two Xeon 6154 + Mem: total 256G + + Node 1 was only used as a ram disk to reduce the variance in the + results. + + patch drivers/block/brd.c < gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM | __GFP_THISNODE; + > page = alloc_pages_node(1, gfp_flags, 0); + EOF + + cat >>/etc/systemd/system.conf <>/etc/memcached.conf </sys/fs/cgroup/user.slice/test/memory.max + echo $$ >/sys/fs/cgroup/user.slice/test/cgroup.procs + fio -name=mglru --numjobs=72 --directory=/mnt --size=1408m \ + --buffered=1 --ioengine=io_uring --iodepth=128 \ + --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ + --rw=randread --random_distribution=random --norandommap \ + --time_based --ramp_time=10m --runtime=5m --group_reporting + + cat memcached.sh + modprobe brd rd_nr=1 rd_size=113246208 + swapoff -a + mkswap /dev/ram0 + swapon /dev/ram0 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=65000000 --key-pattern=P:P -c 1 -t 36 \ + --ratio 1:0 --pipeline 8 -d 2000 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=65000000 --key-pattern=R:R -c 1 -t 36 \ + --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed + +Client benchmark results: + kswapd profiles: + 5.19-rc1 + 40.33% page_vma_mapped_walk (overhead) + 21.80% lzo1x_1_do_compress (real work) + 7.53% do_raw_spin_lock + 3.95% _raw_spin_unlock_irq + 2.52% vma_interval_tree_iter_next + 2.37% page_referenced_one + 2.28% vma_interval_tree_subtree_search + 1.97% anon_vma_interval_tree_iter_first + 1.60% ptep_clear_flush + 1.06% __zram_bvec_write + + patch1-6 + 39.03% lzo1x_1_do_compress (real work) + 18.47% page_vma_mapped_walk (overhead) + 6.74% _raw_spin_unlock_irq + 3.97% do_raw_spin_lock + 2.49% ptep_clear_flush + 2.48% anon_vma_interval_tree_iter_first + 1.92% page_referenced_one + 1.88% __zram_bvec_write + 1.48% memmove + 1.31% vma_interval_tree_iter_next + + Configurations: + CPU: single Snapdragon 7c + Mem: total 4G + + ChromeOS MemoryPressure [1] + +[1] https://chromium.googlesource.com/chromiumos/platform/tast-tests/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-7-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 36 ++ + include/linux/mmzone.h | 41 ++ + include/linux/page-flags-layout.h | 5 +- + kernel/bounds.c | 2 + + mm/Kconfig | 11 + + mm/swap.c | 39 ++ + mm/vmscan.c | 792 +++++++++++++++++++++++++++++- + mm/workingset.c | 110 ++++- + 8 files changed, 1025 insertions(+), 11 deletions(-) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -106,6 +106,33 @@ static inline int lru_gen_from_seq(unsig + return seq % MAX_NR_GENS; + } + ++static inline int lru_hist_from_seq(unsigned long seq) ++{ ++ return seq % NR_HIST_GENS; ++} ++ ++static inline int lru_tier_from_refs(int refs) ++{ ++ VM_WARN_ON_ONCE(refs > BIT(LRU_REFS_WIDTH)); ++ ++ /* see the comment in page_lru_refs() */ ++ return order_base_2(refs + 1); ++} ++ ++static inline int page_lru_refs(struct page *page) ++{ ++ unsigned long flags = READ_ONCE(page->flags); ++ bool workingset = flags & BIT(PG_workingset); ++ ++ /* ++ * Return the number of accesses beyond PG_referenced, i.e., N-1 if the ++ * total number of accesses is N>1, since N=0,1 both map to the first ++ * tier. lru_tier_from_refs() will account for this off-by-one. Also see ++ * the comment on MAX_NR_TIERS. ++ */ ++ return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset; ++} ++ + static inline int page_lru_gen(struct page *page) + { + unsigned long flags = READ_ONCE(page->flags); +@@ -158,6 +185,15 @@ static inline void lru_gen_update_size(s + __update_lru_size(lruvec, lru, zone, -delta); + return; + } ++ ++ /* promotion */ ++ if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { ++ __update_lru_size(lruvec, lru, zone, -delta); ++ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); ++ } ++ ++ /* demotion requires isolation, e.g., lru_deactivate_fn() */ ++ VM_WARN_ON_ONCE(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); + } + + static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -327,6 +327,28 @@ enum lruvec_flags { + #define MIN_NR_GENS 2U + #define MAX_NR_GENS 4U + ++/* ++ * Each generation is divided into multiple tiers. A page accessed N times ++ * through file descriptors is in tier order_base_2(N). A page in the first tier ++ * (N=0,1) is marked by PG_referenced unless it was faulted in through page ++ * tables or read ahead. A page in any other tier (N>1) is marked by ++ * PG_referenced and PG_workingset. This implies a minimum of two tiers is ++ * supported without using additional bits in page->flags. ++ * ++ * In contrast to moving across generations which requires the LRU lock, moving ++ * across tiers only involves atomic operations on page->flags and therefore ++ * has a negligible cost in the buffered access path. In the eviction path, ++ * comparisons of refaulted/(evicted+protected) from the first tier and the ++ * rest infer whether pages accessed multiple times through file descriptors ++ * are statistically hot and thus worth protecting. ++ * ++ * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice the ++ * number of categories of the active/inactive LRU when keeping track of ++ * accesses through file descriptors. This uses MAX_NR_TIERS-2 spare bits in ++ * page->flags. ++ */ ++#define MAX_NR_TIERS 4U ++ + #ifndef __GENERATING_BOUNDS_H + + struct lruvec; +@@ -341,6 +363,16 @@ enum { + LRU_GEN_FILE, + }; + ++#define MIN_LRU_BATCH BITS_PER_LONG ++#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) ++ ++/* whether to keep historical stats from evicted generations */ ++#ifdef CONFIG_LRU_GEN_STATS ++#define NR_HIST_GENS MAX_NR_GENS ++#else ++#define NR_HIST_GENS 1U ++#endif ++ + /* + * The youngest generation number is stored in max_seq for both anon and file + * types as they are aged on an equal footing. The oldest generation numbers are +@@ -363,6 +395,15 @@ struct lru_gen_struct { + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ + long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* the exponential moving average of refaulted */ ++ unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; ++ /* the exponential moving average of evicted+protected */ ++ unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; ++ /* the first tier doesn't need protection, hence the minus one */ ++ unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; ++ /* can be modified without holding the LRU lock */ ++ atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; ++ atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + }; + + void lru_gen_init_lruvec(struct lruvec *lruvec); +--- a/include/linux/page-flags-layout.h ++++ b/include/linux/page-flags-layout.h +@@ -106,7 +106,10 @@ + #error "Not enough bits in page flags" + #endif + +-#define LRU_REFS_WIDTH 0 ++/* see the comment on MAX_NR_TIERS */ ++#define LRU_REFS_WIDTH min(__LRU_REFS_WIDTH, BITS_PER_LONG - NR_PAGEFLAGS - \ ++ ZONES_WIDTH - LRU_GEN_WIDTH - SECTIONS_WIDTH - \ ++ NODES_WIDTH - KASAN_TAG_WIDTH - LAST_CPUPID_WIDTH) + + #endif + #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ +--- a/kernel/bounds.c ++++ b/kernel/bounds.c +@@ -24,8 +24,10 @@ int main(void) + DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); + #ifdef CONFIG_LRU_GEN + DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); ++ DEFINE(__LRU_REFS_WIDTH, MAX_NR_TIERS - 2); + #else + DEFINE(LRU_GEN_WIDTH, 0); ++ DEFINE(__LRU_REFS_WIDTH, 0); + #endif + /* End of constants */ + +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -897,6 +897,7 @@ config IO_MAPPING + config SECRETMEM + def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED + ++# multi-gen LRU { + config LRU_GEN + bool "Multi-Gen LRU" + depends on MMU +@@ -905,6 +906,16 @@ config LRU_GEN + help + A high performance LRU implementation to overcommit memory. + ++config LRU_GEN_STATS ++ bool "Full stats for debugging" ++ depends on LRU_GEN ++ help ++ Do not enable this option unless you plan to look at historical stats ++ from evicted generations for debugging purpose. ++ ++ This option has a per-memcg and per-node memory overhead. ++# } ++ + source "mm/damon/Kconfig" + + endmenu +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -389,6 +389,40 @@ static void __lru_cache_activate_page(st + local_unlock(&lru_pvecs.lock); + } + ++#ifdef CONFIG_LRU_GEN ++static void page_inc_refs(struct page *page) ++{ ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ if (PageUnevictable(page)) ++ return; ++ ++ if (!PageReferenced(page)) { ++ SetPageReferenced(page); ++ return; ++ } ++ ++ if (!PageWorkingset(page)) { ++ SetPageWorkingset(page); ++ return; ++ } ++ ++ /* see the comment on MAX_NR_TIERS */ ++ do { ++ new_flags = old_flags & LRU_REFS_MASK; ++ if (new_flags == LRU_REFS_MASK) ++ break; ++ ++ new_flags += BIT(LRU_REFS_PGOFF); ++ new_flags |= old_flags & ~LRU_REFS_MASK; ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++} ++#else ++static void page_inc_refs(struct page *page) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + /* + * Mark a page as having seen activity. + * +@@ -403,6 +437,11 @@ void mark_page_accessed(struct page *pag + { + page = compound_head(page); + ++ if (lru_gen_enabled()) { ++ page_inc_refs(page); ++ return; ++ } ++ + if (!PageReferenced(page)) { + SetPageReferenced(page); + } else if (PageUnevictable(page)) { +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1142,9 +1142,11 @@ static int __remove_mapping(struct addre + + if (PageSwapCache(page)) { + swp_entry_t swap = { .val = page_private(page) }; +- mem_cgroup_swapout(page, swap); ++ ++ /* get a shadow entry before mem_cgroup_swapout() clears page_memcg() */ + if (reclaimed && !mapping_exiting(mapping)) + shadow = workingset_eviction(page, target_memcg); ++ mem_cgroup_swapout(page, swap); + __delete_from_swap_cache(page, swap, shadow); + xa_unlock_irq(&mapping->i_pages); + put_swap_page(page, swap); +@@ -2502,6 +2504,9 @@ static void prepare_scan_count(pg_data_t + unsigned long file; + struct lruvec *target_lruvec; + ++ if (lru_gen_enabled()) ++ return; ++ + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + /* +@@ -2827,6 +2832,17 @@ static bool can_age_anon_pages(struct pg + * shorthand helpers + ******************************************************************************/ + ++#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) ++ ++#define DEFINE_MAX_SEQ(lruvec) \ ++ unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) ++ ++#define DEFINE_MIN_SEQ(lruvec) \ ++ unsigned long min_seq[ANON_AND_FILE] = { \ ++ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ ++ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ ++ } ++ + #define for_each_gen_type_zone(gen, type, zone) \ + for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ +@@ -2852,6 +2868,745 @@ static struct lruvec __maybe_unused *get + return pgdat ? &pgdat->__lruvec : NULL; + } + ++static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ if (!can_demote(pgdat->node_id, sc) && ++ mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) ++ return 0; ++ ++ return mem_cgroup_swappiness(memcg); ++} ++ ++static int get_nr_gens(struct lruvec *lruvec, int type) ++{ ++ return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; ++} ++ ++static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) ++{ ++ /* see the comment on lru_gen_struct */ ++ return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && ++ get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && ++ get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; ++} ++ ++/****************************************************************************** ++ * refault feedback loop ++ ******************************************************************************/ ++ ++/* ++ * A feedback loop based on Proportional-Integral-Derivative (PID) controller. ++ * ++ * The P term is refaulted/(evicted+protected) from a tier in the generation ++ * currently being evicted; the I term is the exponential moving average of the ++ * P term over the generations previously evicted, using the smoothing factor ++ * 1/2; the D term isn't supported. ++ * ++ * The setpoint (SP) is always the first tier of one type; the process variable ++ * (PV) is either any tier of the other type or any other tier of the same ++ * type. ++ * ++ * The error is the difference between the SP and the PV; the correction is to ++ * turn off protection when SP>PV or turn on protection when SPlrugen; ++ int hist = lru_hist_from_seq(lrugen->min_seq[type]); ++ ++ pos->refaulted = lrugen->avg_refaulted[type][tier] + ++ atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ pos->total = lrugen->avg_total[type][tier] + ++ atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ pos->total += lrugen->protected[hist][type][tier - 1]; ++ pos->gain = gain; ++} ++ ++static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) ++{ ++ int hist, tier; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; ++ unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; ++ ++ lockdep_assert_held(&lruvec->lru_lock); ++ ++ if (!carryover && !clear) ++ return; ++ ++ hist = lru_hist_from_seq(seq); ++ ++ for (tier = 0; tier < MAX_NR_TIERS; tier++) { ++ if (carryover) { ++ unsigned long sum; ++ ++ sum = lrugen->avg_refaulted[type][tier] + ++ atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); ++ ++ sum = lrugen->avg_total[type][tier] + ++ atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ sum += lrugen->protected[hist][type][tier - 1]; ++ WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); ++ } ++ ++ if (clear) { ++ atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); ++ atomic_long_set(&lrugen->evicted[hist][type][tier], 0); ++ if (tier) ++ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); ++ } ++ } ++} ++ ++static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) ++{ ++ /* ++ * Return true if the PV has a limited number of refaults or a lower ++ * refaulted/total than the SP. ++ */ ++ return pv->refaulted < MIN_LRU_BATCH || ++ pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= ++ (sp->refaulted + 1) * pv->total * pv->gain; ++} ++ ++/****************************************************************************** ++ * the aging ++ ******************************************************************************/ ++ ++/* protect pages accessed multiple times through file descriptors */ ++static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) ++{ ++ int type = page_is_file_lru(page); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); ++ ++ do { ++ new_gen = (old_gen + 1) % MAX_NR_GENS; ++ ++ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); ++ new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; ++ /* for end_page_writeback() */ ++ if (reclaiming) ++ new_flags |= BIT(PG_reclaim); ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++ ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ ++ return new_gen; ++} ++ ++static void inc_min_seq(struct lruvec *lruvec, int type) ++{ ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ reset_ctrl_pos(lruvec, type, true); ++ WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); ++} ++ ++static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) ++{ ++ int gen, type, zone; ++ bool success = false; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ DEFINE_MIN_SEQ(lruvec); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ ++ /* find the oldest populated generation */ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { ++ gen = lru_gen_from_seq(min_seq[type]); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ if (!list_empty(&lrugen->lists[gen][type][zone])) ++ goto next; ++ } ++ ++ min_seq[type]++; ++ } ++next: ++ ; ++ } ++ ++ /* see the comment on lru_gen_struct */ ++ if (can_swap) { ++ min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); ++ min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); ++ } ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ if (min_seq[type] == lrugen->min_seq[type]) ++ continue; ++ ++ reset_ctrl_pos(lruvec, type, true); ++ WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); ++ success = true; ++ } ++ ++ return success; ++} ++ ++static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) ++{ ++ int prev, next; ++ int type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ ++ if (max_seq != lrugen->max_seq) ++ goto unlock; ++ ++ for (type = ANON_AND_FILE - 1; type >= 0; type--) { ++ if (get_nr_gens(lruvec, type) != MAX_NR_GENS) ++ continue; ++ ++ VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); ++ ++ inc_min_seq(lruvec, type); ++ } ++ ++ /* ++ * Update the active/inactive LRU sizes for compatibility. Both sides of ++ * the current max_seq need to be covered, since max_seq+1 can overlap ++ * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do ++ * overlap, cold/hot inversion happens. ++ */ ++ prev = lru_gen_from_seq(lrugen->max_seq - 1); ++ next = lru_gen_from_seq(lrugen->max_seq + 1); ++ ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ long delta = lrugen->nr_pages[prev][type][zone] - ++ lrugen->nr_pages[next][type][zone]; ++ ++ if (!delta) ++ continue; ++ ++ __update_lru_size(lruvec, lru, zone, delta); ++ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); ++ } ++ } ++ ++ for (type = 0; type < ANON_AND_FILE; type++) ++ reset_ctrl_pos(lruvec, type, false); ++ ++ /* make sure preceding modifications appear */ ++ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); ++unlock: ++ spin_unlock_irq(&lruvec->lru_lock); ++} ++ ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, ++ struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) ++{ ++ int gen, type, zone; ++ unsigned long old = 0; ++ unsigned long young = 0; ++ unsigned long total = 0; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; ++ ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ unsigned long size = 0; ++ ++ gen = lru_gen_from_seq(seq); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ total += size; ++ if (seq == max_seq) ++ young += size; ++ else if (seq + MIN_NR_GENS == max_seq) ++ old += size; ++ } ++ } ++ ++ /* try to scrape all its memory if this memcg was deleted */ ++ *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++ ++ /* ++ * The aging tries to be lazy to reduce the overhead, while the eviction ++ * stalls when the number of generations reaches MIN_NR_GENS. Hence, the ++ * ideal number of generations is MIN_NR_GENS+1. ++ */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) ++ return true; ++ if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) ++ return false; ++ ++ /* ++ * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) ++ * of the total number of pages for each generation. A reasonable range ++ * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The ++ * aging cares about the upper bound of hot pages, while the eviction ++ * cares about the lower bound of cold pages. ++ */ ++ if (young * MIN_NR_GENS > total) ++ return true; ++ if (old * (MIN_NR_GENS + 2) < total) ++ return true; ++ ++ return false; ++} ++ ++static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ bool need_aging; ++ unsigned long nr_to_scan; ++ int swappiness = get_swappiness(lruvec, sc); ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ VM_WARN_ON_ONCE(sc->memcg_low_reclaim); ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ if (mem_cgroup_below_min(memcg)) ++ return; ++ ++ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ if (need_aging) ++ inc_max_seq(lruvec, max_seq, swappiness); ++} ++ ++static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ struct mem_cgroup *memcg; ++ ++ VM_WARN_ON_ONCE(!current_is_kswapd()); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ ++ age_lruvec(lruvec, sc); ++ ++ cond_resched(); ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++} ++ ++/****************************************************************************** ++ * the eviction ++ ******************************************************************************/ ++ ++static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) ++{ ++ bool success; ++ int gen = page_lru_gen(page); ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ int refs = page_lru_refs(page); ++ int tier = lru_tier_from_refs(refs); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); ++ ++ /* unevictable */ ++ if (!page_evictable(page)) { ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ SetPageUnevictable(page); ++ add_page_to_lru_list(page, lruvec); ++ __count_vm_events(UNEVICTABLE_PGCULLED, delta); ++ return true; ++ } ++ ++ /* dirty lazyfree */ ++ if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ SetPageSwapBacked(page); ++ add_page_to_lru_list_tail(page, lruvec); ++ return true; ++ } ++ ++ /* protected */ ++ if (tier > tier_idx) { ++ int hist = lru_hist_from_seq(lrugen->min_seq[type]); ++ ++ gen = page_inc_gen(lruvec, page, false); ++ list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ ++ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], ++ lrugen->protected[hist][type][tier - 1] + delta); ++ __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); ++ return true; ++ } ++ ++ /* waiting for writeback */ ++ if (PageLocked(page) || PageWriteback(page) || ++ (type == LRU_GEN_FILE && PageDirty(page))) { ++ gen = page_inc_gen(lruvec, page, true); ++ list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ return true; ++ } ++ ++ return false; ++} ++ ++static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) ++{ ++ bool success; ++ ++ /* unmapping inhibited */ ++ if (!sc->may_unmap && page_mapped(page)) ++ return false; ++ ++ /* swapping inhibited */ ++ if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && ++ (PageDirty(page) || ++ (PageAnon(page) && !PageSwapCache(page)))) ++ return false; ++ ++ /* raced with release_pages() */ ++ if (!get_page_unless_zero(page)) ++ return false; ++ ++ /* raced with another isolation */ ++ if (!TestClearPageLRU(page)) { ++ put_page(page); ++ return false; ++ } ++ ++ /* see the comment on MAX_NR_TIERS */ ++ if (!PageReferenced(page)) ++ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0); ++ ++ /* for shrink_page_list() */ ++ ClearPageReclaim(page); ++ ClearPageReferenced(page); ++ ++ success = lru_gen_del_page(lruvec, page, true); ++ VM_WARN_ON_ONCE_PAGE(!success, page); ++ ++ return true; ++} ++ ++static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, ++ int type, int tier, struct list_head *list) ++{ ++ int gen, zone; ++ enum vm_event_item item; ++ int sorted = 0; ++ int scanned = 0; ++ int isolated = 0; ++ int remaining = MAX_LRU_BATCH; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ VM_WARN_ON_ONCE(!list_empty(list)); ++ ++ if (get_nr_gens(lruvec, type) == MIN_NR_GENS) ++ return 0; ++ ++ gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ ++ for (zone = sc->reclaim_idx; zone >= 0; zone--) { ++ LIST_HEAD(moved); ++ int skipped = 0; ++ struct list_head *head = &lrugen->lists[gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ struct page *page = lru_to_page(head); ++ int delta = thp_nr_pages(page); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); ++ ++ scanned += delta; ++ ++ if (sort_page(lruvec, page, tier)) ++ sorted += delta; ++ else if (isolate_page(lruvec, page, sc)) { ++ list_add(&page->lru, list); ++ isolated += delta; ++ } else { ++ list_move(&page->lru, &moved); ++ skipped += delta; ++ } ++ ++ if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) ++ break; ++ } ++ ++ if (skipped) { ++ list_splice(&moved, head); ++ __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); ++ } ++ ++ if (!remaining || isolated >= MIN_LRU_BATCH) ++ break; ++ } ++ ++ item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; ++ if (!cgroup_reclaim(sc)) { ++ __count_vm_events(item, isolated); ++ __count_vm_events(PGREFILL, sorted); ++ } ++ __count_memcg_events(memcg, item, isolated); ++ __count_memcg_events(memcg, PGREFILL, sorted); ++ __count_vm_events(PGSCAN_ANON + type, isolated); ++ ++ /* ++ * There might not be eligible pages due to reclaim_idx, may_unmap and ++ * may_writepage. Check the remaining to prevent livelock if it's not ++ * making progress. ++ */ ++ return isolated || !remaining ? scanned : 0; ++} ++ ++static int get_tier_idx(struct lruvec *lruvec, int type) ++{ ++ int tier; ++ struct ctrl_pos sp, pv; ++ ++ /* ++ * To leave a margin for fluctuations, use a larger gain factor (1:2). ++ * This value is chosen because any other tier would have at least twice ++ * as many refaults as the first tier. ++ */ ++ read_ctrl_pos(lruvec, type, 0, 1, &sp); ++ for (tier = 1; tier < MAX_NR_TIERS; tier++) { ++ read_ctrl_pos(lruvec, type, tier, 2, &pv); ++ if (!positive_ctrl_err(&sp, &pv)) ++ break; ++ } ++ ++ return tier - 1; ++} ++ ++static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) ++{ ++ int type, tier; ++ struct ctrl_pos sp, pv; ++ int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; ++ ++ /* ++ * Compare the first tier of anon with that of file to determine which ++ * type to scan. Also need to compare other tiers of the selected type ++ * with the first tier of the other type to determine the last tier (of ++ * the selected type) to evict. ++ */ ++ read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); ++ read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); ++ type = positive_ctrl_err(&sp, &pv); ++ ++ read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); ++ for (tier = 1; tier < MAX_NR_TIERS; tier++) { ++ read_ctrl_pos(lruvec, type, tier, gain[type], &pv); ++ if (!positive_ctrl_err(&sp, &pv)) ++ break; ++ } ++ ++ *tier_idx = tier - 1; ++ ++ return type; ++} ++ ++static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, ++ int *type_scanned, struct list_head *list) ++{ ++ int i; ++ int type; ++ int scanned; ++ int tier = -1; ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* ++ * Try to make the obvious choice first. When anon and file are both ++ * available from the same generation, interpret swappiness 1 as file ++ * first and 200 as anon first. ++ */ ++ if (!swappiness) ++ type = LRU_GEN_FILE; ++ else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) ++ type = LRU_GEN_ANON; ++ else if (swappiness == 1) ++ type = LRU_GEN_FILE; ++ else if (swappiness == 200) ++ type = LRU_GEN_ANON; ++ else ++ type = get_type_to_scan(lruvec, swappiness, &tier); ++ ++ for (i = !swappiness; i < ANON_AND_FILE; i++) { ++ if (tier < 0) ++ tier = get_tier_idx(lruvec, type); ++ ++ scanned = scan_pages(lruvec, sc, type, tier, list); ++ if (scanned) ++ break; ++ ++ type = !type; ++ tier = -1; ++ } ++ ++ *type_scanned = type; ++ ++ return scanned; ++} ++ ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) ++{ ++ int type; ++ int scanned; ++ int reclaimed; ++ LIST_HEAD(list); ++ struct page *page; ++ enum vm_event_item item; ++ struct reclaim_stat stat; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); ++ ++ scanned += try_to_inc_min_seq(lruvec, swappiness); ++ ++ if (get_nr_gens(lruvec, !swappiness) == MIN_NR_GENS) ++ scanned = 0; ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ if (list_empty(&list)) ++ return scanned; ++ ++ reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); ++ ++ list_for_each_entry(page, &list, lru) { ++ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ ++ if (PageWorkingset(page)) ++ SetPageReferenced(page); ++ ++ /* don't add rejected pages to the oldest generation */ ++ if (PageReclaim(page) && ++ (PageDirty(page) || PageWriteback(page))) ++ ClearPageActive(page); ++ else ++ SetPageActive(page); ++ } ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ move_pages_to_lru(lruvec, &list); ++ ++ item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; ++ if (!cgroup_reclaim(sc)) ++ __count_vm_events(item, reclaimed); ++ __count_memcg_events(memcg, item, reclaimed); ++ __count_vm_events(PGSTEAL_ANON + type, reclaimed); ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ mem_cgroup_uncharge_list(&list); ++ free_unref_page_list(&list); ++ ++ sc->nr_reclaimed += reclaimed; ++ ++ return scanned; ++} ++ ++static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, ++ bool can_swap) ++{ ++ bool need_aging; ++ unsigned long nr_to_scan; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (mem_cgroup_below_min(memcg) || ++ (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) ++ return 0; ++ ++ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); ++ if (!need_aging) ++ return nr_to_scan; ++ ++ /* skip the aging path at the default priority */ ++ if (sc->priority == DEF_PRIORITY) ++ goto done; ++ ++ /* leave the work to lru_gen_age_node() */ ++ if (current_is_kswapd()) ++ return 0; ++ ++ inc_max_seq(lruvec, max_seq, can_swap); ++done: ++ return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ unsigned long scanned = 0; ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ while (true) { ++ int delta; ++ int swappiness; ++ unsigned long nr_to_scan; ++ ++ if (sc->may_swap) ++ swappiness = get_swappiness(lruvec, sc); ++ else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) ++ swappiness = 1; ++ else ++ swappiness = 0; ++ ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); ++ if (!nr_to_scan) ++ break; ++ ++ delta = evict_pages(lruvec, sc, swappiness); ++ if (!delta) ++ break; ++ ++ scanned += delta; ++ if (scanned >= nr_to_scan) ++ break; ++ ++ cond_resched(); ++ } ++ ++ blk_finish_plug(&plug); ++} ++ + /****************************************************************************** + * initialization + ******************************************************************************/ +@@ -2894,6 +3649,16 @@ static int __init init_lru_gen(void) + }; + late_initcall(init_lru_gen); + ++#else /* !CONFIG_LRU_GEN */ ++ ++static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++} ++ + #endif /* CONFIG_LRU_GEN */ + + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -2907,6 +3672,11 @@ static void shrink_lruvec(struct lruvec + bool proportional_reclaim; + struct blk_plug plug; + ++ if (lru_gen_enabled()) { ++ lru_gen_shrink_lruvec(lruvec, sc); ++ return; ++ } ++ + get_scan_count(lruvec, sc, nr); + + /* Record the original scan target for proportional adjustments later */ +@@ -3372,6 +4142,9 @@ static void snapshot_refaults(struct mem + struct lruvec *target_lruvec; + unsigned long refaults; + ++ if (lru_gen_enabled()) ++ return; ++ + target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); + refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); + target_lruvec->refaults[0] = refaults; +@@ -3736,12 +4509,16 @@ unsigned long try_to_free_mem_cgroup_pag + } + #endif + +-static void age_active_anon(struct pglist_data *pgdat, +- struct scan_control *sc) ++static void kswapd_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; + struct lruvec *lruvec; + ++ if (lru_gen_enabled()) { ++ lru_gen_age_node(pgdat, sc); ++ return; ++ } ++ + if (!can_age_anon_pages(pgdat, sc)) + return; + +@@ -4058,12 +4835,11 @@ restart: + sc.may_swap = !nr_boost_reclaim; + + /* +- * Do some background aging of the anon list, to give +- * pages a chance to be referenced before reclaiming. All +- * pages are rotated regardless of classzone as this is +- * about consistent aging. ++ * Do some background aging, to give pages a chance to be ++ * referenced before reclaiming. All pages are rotated ++ * regardless of classzone as this is about consistent aging. + */ +- age_active_anon(pgdat, &sc); ++ kswapd_age_node(pgdat, &sc); + + /* + * If we're getting trouble reclaiming, start doing writepage +--- a/mm/workingset.c ++++ b/mm/workingset.c +@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_ + static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, + bool workingset) + { +- eviction >>= bucket_order; + eviction &= EVICTION_MASK; + eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; + eviction = (eviction << NODES_SHIFT) | pgdat->node_id; +@@ -212,10 +211,107 @@ static void unpack_shadow(void *shadow, + + *memcgidp = memcgid; + *pgdat = NODE_DATA(nid); +- *evictionp = entry << bucket_order; ++ *evictionp = entry; + *workingsetp = workingset; + } + ++#ifdef CONFIG_LRU_GEN ++ ++static void *lru_gen_eviction(struct page *page) ++{ ++ int hist; ++ unsigned long token; ++ unsigned long min_seq; ++ struct lruvec *lruvec; ++ struct lru_gen_struct *lrugen; ++ int type = page_is_file_lru(page); ++ int delta = thp_nr_pages(page); ++ int refs = page_lru_refs(page); ++ int tier = lru_tier_from_refs(refs); ++ struct mem_cgroup *memcg = page_memcg(page); ++ struct pglist_data *pgdat = page_pgdat(page); ++ ++ BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); ++ ++ lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ lrugen = &lruvec->lrugen; ++ min_seq = READ_ONCE(lrugen->min_seq[type]); ++ token = (min_seq << LRU_REFS_WIDTH) | max(refs - 1, 0); ++ ++ hist = lru_hist_from_seq(min_seq); ++ atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); ++ ++ return pack_shadow(mem_cgroup_id(memcg), pgdat, token, refs); ++} ++ ++static void lru_gen_refault(struct page *page, void *shadow) ++{ ++ int hist, tier, refs; ++ int memcg_id; ++ bool workingset; ++ unsigned long token; ++ unsigned long min_seq; ++ struct lruvec *lruvec; ++ struct lru_gen_struct *lrugen; ++ struct mem_cgroup *memcg; ++ struct pglist_data *pgdat; ++ int type = page_is_file_lru(page); ++ int delta = thp_nr_pages(page); ++ ++ unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); ++ ++ if (pgdat != page_pgdat(page)) ++ return; ++ ++ rcu_read_lock(); ++ ++ memcg = page_memcg_rcu(page); ++ if (memcg_id != mem_cgroup_id(memcg)) ++ goto unlock; ++ ++ lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ lrugen = &lruvec->lrugen; ++ ++ min_seq = READ_ONCE(lrugen->min_seq[type]); ++ if ((token >> LRU_REFS_WIDTH) != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) ++ goto unlock; ++ ++ hist = lru_hist_from_seq(min_seq); ++ /* see the comment in page_lru_refs() */ ++ refs = (token & (BIT(LRU_REFS_WIDTH) - 1)) + workingset; ++ tier = lru_tier_from_refs(refs); ++ ++ atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); ++ mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); ++ ++ /* ++ * Count the following two cases as stalls: ++ * 1. For pages accessed through page tables, hotter pages pushed out ++ * hot pages which refaulted immediately. ++ * 2. For pages accessed multiple times through file descriptors, ++ * numbers of accesses might have been out of the range. ++ */ ++ if (lru_gen_in_fault() || refs == BIT(LRU_REFS_WIDTH)) { ++ SetPageWorkingset(page); ++ mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); ++ } ++unlock: ++ rcu_read_unlock(); ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static void *lru_gen_eviction(struct page *page) ++{ ++ return NULL; ++} ++ ++static void lru_gen_refault(struct page *page, void *shadow) ++{ ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + /** + * workingset_age_nonresident - age non-resident entries as LRU ages + * @lruvec: the lruvec that was aged +@@ -264,10 +360,14 @@ void *workingset_eviction(struct page *p + VM_BUG_ON_PAGE(page_count(page), page); + VM_BUG_ON_PAGE(!PageLocked(page), page); + ++ if (lru_gen_enabled()) ++ return lru_gen_eviction(page); ++ + lruvec = mem_cgroup_lruvec(target_memcg, pgdat); + /* XXX: target_memcg can be NULL, go through lruvec */ + memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); + eviction = atomic_long_read(&lruvec->nonresident_age); ++ eviction >>= bucket_order; + workingset_age_nonresident(lruvec, thp_nr_pages(page)); + return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); + } +@@ -296,7 +396,13 @@ void workingset_refault(struct page *pag + bool workingset; + int memcgid; + ++ if (lru_gen_enabled()) { ++ lru_gen_refault(page, shadow); ++ return; ++ } ++ + unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); ++ eviction <<= bucket_order; + + rcu_read_lock(); + /* diff --git a/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch b/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch new file mode 100644 index 00000000000..5cd6e03dc60 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch @@ -0,0 +1,491 @@ +From e4277535f6d6708bb19b88c4bad155832671d69b Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:04 -0600 +Subject: [PATCH 07/29] mm: multi-gen LRU: exploit locality in rmap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Searching the rmap for PTEs mapping each page on an LRU list (to test and +clear the accessed bit) can be expensive because pages from different VMAs +(PA space) are not cache friendly to the rmap (VA space). For workloads +mostly using mapped pages, searching the rmap can incur the highest CPU +cost in the reclaim path. + +This patch exploits spatial locality to reduce the trips into the rmap. +When shrink_page_list() walks the rmap and finds a young PTE, a new +function lru_gen_look_around() scans at most BITS_PER_LONG-1 adjacent +PTEs. On finding another young PTE, it clears the accessed bit and +updates the gen counter of the page mapped by this PTE to +(max_seq%MAX_NR_GENS)+1. + +Server benchmark results: + Single workload: + fio (buffered I/O): no change + + Single workload: + memcached (anon): +[3, 5]% + Ops/sec KB/sec + patch1-6: 1106168.46 43025.04 + patch1-7: 1147696.57 44640.29 + + Configurations: + no change + +Client benchmark results: + kswapd profiles: + patch1-6 + 39.03% lzo1x_1_do_compress (real work) + 18.47% page_vma_mapped_walk (overhead) + 6.74% _raw_spin_unlock_irq + 3.97% do_raw_spin_lock + 2.49% ptep_clear_flush + 2.48% anon_vma_interval_tree_iter_first + 1.92% page_referenced_one + 1.88% __zram_bvec_write + 1.48% memmove + 1.31% vma_interval_tree_iter_next + + patch1-7 + 48.16% lzo1x_1_do_compress (real work) + 8.20% page_vma_mapped_walk (overhead) + 7.06% _raw_spin_unlock_irq + 2.92% ptep_clear_flush + 2.53% __zram_bvec_write + 2.11% do_raw_spin_lock + 2.02% memmove + 1.93% lru_gen_look_around + 1.56% free_unref_page_list + 1.40% memset + + Configurations: + no change + +Link: https://lkml.kernel.org/r/20220918080010.2920238-8-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Barry Song +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/memcontrol.h | 31 +++++++ + include/linux/mmzone.h | 6 ++ + mm/internal.h | 1 + + mm/memcontrol.c | 1 + + mm/rmap.c | 7 ++ + mm/swap.c | 4 +- + mm/vmscan.c | 184 +++++++++++++++++++++++++++++++++++++ + 7 files changed, 232 insertions(+), 2 deletions(-) + +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -442,6 +442,7 @@ static inline struct obj_cgroup *__page_ + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + * + * For a kmem page a caller should hold an rcu read lock to protect memcg + * associated with a kmem page from being released. +@@ -497,6 +498,7 @@ static inline struct mem_cgroup *page_me + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + * + * For a kmem page a caller should hold an rcu read lock to protect memcg + * associated with a kmem page from being released. +@@ -953,6 +955,23 @@ void unlock_page_memcg(struct page *page + + void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); + ++/* try to stablize page_memcg() for all the pages in a memcg */ ++static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) ++{ ++ rcu_read_lock(); ++ ++ if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) ++ return true; ++ ++ rcu_read_unlock(); ++ return false; ++} ++ ++static inline void mem_cgroup_unlock_pages(void) ++{ ++ rcu_read_unlock(); ++} ++ + /* idx can be of type enum memcg_stat_item or node_stat_item */ + static inline void mod_memcg_state(struct mem_cgroup *memcg, + int idx, int val) +@@ -1369,6 +1388,18 @@ static inline void unlock_page_memcg(str + { + } + ++static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) ++{ ++ /* to match page_memcg_rcu() */ ++ rcu_read_lock(); ++ return true; ++} ++ ++static inline void mem_cgroup_unlock_pages(void) ++{ ++ rcu_read_unlock(); ++} ++ + static inline void mem_cgroup_handle_over_high(void) + { + } +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -352,6 +352,7 @@ enum lruvec_flags { + #ifndef __GENERATING_BOUNDS_H + + struct lruvec; ++struct page_vma_mapped_walk; + + #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) + #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) +@@ -407,6 +408,7 @@ struct lru_gen_struct { + }; + + void lru_gen_init_lruvec(struct lruvec *lruvec); ++void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + + #ifdef CONFIG_MEMCG + void lru_gen_init_memcg(struct mem_cgroup *memcg); +@@ -419,6 +421,10 @@ static inline void lru_gen_init_lruvec(s + { + } + ++static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) ++{ ++} ++ + #ifdef CONFIG_MEMCG + static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) + { +--- a/mm/internal.h ++++ b/mm/internal.h +@@ -35,6 +35,7 @@ + void page_writeback_init(void); + + vm_fault_t do_swap_page(struct vm_fault *vmf); ++void activate_page(struct page *page); + + void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, + unsigned long floor, unsigned long ceiling); +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -2798,6 +2798,7 @@ static void commit_charge(struct page *p + * - LRU isolation + * - lock_page_memcg() + * - exclusive reference ++ * - mem_cgroup_trylock_pages() + */ + page->memcg_data = (unsigned long)memcg; + } +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -73,6 +73,7 @@ + #include + #include + #include ++#include + + #include + +@@ -793,6 +794,12 @@ static bool page_referenced_one(struct p + } + + if (pvmw.pte) { ++ if (lru_gen_enabled() && pte_young(*pvmw.pte) && ++ !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { ++ lru_gen_look_around(&pvmw); ++ referenced++; ++ } ++ + if (ptep_clear_flush_young_notify(vma, address, + pvmw.pte)) { + /* +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -325,7 +325,7 @@ static bool need_activate_page_drain(int + return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; + } + +-static void activate_page(struct page *page) ++void activate_page(struct page *page) + { + page = compound_head(page); + if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { +@@ -345,7 +345,7 @@ static inline void activate_page_drain(i + { + } + +-static void activate_page(struct page *page) ++void activate_page(struct page *page) + { + struct lruvec *lruvec; + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -1409,6 +1409,11 @@ retry: + if (!sc->may_unmap && page_mapped(page)) + goto keep_locked; + ++ /* page_update_gen() tried to promote this page? */ ++ if (lru_gen_enabled() && !ignore_references && ++ page_mapped(page) && PageReferenced(page)) ++ goto keep_locked; ++ + may_enter_fs = (sc->gfp_mask & __GFP_FS) || + (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); + +@@ -2990,6 +2995,29 @@ static bool positive_ctrl_err(struct ctr + * the aging + ******************************************************************************/ + ++/* promote pages accessed through page tables */ ++static int page_update_gen(struct page *page, int gen) ++{ ++ unsigned long new_flags, old_flags = READ_ONCE(page->flags); ++ ++ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(!rcu_read_lock_held()); ++ ++ do { ++ /* lru_gen_del_page() has isolated this page? */ ++ if (!(old_flags & LRU_GEN_MASK)) { ++ /* for shrink_page_list() */ ++ new_flags = old_flags | BIT(PG_referenced); ++ continue; ++ } ++ ++ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); ++ new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; ++ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); ++ ++ return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++} ++ + /* protect pages accessed multiple times through file descriptors */ + static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) + { +@@ -3001,6 +3029,11 @@ static int page_inc_gen(struct lruvec *l + VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); + + do { ++ new_gen = ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; ++ /* page_update_gen() has promoted this page? */ ++ if (new_gen >= 0 && new_gen != old_gen) ++ return new_gen; ++ + new_gen = (old_gen + 1) % MAX_NR_GENS; + + new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); +@@ -3015,6 +3048,43 @@ static int page_inc_gen(struct lruvec *l + return new_gen; + } + ++static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) ++{ ++ unsigned long pfn = pte_pfn(pte); ++ ++ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); ++ ++ if (!pte_present(pte) || is_zero_pfn(pfn)) ++ return -1; ++ ++ if (WARN_ON_ONCE(pte_devmap(pte) || pte_special(pte))) ++ return -1; ++ ++ if (WARN_ON_ONCE(!pfn_valid(pfn))) ++ return -1; ++ ++ return pfn; ++} ++ ++static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, ++ struct pglist_data *pgdat) ++{ ++ struct page *page; ++ ++ /* try to avoid unnecessary memory loads */ ++ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) ++ return NULL; ++ ++ page = compound_head(pfn_to_page(pfn)); ++ if (page_to_nid(page) != pgdat->node_id) ++ return NULL; ++ ++ if (page_memcg_rcu(page) != memcg) ++ return NULL; ++ ++ return page; ++} ++ + static void inc_min_seq(struct lruvec *lruvec, int type) + { + struct lru_gen_struct *lrugen = &lruvec->lrugen; +@@ -3214,6 +3284,114 @@ static void lru_gen_age_node(struct pgli + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + } + ++/* ++ * This function exploits spatial locality when shrink_page_list() walks the ++ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. ++ */ ++void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) ++{ ++ int i; ++ pte_t *pte; ++ unsigned long start; ++ unsigned long end; ++ unsigned long addr; ++ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; ++ struct page *page = pvmw->page; ++ struct mem_cgroup *memcg = page_memcg(page); ++ struct pglist_data *pgdat = page_pgdat(page); ++ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); ++ DEFINE_MAX_SEQ(lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(max_seq); ++ ++ lockdep_assert_held(pvmw->ptl); ++ VM_WARN_ON_ONCE_PAGE(PageLRU(page), page); ++ ++ if (spin_is_contended(pvmw->ptl)) ++ return; ++ ++ start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); ++ end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; ++ ++ if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { ++ if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ end = start + MIN_LRU_BATCH * PAGE_SIZE; ++ else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ start = end - MIN_LRU_BATCH * PAGE_SIZE; ++ else { ++ start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; ++ end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; ++ } ++ } ++ ++ pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; ++ ++ rcu_read_lock(); ++ arch_enter_lazy_mmu_mode(); ++ ++ for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { ++ unsigned long pfn; ++ ++ pfn = get_pte_pfn(pte[i], pvmw->vma, addr); ++ if (pfn == -1) ++ continue; ++ ++ if (!pte_young(pte[i])) ++ continue; ++ ++ page = get_pfn_page(pfn, memcg, pgdat); ++ if (!page) ++ continue; ++ ++ if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) ++ VM_WARN_ON_ONCE(true); ++ ++ if (pte_dirty(pte[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_lru_gen(page); ++ if (old_gen < 0) ++ SetPageReferenced(page); ++ else if (old_gen != new_gen) ++ __set_bit(i, bitmap); ++ } ++ ++ arch_leave_lazy_mmu_mode(); ++ rcu_read_unlock(); ++ ++ if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { ++ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { ++ page = pte_page(pte[i]); ++ activate_page(page); ++ } ++ return; ++ } ++ ++ /* page_update_gen() requires stable page_memcg() */ ++ if (!mem_cgroup_trylock_pages(memcg)) ++ return; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ ++ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { ++ page = compound_head(pte_page(pte[i])); ++ if (page_memcg_rcu(page) != memcg) ++ continue; ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen < 0 || old_gen == new_gen) ++ continue; ++ ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ } ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ ++ mem_cgroup_unlock_pages(); ++} ++ + /****************************************************************************** + * the eviction + ******************************************************************************/ +@@ -3250,6 +3428,12 @@ static bool sort_page(struct lruvec *lru + return true; + } + ++ /* promoted */ ++ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { ++ list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ return true; ++ } ++ + /* protected */ + if (tier > tier_idx) { + int hist = lru_hist_from_seq(lrugen->min_seq[type]); diff --git a/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch b/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch new file mode 100644 index 00000000000..dad21dccb58 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch @@ -0,0 +1,1687 @@ +From 05223c4e80b34e29f2255c04ffebc2c4475e7593 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:05 -0600 +Subject: [PATCH 08/29] mm: multi-gen LRU: support page table walks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +To further exploit spatial locality, the aging prefers to walk page tables +to search for young PTEs and promote hot pages. A kill switch will be +added in the next patch to disable this behavior. When disabled, the +aging relies on the rmap only. + +NB: this behavior has nothing similar with the page table scanning in the +2.4 kernel [1], which searches page tables for old PTEs, adds cold pages +to swapcache and unmaps them. + +To avoid confusion, the term "iteration" specifically means the traversal +of an entire mm_struct list; the term "walk" will be applied to page +tables and the rmap, as usual. + +An mm_struct list is maintained for each memcg, and an mm_struct follows +its owner task to the new memcg when this task is migrated. Given an +lruvec, the aging iterates lruvec_memcg()->mm_list and calls +walk_page_range() with each mm_struct on this list to promote hot pages +before it increments max_seq. + +When multiple page table walkers iterate the same list, each of them gets +a unique mm_struct; therefore they can run concurrently. Page table +walkers ignore any misplaced pages, e.g., if an mm_struct was migrated, +pages it left in the previous memcg will not be promoted when its current +memcg is under reclaim. Similarly, page table walkers will not promote +pages from nodes other than the one under reclaim. + +This patch uses the following optimizations when walking page tables: +1. It tracks the usage of mm_struct's between context switches so that + page table walkers can skip processes that have been sleeping since + the last iteration. +2. It uses generational Bloom filters to record populated branches so + that page table walkers can reduce their search space based on the + query results, e.g., to skip page tables containing mostly holes or + misplaced pages. +3. It takes advantage of the accessed bit in non-leaf PMD entries when + CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y. +4. It does not zigzag between a PGD table and the same PMD table + spanning multiple VMAs. IOW, it finishes all the VMAs within the + range of the same PMD table before it returns to a PGD table. This + improves the cache performance for workloads that have large + numbers of tiny VMAs [2], especially when CONFIG_PGTABLE_LEVELS=5. + +Server benchmark results: + Single workload: + fio (buffered I/O): no change + + Single workload: + memcached (anon): +[8, 10]% + Ops/sec KB/sec + patch1-7: 1147696.57 44640.29 + patch1-8: 1245274.91 48435.66 + + Configurations: + no change + +Client benchmark results: + kswapd profiles: + patch1-7 + 48.16% lzo1x_1_do_compress (real work) + 8.20% page_vma_mapped_walk (overhead) + 7.06% _raw_spin_unlock_irq + 2.92% ptep_clear_flush + 2.53% __zram_bvec_write + 2.11% do_raw_spin_lock + 2.02% memmove + 1.93% lru_gen_look_around + 1.56% free_unref_page_list + 1.40% memset + + patch1-8 + 49.44% lzo1x_1_do_compress (real work) + 6.19% page_vma_mapped_walk (overhead) + 5.97% _raw_spin_unlock_irq + 3.13% get_pfn_page + 2.85% ptep_clear_flush + 2.42% __zram_bvec_write + 2.08% do_raw_spin_lock + 1.92% memmove + 1.44% alloc_zspage + 1.36% memset + + Configurations: + no change + +Thanks to the following developers for their efforts [3]. + kernel test robot + +[1] https://lwn.net/Articles/23732/ +[2] https://llvm.org/docs/ScudoHardenedAllocator.html +[3] https://lore.kernel.org/r/202204160827.ekEARWQo-lkp@intel.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-9-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + fs/exec.c | 2 + + include/linux/memcontrol.h | 5 + + include/linux/mm_types.h | 76 +++ + include/linux/mmzone.h | 56 +- + include/linux/swap.h | 4 + + kernel/exit.c | 1 + + kernel/fork.c | 9 + + kernel/sched/core.c | 1 + + mm/memcontrol.c | 25 + + mm/vmscan.c | 1010 +++++++++++++++++++++++++++++++++++- + 10 files changed, 1172 insertions(+), 17 deletions(-) + +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *m + active_mm = tsk->active_mm; + tsk->active_mm = mm; + tsk->mm = mm; ++ lru_gen_add_mm(mm); + /* + * This prevents preemption while active_mm is being loaded and + * it and mm are being updated, which could cause problems for +@@ -1028,6 +1029,7 @@ static int exec_mmap(struct mm_struct *m + tsk->mm->vmacache_seqnum = 0; + vmacache_flush(tsk); + task_unlock(tsk); ++ lru_gen_use_mm(mm); + if (old_mm) { + mmap_read_unlock(old_mm); + BUG_ON(active_mm != old_mm); +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -348,6 +348,11 @@ struct mem_cgroup { + struct deferred_split deferred_split_queue; + #endif + ++#ifdef CONFIG_LRU_GEN ++ /* per-memcg mm_struct list */ ++ struct lru_gen_mm_list mm_list; ++#endif ++ + struct mem_cgroup_per_node *nodeinfo[]; + }; + +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -580,6 +580,22 @@ struct mm_struct { + #ifdef CONFIG_IOMMU_SUPPORT + u32 pasid; + #endif ++#ifdef CONFIG_LRU_GEN ++ struct { ++ /* this mm_struct is on lru_gen_mm_list */ ++ struct list_head list; ++ /* ++ * Set when switching to this mm_struct, as a hint of ++ * whether it has been used since the last time per-node ++ * page table walkers cleared the corresponding bits. ++ */ ++ unsigned long bitmap; ++#ifdef CONFIG_MEMCG ++ /* points to the memcg of "owner" above */ ++ struct mem_cgroup *memcg; ++#endif ++ } lru_gen; ++#endif /* CONFIG_LRU_GEN */ + } __randomize_layout; + + /* +@@ -606,6 +622,66 @@ static inline cpumask_t *mm_cpumask(stru + return (struct cpumask *)&mm->cpu_bitmap; + } + ++#ifdef CONFIG_LRU_GEN ++ ++struct lru_gen_mm_list { ++ /* mm_struct list for page table walkers */ ++ struct list_head fifo; ++ /* protects the list above */ ++ spinlock_t lock; ++}; ++ ++void lru_gen_add_mm(struct mm_struct *mm); ++void lru_gen_del_mm(struct mm_struct *mm); ++#ifdef CONFIG_MEMCG ++void lru_gen_migrate_mm(struct mm_struct *mm); ++#endif ++ ++static inline void lru_gen_init_mm(struct mm_struct *mm) ++{ ++ INIT_LIST_HEAD(&mm->lru_gen.list); ++ mm->lru_gen.bitmap = 0; ++#ifdef CONFIG_MEMCG ++ mm->lru_gen.memcg = NULL; ++#endif ++} ++ ++static inline void lru_gen_use_mm(struct mm_struct *mm) ++{ ++ /* ++ * When the bitmap is set, page reclaim knows this mm_struct has been ++ * used since the last time it cleared the bitmap. So it might be worth ++ * walking the page tables of this mm_struct to clear the accessed bit. ++ */ ++ WRITE_ONCE(mm->lru_gen.bitmap, -1); ++} ++ ++#else /* !CONFIG_LRU_GEN */ ++ ++static inline void lru_gen_add_mm(struct mm_struct *mm) ++{ ++} ++ ++static inline void lru_gen_del_mm(struct mm_struct *mm) ++{ ++} ++ ++#ifdef CONFIG_MEMCG ++static inline void lru_gen_migrate_mm(struct mm_struct *mm) ++{ ++} ++#endif ++ ++static inline void lru_gen_init_mm(struct mm_struct *mm) ++{ ++} ++ ++static inline void lru_gen_use_mm(struct mm_struct *mm) ++{ ++} ++ ++#endif /* CONFIG_LRU_GEN */ ++ + struct mmu_gather; + extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); + extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -385,7 +385,7 @@ enum { + * min_seq behind. + * + * The number of pages in each generation is eventually consistent and therefore +- * can be transiently negative. ++ * can be transiently negative when reset_batch_size() is pending. + */ + struct lru_gen_struct { + /* the aging increments the youngest generation number */ +@@ -407,6 +407,53 @@ struct lru_gen_struct { + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + }; + ++enum { ++ MM_LEAF_TOTAL, /* total leaf entries */ ++ MM_LEAF_OLD, /* old leaf entries */ ++ MM_LEAF_YOUNG, /* young leaf entries */ ++ MM_NONLEAF_TOTAL, /* total non-leaf entries */ ++ MM_NONLEAF_FOUND, /* non-leaf entries found in Bloom filters */ ++ MM_NONLEAF_ADDED, /* non-leaf entries added to Bloom filters */ ++ NR_MM_STATS ++}; ++ ++/* double-buffering Bloom filters */ ++#define NR_BLOOM_FILTERS 2 ++ ++struct lru_gen_mm_state { ++ /* set to max_seq after each iteration */ ++ unsigned long seq; ++ /* where the current iteration continues (inclusive) */ ++ struct list_head *head; ++ /* where the last iteration ended (exclusive) */ ++ struct list_head *tail; ++ /* to wait for the last page table walker to finish */ ++ struct wait_queue_head wait; ++ /* Bloom filters flip after each iteration */ ++ unsigned long *filters[NR_BLOOM_FILTERS]; ++ /* the mm stats for debugging */ ++ unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; ++ /* the number of concurrent page table walkers */ ++ int nr_walkers; ++}; ++ ++struct lru_gen_mm_walk { ++ /* the lruvec under reclaim */ ++ struct lruvec *lruvec; ++ /* unstable max_seq from lru_gen_struct */ ++ unsigned long max_seq; ++ /* the next address within an mm to scan */ ++ unsigned long next_addr; ++ /* to batch promoted pages */ ++ int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ /* to batch the mm stats */ ++ int mm_stats[NR_MM_STATS]; ++ /* total batched items */ ++ int batched; ++ bool can_swap; ++ bool force_scan; ++}; ++ + void lru_gen_init_lruvec(struct lruvec *lruvec); + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + +@@ -457,6 +504,8 @@ struct lruvec { + #ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ + struct lru_gen_struct lrugen; ++ /* to concurrently iterate lru_gen_mm_list */ ++ struct lru_gen_mm_state mm_state; + #endif + #ifdef CONFIG_MEMCG + struct pglist_data *pgdat; +@@ -1042,6 +1091,11 @@ typedef struct pglist_data { + + unsigned long flags; + ++#ifdef CONFIG_LRU_GEN ++ /* kswap mm walk data */ ++ struct lru_gen_mm_walk mm_walk; ++#endif ++ + ZONE_PADDING(_pad2_) + + /* Per-node vmstats */ +--- a/include/linux/swap.h ++++ b/include/linux/swap.h +@@ -137,6 +137,10 @@ union swap_header { + */ + struct reclaim_state { + unsigned long reclaimed_slab; ++#ifdef CONFIG_LRU_GEN ++ /* per-thread mm walk data */ ++ struct lru_gen_mm_walk *mm_walk; ++#endif + }; + + #ifdef __KERNEL__ +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -469,6 +469,7 @@ assign_new_owner: + goto retry; + } + WRITE_ONCE(mm->owner, c); ++ lru_gen_migrate_mm(mm); + task_unlock(c); + put_task_struct(c); + } +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct + goto fail_nocontext; + + mm->user_ns = get_user_ns(user_ns); ++ lru_gen_init_mm(mm); + return mm; + + fail_nocontext: +@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_str + } + if (mm->binfmt) + module_put(mm->binfmt->module); ++ lru_gen_del_mm(mm); + mmdrop(mm); + } + +@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_a + get_task_struct(p); + } + ++ if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { ++ /* lock the task to synchronize with memcg migration */ ++ task_lock(p); ++ lru_gen_add_mm(p->mm); ++ task_unlock(p); ++ } ++ + wake_up_new_task(p); + + /* forking complete and child started to run, tell ptracer */ +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -5010,6 +5010,7 @@ context_switch(struct rq *rq, struct tas + * finish_task_switch()'s mmdrop(). + */ + switch_mm_irqs_off(prev->active_mm, next->mm, next); ++ lru_gen_use_mm(next->mm); + + if (!prev->mm) { // from kernel + /* will mmdrop() in finish_task_switch(). */ +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -6212,6 +6212,30 @@ static void mem_cgroup_move_task(void) + } + #endif + ++#ifdef CONFIG_LRU_GEN ++static void mem_cgroup_attach(struct cgroup_taskset *tset) ++{ ++ struct task_struct *task; ++ struct cgroup_subsys_state *css; ++ ++ /* find the first leader if there is any */ ++ cgroup_taskset_for_each_leader(task, css, tset) ++ break; ++ ++ if (!task) ++ return; ++ ++ task_lock(task); ++ if (task->mm && READ_ONCE(task->mm->owner) == task) ++ lru_gen_migrate_mm(task->mm); ++ task_unlock(task); ++} ++#else ++static void mem_cgroup_attach(struct cgroup_taskset *tset) ++{ ++} ++#endif /* CONFIG_LRU_GEN */ ++ + static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value) + { + if (value == PAGE_COUNTER_MAX) +@@ -6555,6 +6579,7 @@ struct cgroup_subsys memory_cgrp_subsys + .css_reset = mem_cgroup_css_reset, + .css_rstat_flush = mem_cgroup_css_rstat_flush, + .can_attach = mem_cgroup_can_attach, ++ .attach = mem_cgroup_attach, + .cancel_attach = mem_cgroup_cancel_attach, + .post_attach = mem_cgroup_move_task, + .dfl_cftypes = memory_files, +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -50,6 +50,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -2853,7 +2855,7 @@ static bool can_age_anon_pages(struct pg + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) + +-static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) ++static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) + { + struct pglist_data *pgdat = NODE_DATA(nid); + +@@ -2899,6 +2901,371 @@ static bool __maybe_unused seq_is_valid( + } + + /****************************************************************************** ++ * mm_struct list ++ ******************************************************************************/ ++ ++static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) ++{ ++ static struct lru_gen_mm_list mm_list = { ++ .fifo = LIST_HEAD_INIT(mm_list.fifo), ++ .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), ++ }; ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) ++ return &memcg->mm_list; ++#endif ++ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); ++ ++ return &mm_list; ++} ++ ++void lru_gen_add_mm(struct mm_struct *mm) ++{ ++ int nid; ++ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ ++ VM_WARN_ON_ONCE(!list_empty(&mm->lru_gen.list)); ++#ifdef CONFIG_MEMCG ++ VM_WARN_ON_ONCE(mm->lru_gen.memcg); ++ mm->lru_gen.memcg = memcg; ++#endif ++ spin_lock(&mm_list->lock); ++ ++ for_each_node_state(nid, N_MEMORY) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ /* the first addition since the last iteration */ ++ if (lruvec->mm_state.tail == &mm_list->fifo) ++ lruvec->mm_state.tail = &mm->lru_gen.list; ++ } ++ ++ list_add_tail(&mm->lru_gen.list, &mm_list->fifo); ++ ++ spin_unlock(&mm_list->lock); ++} ++ ++void lru_gen_del_mm(struct mm_struct *mm) ++{ ++ int nid; ++ struct lru_gen_mm_list *mm_list; ++ struct mem_cgroup *memcg = NULL; ++ ++ if (list_empty(&mm->lru_gen.list)) ++ return; ++ ++#ifdef CONFIG_MEMCG ++ memcg = mm->lru_gen.memcg; ++#endif ++ mm_list = get_mm_list(memcg); ++ ++ spin_lock(&mm_list->lock); ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ /* where the last iteration ended (exclusive) */ ++ if (lruvec->mm_state.tail == &mm->lru_gen.list) ++ lruvec->mm_state.tail = lruvec->mm_state.tail->next; ++ ++ /* where the current iteration continues (inclusive) */ ++ if (lruvec->mm_state.head != &mm->lru_gen.list) ++ continue; ++ ++ lruvec->mm_state.head = lruvec->mm_state.head->next; ++ /* the deletion ends the current iteration */ ++ if (lruvec->mm_state.head == &mm_list->fifo) ++ WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); ++ } ++ ++ list_del_init(&mm->lru_gen.list); ++ ++ spin_unlock(&mm_list->lock); ++ ++#ifdef CONFIG_MEMCG ++ mem_cgroup_put(mm->lru_gen.memcg); ++ mm->lru_gen.memcg = NULL; ++#endif ++} ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_migrate_mm(struct mm_struct *mm) ++{ ++ struct mem_cgroup *memcg; ++ struct task_struct *task = rcu_dereference_protected(mm->owner, true); ++ ++ VM_WARN_ON_ONCE(task->mm != mm); ++ lockdep_assert_held(&task->alloc_lock); ++ ++ /* for mm_update_next_owner() */ ++ if (mem_cgroup_disabled()) ++ return; ++ ++ rcu_read_lock(); ++ memcg = mem_cgroup_from_task(task); ++ rcu_read_unlock(); ++ if (memcg == mm->lru_gen.memcg) ++ return; ++ ++ VM_WARN_ON_ONCE(!mm->lru_gen.memcg); ++ VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); ++ ++ lru_gen_del_mm(mm); ++ lru_gen_add_mm(mm); ++} ++#endif ++ ++/* ++ * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when ++ * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of ++ * bits in a bitmap, k is the number of hash functions and n is the number of ++ * inserted items. ++ * ++ * Page table walkers use one of the two filters to reduce their search space. ++ * To get rid of non-leaf entries that no longer have enough leaf entries, the ++ * aging uses the double-buffering technique to flip to the other filter each ++ * time it produces a new generation. For non-leaf entries that have enough ++ * leaf entries, the aging carries them over to the next generation in ++ * walk_pmd_range(); the eviction also report them when walking the rmap ++ * in lru_gen_look_around(). ++ * ++ * For future optimizations: ++ * 1. It's not necessary to keep both filters all the time. The spare one can be ++ * freed after the RCU grace period and reallocated if needed again. ++ * 2. And when reallocating, it's worth scaling its size according to the number ++ * of inserted entries in the other filter, to reduce the memory overhead on ++ * small systems and false positives on large systems. ++ * 3. Jenkins' hash function is an alternative to Knuth's. ++ */ ++#define BLOOM_FILTER_SHIFT 15 ++ ++static inline int filter_gen_from_seq(unsigned long seq) ++{ ++ return seq % NR_BLOOM_FILTERS; ++} ++ ++static void get_item_key(void *item, int *key) ++{ ++ u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); ++ ++ BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); ++ ++ key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); ++ key[1] = hash >> BLOOM_FILTER_SHIFT; ++} ++ ++static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) ++{ ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = lruvec->mm_state.filters[gen]; ++ if (filter) { ++ bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); ++ return; ++ } ++ ++ filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), ++ __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); ++ WRITE_ONCE(lruvec->mm_state.filters[gen], filter); ++} ++ ++static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return; ++ ++ get_item_key(item, key); ++ ++ if (!test_bit(key[0], filter)) ++ set_bit(key[0], filter); ++ if (!test_bit(key[1], filter)) ++ set_bit(key[1], filter); ++} ++ ++static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return true; ++ ++ get_item_key(item, key); ++ ++ return test_bit(key[0], filter) && test_bit(key[1], filter); ++} ++ ++static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) ++{ ++ int i; ++ int hist; ++ ++ lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); ++ ++ if (walk) { ++ hist = lru_hist_from_seq(walk->max_seq); ++ ++ for (i = 0; i < NR_MM_STATS; i++) { ++ WRITE_ONCE(lruvec->mm_state.stats[hist][i], ++ lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); ++ walk->mm_stats[i] = 0; ++ } ++ } ++ ++ if (NR_HIST_GENS > 1 && last) { ++ hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); ++ ++ for (i = 0; i < NR_MM_STATS; i++) ++ WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); ++ } ++} ++ ++static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) ++{ ++ int type; ++ unsigned long size = 0; ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int key = pgdat->node_id % BITS_PER_TYPE(mm->lru_gen.bitmap); ++ ++ if (!walk->force_scan && !test_bit(key, &mm->lru_gen.bitmap)) ++ return true; ++ ++ clear_bit(key, &mm->lru_gen.bitmap); ++ ++ for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { ++ size += type ? get_mm_counter(mm, MM_FILEPAGES) : ++ get_mm_counter(mm, MM_ANONPAGES) + ++ get_mm_counter(mm, MM_SHMEMPAGES); ++ } ++ ++ if (size < MIN_LRU_BATCH) ++ return true; ++ ++ return !mmget_not_zero(mm); ++} ++ ++static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, ++ struct mm_struct **iter) ++{ ++ bool first = false; ++ bool last = true; ++ struct mm_struct *mm = NULL; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; ++ ++ /* ++ * There are four interesting cases for this page table walker: ++ * 1. It tries to start a new iteration of mm_list with a stale max_seq; ++ * there is nothing left to do. ++ * 2. It's the first of the current generation, and it needs to reset ++ * the Bloom filter for the next generation. ++ * 3. It reaches the end of mm_list, and it needs to increment ++ * mm_state->seq; the iteration is done. ++ * 4. It's the last of the current generation, and it needs to reset the ++ * mm stats counters for the next generation. ++ */ ++ spin_lock(&mm_list->lock); ++ ++ VM_WARN_ON_ONCE(mm_state->seq + 1 < walk->max_seq); ++ VM_WARN_ON_ONCE(*iter && mm_state->seq > walk->max_seq); ++ VM_WARN_ON_ONCE(*iter && !mm_state->nr_walkers); ++ ++ if (walk->max_seq <= mm_state->seq) { ++ if (!*iter) ++ last = false; ++ goto done; ++ } ++ ++ if (!mm_state->nr_walkers) { ++ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ ++ mm_state->head = mm_list->fifo.next; ++ first = true; ++ } ++ ++ while (!mm && mm_state->head != &mm_list->fifo) { ++ mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); ++ ++ mm_state->head = mm_state->head->next; ++ ++ /* force scan for those added after the last iteration */ ++ if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { ++ mm_state->tail = mm_state->head; ++ walk->force_scan = true; ++ } ++ ++ if (should_skip_mm(mm, walk)) ++ mm = NULL; ++ } ++ ++ if (mm_state->head == &mm_list->fifo) ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++done: ++ if (*iter && !mm) ++ mm_state->nr_walkers--; ++ if (!*iter && mm) ++ mm_state->nr_walkers++; ++ ++ if (mm_state->nr_walkers) ++ last = false; ++ ++ if (*iter || last) ++ reset_mm_stats(lruvec, walk, last); ++ ++ spin_unlock(&mm_list->lock); ++ ++ if (mm && first) ++ reset_bloom_filter(lruvec, walk->max_seq + 1); ++ ++ if (*iter) ++ mmput_async(*iter); ++ ++ *iter = mm; ++ ++ return last; ++} ++ ++static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) ++{ ++ bool success = false; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); ++ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; ++ ++ spin_lock(&mm_list->lock); ++ ++ VM_WARN_ON_ONCE(mm_state->seq + 1 < max_seq); ++ ++ if (max_seq > mm_state->seq && !mm_state->nr_walkers) { ++ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ reset_mm_stats(lruvec, NULL, true); ++ success = true; ++ } ++ ++ spin_unlock(&mm_list->lock); ++ ++ return success; ++} ++ ++/****************************************************************************** + * refault feedback loop + ******************************************************************************/ + +@@ -3048,6 +3415,118 @@ static int page_inc_gen(struct lruvec *l + return new_gen; + } + ++static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, ++ int old_gen, int new_gen) ++{ ++ int type = page_is_file_lru(page); ++ int zone = page_zonenum(page); ++ int delta = thp_nr_pages(page); ++ ++ VM_WARN_ON_ONCE(old_gen >= MAX_NR_GENS); ++ VM_WARN_ON_ONCE(new_gen >= MAX_NR_GENS); ++ ++ walk->batched++; ++ ++ walk->nr_pages[old_gen][type][zone] -= delta; ++ walk->nr_pages[new_gen][type][zone] += delta; ++} ++ ++static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) ++{ ++ int gen, type, zone; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ walk->batched = 0; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ enum lru_list lru = type * LRU_INACTIVE_FILE; ++ int delta = walk->nr_pages[gen][type][zone]; ++ ++ if (!delta) ++ continue; ++ ++ walk->nr_pages[gen][type][zone] = 0; ++ WRITE_ONCE(lrugen->nr_pages[gen][type][zone], ++ lrugen->nr_pages[gen][type][zone] + delta); ++ ++ if (lru_gen_is_active(lruvec, gen)) ++ lru += LRU_ACTIVE; ++ __update_lru_size(lruvec, lru, zone, delta); ++ } ++} ++ ++static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *args) ++{ ++ struct address_space *mapping; ++ struct vm_area_struct *vma = args->vma; ++ struct lru_gen_mm_walk *walk = args->private; ++ ++ if (!vma_is_accessible(vma)) ++ return true; ++ ++ if (is_vm_hugetlb_page(vma)) ++ return true; ++ ++ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) ++ return true; ++ ++ if (vma == get_gate_vma(vma->vm_mm)) ++ return true; ++ ++ if (vma_is_anonymous(vma)) ++ return !walk->can_swap; ++ ++ if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) ++ return true; ++ ++ mapping = vma->vm_file->f_mapping; ++ if (mapping_unevictable(mapping)) ++ return true; ++ ++ if (shmem_mapping(mapping)) ++ return !walk->can_swap; ++ ++ /* to exclude special mappings like dax, etc. */ ++ return !mapping->a_ops->readpage; ++} ++ ++/* ++ * Some userspace memory allocators map many single-page VMAs. Instead of ++ * returning back to the PGD table for each of such VMAs, finish an entire PMD ++ * table to reduce zigzags and improve cache performance. ++ */ ++static bool get_next_vma(unsigned long mask, unsigned long size, struct mm_walk *args, ++ unsigned long *vm_start, unsigned long *vm_end) ++{ ++ unsigned long start = round_up(*vm_end, size); ++ unsigned long end = (start | ~mask) + 1; ++ ++ VM_WARN_ON_ONCE(mask & size); ++ VM_WARN_ON_ONCE((start & mask) != (*vm_start & mask)); ++ ++ while (args->vma) { ++ if (start >= args->vma->vm_end) { ++ args->vma = args->vma->vm_next; ++ continue; ++ } ++ ++ if (end && end <= args->vma->vm_start) ++ return false; ++ ++ if (should_skip_vma(args->vma->vm_start, args->vma->vm_end, args)) { ++ args->vma = args->vma->vm_next; ++ continue; ++ } ++ ++ *vm_start = max(start, args->vma->vm_start); ++ *vm_end = min(end - 1, args->vma->vm_end - 1) + 1; ++ ++ return true; ++ } ++ ++ return false; ++} ++ + static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) + { + unsigned long pfn = pte_pfn(pte); +@@ -3066,8 +3545,28 @@ static unsigned long get_pte_pfn(pte_t p + return pfn; + } + ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) ++static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr) ++{ ++ unsigned long pfn = pmd_pfn(pmd); ++ ++ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); ++ ++ if (!pmd_present(pmd) || is_huge_zero_pmd(pmd)) ++ return -1; ++ ++ if (WARN_ON_ONCE(pmd_devmap(pmd))) ++ return -1; ++ ++ if (WARN_ON_ONCE(!pfn_valid(pfn))) ++ return -1; ++ ++ return pfn; ++} ++#endif ++ + static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, +- struct pglist_data *pgdat) ++ struct pglist_data *pgdat, bool can_swap) + { + struct page *page; + +@@ -3082,9 +3581,375 @@ static struct page *get_pfn_page(unsigne + if (page_memcg_rcu(page) != memcg) + return NULL; + ++ /* file VMAs can contain anon pages from COW */ ++ if (!page_is_file_lru(page) && !can_swap) ++ return NULL; ++ + return page; + } + ++static bool suitable_to_scan(int total, int young) ++{ ++ int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); ++ ++ /* suitable if the average number of young PTEs per cacheline is >=1 */ ++ return young * n >= total; ++} ++ ++static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pte_t *pte; ++ spinlock_t *ptl; ++ unsigned long addr; ++ int total = 0; ++ int young = 0; ++ struct lru_gen_mm_walk *walk = args->private; ++ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); ++ ++ VM_WARN_ON_ONCE(pmd_leaf(*pmd)); ++ ++ ptl = pte_lockptr(args->mm, pmd); ++ if (!spin_trylock(ptl)) ++ return false; ++ ++ arch_enter_lazy_mmu_mode(); ++ ++ pte = pte_offset_map(pmd, start & PMD_MASK); ++restart: ++ for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { ++ unsigned long pfn; ++ struct page *page; ++ ++ total++; ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ ++ pfn = get_pte_pfn(pte[i], args->vma, addr); ++ if (pfn == -1) ++ continue; ++ ++ if (!pte_young(pte[i])) { ++ walk->mm_stats[MM_LEAF_OLD]++; ++ continue; ++ } ++ ++ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); ++ if (!page) ++ continue; ++ ++ if (!ptep_test_and_clear_young(args->vma, addr, pte + i)) ++ VM_WARN_ON_ONCE(true); ++ ++ young++; ++ walk->mm_stats[MM_LEAF_YOUNG]++; ++ ++ if (pte_dirty(pte[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen >= 0 && old_gen != new_gen) ++ update_batch_size(walk, page, old_gen, new_gen); ++ } ++ ++ if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end)) ++ goto restart; ++ ++ pte_unmap(pte); ++ ++ arch_leave_lazy_mmu_mode(); ++ spin_unlock(ptl); ++ ++ return suitable_to_scan(total, young); ++} ++ ++#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) ++static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++{ ++ int i; ++ pmd_t *pmd; ++ spinlock_t *ptl; ++ struct lru_gen_mm_walk *walk = args->private; ++ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); ++ ++ VM_WARN_ON_ONCE(pud_leaf(*pud)); ++ ++ /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ ++ if (*start == -1) { ++ *start = next; ++ return; ++ } ++ ++ i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); ++ if (i && i <= MIN_LRU_BATCH) { ++ __set_bit(i - 1, bitmap); ++ return; ++ } ++ ++ pmd = pmd_offset(pud, *start); ++ ++ ptl = pmd_lockptr(args->mm, pmd); ++ if (!spin_trylock(ptl)) ++ goto done; ++ ++ arch_enter_lazy_mmu_mode(); ++ ++ do { ++ unsigned long pfn; ++ struct page *page; ++ unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; ++ ++ pfn = get_pmd_pfn(pmd[i], vma, addr); ++ if (pfn == -1) ++ goto next; ++ ++ if (!pmd_trans_huge(pmd[i])) { ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) ++ pmdp_test_and_clear_young(vma, addr, pmd + i); ++ goto next; ++ } ++ ++ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); ++ if (!page) ++ goto next; ++ ++ if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) ++ goto next; ++ ++ walk->mm_stats[MM_LEAF_YOUNG]++; ++ ++ if (pmd_dirty(pmd[i]) && !PageDirty(page) && ++ !(PageAnon(page) && PageSwapBacked(page) && ++ !PageSwapCache(page))) ++ set_page_dirty(page); ++ ++ old_gen = page_update_gen(page, new_gen); ++ if (old_gen >= 0 && old_gen != new_gen) ++ update_batch_size(walk, page, old_gen, new_gen); ++next: ++ i = i > MIN_LRU_BATCH ? 0 : find_next_bit(bitmap, MIN_LRU_BATCH, i) + 1; ++ } while (i <= MIN_LRU_BATCH); ++ ++ arch_leave_lazy_mmu_mode(); ++ spin_unlock(ptl); ++done: ++ *start = -1; ++ bitmap_zero(bitmap, MIN_LRU_BATCH); ++} ++#else ++static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++{ ++} ++#endif ++ ++static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pmd_t *pmd; ++ unsigned long next; ++ unsigned long addr; ++ struct vm_area_struct *vma; ++ unsigned long pos = -1; ++ struct lru_gen_mm_walk *walk = args->private; ++ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; ++ ++ VM_WARN_ON_ONCE(pud_leaf(*pud)); ++ ++ /* ++ * Finish an entire PMD in two passes: the first only reaches to PTE ++ * tables to avoid taking the PMD lock; the second, if necessary, takes ++ * the PMD lock to clear the accessed bit in PMD entries. ++ */ ++ pmd = pmd_offset(pud, start & PUD_MASK); ++restart: ++ /* walk_pte_range() may call get_next_vma() */ ++ vma = args->vma; ++ for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { ++ pmd_t val = pmd_read_atomic(pmd + i); ++ ++ /* for pmd_read_atomic() */ ++ barrier(); ++ ++ next = pmd_addr_end(addr, end); ++ ++ if (!pmd_present(val) || is_huge_zero_pmd(val)) { ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ continue; ++ } ++ ++#ifdef CONFIG_TRANSPARENT_HUGEPAGE ++ if (pmd_trans_huge(val)) { ++ unsigned long pfn = pmd_pfn(val); ++ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); ++ ++ walk->mm_stats[MM_LEAF_TOTAL]++; ++ ++ if (!pmd_young(val)) { ++ walk->mm_stats[MM_LEAF_OLD]++; ++ continue; ++ } ++ ++ /* try to avoid unnecessary memory loads */ ++ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) ++ continue; ++ ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ continue; ++ } ++#endif ++ walk->mm_stats[MM_NONLEAF_TOTAL]++; ++ ++#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG ++ if (!pmd_young(val)) ++ continue; ++ ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++#endif ++ if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) ++ continue; ++ ++ walk->mm_stats[MM_NONLEAF_FOUND]++; ++ ++ if (!walk_pte_range(&val, addr, next, args)) ++ continue; ++ ++ walk->mm_stats[MM_NONLEAF_ADDED]++; ++ ++ /* carry over to the next generation */ ++ update_bloom_filter(walk->lruvec, walk->max_seq + 1, pmd + i); ++ } ++ ++ walk_pmd_range_locked(pud, -1, vma, args, bitmap, &pos); ++ ++ if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end)) ++ goto restart; ++} ++ ++static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, ++ struct mm_walk *args) ++{ ++ int i; ++ pud_t *pud; ++ unsigned long addr; ++ unsigned long next; ++ struct lru_gen_mm_walk *walk = args->private; ++ ++ VM_WARN_ON_ONCE(p4d_leaf(*p4d)); ++ ++ pud = pud_offset(p4d, start & P4D_MASK); ++restart: ++ for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { ++ pud_t val = READ_ONCE(pud[i]); ++ ++ next = pud_addr_end(addr, end); ++ ++ if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) ++ continue; ++ ++ walk_pmd_range(&val, addr, next, args); ++ ++ /* a racy check to curtail the waiting time */ ++ if (wq_has_sleeper(&walk->lruvec->mm_state.wait)) ++ return 1; ++ ++ if (need_resched() || walk->batched >= MAX_LRU_BATCH) { ++ end = (addr | ~PUD_MASK) + 1; ++ goto done; ++ } ++ } ++ ++ if (i < PTRS_PER_PUD && get_next_vma(P4D_MASK, PUD_SIZE, args, &start, &end)) ++ goto restart; ++ ++ end = round_up(end, P4D_SIZE); ++done: ++ if (!end || !args->vma) ++ return 1; ++ ++ walk->next_addr = max(end, args->vma->vm_start); ++ ++ return -EAGAIN; ++} ++ ++static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) ++{ ++ static const struct mm_walk_ops mm_walk_ops = { ++ .test_walk = should_skip_vma, ++ .p4d_entry = walk_pud_range, ++ }; ++ ++ int err; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ ++ walk->next_addr = FIRST_USER_ADDRESS; ++ ++ do { ++ err = -EBUSY; ++ ++ /* page_update_gen() requires stable page_memcg() */ ++ if (!mem_cgroup_trylock_pages(memcg)) ++ break; ++ ++ /* the caller might be holding the lock for write */ ++ if (mmap_read_trylock(mm)) { ++ err = walk_page_range(mm, walk->next_addr, ULONG_MAX, &mm_walk_ops, walk); ++ ++ mmap_read_unlock(mm); ++ } ++ ++ mem_cgroup_unlock_pages(); ++ ++ if (walk->batched) { ++ spin_lock_irq(&lruvec->lru_lock); ++ reset_batch_size(lruvec, walk); ++ spin_unlock_irq(&lruvec->lru_lock); ++ } ++ ++ cond_resched(); ++ } while (err == -EAGAIN); ++} ++ ++static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) ++{ ++ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; ++ ++ if (pgdat && current_is_kswapd()) { ++ VM_WARN_ON_ONCE(walk); ++ ++ walk = &pgdat->mm_walk; ++ } else if (!pgdat && !walk) { ++ VM_WARN_ON_ONCE(current_is_kswapd()); ++ ++ walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); ++ } ++ ++ current->reclaim_state->mm_walk = walk; ++ ++ return walk; ++} ++ ++static void clear_mm_walk(void) ++{ ++ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; ++ ++ VM_WARN_ON_ONCE(walk && memchr_inv(walk->nr_pages, 0, sizeof(walk->nr_pages))); ++ VM_WARN_ON_ONCE(walk && memchr_inv(walk->mm_stats, 0, sizeof(walk->mm_stats))); ++ ++ current->reclaim_state->mm_walk = NULL; ++ ++ if (!current_is_kswapd()) ++ kfree(walk); ++} ++ + static void inc_min_seq(struct lruvec *lruvec, int type) + { + struct lru_gen_struct *lrugen = &lruvec->lrugen; +@@ -3136,7 +4001,7 @@ next: + return success; + } + +-static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) ++static void inc_max_seq(struct lruvec *lruvec, bool can_swap) + { + int prev, next; + int type, zone; +@@ -3146,9 +4011,6 @@ static void inc_max_seq(struct lruvec *l + + VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); + +- if (max_seq != lrugen->max_seq) +- goto unlock; +- + for (type = ANON_AND_FILE - 1; type >= 0; type--) { + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; +@@ -3186,10 +4048,76 @@ static void inc_max_seq(struct lruvec *l + + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); +-unlock: ++ + spin_unlock_irq(&lruvec->lru_lock); + } + ++static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, ++ struct scan_control *sc, bool can_swap) ++{ ++ bool success; ++ struct lru_gen_mm_walk *walk; ++ struct mm_struct *mm = NULL; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); ++ ++ /* see the comment in iterate_mm_list() */ ++ if (max_seq <= READ_ONCE(lruvec->mm_state.seq)) { ++ success = false; ++ goto done; ++ } ++ ++ /* ++ * If the hardware doesn't automatically set the accessed bit, fallback ++ * to lru_gen_look_around(), which only clears the accessed bit in a ++ * handful of PTEs. Spreading the work out over a period of time usually ++ * is less efficient, but it avoids bursty page faults. ++ */ ++ if (!arch_has_hw_pte_young()) { ++ success = iterate_mm_list_nowalk(lruvec, max_seq); ++ goto done; ++ } ++ ++ walk = set_mm_walk(NULL); ++ if (!walk) { ++ success = iterate_mm_list_nowalk(lruvec, max_seq); ++ goto done; ++ } ++ ++ walk->lruvec = lruvec; ++ walk->max_seq = max_seq; ++ walk->can_swap = can_swap; ++ walk->force_scan = false; ++ ++ do { ++ success = iterate_mm_list(lruvec, walk, &mm); ++ if (mm) ++ walk_mm(lruvec, mm, walk); ++ ++ cond_resched(); ++ } while (mm); ++done: ++ if (!success) { ++ if (sc->priority <= DEF_PRIORITY - 2) ++ wait_event_killable(lruvec->mm_state.wait, ++ max_seq < READ_ONCE(lrugen->max_seq)); ++ ++ return max_seq < READ_ONCE(lrugen->max_seq); ++ } ++ ++ VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); ++ ++ inc_max_seq(lruvec, can_swap); ++ /* either this sees any waiters or they will see updated max_seq */ ++ if (wq_has_sleeper(&lruvec->mm_state.wait)) ++ wake_up_all(&lruvec->mm_state.wait); ++ ++ wakeup_flusher_threads(WB_REASON_VMSCAN); ++ ++ return true; ++} ++ + static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, + struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) + { +@@ -3265,7 +4193,7 @@ static void age_lruvec(struct lruvec *lr + + need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); + if (need_aging) +- inc_max_seq(lruvec, max_seq, swappiness); ++ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); + } + + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) +@@ -3274,6 +4202,8 @@ static void lru_gen_age_node(struct pgli + + VM_WARN_ON_ONCE(!current_is_kswapd()); + ++ set_mm_walk(pgdat); ++ + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); +@@ -3282,11 +4212,16 @@ static void lru_gen_age_node(struct pgli + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++ ++ clear_mm_walk(); + } + + /* + * This function exploits spatial locality when shrink_page_list() walks the +- * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. ++ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. If ++ * the scan was done cacheline efficiently, it adds the PMD entry pointing to ++ * the PTE table to the Bloom filter. This forms a feedback loop between the ++ * eviction and the aging. + */ + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + { +@@ -3295,6 +4230,8 @@ void lru_gen_look_around(struct page_vma + unsigned long start; + unsigned long end; + unsigned long addr; ++ struct lru_gen_mm_walk *walk; ++ int young = 0; + unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + struct page *page = pvmw->page; + struct mem_cgroup *memcg = page_memcg(page); +@@ -3309,6 +4246,9 @@ void lru_gen_look_around(struct page_vma + if (spin_is_contended(pvmw->ptl)) + return; + ++ /* avoid taking the LRU lock under the PTL when possible */ ++ walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; ++ + start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); + end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; + +@@ -3338,13 +4278,15 @@ void lru_gen_look_around(struct page_vma + if (!pte_young(pte[i])) + continue; + +- page = get_pfn_page(pfn, memcg, pgdat); ++ page = get_pfn_page(pfn, memcg, pgdat, !walk || walk->can_swap); + if (!page) + continue; + + if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) + VM_WARN_ON_ONCE(true); + ++ young++; ++ + if (pte_dirty(pte[i]) && !PageDirty(page) && + !(PageAnon(page) && PageSwapBacked(page) && + !PageSwapCache(page))) +@@ -3360,7 +4302,11 @@ void lru_gen_look_around(struct page_vma + arch_leave_lazy_mmu_mode(); + rcu_read_unlock(); + +- if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { ++ /* feedback from rmap walkers to page table walkers */ ++ if (suitable_to_scan(i, young)) ++ update_bloom_filter(lruvec, max_seq, pvmw->pmd); ++ ++ if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = pte_page(pte[i]); + activate_page(page); +@@ -3372,8 +4318,10 @@ void lru_gen_look_around(struct page_vma + if (!mem_cgroup_trylock_pages(memcg)) + return; + +- spin_lock_irq(&lruvec->lru_lock); +- new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ if (!walk) { ++ spin_lock_irq(&lruvec->lru_lock); ++ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); ++ } + + for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { + page = compound_head(pte_page(pte[i])); +@@ -3384,10 +4332,14 @@ void lru_gen_look_around(struct page_vma + if (old_gen < 0 || old_gen == new_gen) + continue; + +- lru_gen_update_size(lruvec, page, old_gen, new_gen); ++ if (walk) ++ update_batch_size(walk, page, old_gen, new_gen); ++ else ++ lru_gen_update_size(lruvec, page, old_gen, new_gen); + } + +- spin_unlock_irq(&lruvec->lru_lock); ++ if (!walk) ++ spin_unlock_irq(&lruvec->lru_lock); + + mem_cgroup_unlock_pages(); + } +@@ -3670,6 +4622,7 @@ static int evict_pages(struct lruvec *lr + struct page *page; + enum vm_event_item item; + struct reclaim_stat stat; ++ struct lru_gen_mm_walk *walk; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + +@@ -3706,6 +4659,10 @@ static int evict_pages(struct lruvec *lr + + move_pages_to_lru(lruvec, &list); + ++ walk = current->reclaim_state->mm_walk; ++ if (walk && walk->batched) ++ reset_batch_size(lruvec, walk); ++ + item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; + if (!cgroup_reclaim(sc)) + __count_vm_events(item, reclaimed); +@@ -3722,6 +4679,11 @@ static int evict_pages(struct lruvec *lr + return scanned; + } + ++/* ++ * For future optimizations: ++ * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg ++ * reclaim. ++ */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, + bool can_swap) + { +@@ -3747,7 +4709,8 @@ static unsigned long get_nr_to_scan(stru + if (current_is_kswapd()) + return 0; + +- inc_max_seq(lruvec, max_seq, can_swap); ++ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) ++ return nr_to_scan; + done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } +@@ -3761,6 +4724,8 @@ static void lru_gen_shrink_lruvec(struct + + blk_start_plug(&plug); + ++ set_mm_walk(lruvec_pgdat(lruvec)); ++ + while (true) { + int delta; + int swappiness; +@@ -3788,6 +4753,8 @@ static void lru_gen_shrink_lruvec(struct + cond_resched(); + } + ++ clear_mm_walk(); ++ + blk_finish_plug(&plug); + } + +@@ -3804,15 +4771,21 @@ void lru_gen_init_lruvec(struct lruvec * + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++ ++ lruvec->mm_state.seq = MIN_NR_GENS; ++ init_waitqueue_head(&lruvec->mm_state.wait); + } + + #ifdef CONFIG_MEMCG + void lru_gen_init_memcg(struct mem_cgroup *memcg) + { ++ INIT_LIST_HEAD(&memcg->mm_list.fifo); ++ spin_lock_init(&memcg->mm_list.lock); + } + + void lru_gen_exit_memcg(struct mem_cgroup *memcg) + { ++ int i; + int nid; + + for_each_node(nid) { +@@ -3820,6 +4793,11 @@ void lru_gen_exit_memcg(struct mem_cgrou + + VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); ++ ++ for (i = 0; i < NR_BLOOM_FILTERS; i++) { ++ bitmap_free(lruvec->mm_state.filters[i]); ++ lruvec->mm_state.filters[i] = NULL; ++ } + } + } + #endif diff --git a/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch b/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch new file mode 100644 index 00000000000..b5fb1951514 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch @@ -0,0 +1,315 @@ +From 36a18a68ea458e8f4db2ca86b00091daf32c6c74 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:06 -0600 +Subject: [PATCH 09/29] mm: multi-gen LRU: optimize multiple memcgs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When multiple memcgs are available, it is possible to use generations as a +frame of reference to make better choices and improve overall performance +under global memory pressure. This patch adds a basic optimization to +select memcgs that can drop single-use unmapped clean pages first. Doing +so reduces the chance of going into the aging path or swapping, which can +be costly. + +A typical example that benefits from this optimization is a server running +mixed types of workloads, e.g., heavy anon workload in one memcg and heavy +buffered I/O workload in the other. + +Though this optimization can be applied to both kswapd and direct reclaim, +it is only added to kswapd to keep the patchset manageable. Later +improvements may cover the direct reclaim path. + +While ensuring certain fairness to all eligible memcgs, proportional scans +of individual memcgs also require proper backoff to avoid overshooting +their aggregate reclaim target by too much. Otherwise it can cause high +direct reclaim latency. The conditions for backoff are: + +1. At low priorities, for direct reclaim, if aging fairness or direct + reclaim latency is at risk, i.e., aging one memcg multiple times or + swapping after the target is met. +2. At high priorities, for global reclaim, if per-zone free pages are + above respective watermarks. + +Server benchmark results: + Mixed workloads: + fio (buffered I/O): +[19, 21]% + IOPS BW + patch1-8: 1880k 7343MiB/s + patch1-9: 2252k 8796MiB/s + + memcached (anon): +[119, 123]% + Ops/sec KB/sec + patch1-8: 862768.65 33514.68 + patch1-9: 1911022.12 74234.54 + + Mixed workloads: + fio (buffered I/O): +[75, 77]% + IOPS BW + 5.19-rc1: 1279k 4996MiB/s + patch1-9: 2252k 8796MiB/s + + memcached (anon): +[13, 15]% + Ops/sec KB/sec + 5.19-rc1: 1673524.04 65008.87 + patch1-9: 1911022.12 74234.54 + + Configurations: + (changes since patch 6) + + cat mixed.sh + modprobe brd rd_nr=2 rd_size=56623104 + + swapoff -a + mkswap /dev/ram0 + swapon /dev/ram0 + + mkfs.ext4 /dev/ram1 + mount -t ext4 /dev/ram1 /mnt + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=50000000 --key-pattern=P:P -c 1 -t 36 \ + --ratio 1:0 --pipeline 8 -d 2000 + + fio -name=mglru --numjobs=36 --directory=/mnt --size=1408m \ + --buffered=1 --ioengine=io_uring --iodepth=128 \ + --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ + --rw=randread --random_distribution=random --norandommap \ + --time_based --ramp_time=10m --runtime=90m --group_reporting & + pid=$! + + sleep 200 + + memtier_benchmark -S /var/run/memcached/memcached.sock \ + -P memcache_binary -n allkeys --key-minimum=1 \ + --key-maximum=50000000 --key-pattern=R:R -c 1 -t 36 \ + --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed + + kill -INT $pid + wait + +Client benchmark results: + no change (CONFIG_MEMCG=n) + +Link: https://lkml.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 96 insertions(+), 9 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -127,6 +127,12 @@ struct scan_control { + /* Always discard instead of demoting to lower tier memory */ + unsigned int no_demotion:1; + ++#ifdef CONFIG_LRU_GEN ++ /* help kswapd make better choices among multiple memcgs */ ++ unsigned int memcgs_need_aging:1; ++ unsigned long last_reclaimed; ++#endif ++ + /* Allocation order */ + s8 order; + +@@ -4202,6 +4208,19 @@ static void lru_gen_age_node(struct pgli + + VM_WARN_ON_ONCE(!current_is_kswapd()); + ++ sc->last_reclaimed = sc->nr_reclaimed; ++ ++ /* ++ * To reduce the chance of going into the aging path, which can be ++ * costly, optimistically skip it if the flag below was cleared in the ++ * eviction path. This improves the overall performance when multiple ++ * memcgs are available. ++ */ ++ if (!sc->memcgs_need_aging) { ++ sc->memcgs_need_aging = true; ++ return; ++ } ++ + set_mm_walk(pgdat); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); +@@ -4613,7 +4632,8 @@ static int isolate_pages(struct lruvec * + return scanned; + } + +-static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, ++ bool *need_swapping) + { + int type; + int scanned; +@@ -4676,6 +4696,9 @@ static int evict_pages(struct lruvec *lr + + sc->nr_reclaimed += reclaimed; + ++ if (need_swapping && type == LRU_GEN_ANON) ++ *need_swapping = true; ++ + return scanned; + } + +@@ -4685,9 +4708,8 @@ static int evict_pages(struct lruvec *lr + * reclaim. + */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap) ++ bool can_swap, bool *need_aging) + { +- bool need_aging; + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +@@ -4697,8 +4719,8 @@ static unsigned long get_nr_to_scan(stru + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + +- need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); +- if (!need_aging) ++ *need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); ++ if (!*need_aging) + return nr_to_scan; + + /* skip the aging path at the default priority */ +@@ -4715,10 +4737,68 @@ done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } + ++static bool should_abort_scan(struct lruvec *lruvec, unsigned long seq, ++ struct scan_control *sc, bool need_swapping) ++{ ++ int i; ++ DEFINE_MAX_SEQ(lruvec); ++ ++ if (!current_is_kswapd()) { ++ /* age each memcg once to ensure fairness */ ++ if (max_seq - seq > 1) ++ return true; ++ ++ /* over-swapping can increase allocation latency */ ++ if (sc->nr_reclaimed >= sc->nr_to_reclaim && need_swapping) ++ return true; ++ ++ /* give this thread a chance to exit and free its memory */ ++ if (fatal_signal_pending(current)) { ++ sc->nr_reclaimed += MIN_LRU_BATCH; ++ return true; ++ } ++ ++ if (cgroup_reclaim(sc)) ++ return false; ++ } else if (sc->nr_reclaimed - sc->last_reclaimed < sc->nr_to_reclaim) ++ return false; ++ ++ /* keep scanning at low priorities to ensure fairness */ ++ if (sc->priority > DEF_PRIORITY - 2) ++ return false; ++ ++ /* ++ * A minimum amount of work was done under global memory pressure. For ++ * kswapd, it may be overshooting. For direct reclaim, the target isn't ++ * met, and yet the allocation may still succeed, since kswapd may have ++ * caught up. In either case, it's better to stop now, and restart if ++ * necessary. ++ */ ++ for (i = 0; i <= sc->reclaim_idx; i++) { ++ unsigned long wmark; ++ struct zone *zone = lruvec_pgdat(lruvec)->node_zones + i; ++ ++ if (!managed_zone(zone)) ++ continue; ++ ++ wmark = current_is_kswapd() ? high_wmark_pages(zone) : low_wmark_pages(zone); ++ if (wmark > zone_page_state(zone, NR_FREE_PAGES)) ++ return false; ++ } ++ ++ sc->nr_reclaimed += MIN_LRU_BATCH; ++ ++ return true; ++} ++ + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; ++ bool need_aging = false; ++ bool need_swapping = false; + unsigned long scanned = 0; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ DEFINE_MAX_SEQ(lruvec); + + lru_add_drain(); + +@@ -4738,21 +4818,28 @@ static void lru_gen_shrink_lruvec(struct + else + swappiness = 0; + +- nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, &need_aging); + if (!nr_to_scan) +- break; ++ goto done; + +- delta = evict_pages(lruvec, sc, swappiness); ++ delta = evict_pages(lruvec, sc, swappiness, &need_swapping); + if (!delta) +- break; ++ goto done; + + scanned += delta; + if (scanned >= nr_to_scan) + break; + ++ if (should_abort_scan(lruvec, max_seq, sc, need_swapping)) ++ break; ++ + cond_resched(); + } + ++ /* see the comment in lru_gen_age_node() */ ++ if (sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH && !need_aging) ++ sc->memcgs_need_aging = false; ++done: + clear_mm_walk(); + + blk_finish_plug(&plug); diff --git a/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch b/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch new file mode 100644 index 00000000000..cf5b8f0e9f7 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch @@ -0,0 +1,498 @@ +From 640db3a029dca909af47157ca18f52b29d34a1b9 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:07 -0600 +Subject: [PATCH 10/29] mm: multi-gen LRU: kill switch +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/mm/lru_gen/enabled as a kill switch. Components that +can be disabled include: + 0x0001: the multi-gen LRU core + 0x0002: walking page table, when arch_has_hw_pte_young() returns + true + 0x0004: clearing the accessed bit in non-leaf PMD entries, when + CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y + [yYnN]: apply to all the components above +E.g., + echo y >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0007 + echo 5 >/sys/kernel/mm/lru_gen/enabled + cat /sys/kernel/mm/lru_gen/enabled + 0x0005 + +NB: the page table walks happen on the scale of seconds under heavy memory +pressure, in which case the mmap_lock contention is a lesser concern, +compared with the LRU lock contention and the I/O congestion. So far the +only well-known case of the mmap_lock contention happens on Android, due +to Scudo [1] which allocates several thousand VMAs for merely a few +hundred MBs. The SPF and the Maple Tree also have provided their own +assessments [2][3]. However, if walking page tables does worsen the +mmap_lock contention, the kill switch can be used to disable it. In this +case the multi-gen LRU will suffer a minor performance degradation, as +shown previously. + +Clearing the accessed bit in non-leaf PMD entries can also be disabled, +since this behavior was not tested on x86 varieties other than Intel and +AMD. + +[1] https://source.android.com/devices/tech/debug/scudo +[2] https://lore.kernel.org/r/20220128131006.67712-1-michel@lespinasse.org/ +[3] https://lore.kernel.org/r/20220426150616.3937571-1-Liam.Howlett@oracle.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-11-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/cgroup.h | 15 ++- + include/linux/mm_inline.h | 15 ++- + include/linux/mmzone.h | 9 ++ + kernel/cgroup/cgroup-internal.h | 1 - + mm/Kconfig | 6 + + mm/vmscan.c | 228 +++++++++++++++++++++++++++++++- + 6 files changed, 265 insertions(+), 9 deletions(-) + +--- a/include/linux/cgroup.h ++++ b/include/linux/cgroup.h +@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgr + css_put(&cgrp->self); + } + ++extern struct mutex cgroup_mutex; ++ ++static inline void cgroup_lock(void) ++{ ++ mutex_lock(&cgroup_mutex); ++} ++ ++static inline void cgroup_unlock(void) ++{ ++ mutex_unlock(&cgroup_mutex); ++} ++ + /** + * task_css_set_check - obtain a task's css_set with extra access conditions + * @task: the task to obtain css_set for +@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgr + * as locks used during the cgroup_subsys::attach() methods. + */ + #ifdef CONFIG_PROVE_RCU +-extern struct mutex cgroup_mutex; + extern spinlock_t css_set_lock; + #define task_css_set_check(task, __c) \ + rcu_dereference_check((task)->cgroups, \ +@@ -708,6 +719,8 @@ struct cgroup; + static inline u64 cgroup_id(const struct cgroup *cgrp) { return 1; } + static inline void css_get(struct cgroup_subsys_state *css) {} + static inline void css_put(struct cgroup_subsys_state *css) {} ++static inline void cgroup_lock(void) {} ++static inline void cgroup_unlock(void) {} + static inline int cgroup_attach_task_all(struct task_struct *from, + struct task_struct *t) { return 0; } + static inline int cgroupstats_build(struct cgroupstats *stats, +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -91,10 +91,21 @@ static __always_inline enum lru_list pag + + #ifdef CONFIG_LRU_GEN + ++#ifdef CONFIG_LRU_GEN_ENABLED + static inline bool lru_gen_enabled(void) + { +- return true; ++ DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); ++ ++ return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); ++} ++#else ++static inline bool lru_gen_enabled(void) ++{ ++ DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); ++ ++ return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); + } ++#endif + + static inline bool lru_gen_in_fault(void) + { +@@ -207,7 +218,7 @@ static inline bool lru_gen_add_page(stru + + VM_WARN_ON_ONCE_PAGE(gen != -1, page); + +- if (PageUnevictable(page)) ++ if (PageUnevictable(page) || !lrugen->enabled) + return false; + /* + * There are three common cases for this page: +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -364,6 +364,13 @@ enum { + LRU_GEN_FILE, + }; + ++enum { ++ LRU_GEN_CORE, ++ LRU_GEN_MM_WALK, ++ LRU_GEN_NONLEAF_YOUNG, ++ NR_LRU_GEN_CAPS ++}; ++ + #define MIN_LRU_BATCH BITS_PER_LONG + #define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) + +@@ -405,6 +412,8 @@ struct lru_gen_struct { + /* can be modified without holding the LRU lock */ + atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; ++ /* whether the multi-gen LRU is enabled */ ++ bool enabled; + }; + + enum { +--- a/kernel/cgroup/cgroup-internal.h ++++ b/kernel/cgroup/cgroup-internal.h +@@ -165,7 +165,6 @@ struct cgroup_mgctx { + #define DEFINE_CGROUP_MGCTX(name) \ + struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) + +-extern struct mutex cgroup_mutex; + extern spinlock_t css_set_lock; + extern struct cgroup_subsys *cgroup_subsys[]; + extern struct list_head cgroup_roots; +--- a/mm/Kconfig ++++ b/mm/Kconfig +@@ -906,6 +906,12 @@ config LRU_GEN + help + A high performance LRU implementation to overcommit memory. + ++config LRU_GEN_ENABLED ++ bool "Enable by default" ++ depends on LRU_GEN ++ help ++ This option enables the multi-gen LRU by default. ++ + config LRU_GEN_STATS + bool "Full stats for debugging" + depends on LRU_GEN +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -52,6 +52,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -2841,6 +2842,14 @@ static bool can_age_anon_pages(struct pg + + #ifdef CONFIG_LRU_GEN + ++#ifdef CONFIG_LRU_GEN_ENABLED ++DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); ++#define get_cap(cap) static_branch_likely(&lru_gen_caps[cap]) ++#else ++DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); ++#define get_cap(cap) static_branch_unlikely(&lru_gen_caps[cap]) ++#endif ++ + /****************************************************************************** + * shorthand helpers + ******************************************************************************/ +@@ -3717,7 +3726,8 @@ static void walk_pmd_range_locked(pud_t + goto next; + + if (!pmd_trans_huge(pmd[i])) { +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && ++ get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } +@@ -3815,10 +3825,12 @@ restart: + walk->mm_stats[MM_NONLEAF_TOTAL]++; + + #ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +- if (!pmd_young(val)) +- continue; ++ if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { ++ if (!pmd_young(val)) ++ continue; + +- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ } + #endif + if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) + continue; +@@ -4080,7 +4092,7 @@ static bool try_to_inc_max_seq(struct lr + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!arch_has_hw_pte_young()) { ++ if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } +@@ -4846,6 +4858,208 @@ done: + } + + /****************************************************************************** ++ * state change ++ ******************************************************************************/ ++ ++static bool __maybe_unused state_is_valid(struct lruvec *lruvec) ++{ ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ if (lrugen->enabled) { ++ enum lru_list lru; ++ ++ for_each_evictable_lru(lru) { ++ if (!list_empty(&lruvec->lists[lru])) ++ return false; ++ } ++ } else { ++ int gen, type, zone; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ if (!list_empty(&lrugen->lists[gen][type][zone])) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static bool fill_evictable(struct lruvec *lruvec) ++{ ++ enum lru_list lru; ++ int remaining = MAX_LRU_BATCH; ++ ++ for_each_evictable_lru(lru) { ++ int type = is_file_lru(lru); ++ bool active = is_active_lru(lru); ++ struct list_head *head = &lruvec->lists[lru]; ++ ++ while (!list_empty(head)) { ++ bool success; ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page) != active, page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_lru_gen(page) != -1, page); ++ ++ del_page_from_lru_list(page, lruvec); ++ success = lru_gen_add_page(lruvec, page, false); ++ VM_WARN_ON_ONCE(!success); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static bool drain_evictable(struct lruvec *lruvec) ++{ ++ int gen, type, zone; ++ int remaining = MAX_LRU_BATCH; ++ ++ for_each_gen_type_zone(gen, type, zone) { ++ struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ bool success; ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); ++ ++ success = lru_gen_del_page(lruvec, page, false); ++ VM_WARN_ON_ONCE(!success); ++ add_page_to_lru_list(page, lruvec); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++static void lru_gen_change_state(bool enabled) ++{ ++ static DEFINE_MUTEX(state_mutex); ++ ++ struct mem_cgroup *memcg; ++ ++ cgroup_lock(); ++ cpus_read_lock(); ++ get_online_mems(); ++ mutex_lock(&state_mutex); ++ ++ if (enabled == lru_gen_enabled()) ++ goto unlock; ++ ++ if (enabled) ++ static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); ++ else ++ static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ if (!lruvec) ++ continue; ++ ++ spin_lock_irq(&lruvec->lru_lock); ++ ++ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); ++ VM_WARN_ON_ONCE(!state_is_valid(lruvec)); ++ ++ lruvec->lrugen.enabled = enabled; ++ ++ while (!(enabled ? fill_evictable(lruvec) : drain_evictable(lruvec))) { ++ spin_unlock_irq(&lruvec->lru_lock); ++ cond_resched(); ++ spin_lock_irq(&lruvec->lru_lock); ++ } ++ ++ spin_unlock_irq(&lruvec->lru_lock); ++ } ++ ++ cond_resched(); ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++unlock: ++ mutex_unlock(&state_mutex); ++ put_online_mems(); ++ cpus_read_unlock(); ++ cgroup_unlock(); ++} ++ ++/****************************************************************************** ++ * sysfs interface ++ ******************************************************************************/ ++ ++static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ unsigned int caps = 0; ++ ++ if (get_cap(LRU_GEN_CORE)) ++ caps |= BIT(LRU_GEN_CORE); ++ ++ if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) ++ caps |= BIT(LRU_GEN_MM_WALK); ++ ++ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) ++ caps |= BIT(LRU_GEN_NONLEAF_YOUNG); ++ ++ return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); ++} ++ ++static ssize_t store_enabled(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t len) ++{ ++ int i; ++ unsigned int caps; ++ ++ if (tolower(*buf) == 'n') ++ caps = 0; ++ else if (tolower(*buf) == 'y') ++ caps = -1; ++ else if (kstrtouint(buf, 0, &caps)) ++ return -EINVAL; ++ ++ for (i = 0; i < NR_LRU_GEN_CAPS; i++) { ++ bool enabled = caps & BIT(i); ++ ++ if (i == LRU_GEN_CORE) ++ lru_gen_change_state(enabled); ++ else if (enabled) ++ static_branch_enable(&lru_gen_caps[i]); ++ else ++ static_branch_disable(&lru_gen_caps[i]); ++ } ++ ++ return len; ++} ++ ++static struct kobj_attribute lru_gen_enabled_attr = __ATTR( ++ enabled, 0644, show_enabled, store_enabled ++); ++ ++static struct attribute *lru_gen_attrs[] = { ++ &lru_gen_enabled_attr.attr, ++ NULL ++}; ++ ++static struct attribute_group lru_gen_attr_group = { ++ .name = "lru_gen", ++ .attrs = lru_gen_attrs, ++}; ++ ++/****************************************************************************** + * initialization + ******************************************************************************/ + +@@ -4855,6 +5069,7 @@ void lru_gen_init_lruvec(struct lruvec * + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; ++ lrugen->enabled = lru_gen_enabled(); + + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); +@@ -4894,6 +5109,9 @@ static int __init init_lru_gen(void) + BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); + BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); + ++ if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) ++ pr_err("lru_gen: failed to create sysfs group\n"); ++ + return 0; + }; + late_initcall(init_lru_gen); diff --git a/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch b/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch new file mode 100644 index 00000000000..30e20aff6ed --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch @@ -0,0 +1,226 @@ +From 73d1ff551760f0c79c47ab70faa4c2ca91413f5c Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:08 -0600 +Subject: [PATCH 11/29] mm: multi-gen LRU: thrashing prevention +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/mm/lru_gen/min_ttl_ms for thrashing prevention, as +requested by many desktop users [1]. + +When set to value N, it prevents the working set of N milliseconds from +getting evicted. The OOM killer is triggered if this working set cannot +be kept in memory. Based on the average human detectable lag (~100ms), +N=1000 usually eliminates intolerable lags due to thrashing. Larger +values like N=3000 make lags less noticeable at the risk of premature OOM +kills. + +Compared with the size-based approach [2], this time-based approach +has the following advantages: + +1. It is easier to configure because it is agnostic to applications + and memory sizes. +2. It is more reliable because it is directly wired to the OOM killer. + +[1] https://lore.kernel.org/r/Ydza%2FzXKY9ATRoh6@google.com/ +[2] https://lore.kernel.org/r/20101028191523.GA14972@google.com/ + +Link: https://lkml.kernel.org/r/20220918080010.2920238-12-yuzhao@google.com +Signed-off-by: Yu Zhao +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Qi Zheng +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/mmzone.h | 2 ++ + mm/vmscan.c | 74 ++++++++++++++++++++++++++++++++++++++++-- + 2 files changed, 73 insertions(+), 3 deletions(-) + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -399,6 +399,8 @@ struct lru_gen_struct { + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ + unsigned long min_seq[ANON_AND_FILE]; ++ /* the birth time of each generation in jiffies */ ++ unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists, lazily sorted on eviction */ + struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4064,6 +4064,7 @@ static void inc_max_seq(struct lruvec *l + for (type = 0; type < ANON_AND_FILE; type++) + reset_ctrl_pos(lruvec, type, false); + ++ WRITE_ONCE(lrugen->timestamps[next], jiffies); + /* make sure preceding modifications appear */ + smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); + +@@ -4193,7 +4194,7 @@ static bool should_run_aging(struct lruv + return false; + } + +-static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned long min_ttl) + { + bool need_aging; + unsigned long nr_to_scan; +@@ -4207,16 +4208,36 @@ static void age_lruvec(struct lruvec *lr + mem_cgroup_calculate_protection(NULL, memcg); + + if (mem_cgroup_below_min(memcg)) +- return; ++ return false; + + need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ ++ if (min_ttl) { ++ int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); ++ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++ ++ if (time_is_after_jiffies(birth + min_ttl)) ++ return false; ++ ++ /* the size is likely too small to be helpful */ ++ if (!nr_to_scan && sc->priority != DEF_PRIORITY) ++ return false; ++ } ++ + if (need_aging) + try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); ++ ++ return true; + } + ++/* to protect the working set of the last N jiffies */ ++static unsigned long lru_gen_min_ttl __read_mostly; ++ + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; ++ bool success = false; ++ unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_WARN_ON_ONCE(!current_is_kswapd()); + +@@ -4239,12 +4260,32 @@ static void lru_gen_age_node(struct pgli + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + +- age_lruvec(lruvec, sc); ++ if (age_lruvec(lruvec, sc, min_ttl)) ++ success = true; + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + + clear_mm_walk(); ++ ++ /* check the order to exclude compaction-induced reclaim */ ++ if (success || !min_ttl || sc->order) ++ return; ++ ++ /* ++ * The main goal is to OOM kill if every generation from all memcgs is ++ * younger than min_ttl. However, another possibility is all memcgs are ++ * either below min or empty. ++ */ ++ if (mutex_trylock(&oom_lock)) { ++ struct oom_control oc = { ++ .gfp_mask = sc->gfp_mask, ++ }; ++ ++ out_of_memory(&oc); ++ ++ mutex_unlock(&oom_lock); ++ } + } + + /* +@@ -5002,6 +5043,28 @@ unlock: + * sysfs interface + ******************************************************************************/ + ++static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); ++} ++ ++static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t len) ++{ ++ unsigned int msecs; ++ ++ if (kstrtouint(buf, 0, &msecs)) ++ return -EINVAL; ++ ++ WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); ++ ++ return len; ++} ++ ++static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( ++ min_ttl_ms, 0644, show_min_ttl, store_min_ttl ++); ++ + static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) + { + unsigned int caps = 0; +@@ -5050,6 +5113,7 @@ static struct kobj_attribute lru_gen_ena + ); + + static struct attribute *lru_gen_attrs[] = { ++ &lru_gen_min_ttl_attr.attr, + &lru_gen_enabled_attr.attr, + NULL + }; +@@ -5065,12 +5129,16 @@ static struct attribute_group lru_gen_at + + void lru_gen_init_lruvec(struct lruvec *lruvec) + { ++ int i; + int gen, type, zone; + struct lru_gen_struct *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); + ++ for (i = 0; i <= MIN_NR_GENS + 1; i++) ++ lrugen->timestamps[i] = jiffies; ++ + for_each_gen_type_zone(gen, type, zone) + INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); + diff --git a/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch b/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch new file mode 100644 index 00000000000..482e714bb6a --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch @@ -0,0 +1,579 @@ +From 530716d008ca26315f246cd70dc1cefc636beaa4 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 18 Sep 2022 02:00:09 -0600 +Subject: [PATCH 12/29] mm: multi-gen LRU: debugfs interface +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add /sys/kernel/debug/lru_gen for working set estimation and proactive +reclaim. These techniques are commonly used to optimize job scheduling +(bin packing) in data centers [1][2]. + +Compared with the page table-based approach and the PFN-based +approach, this lruvec-based approach has the following advantages: +1. It offers better choices because it is aware of memcgs, NUMA nodes, + shared mappings and unmapped page cache. +2. It is more scalable because it is O(nr_hot_pages), whereas the + PFN-based approach is O(nr_total_pages). + +Add /sys/kernel/debug/lru_gen_full for debugging. + +[1] https://dl.acm.org/doi/10.1145/3297858.3304053 +[2] https://dl.acm.org/doi/10.1145/3503222.3507731 + +Link: https://lkml.kernel.org/r/20220918080010.2920238-13-yuzhao@google.com +Signed-off-by: Yu Zhao +Reviewed-by: Qi Zheng +Acked-by: Brian Geffon +Acked-by: Jan Alexander Steffens (heftig) +Acked-by: Oleksandr Natalenko +Acked-by: Steven Barrett +Acked-by: Suleiman Souhlal +Tested-by: Daniel Byrne +Tested-by: Donald Carr +Tested-by: Holger Hoffstätte +Tested-by: Konstantin Kharlamov +Tested-by: Shuang Zhai +Tested-by: Sofia Trinh +Tested-by: Vaibhav Jain +Cc: Andi Kleen +Cc: Aneesh Kumar K.V +Cc: Barry Song +Cc: Catalin Marinas +Cc: Dave Hansen +Cc: Hillf Danton +Cc: Jens Axboe +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Linus Torvalds +Cc: Matthew Wilcox +Cc: Mel Gorman +Cc: Miaohe Lin +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Mike Rapoport +Cc: Peter Zijlstra +Cc: Tejun Heo +Cc: Vlastimil Babka +Cc: Will Deacon +Signed-off-by: Andrew Morton +--- + include/linux/nodemask.h | 1 + + mm/vmscan.c | 411 ++++++++++++++++++++++++++++++++++++++- + 2 files changed, 402 insertions(+), 10 deletions(-) + +--- a/include/linux/nodemask.h ++++ b/include/linux/nodemask.h +@@ -485,6 +485,7 @@ static inline int num_node_state(enum no + #define first_online_node 0 + #define first_memory_node 0 + #define next_online_node(nid) (MAX_NUMNODES) ++#define next_memory_node(nid) (MAX_NUMNODES) + #define nr_node_ids 1U + #define nr_online_nodes 1U + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -53,6 +53,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -3968,12 +3969,40 @@ static void clear_mm_walk(void) + kfree(walk); + } + +-static void inc_min_seq(struct lruvec *lruvec, int type) ++static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) + { ++ int zone; ++ int remaining = MAX_LRU_BATCH; + struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); ++ ++ if (type == LRU_GEN_ANON && !can_swap) ++ goto done; ++ ++ /* prevent cold/hot inversion if force_scan is true */ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) { ++ struct list_head *head = &lrugen->lists[old_gen][type][zone]; ++ ++ while (!list_empty(head)) { ++ struct page *page = lru_to_page(head); ++ ++ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); ++ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); ++ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); ++ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); + ++ new_gen = page_inc_gen(lruvec, page, false); ++ list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); ++ ++ if (!--remaining) ++ return false; ++ } ++ } ++done: + reset_ctrl_pos(lruvec, type, true); + WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); ++ ++ return true; + } + + static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) +@@ -4019,7 +4048,7 @@ next: + return success; + } + +-static void inc_max_seq(struct lruvec *lruvec, bool can_swap) ++static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) + { + int prev, next; + int type, zone; +@@ -4033,9 +4062,13 @@ static void inc_max_seq(struct lruvec *l + if (get_nr_gens(lruvec, type) != MAX_NR_GENS) + continue; + +- VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); ++ VM_WARN_ON_ONCE(!force_scan && (type == LRU_GEN_FILE || can_swap)); + +- inc_min_seq(lruvec, type); ++ while (!inc_min_seq(lruvec, type, can_swap)) { ++ spin_unlock_irq(&lruvec->lru_lock); ++ cond_resched(); ++ spin_lock_irq(&lruvec->lru_lock); ++ } + } + + /* +@@ -4072,7 +4105,7 @@ static void inc_max_seq(struct lruvec *l + } + + static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, +- struct scan_control *sc, bool can_swap) ++ struct scan_control *sc, bool can_swap, bool force_scan) + { + bool success; + struct lru_gen_mm_walk *walk; +@@ -4093,7 +4126,7 @@ static bool try_to_inc_max_seq(struct lr + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { ++ if (!force_scan && !(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } +@@ -4107,7 +4140,7 @@ static bool try_to_inc_max_seq(struct lr + walk->lruvec = lruvec; + walk->max_seq = max_seq; + walk->can_swap = can_swap; +- walk->force_scan = false; ++ walk->force_scan = force_scan; + + do { + success = iterate_mm_list(lruvec, walk, &mm); +@@ -4127,7 +4160,7 @@ done: + + VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); + +- inc_max_seq(lruvec, can_swap); ++ inc_max_seq(lruvec, can_swap, force_scan); + /* either this sees any waiters or they will see updated max_seq */ + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); +@@ -4225,7 +4258,7 @@ static bool age_lruvec(struct lruvec *lr + } + + if (need_aging) +- try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); ++ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); + + return true; + } +@@ -4784,7 +4817,7 @@ static unsigned long get_nr_to_scan(stru + if (current_is_kswapd()) + return 0; + +- if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) ++ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) + return nr_to_scan; + done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; +@@ -5124,6 +5157,361 @@ static struct attribute_group lru_gen_at + }; + + /****************************************************************************** ++ * debugfs interface ++ ******************************************************************************/ ++ ++static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) ++{ ++ struct mem_cgroup *memcg; ++ loff_t nr_to_skip = *pos; ++ ++ m->private = kvmalloc(PATH_MAX, GFP_KERNEL); ++ if (!m->private) ++ return ERR_PTR(-ENOMEM); ++ ++ memcg = mem_cgroup_iter(NULL, NULL, NULL); ++ do { ++ int nid; ++ ++ for_each_node_state(nid, N_MEMORY) { ++ if (!nr_to_skip--) ++ return get_lruvec(memcg, nid); ++ } ++ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); ++ ++ return NULL; ++} ++ ++static void lru_gen_seq_stop(struct seq_file *m, void *v) ++{ ++ if (!IS_ERR_OR_NULL(v)) ++ mem_cgroup_iter_break(NULL, lruvec_memcg(v)); ++ ++ kvfree(m->private); ++ m->private = NULL; ++} ++ ++static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ int nid = lruvec_pgdat(v)->node_id; ++ struct mem_cgroup *memcg = lruvec_memcg(v); ++ ++ ++*pos; ++ ++ nid = next_memory_node(nid); ++ if (nid == MAX_NUMNODES) { ++ memcg = mem_cgroup_iter(NULL, memcg, NULL); ++ if (!memcg) ++ return NULL; ++ ++ nid = first_memory_node; ++ } ++ ++ return get_lruvec(memcg, nid); ++} ++ ++static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, ++ unsigned long max_seq, unsigned long *min_seq, ++ unsigned long seq) ++{ ++ int i; ++ int type, tier; ++ int hist = lru_hist_from_seq(seq); ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ ++ for (tier = 0; tier < MAX_NR_TIERS; tier++) { ++ seq_printf(m, " %10d", tier); ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ const char *s = " "; ++ unsigned long n[3] = {}; ++ ++ if (seq == max_seq) { ++ s = "RT "; ++ n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); ++ n[1] = READ_ONCE(lrugen->avg_total[type][tier]); ++ } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { ++ s = "rep"; ++ n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); ++ n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); ++ if (tier) ++ n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); ++ } ++ ++ for (i = 0; i < 3; i++) ++ seq_printf(m, " %10lu%c", n[i], s[i]); ++ } ++ seq_putc(m, '\n'); ++ } ++ ++ seq_puts(m, " "); ++ for (i = 0; i < NR_MM_STATS; i++) { ++ const char *s = " "; ++ unsigned long n = 0; ++ ++ if (seq == max_seq && NR_HIST_GENS == 1) { ++ s = "LOYNFA"; ++ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); ++ } else if (seq != max_seq && NR_HIST_GENS > 1) { ++ s = "loynfa"; ++ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); ++ } ++ ++ seq_printf(m, " %10lu%c", n, s[i]); ++ } ++ seq_putc(m, '\n'); ++} ++ ++static int lru_gen_seq_show(struct seq_file *m, void *v) ++{ ++ unsigned long seq; ++ bool full = !debugfs_real_fops(m->file)->write; ++ struct lruvec *lruvec = v; ++ struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ int nid = lruvec_pgdat(lruvec)->node_id; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (nid == first_memory_node) { ++ const char *path = memcg ? m->private : ""; ++ ++#ifdef CONFIG_MEMCG ++ if (memcg) ++ cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); ++#endif ++ seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); ++ } ++ ++ seq_printf(m, " node %5d\n", nid); ++ ++ if (!full) ++ seq = min_seq[LRU_GEN_ANON]; ++ else if (max_seq >= MAX_NR_GENS) ++ seq = max_seq - MAX_NR_GENS + 1; ++ else ++ seq = 0; ++ ++ for (; seq <= max_seq; seq++) { ++ int type, zone; ++ int gen = lru_gen_from_seq(seq); ++ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++ ++ seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); ++ ++ for (type = 0; type < ANON_AND_FILE; type++) { ++ unsigned long size = 0; ++ char mark = full && seq < min_seq[type] ? 'x' : ' '; ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ seq_printf(m, " %10lu%c", size, mark); ++ } ++ ++ seq_putc(m, '\n'); ++ ++ if (full) ++ lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); ++ } ++ ++ return 0; ++} ++ ++static const struct seq_operations lru_gen_seq_ops = { ++ .start = lru_gen_seq_start, ++ .stop = lru_gen_seq_stop, ++ .next = lru_gen_seq_next, ++ .show = lru_gen_seq_show, ++}; ++ ++static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, ++ bool can_swap, bool force_scan) ++{ ++ DEFINE_MAX_SEQ(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (seq < max_seq) ++ return 0; ++ ++ if (seq > max_seq) ++ return -EINVAL; ++ ++ if (!force_scan && min_seq[!can_swap] + MAX_NR_GENS - 1 <= max_seq) ++ return -ERANGE; ++ ++ try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, force_scan); ++ ++ return 0; ++} ++ ++static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, ++ int swappiness, unsigned long nr_to_reclaim) ++{ ++ DEFINE_MAX_SEQ(lruvec); ++ ++ if (seq + MIN_NR_GENS > max_seq) ++ return -EINVAL; ++ ++ sc->nr_reclaimed = 0; ++ ++ while (!signal_pending(current)) { ++ DEFINE_MIN_SEQ(lruvec); ++ ++ if (seq < min_seq[!swappiness]) ++ return 0; ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ return 0; ++ ++ if (!evict_pages(lruvec, sc, swappiness, NULL)) ++ return 0; ++ ++ cond_resched(); ++ } ++ ++ return -EINTR; ++} ++ ++static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, ++ struct scan_control *sc, int swappiness, unsigned long opt) ++{ ++ struct lruvec *lruvec; ++ int err = -EINVAL; ++ struct mem_cgroup *memcg = NULL; ++ ++ if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) ++ return -EINVAL; ++ ++ if (!mem_cgroup_disabled()) { ++ rcu_read_lock(); ++ memcg = mem_cgroup_from_id(memcg_id); ++#ifdef CONFIG_MEMCG ++ if (memcg && !css_tryget(&memcg->css)) ++ memcg = NULL; ++#endif ++ rcu_read_unlock(); ++ ++ if (!memcg) ++ return -EINVAL; ++ } ++ ++ if (memcg_id != mem_cgroup_id(memcg)) ++ goto done; ++ ++ lruvec = get_lruvec(memcg, nid); ++ ++ if (swappiness < 0) ++ swappiness = get_swappiness(lruvec, sc); ++ else if (swappiness > 200) ++ goto done; ++ ++ switch (cmd) { ++ case '+': ++ err = run_aging(lruvec, seq, sc, swappiness, opt); ++ break; ++ case '-': ++ err = run_eviction(lruvec, seq, sc, swappiness, opt); ++ break; ++ } ++done: ++ mem_cgroup_put(memcg); ++ ++ return err; ++} ++ ++static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, ++ size_t len, loff_t *pos) ++{ ++ void *buf; ++ char *cur, *next; ++ unsigned int flags; ++ struct blk_plug plug; ++ int err = -EINVAL; ++ struct scan_control sc = { ++ .may_writepage = true, ++ .may_unmap = true, ++ .may_swap = true, ++ .reclaim_idx = MAX_NR_ZONES - 1, ++ .gfp_mask = GFP_KERNEL, ++ }; ++ ++ buf = kvmalloc(len + 1, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (copy_from_user(buf, src, len)) { ++ kvfree(buf); ++ return -EFAULT; ++ } ++ ++ set_task_reclaim_state(current, &sc.reclaim_state); ++ flags = memalloc_noreclaim_save(); ++ blk_start_plug(&plug); ++ if (!set_mm_walk(NULL)) { ++ err = -ENOMEM; ++ goto done; ++ } ++ ++ next = buf; ++ next[len] = '\0'; ++ ++ while ((cur = strsep(&next, ",;\n"))) { ++ int n; ++ int end; ++ char cmd; ++ unsigned int memcg_id; ++ unsigned int nid; ++ unsigned long seq; ++ unsigned int swappiness = -1; ++ unsigned long opt = -1; ++ ++ cur = skip_spaces(cur); ++ if (!*cur) ++ continue; ++ ++ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, ++ &seq, &end, &swappiness, &end, &opt, &end); ++ if (n < 4 || cur[end]) { ++ err = -EINVAL; ++ break; ++ } ++ ++ err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); ++ if (err) ++ break; ++ } ++done: ++ clear_mm_walk(); ++ blk_finish_plug(&plug); ++ memalloc_noreclaim_restore(flags); ++ set_task_reclaim_state(current, NULL); ++ ++ kvfree(buf); ++ ++ return err ? : len; ++} ++ ++static int lru_gen_seq_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &lru_gen_seq_ops); ++} ++ ++static const struct file_operations lru_gen_rw_fops = { ++ .open = lru_gen_seq_open, ++ .read = seq_read, ++ .write = lru_gen_seq_write, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static const struct file_operations lru_gen_ro_fops = { ++ .open = lru_gen_seq_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++/****************************************************************************** + * initialization + ******************************************************************************/ + +@@ -5180,6 +5568,9 @@ static int __init init_lru_gen(void) + if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) + pr_err("lru_gen: failed to create sysfs group\n"); + ++ debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); ++ debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); ++ + return 0; + }; + late_initcall(init_lru_gen); diff --git a/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch b/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch new file mode 100644 index 00000000000..fd4aa727473 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch @@ -0,0 +1,32 @@ +From 92d430e8955c976eacb7cc91d7ff849c0dd009af Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 28 Sep 2022 13:36:58 -0600 +Subject: [PATCH 13/29] mm/mglru: don't sync disk for each aging cycle + +wakeup_flusher_threads() was added under the assumption that if a system +runs out of clean cold pages, it might want to write back dirty pages more +aggressively so that they can become clean and be dropped. + +However, doing so can breach the rate limit a system wants to impose on +writeback, resulting in early SSD wearout. + +Link: https://lkml.kernel.org/r/YzSiWq9UEER5LKup@google.com +Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Yu Zhao +Reported-by: Axel Rasmussen +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4165,8 +4165,6 @@ done: + if (wq_has_sleeper(&lruvec->mm_state.wait)) + wake_up_all(&lruvec->mm_state.wait); + +- wakeup_flusher_threads(WB_REASON_VMSCAN); +- + return true; + } + diff --git a/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch b/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch new file mode 100644 index 00000000000..31b35cbc4b6 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch @@ -0,0 +1,124 @@ +From 6f315879ad750391a0b1fab8c9170bc054a5f5d7 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Tue, 15 Nov 2022 18:38:07 -0700 +Subject: [PATCH 14/29] mm: multi-gen LRU: retry pages written back while + isolated + +The page reclaim isolates a batch of pages from the tail of one of the +LRU lists and works on those pages one by one. For a suitable +swap-backed page, if the swap device is async, it queues that page for +writeback. After the page reclaim finishes an entire batch, it puts back +the pages it queued for writeback to the head of the original LRU list. + +In the meantime, the page writeback flushes the queued pages also by +batches. Its batching logic is independent from that of the page reclaim. +For each of the pages it writes back, the page writeback calls +rotate_reclaimable_page() which tries to rotate a page to the tail. + +rotate_reclaimable_page() only works for a page after the page reclaim +has put it back. If an async swap device is fast enough, the page +writeback can finish with that page while the page reclaim is still +working on the rest of the batch containing it. In this case, that page +will remain at the head and the page reclaim will not retry it before +reaching there. + +This patch adds a retry to evict_pages(). After evict_pages() has +finished an entire batch and before it puts back pages it cannot free +immediately, it retries those that may have missed the rotation. + +Before this patch, ~60% of pages swapped to an Intel Optane missed +rotate_reclaimable_page(). After this patch, ~99% of missed pages were +reclaimed upon retry. + +This problem affects relatively slow async swap devices like Samsung 980 +Pro much less and does not affect sync swap devices like zram or zswap at +all. + +Link: https://lkml.kernel.org/r/20221116013808.3995280-1-yuzhao@google.com +Fixes: ac35a4902374 ("mm: multi-gen LRU: minimal implementation") +Signed-off-by: Yu Zhao +Cc: "Yin, Fengwei" +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 48 +++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 37 insertions(+), 11 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lr + int scanned; + int reclaimed; + LIST_HEAD(list); ++ LIST_HEAD(clean); + struct page *page; ++ struct page *next; + enum vm_event_item item; + struct reclaim_stat stat; + struct lru_gen_mm_walk *walk; ++ bool skip_retry = false; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + +@@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lr + + if (list_empty(&list)) + return scanned; +- ++retry: + reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); ++ sc->nr_reclaimed += reclaimed; + +- list_for_each_entry(page, &list, lru) { +- /* restore LRU_REFS_FLAGS cleared by isolate_page() */ +- if (PageWorkingset(page)) +- SetPageReferenced(page); ++ list_for_each_entry_safe_reverse(page, next, &list, lru) { ++ if (!page_evictable(page)) { ++ list_del(&page->lru); ++ putback_lru_page(page); ++ continue; ++ } + +- /* don't add rejected pages to the oldest generation */ + if (PageReclaim(page) && +- (PageDirty(page) || PageWriteback(page))) +- ClearPageActive(page); +- else +- SetPageActive(page); ++ (PageDirty(page) || PageWriteback(page))) { ++ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ ++ if (PageWorkingset(page)) ++ SetPageReferenced(page); ++ continue; ++ } ++ ++ if (skip_retry || PageActive(page) || PageReferenced(page) || ++ page_mapped(page) || PageLocked(page) || ++ PageDirty(page) || PageWriteback(page)) { ++ /* don't add rejected pages to the oldest generation */ ++ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, ++ BIT(PG_active)); ++ continue; ++ } ++ ++ /* retry pages that may have missed rotate_reclaimable_page() */ ++ list_move(&page->lru, &clean); ++ sc->nr_scanned -= thp_nr_pages(page); + } + + spin_lock_irq(&lruvec->lru_lock); +@@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lr + mem_cgroup_uncharge_list(&list); + free_unref_page_list(&list); + +- sc->nr_reclaimed += reclaimed; ++ INIT_LIST_HEAD(&list); ++ list_splice_init(&clean, &list); ++ ++ if (!list_empty(&list)) { ++ skip_retry = true; ++ goto retry; ++ } + + if (need_swapping && type == LRU_GEN_ANON) + *need_swapping = true; diff --git a/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch b/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch new file mode 100644 index 00000000000..5b1d378504a --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch @@ -0,0 +1,49 @@ +From 255bb0ac393f1c2818cd75af45a9226300ab3daf Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior +Date: Wed, 26 Oct 2022 15:48:30 +0200 +Subject: [PATCH 15/29] mm: multi-gen LRU: move lru_gen_add_mm() out of IRQ-off + region + +lru_gen_add_mm() has been added within an IRQ-off region in the commit +mentioned below. The other invocations of lru_gen_add_mm() are not within +an IRQ-off region. + +The invocation within IRQ-off region is problematic on PREEMPT_RT because +the function is using a spin_lock_t which must not be used within +IRQ-disabled regions. + +The other invocations of lru_gen_add_mm() occur while +task_struct::alloc_lock is acquired. Move lru_gen_add_mm() after +interrupts are enabled and before task_unlock(). + +Link: https://lkml.kernel.org/r/20221026134830.711887-1-bigeasy@linutronix.de +Fixes: bd74fdaea1460 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Sebastian Andrzej Siewior +Acked-by: Yu Zhao +Cc: Al Viro +Cc: "Eric W . Biederman" +Cc: Kees Cook +Cc: Thomas Gleixner +Signed-off-by: Andrew Morton +--- + fs/exec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1013,7 +1013,6 @@ static int exec_mmap(struct mm_struct *m + active_mm = tsk->active_mm; + tsk->active_mm = mm; + tsk->mm = mm; +- lru_gen_add_mm(mm); + /* + * This prevents preemption while active_mm is being loaded and + * it and mm are being updated, which could cause problems for +@@ -1028,6 +1027,7 @@ static int exec_mmap(struct mm_struct *m + local_irq_enable(); + tsk->mm->vmacache_seqnum = 0; + vmacache_flush(tsk); ++ lru_gen_add_mm(mm); + task_unlock(tsk); + lru_gen_use_mm(mm); + if (old_mm) { diff --git a/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch b/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch new file mode 100644 index 00000000000..1c10c168a50 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch @@ -0,0 +1,96 @@ +From c5ec455ebd2b488d91de9d8915a0c8036a2a04dd Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Wed, 30 Nov 2022 14:49:41 -0800 +Subject: [PATCH 17/29] mm: add dummy pmd_young() for architectures not having + it + +In order to avoid #ifdeffery add a dummy pmd_young() implementation as a +fallback. This is required for the later patch "mm: introduce +arch_has_hw_nonleaf_pmd_young()". + +Link: https://lkml.kernel.org/r/fd3ac3cd-7349-6bbd-890a-71a9454ca0b3@suse.com +Signed-off-by: Juergen Gross +Acked-by: Yu Zhao +Cc: Borislav Petkov +Cc: Dave Hansen +Cc: Geert Uytterhoeven +Cc: "H. Peter Anvin" +Cc: Ingo Molnar +Cc: Sander Eikelenboom +Cc: Thomas Gleixner +Signed-off-by: Andrew Morton +--- + arch/mips/include/asm/pgtable.h | 1 + + arch/riscv/include/asm/pgtable.h | 1 + + arch/s390/include/asm/pgtable.h | 1 + + arch/sparc/include/asm/pgtable_64.h | 1 + + arch/x86/include/asm/pgtable.h | 1 + + include/linux/pgtable.h | 7 +++++++ + 6 files changed, 12 insertions(+) + +--- a/arch/mips/include/asm/pgtable.h ++++ b/arch/mips/include/asm/pgtable.h +@@ -632,6 +632,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pm + return pmd; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return !!(pmd_val(pmd) & _PAGE_ACCESSED); +--- a/arch/riscv/include/asm/pgtable.h ++++ b/arch/riscv/include/asm/pgtable.h +@@ -535,6 +535,7 @@ static inline int pmd_dirty(pmd_t pmd) + return pte_dirty(pmd_pte(pmd)); + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return pte_young(pmd_pte(pmd)); +--- a/arch/s390/include/asm/pgtable.h ++++ b/arch/s390/include/asm/pgtable.h +@@ -748,6 +748,7 @@ static inline int pmd_dirty(pmd_t pmd) + return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; +--- a/arch/sparc/include/asm/pgtable_64.h ++++ b/arch/sparc/include/asm/pgtable_64.h +@@ -712,6 +712,7 @@ static inline unsigned long pmd_dirty(pm + return pte_dirty(pte); + } + ++#define pmd_young pmd_young + static inline unsigned long pmd_young(pmd_t pmd) + { + pte_t pte = __pte(pmd_val(pmd)); +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -136,6 +136,7 @@ static inline int pmd_dirty(pmd_t pmd) + return pmd_flags(pmd) & _PAGE_DIRTY; + } + ++#define pmd_young pmd_young + static inline int pmd_young(pmd_t pmd) + { + return pmd_flags(pmd) & _PAGE_ACCESSED; +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -164,6 +164,13 @@ static inline pte_t *virt_to_kpte(unsign + return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr); + } + ++#ifndef pmd_young ++static inline int pmd_young(pmd_t pmd) ++{ ++ return 0; ++} ++#endif ++ + #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS + extern int ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, diff --git a/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch b/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch new file mode 100644 index 00000000000..9a1f9bead6c --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch @@ -0,0 +1,113 @@ +From 46cbda7b65998a5af4493f745d94417af697bd68 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Wed, 23 Nov 2022 07:45:10 +0100 +Subject: [PATCH 18/29] mm: introduce arch_has_hw_nonleaf_pmd_young() + +When running as a Xen PV guests commit eed9a328aa1a ("mm: x86: add +CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") can cause a protection violation in +pmdp_test_and_clear_young(): + + BUG: unable to handle page fault for address: ffff8880083374d0 + #PF: supervisor write access in kernel mode + #PF: error_code(0x0003) - permissions violation + PGD 3026067 P4D 3026067 PUD 3027067 PMD 7fee5067 PTE 8010000008337065 + Oops: 0003 [#1] PREEMPT SMP NOPTI + CPU: 7 PID: 158 Comm: kswapd0 Not tainted 6.1.0-rc5-20221118-doflr+ #1 + RIP: e030:pmdp_test_and_clear_young+0x25/0x40 + +This happens because the Xen hypervisor can't emulate direct writes to +page table entries other than PTEs. + +This can easily be fixed by introducing arch_has_hw_nonleaf_pmd_young() +similar to arch_has_hw_pte_young() and test that instead of +CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG. + +Link: https://lkml.kernel.org/r/20221123064510.16225-1-jgross@suse.com +Fixes: eed9a328aa1a ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") +Signed-off-by: Juergen Gross +Reported-by: Sander Eikelenboom +Acked-by: Yu Zhao +Tested-by: Sander Eikelenboom +Acked-by: David Hildenbrand [core changes] +Signed-off-by: Andrew Morton +--- + arch/x86/include/asm/pgtable.h | 8 ++++++++ + include/linux/pgtable.h | 11 +++++++++++ + mm/vmscan.c | 10 +++++----- + 3 files changed, 24 insertions(+), 5 deletions(-) + +--- a/arch/x86/include/asm/pgtable.h ++++ b/arch/x86/include/asm/pgtable.h +@@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young + return true; + } + ++#ifdef CONFIG_XEN_PV ++#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young ++static inline bool arch_has_hw_nonleaf_pmd_young(void) ++{ ++ return !cpu_feature_enabled(X86_FEATURE_XENPV); ++} ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _ASM_X86_PGTABLE_H */ +--- a/include/linux/pgtable.h ++++ b/include/linux/pgtable.h +@@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young + #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + #endif + ++#ifndef arch_has_hw_nonleaf_pmd_young ++/* ++ * Return whether the accessed bit in non-leaf PMD entries is supported on the ++ * local CPU. ++ */ ++static inline bool arch_has_hw_nonleaf_pmd_young(void) ++{ ++ return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG); ++} ++#endif ++ + #ifndef arch_has_hw_pte_young + /* + * Return whether the accessed bit is supported on the local CPU. +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3727,7 +3727,7 @@ static void walk_pmd_range_locked(pud_t + goto next; + + if (!pmd_trans_huge(pmd[i])) { +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && ++ if (arch_has_hw_nonleaf_pmd_young() && + get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; +@@ -3825,14 +3825,14 @@ restart: + #endif + walk->mm_stats[MM_NONLEAF_TOTAL]++; + +-#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG +- if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { ++ if (arch_has_hw_nonleaf_pmd_young() && ++ get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + + walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); + } +-#endif ++ + if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) + continue; + +@@ -5132,7 +5132,7 @@ static ssize_t show_enabled(struct kobje + if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) + caps |= BIT(LRU_GEN_MM_WALK); + +- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) ++ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG)) + caps |= BIT(LRU_GEN_NONLEAF_YOUNG); + + return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); diff --git a/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch b/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch new file mode 100644 index 00000000000..e37386abdf1 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch @@ -0,0 +1,56 @@ +From c7dfefd4bdfba3d5171038d1cc2d4160288e6ee4 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Sun, 15 Jan 2023 20:44:05 -0700 +Subject: [PATCH 16/29] mm: multi-gen LRU: fix crash during cgroup migration + +lru_gen_migrate_mm() assumes lru_gen_add_mm() runs prior to itself. This +isn't true for the following scenario: + + CPU 1 CPU 2 + + clone() + cgroup_can_fork() + cgroup_procs_write() + cgroup_post_fork() + task_lock() + lru_gen_migrate_mm() + task_unlock() + task_lock() + lru_gen_add_mm() + task_unlock() + +And when the above happens, kernel crashes because of linked list +corruption (mm_struct->lru_gen.list). + +Link: https://lore.kernel.org/r/20230115134651.30028-1-msizanoen@qtmlabs.xyz/ +Link: https://lkml.kernel.org/r/20230116034405.2960276-1-yuzhao@google.com +Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Yu Zhao +Reported-by: msizanoen +Tested-by: msizanoen +Cc: [6.1+] +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3024,13 +3024,16 @@ void lru_gen_migrate_mm(struct mm_struct + if (mem_cgroup_disabled()) + return; + ++ /* migration can happen before addition */ ++ if (!mm->lru_gen.memcg) ++ return; ++ + rcu_read_lock(); + memcg = mem_cgroup_from_task(task); + rcu_read_unlock(); + if (memcg == mm->lru_gen.memcg) + return; + +- VM_WARN_ON_ONCE(!mm->lru_gen.memcg); + VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); + + lru_gen_del_mm(mm); diff --git a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch new file mode 100644 index 00000000000..d740c5bd1d5 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch @@ -0,0 +1,196 @@ +From 6c7f552a48b49a8612786a28a2239fbc24fac289 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Fri, 30 Dec 2022 14:52:51 -0700 +Subject: [PATCH 19/29] mm: add vma_has_recency() + +Add vma_has_recency() to indicate whether a VMA may exhibit temporal +locality that the LRU algorithm relies on. + +This function returns false for VMAs marked by VM_SEQ_READ or +VM_RAND_READ. While the former flag indicates linear access, i.e., a +special case of spatial locality, both flags indicate a lack of temporal +locality, i.e., the reuse of an area within a relatively small duration. + +"Recency" is chosen over "locality" to avoid confusion between temporal +and spatial localities. + +Before this patch, the active/inactive LRU only ignored the accessed bit +from VMAs marked by VM_SEQ_READ. After this patch, the active/inactive +LRU and MGLRU share the same logic: they both ignore the accessed bit if +vma_has_recency() returns false. + +For the active/inactive LRU, the following fio test showed a [6, 8]% +increase in IOPS when randomly accessing mapped files under memory +pressure. + + kb=$(awk '/MemTotal/ { print $2 }' /proc/meminfo) + kb=$((kb - 8*1024*1024)) + + modprobe brd rd_nr=1 rd_size=$kb + dd if=/dev/zero of=/dev/ram0 bs=1M + + mkfs.ext4 /dev/ram0 + mount /dev/ram0 /mnt/ + swapoff -a + + fio --name=test --directory=/mnt/ --ioengine=mmap --numjobs=8 \ + --size=8G --rw=randrw --time_based --runtime=10m \ + --group_reporting + +The discussion that led to this patch is here [1]. Additional test +results are available in that thread. + +[1] https://lore.kernel.org/r/Y31s%2FK8T85jh05wH@google.com/ + +Link: https://lkml.kernel.org/r/20221230215252.2628425-1-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Alexander Viro +Cc: Andrea Righi +Cc: Johannes Weiner +Cc: Michael Larabel +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 9 +++++++++ + mm/memory.c | 8 ++++---- + mm/rmap.c | 42 +++++++++++++++++---------------------- + mm/vmscan.c | 5 ++++- + 4 files changed, 35 insertions(+), 29 deletions(-) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -333,4 +333,13 @@ static __always_inline void del_page_fro + update_lru_size(lruvec, page_lru(page), page_zonenum(page), + -thp_nr_pages(page)); + } ++ ++static inline bool vma_has_recency(struct vm_area_struct *vma) ++{ ++ if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) ++ return false; ++ ++ return true; ++} ++ + #endif +--- a/mm/memory.c ++++ b/mm/memory.c +@@ -41,6 +41,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -1353,8 +1354,7 @@ again: + force_flush = 1; + set_page_dirty(page); + } +- if (pte_young(ptent) && +- likely(!(vma->vm_flags & VM_SEQ_READ))) ++ if (pte_young(ptent) && likely(vma_has_recency(vma))) + mark_page_accessed(page); + } + rss[mm_counter(page)]--; +@@ -4795,8 +4795,8 @@ static inline void mm_account_fault(stru + #ifdef CONFIG_LRU_GEN + static void lru_gen_enter_fault(struct vm_area_struct *vma) + { +- /* the LRU algorithm doesn't apply to sequential or random reads */ +- current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); ++ /* the LRU algorithm only applies to accesses with recency */ ++ current->in_lru_fault = vma_has_recency(vma); + } + + static void lru_gen_exit_fault(void) +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -794,25 +794,14 @@ static bool page_referenced_one(struct p + } + + if (pvmw.pte) { +- if (lru_gen_enabled() && pte_young(*pvmw.pte) && +- !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { ++ if (lru_gen_enabled() && pte_young(*pvmw.pte)) { + lru_gen_look_around(&pvmw); + referenced++; + } + + if (ptep_clear_flush_young_notify(vma, address, +- pvmw.pte)) { +- /* +- * Don't treat a reference through +- * a sequentially read mapping as such. +- * If the page has been used in another mapping, +- * we will catch it; if this other mapping is +- * already gone, the unmap path will have set +- * PG_referenced or activated the page. +- */ +- if (likely(!(vma->vm_flags & VM_SEQ_READ))) +- referenced++; +- } ++ pvmw.pte)) ++ referenced++; + } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { + if (pmdp_clear_flush_young_notify(vma, address, + pvmw.pmd)) +@@ -846,7 +835,20 @@ static bool invalid_page_referenced_vma( + struct page_referenced_arg *pra = arg; + struct mem_cgroup *memcg = pra->memcg; + +- if (!mm_match_cgroup(vma->vm_mm, memcg)) ++ /* ++ * Ignore references from this mapping if it has no recency. If the ++ * page has been used in another mapping, we will catch it; if this ++ * other mapping is already gone, the unmap path will have set the ++ * referenced flag or activated the page in zap_pte_range(). ++ */ ++ if (!vma_has_recency(vma)) ++ return true; ++ ++ /* ++ * If we are reclaiming on behalf of a cgroup, skip counting on behalf ++ * of references from different cgroups. ++ */ ++ if (memcg && !mm_match_cgroup(vma->vm_mm, memcg)) + return true; + + return false; +@@ -876,6 +878,7 @@ int page_referenced(struct page *page, + .rmap_one = page_referenced_one, + .arg = (void *)&pra, + .anon_lock = page_lock_anon_vma_read, ++ .invalid_vma = invalid_page_referenced_vma, + }; + + *vm_flags = 0; +@@ -891,15 +894,6 @@ int page_referenced(struct page *page, + return 1; + } + +- /* +- * If we are reclaiming on behalf of a cgroup, skip +- * counting on behalf of references from different +- * cgroups +- */ +- if (memcg) { +- rwc.invalid_vma = invalid_page_referenced_vma; +- } +- + rmap_walk(page, &rwc); + *vm_flags = pra.vm_flags; + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3486,7 +3486,10 @@ static int should_skip_vma(unsigned long + if (is_vm_hugetlb_page(vma)) + return true; + +- if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) ++ if (!vma_has_recency(vma)) ++ return true; ++ ++ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) + return true; + + if (vma == get_gate_vma(vma->vm_mm)) diff --git a/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch b/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch new file mode 100644 index 00000000000..3bb075bf367 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch @@ -0,0 +1,125 @@ +From 686c3d4f71de9e0e7a27f03a5617a712385f90cd Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Fri, 30 Dec 2022 14:52:52 -0700 +Subject: [PATCH 20/29] mm: support POSIX_FADV_NOREUSE + +This patch adds POSIX_FADV_NOREUSE to vma_has_recency() so that the LRU +algorithm can ignore access to mapped files marked by this flag. + +The advantages of POSIX_FADV_NOREUSE are: +1. Unlike MADV_SEQUENTIAL and MADV_RANDOM, it does not alter the + default readahead behavior. +2. Unlike MADV_SEQUENTIAL and MADV_RANDOM, it does not split VMAs and + therefore does not take mmap_lock. +3. Unlike MADV_COLD, setting it has a negligible cost, regardless of + how many pages it affects. + +Its limitations are: +1. Like POSIX_FADV_RANDOM and POSIX_FADV_SEQUENTIAL, it currently does + not support range. IOW, its scope is the entire file. +2. It currently does not ignore access through file descriptors. + Specifically, for the active/inactive LRU, given a file page shared + by two users and one of them having set POSIX_FADV_NOREUSE on the + file, this page will be activated upon the second user accessing + it. This corner case can be covered by checking POSIX_FADV_NOREUSE + before calling mark_page_accessed() on the read path. But it is + considered not worth the effort. + +There have been a few attempts to support POSIX_FADV_NOREUSE, e.g., [1]. +This time the goal is to fill a niche: a few desktop applications, e.g., +large file transferring and video encoding/decoding, want fast file +streaming with mmap() rather than direct IO. Among those applications, an +SVT-AV1 regression was reported when running with MGLRU [2]. The +following test can reproduce that regression. + + kb=$(awk '/MemTotal/ { print $2 }' /proc/meminfo) + kb=$((kb - 8*1024*1024)) + + modprobe brd rd_nr=1 rd_size=$kb + dd if=/dev/zero of=/dev/ram0 bs=1M + + mkfs.ext4 /dev/ram0 + mount /dev/ram0 /mnt/ + swapoff -a + + fallocate -l 8G /mnt/swapfile + mkswap /mnt/swapfile + swapon /mnt/swapfile + + wget http://ultravideo.cs.tut.fi/video/Bosphorus_3840x2160_120fps_420_8bit_YUV_Y4M.7z + 7z e -o/mnt/ Bosphorus_3840x2160_120fps_420_8bit_YUV_Y4M.7z + SvtAv1EncApp --preset 12 -w 3840 -h 2160 \ + -i /mnt/Bosphorus_3840x2160.y4m + +For MGLRU, the following change showed a [9-11]% increase in FPS, +which makes it on par with the active/inactive LRU. + + patch Source/App/EncApp/EbAppMain.c < #include + 35d35 + < #include /* _O_BINARY */ + 117a118 + > posix_fadvise(config->mmap.fd, 0, 0, POSIX_FADV_NOREUSE); + EOF + +[1] https://lore.kernel.org/r/1308923350-7932-1-git-send-email-andrea@betterlinux.com/ +[2] https://openbenchmarking.org/result/2209259-PTS-MGLRU8GB57 + +Link: https://lkml.kernel.org/r/20221230215252.2628425-2-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Alexander Viro +Cc: Andrea Righi +Cc: Johannes Weiner +Cc: Michael Larabel +Signed-off-by: Andrew Morton +--- + include/linux/fs.h | 2 ++ + include/linux/mm_inline.h | 3 +++ + mm/fadvise.c | 5 ++++- + 3 files changed, 9 insertions(+), 1 deletion(-) + +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -167,6 +167,8 @@ typedef int (dio_iodone_t)(struct kiocb + /* File is stream-like */ + #define FMODE_STREAM ((__force fmode_t)0x200000) + ++#define FMODE_NOREUSE ((__force fmode_t)0x400000) ++ + /* File was opened by fanotify and shouldn't generate fanotify events */ + #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -339,6 +339,9 @@ static inline bool vma_has_recency(struc + if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) + return false; + ++ if (vma->vm_file && (vma->vm_file->f_mode & FMODE_NOREUSE)) ++ return false; ++ + return true; + } + +--- a/mm/fadvise.c ++++ b/mm/fadvise.c +@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, l + case POSIX_FADV_NORMAL: + file->f_ra.ra_pages = bdi->ra_pages; + spin_lock(&file->f_lock); +- file->f_mode &= ~FMODE_RANDOM; ++ file->f_mode &= ~(FMODE_RANDOM | FMODE_NOREUSE); + spin_unlock(&file->f_lock); + break; + case POSIX_FADV_RANDOM: +@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, l + force_page_cache_readahead(mapping, file, start_index, nrpages); + break; + case POSIX_FADV_NOREUSE: ++ spin_lock(&file->f_lock); ++ file->f_mode |= FMODE_NOREUSE; ++ spin_unlock(&file->f_lock); + break; + case POSIX_FADV_DONTNEED: + if (!inode_write_congested(mapping->host)) diff --git a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch new file mode 100644 index 00000000000..4e09173681f --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch @@ -0,0 +1,348 @@ +From 348fdbada9fb3f0bf1a53651be46319105af187f Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:18:59 -0700 +Subject: [PATCH 21/29] mm: multi-gen LRU: rename lru_gen_struct to + lru_gen_page + +Patch series "mm: multi-gen LRU: memcg LRU", v3. + +Overview +======== + +An memcg LRU is a per-node LRU of memcgs. It is also an LRU of LRUs, +since each node and memcg combination has an LRU of pages (see +mem_cgroup_lruvec()). + +Its goal is to improve the scalability of global reclaim, which is +critical to system-wide memory overcommit in data centers. Note that +memcg reclaim is currently out of scope. + +Its memory bloat is a pointer to each lruvec and negligible to each +pglist_data. In terms of traversing memcgs during global reclaim, it +improves the best-case complexity from O(n) to O(1) and does not affect +the worst-case complexity O(n). Therefore, on average, it has a sublinear +complexity in contrast to the current linear complexity. + +The basic structure of an memcg LRU can be understood by an analogy to +the active/inactive LRU (of pages): +1. It has the young and the old (generations), i.e., the counterparts + to the active and the inactive; +2. The increment of max_seq triggers promotion, i.e., the counterpart + to activation; +3. Other events trigger similar operations, e.g., offlining an memcg + triggers demotion, i.e., the counterpart to deactivation. + +In terms of global reclaim, it has two distinct features: +1. Sharding, which allows each thread to start at a random memcg (in + the old generation) and improves parallelism; +2. Eventual fairness, which allows direct reclaim to bail out at will + and reduces latency without affecting fairness over some time. + +The commit message in patch 6 details the workflow: +https://lore.kernel.org/r/20221222041905.2431096-7-yuzhao@google.com/ + +The following is a simple test to quickly verify its effectiveness. + + Test design: + 1. Create multiple memcgs. + 2. Each memcg contains a job (fio). + 3. All jobs access the same amount of memory randomly. + 4. The system does not experience global memory pressure. + 5. Periodically write to the root memory.reclaim. + + Desired outcome: + 1. All memcgs have similar pgsteal counts, i.e., stddev(pgsteal) + over mean(pgsteal) is close to 0%. + 2. The total pgsteal is close to the total requested through + memory.reclaim, i.e., sum(pgsteal) over sum(requested) is close + to 100%. + + Actual outcome [1]: + MGLRU off MGLRU on + stddev(pgsteal) / mean(pgsteal) 75% 20% + sum(pgsteal) / sum(requested) 425% 95% + + #################################################################### + MEMCGS=128 + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + mkdir /sys/fs/cgroup/memcg$memcg + done + + start() { + echo $BASHPID > /sys/fs/cgroup/memcg$memcg/cgroup.procs + + fio -name=memcg$memcg --numjobs=1 --ioengine=mmap \ + --filename=/dev/zero --size=1920M --rw=randrw \ + --rate=64m,64m --random_distribution=random \ + --fadvise_hint=0 --time_based --runtime=10h \ + --group_reporting --minimal + } + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + start & + done + + sleep 600 + + for ((i = 0; i < 600; i++)); do + echo 256m >/sys/fs/cgroup/memory.reclaim + sleep 6 + done + + for ((memcg = 0; memcg < $MEMCGS; memcg++)); do + grep "pgsteal " /sys/fs/cgroup/memcg$memcg/memory.stat + done + #################################################################### + +[1]: This was obtained from running the above script (touches less + than 256GB memory) on an EPYC 7B13 with 512GB DRAM for over an + hour. + +This patch (of 8): + +The new name lru_gen_page will be more distinct from the coming +lru_gen_memcg. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-1-yuzhao@google.com +Link: https://lkml.kernel.org/r/20221222041905.2431096-2-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 4 ++-- + include/linux/mmzone.h | 6 +++--- + mm/vmscan.c | 34 +++++++++++++++++----------------- + mm/workingset.c | 4 ++-- + 4 files changed, 24 insertions(+), 24 deletions(-) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -168,7 +168,7 @@ static inline void lru_gen_update_size(s + int zone = page_zonenum(page); + int delta = thp_nr_pages(page); + enum lru_list lru = type * LRU_INACTIVE_FILE; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); + VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); +@@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(stru + int gen = page_lru_gen(page); + int type = page_is_file_lru(page); + int zone = page_zonenum(page); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE_PAGE(gen != -1, page); + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -394,7 +394,7 @@ enum { + * The number of pages in each generation is eventually consistent and therefore + * can be transiently negative when reset_batch_size() is pending. + */ +-struct lru_gen_struct { ++struct lru_gen_page { + /* the aging increments the youngest generation number */ + unsigned long max_seq; + /* the eviction increments the oldest generation numbers */ +@@ -451,7 +451,7 @@ struct lru_gen_mm_state { + struct lru_gen_mm_walk { + /* the lruvec under reclaim */ + struct lruvec *lruvec; +- /* unstable max_seq from lru_gen_struct */ ++ /* unstable max_seq from lru_gen_page */ + unsigned long max_seq; + /* the next address within an mm to scan */ + unsigned long next_addr; +@@ -514,7 +514,7 @@ struct lruvec { + unsigned long flags; + #ifdef CONFIG_LRU_GEN + /* evictable pages divided into generations */ +- struct lru_gen_struct lrugen; ++ struct lru_gen_page lrugen; + /* to concurrently iterate lru_gen_mm_list */ + struct lru_gen_mm_state mm_state; + #endif +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2910,7 +2910,7 @@ static int get_nr_gens(struct lruvec *lr + + static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) + { +- /* see the comment on lru_gen_struct */ ++ /* see the comment on lru_gen_page */ + return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && + get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; +@@ -3316,7 +3316,7 @@ struct ctrl_pos { + static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, + struct ctrl_pos *pos) + { +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + pos->refaulted = lrugen->avg_refaulted[type][tier] + +@@ -3331,7 +3331,7 @@ static void read_ctrl_pos(struct lruvec + static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) + { + int hist, tier; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; + unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; + +@@ -3408,7 +3408,7 @@ static int page_update_gen(struct page * + static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) + { + int type = page_is_file_lru(page); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + unsigned long new_flags, old_flags = READ_ONCE(page->flags); + +@@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru + static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) + { + int gen, type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + walk->batched = 0; + +@@ -3979,7 +3979,7 @@ static bool inc_min_seq(struct lruvec *l + { + int zone; + int remaining = MAX_LRU_BATCH; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); + + if (type == LRU_GEN_ANON && !can_swap) +@@ -4015,7 +4015,7 @@ static bool try_to_inc_min_seq(struct lr + { + int gen, type, zone; + bool success = false; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + DEFINE_MIN_SEQ(lruvec); + + VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); +@@ -4036,7 +4036,7 @@ next: + ; + } + +- /* see the comment on lru_gen_struct */ ++ /* see the comment on lru_gen_page */ + if (can_swap) { + min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); + min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); +@@ -4058,7 +4058,7 @@ static void inc_max_seq(struct lruvec *l + { + int prev, next; + int type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + spin_lock_irq(&lruvec->lru_lock); + +@@ -4116,7 +4116,7 @@ static bool try_to_inc_max_seq(struct lr + bool success; + struct lru_gen_mm_walk *walk; + struct mm_struct *mm = NULL; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); + +@@ -4181,7 +4181,7 @@ static bool should_run_aging(struct lruv + unsigned long old = 0; + unsigned long young = 0; + unsigned long total = 0; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + for (type = !can_swap; type < ANON_AND_FILE; type++) { +@@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lru + int delta = thp_nr_pages(page); + int refs = page_lru_refs(page); + int tier = lru_tier_from_refs(refs); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); + +@@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lru + int scanned = 0; + int isolated = 0; + int remaining = MAX_LRU_BATCH; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + + VM_WARN_ON_ONCE(!list_empty(list)); +@@ -4967,7 +4967,7 @@ done: + + static bool __maybe_unused state_is_valid(struct lruvec *lruvec) + { +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + if (lrugen->enabled) { + enum lru_list lru; +@@ -5247,7 +5247,7 @@ static void lru_gen_seq_show_full(struct + int i; + int type, tier; + int hist = lru_hist_from_seq(seq); +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + for (tier = 0; tier < MAX_NR_TIERS; tier++) { + seq_printf(m, " %10d", tier); +@@ -5296,7 +5296,7 @@ static int lru_gen_seq_show(struct seq_f + unsigned long seq; + bool full = !debugfs_real_fops(m->file)->write; + struct lruvec *lruvec = v; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + int nid = lruvec_pgdat(lruvec)->node_id; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +@@ -5549,7 +5549,7 @@ void lru_gen_init_lruvec(struct lruvec * + { + int i; + int gen, type, zone; +- struct lru_gen_struct *lrugen = &lruvec->lrugen; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + + lrugen->max_seq = MIN_NR_GENS + 1; + lrugen->enabled = lru_gen_enabled(); +--- a/mm/workingset.c ++++ b/mm/workingset.c +@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct pag + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; +- struct lru_gen_struct *lrugen; ++ struct lru_gen_page *lrugen; + int type = page_is_file_lru(page); + int delta = thp_nr_pages(page); + int refs = page_lru_refs(page); +@@ -252,7 +252,7 @@ static void lru_gen_refault(struct page + unsigned long token; + unsigned long min_seq; + struct lruvec *lruvec; +- struct lru_gen_struct *lrugen; ++ struct lru_gen_page *lrugen; + struct mem_cgroup *memcg; + struct pglist_data *pgdat; + int type = page_is_file_lru(page); diff --git a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch new file mode 100644 index 00000000000..b548c1c8b3d --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch @@ -0,0 +1,162 @@ +From afd37e73db04c7e6b47411120ac5f6a7eca51fec Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:00 -0700 +Subject: [PATCH 22/29] mm: multi-gen LRU: rename lrugen->lists[] to + lrugen->pages[] + +lru_gen_page will be chained into per-node lists by the coming +lrugen->list. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-3-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mm_inline.h | 4 ++-- + include/linux/mmzone.h | 8 ++++---- + mm/vmscan.c | 20 ++++++++++---------- + 3 files changed, 16 insertions(+), 16 deletions(-) + +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(stru + lru_gen_update_size(lruvec, page, -1, gen); + /* for rotate_reclaimable_page() */ + if (reclaiming) +- list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_add_tail(&page->lru, &lrugen->pages[gen][type][zone]); + else +- list_add(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_add(&page->lru, &lrugen->pages[gen][type][zone]); + + return true; + } +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -302,7 +302,7 @@ enum lruvec_flags { + * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An + * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the + * corresponding generation. The gen counter in page->flags stores gen+1 while +- * a page is on one of lrugen->lists[]. Otherwise it stores 0. ++ * a page is on one of lrugen->pages[]. Otherwise it stores 0. + * + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the +@@ -314,8 +314,8 @@ enum lruvec_flags { + * rest of generations, if they exist, are considered inactive. See + * lru_gen_is_active(). + * +- * PG_active is always cleared while a page is on one of lrugen->lists[] so that +- * the aging needs not to worry about it. And it's set again when a page ++ * PG_active is always cleared while a page is on one of lrugen->pages[] so ++ * that the aging needs not to worry about it. And it's set again when a page + * considered active is isolated for non-reclaiming purposes, e.g., migration. + * See lru_gen_add_page() and lru_gen_del_page(). + * +@@ -402,7 +402,7 @@ struct lru_gen_page { + /* the birth time of each generation in jiffies */ + unsigned long timestamps[MAX_NR_GENS]; + /* the multi-gen LRU lists, lazily sorted on eviction */ +- struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ struct list_head pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the multi-gen LRU sizes, eventually consistent */ + long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + /* the exponential moving average of refaulted */ +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3987,7 +3987,7 @@ static bool inc_min_seq(struct lruvec *l + + /* prevent cold/hot inversion if force_scan is true */ + for (zone = 0; zone < MAX_NR_ZONES; zone++) { +- struct list_head *head = &lrugen->lists[old_gen][type][zone]; ++ struct list_head *head = &lrugen->pages[old_gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); +@@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *l + VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); + + new_gen = page_inc_gen(lruvec, page, false); +- list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); ++ list_move_tail(&page->lru, &lrugen->pages[new_gen][type][zone]); + + if (!--remaining) + return false; +@@ -4026,7 +4026,7 @@ static bool try_to_inc_min_seq(struct lr + gen = lru_gen_from_seq(min_seq[type]); + + for (zone = 0; zone < MAX_NR_ZONES; zone++) { +- if (!list_empty(&lrugen->lists[gen][type][zone])) ++ if (!list_empty(&lrugen->pages[gen][type][zone])) + goto next; + } + +@@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lru + + /* promoted */ + if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { +- list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&page->lru, &lrugen->pages[gen][type][zone]); + return true; + } + +@@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lru + int hist = lru_hist_from_seq(lrugen->min_seq[type]); + + gen = page_inc_gen(lruvec, page, false); +- list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move_tail(&page->lru, &lrugen->pages[gen][type][zone]); + + WRITE_ONCE(lrugen->protected[hist][type][tier - 1], + lrugen->protected[hist][type][tier - 1] + delta); +@@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lru + if (PageLocked(page) || PageWriteback(page) || + (type == LRU_GEN_FILE && PageDirty(page))) { + gen = page_inc_gen(lruvec, page, true); +- list_move(&page->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&page->lru, &lrugen->pages[gen][type][zone]); + return true; + } + +@@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lru + for (zone = sc->reclaim_idx; zone >= 0; zone--) { + LIST_HEAD(moved); + int skipped = 0; +- struct list_head *head = &lrugen->lists[gen][type][zone]; ++ struct list_head *head = &lrugen->pages[gen][type][zone]; + + while (!list_empty(head)) { + struct page *page = lru_to_page(head); +@@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_vali + int gen, type, zone; + + for_each_gen_type_zone(gen, type, zone) { +- if (!list_empty(&lrugen->lists[gen][type][zone])) ++ if (!list_empty(&lrugen->pages[gen][type][zone])) + return false; + } + } +@@ -5025,7 +5025,7 @@ static bool drain_evictable(struct lruve + int remaining = MAX_LRU_BATCH; + + for_each_gen_type_zone(gen, type, zone) { +- struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; ++ struct list_head *head = &lruvec->lrugen.pages[gen][type][zone]; + + while (!list_empty(head)) { + bool success; +@@ -5558,7 +5558,7 @@ void lru_gen_init_lruvec(struct lruvec * + lrugen->timestamps[i] = jiffies; + + for_each_gen_type_zone(gen, type, zone) +- INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); ++ INIT_LIST_HEAD(&lrugen->pages[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; + init_waitqueue_head(&lruvec->mm_state.wait); diff --git a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch new file mode 100644 index 00000000000..2bb6e12a5ae --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch @@ -0,0 +1,188 @@ +From ce45f1c4b32cf69b166f56ef5bc6c761e06ed4e5 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:01 -0700 +Subject: [PATCH 23/29] mm: multi-gen LRU: remove eviction fairness safeguard + +Recall that the eviction consumes the oldest generation: first it +bucket-sorts pages whose gen counters were updated by the aging and +reclaims the rest; then it increments lrugen->min_seq. + +The current eviction fairness safeguard for global reclaim has a +dilemma: when there are multiple eligible memcgs, should it continue +or stop upon meeting the reclaim goal? If it continues, it overshoots +and increases direct reclaim latency; if it stops, it loses fairness +between memcgs it has taken memory away from and those it has yet to. + +With memcg LRU, the eviction, while ensuring eventual fairness, will +stop upon meeting its goal. Therefore the current eviction fairness +safeguard for global reclaim will not be needed. + +Note that memcg LRU only applies to global reclaim. For memcg reclaim, +the eviction will continue, even if it is overshooting. This becomes +unconditional due to code simplification. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-4-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 82 +++++++++++++++-------------------------------------- + 1 file changed, 23 insertions(+), 59 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -443,6 +443,11 @@ static bool cgroup_reclaim(struct scan_c + return sc->target_mem_cgroup; + } + ++static bool global_reclaim(struct scan_control *sc) ++{ ++ return !sc->target_mem_cgroup || mem_cgroup_is_root(sc->target_mem_cgroup); ++} ++ + /** + * writeback_throttling_sane - is the usual dirty throttling mechanism available? + * @sc: scan_control in question +@@ -493,6 +498,11 @@ static bool cgroup_reclaim(struct scan_c + return false; + } + ++static bool global_reclaim(struct scan_control *sc) ++{ ++ return true; ++} ++ + static bool writeback_throttling_sane(struct scan_control *sc) + { + return true; +@@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec * + return scanned; + } + +-static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, +- bool *need_swapping) ++static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) + { + int type; + int scanned; +@@ -4812,9 +4821,6 @@ retry: + goto retry; + } + +- if (need_swapping && type == LRU_GEN_ANON) +- *need_swapping = true; +- + return scanned; + } + +@@ -4853,68 +4859,26 @@ done: + return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; + } + +-static bool should_abort_scan(struct lruvec *lruvec, unsigned long seq, +- struct scan_control *sc, bool need_swapping) ++static unsigned long get_nr_to_reclaim(struct scan_control *sc) + { +- int i; +- DEFINE_MAX_SEQ(lruvec); +- +- if (!current_is_kswapd()) { +- /* age each memcg once to ensure fairness */ +- if (max_seq - seq > 1) +- return true; +- +- /* over-swapping can increase allocation latency */ +- if (sc->nr_reclaimed >= sc->nr_to_reclaim && need_swapping) +- return true; +- +- /* give this thread a chance to exit and free its memory */ +- if (fatal_signal_pending(current)) { +- sc->nr_reclaimed += MIN_LRU_BATCH; +- return true; +- } +- +- if (cgroup_reclaim(sc)) +- return false; +- } else if (sc->nr_reclaimed - sc->last_reclaimed < sc->nr_to_reclaim) +- return false; +- +- /* keep scanning at low priorities to ensure fairness */ +- if (sc->priority > DEF_PRIORITY - 2) +- return false; +- +- /* +- * A minimum amount of work was done under global memory pressure. For +- * kswapd, it may be overshooting. For direct reclaim, the target isn't +- * met, and yet the allocation may still succeed, since kswapd may have +- * caught up. In either case, it's better to stop now, and restart if +- * necessary. +- */ +- for (i = 0; i <= sc->reclaim_idx; i++) { +- unsigned long wmark; +- struct zone *zone = lruvec_pgdat(lruvec)->node_zones + i; +- +- if (!managed_zone(zone)) +- continue; +- +- wmark = current_is_kswapd() ? high_wmark_pages(zone) : low_wmark_pages(zone); +- if (wmark > zone_page_state(zone, NR_FREE_PAGES)) +- return false; +- } ++ /* don't abort memcg reclaim to ensure fairness */ ++ if (!global_reclaim(sc)) ++ return -1; + +- sc->nr_reclaimed += MIN_LRU_BATCH; ++ /* discount the previous progress for kswapd */ ++ if (current_is_kswapd()) ++ return sc->nr_to_reclaim + sc->last_reclaimed; + +- return true; ++ return max(sc->nr_to_reclaim, compact_gap(sc->order)); + } + + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; + bool need_aging = false; +- bool need_swapping = false; + unsigned long scanned = 0; + unsigned long reclaimed = sc->nr_reclaimed; +- DEFINE_MAX_SEQ(lruvec); ++ unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + lru_add_drain(); + +@@ -4938,7 +4902,7 @@ static void lru_gen_shrink_lruvec(struct + if (!nr_to_scan) + goto done; + +- delta = evict_pages(lruvec, sc, swappiness, &need_swapping); ++ delta = evict_pages(lruvec, sc, swappiness); + if (!delta) + goto done; + +@@ -4946,7 +4910,7 @@ static void lru_gen_shrink_lruvec(struct + if (scanned >= nr_to_scan) + break; + +- if (should_abort_scan(lruvec, max_seq, sc, need_swapping)) ++ if (sc->nr_reclaimed >= nr_to_reclaim) + break; + + cond_resched(); +@@ -5393,7 +5357,7 @@ static int run_eviction(struct lruvec *l + if (sc->nr_reclaimed >= nr_to_reclaim) + return 0; + +- if (!evict_pages(lruvec, sc, swappiness, NULL)) ++ if (!evict_pages(lruvec, sc, swappiness)) + return 0; + + cond_resched(); diff --git a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch new file mode 100644 index 00000000000..316217ed028 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch @@ -0,0 +1,287 @@ +From e20b7386fccc18c791796eb1dc1a91eee3ccf801 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:02 -0700 +Subject: [PATCH 24/29] mm: multi-gen LRU: remove aging fairness safeguard + +Recall that the aging produces the youngest generation: first it scans +for accessed pages and updates their gen counters; then it increments +lrugen->max_seq. + +The current aging fairness safeguard for kswapd uses two passes to +ensure the fairness to multiple eligible memcgs. On the first pass, +which is shared with the eviction, it checks whether all eligible +memcgs are low on cold pages. If so, it requires a second pass, on +which it ages all those memcgs at the same time. + +With memcg LRU, the aging, while ensuring eventual fairness, will run +when necessary. Therefore the current aging fairness safeguard for +kswapd will not be needed. + +Note that memcg LRU only applies to global reclaim. For memcg reclaim, +the aging can be unfair to different memcgs, i.e., their +lrugen->max_seq can be incremented at different paces. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-5-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 126 ++++++++++++++++++++++++---------------------------- + 1 file changed, 59 insertions(+), 67 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -131,7 +131,6 @@ struct scan_control { + + #ifdef CONFIG_LRU_GEN + /* help kswapd make better choices among multiple memcgs */ +- unsigned int memcgs_need_aging:1; + unsigned long last_reclaimed; + #endif + +@@ -4184,7 +4183,7 @@ done: + return true; + } + +-static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, + struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) + { + int gen, type, zone; +@@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruv + unsigned long total = 0; + struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* whether this lruvec is completely out of cold pages */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { ++ *nr_to_scan = 0; ++ return true; ++ } + + for (type = !can_swap; type < ANON_AND_FILE; type++) { + unsigned long seq; +@@ -4221,8 +4227,6 @@ static bool should_run_aging(struct lruv + * stalls when the number of generations reaches MIN_NR_GENS. Hence, the + * ideal number of generations is MIN_NR_GENS+1. + */ +- if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) +- return true; + if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) + return false; + +@@ -4241,40 +4245,54 @@ static bool should_run_aging(struct lruv + return false; + } + +-static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned long min_ttl) ++static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) + { +- bool need_aging; +- unsigned long nr_to_scan; +- int swappiness = get_swappiness(lruvec, sc); ++ int gen, type, zone; ++ unsigned long total = 0; ++ bool can_swap = get_swappiness(lruvec, sc); ++ struct lru_gen_page *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + DEFINE_MIN_SEQ(lruvec); + +- VM_WARN_ON_ONCE(sc->memcg_low_reclaim); ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; + +- mem_cgroup_calculate_protection(NULL, memcg); ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ gen = lru_gen_from_seq(seq); + +- if (mem_cgroup_below_min(memcg)) +- return false; ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ total += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ } ++ } + +- need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); ++ /* whether the size is big enough to be helpful */ ++ return mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++} + +- if (min_ttl) { +- int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); +- unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); ++static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc, ++ unsigned long min_ttl) ++{ ++ int gen; ++ unsigned long birth; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); + +- if (time_is_after_jiffies(birth + min_ttl)) +- return false; ++ VM_WARN_ON_ONCE(sc->memcg_low_reclaim); + +- /* the size is likely too small to be helpful */ +- if (!nr_to_scan && sc->priority != DEF_PRIORITY) +- return false; +- } ++ /* see the comment on lru_gen_page */ ++ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); ++ birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); + +- if (need_aging) +- try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); ++ if (time_is_after_jiffies(birth + min_ttl)) ++ return false; + +- return true; ++ if (!lruvec_is_sizable(lruvec, sc)) ++ return false; ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ return !mem_cgroup_below_min(memcg); + } + + /* to protect the working set of the last N jiffies */ +@@ -4283,46 +4301,32 @@ static unsigned long lru_gen_min_ttl __r + static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + { + struct mem_cgroup *memcg; +- bool success = false; + unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); + + VM_WARN_ON_ONCE(!current_is_kswapd()); + + sc->last_reclaimed = sc->nr_reclaimed; + +- /* +- * To reduce the chance of going into the aging path, which can be +- * costly, optimistically skip it if the flag below was cleared in the +- * eviction path. This improves the overall performance when multiple +- * memcgs are available. +- */ +- if (!sc->memcgs_need_aging) { +- sc->memcgs_need_aging = true; ++ /* check the order to exclude compaction-induced reclaim */ ++ if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) + return; +- } +- +- set_mm_walk(pgdat); + + memcg = mem_cgroup_iter(NULL, NULL, NULL); + do { + struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); + +- if (age_lruvec(lruvec, sc, min_ttl)) +- success = true; ++ if (lruvec_is_reclaimable(lruvec, sc, min_ttl)) { ++ mem_cgroup_iter_break(NULL, memcg); ++ return; ++ } + + cond_resched(); + } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); + +- clear_mm_walk(); +- +- /* check the order to exclude compaction-induced reclaim */ +- if (success || !min_ttl || sc->order) +- return; +- + /* + * The main goal is to OOM kill if every generation from all memcgs is + * younger than min_ttl. However, another possibility is all memcgs are +- * either below min or empty. ++ * either too small or below min. + */ + if (mutex_trylock(&oom_lock)) { + struct oom_control oc = { +@@ -4830,33 +4834,27 @@ retry: + * reclaim. + */ + static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap, bool *need_aging) ++ bool can_swap) + { + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); +- DEFINE_MIN_SEQ(lruvec); + + if (mem_cgroup_below_min(memcg) || + (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) + return 0; + +- *need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); +- if (!*need_aging) ++ if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) + return nr_to_scan; + + /* skip the aging path at the default priority */ + if (sc->priority == DEF_PRIORITY) +- goto done; ++ return nr_to_scan; + +- /* leave the work to lru_gen_age_node() */ +- if (current_is_kswapd()) +- return 0; ++ try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); + +- if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) +- return nr_to_scan; +-done: +- return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; ++ /* skip this lruvec as it's low on cold pages */ ++ return 0; + } + + static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4875,9 +4873,7 @@ static unsigned long get_nr_to_reclaim(s + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { + struct blk_plug plug; +- bool need_aging = false; + unsigned long scanned = 0; +- unsigned long reclaimed = sc->nr_reclaimed; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + lru_add_drain(); +@@ -4898,13 +4894,13 @@ static void lru_gen_shrink_lruvec(struct + else + swappiness = 0; + +- nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, &need_aging); ++ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (!nr_to_scan) +- goto done; ++ break; + + delta = evict_pages(lruvec, sc, swappiness); + if (!delta) +- goto done; ++ break; + + scanned += delta; + if (scanned >= nr_to_scan) +@@ -4916,10 +4912,6 @@ static void lru_gen_shrink_lruvec(struct + cond_resched(); + } + +- /* see the comment in lru_gen_age_node() */ +- if (sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH && !need_aging) +- sc->memcgs_need_aging = false; +-done: + clear_mm_walk(); + + blk_finish_plug(&plug); diff --git a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch new file mode 100644 index 00000000000..391ee6e67ce --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -0,0 +1,161 @@ +From 107d54931df3c28d81648122e219bf0034ef4e99 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:03 -0700 +Subject: [PATCH 25/29] mm: multi-gen LRU: shuffle should_run_aging() + +Move should_run_aging() next to its only caller left. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-6-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 124 ++++++++++++++++++++++++++-------------------------- + 1 file changed, 62 insertions(+), 62 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4183,68 +4183,6 @@ done: + return true; + } + +-static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, +- struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) +-{ +- int gen, type, zone; +- unsigned long old = 0; +- unsigned long young = 0; +- unsigned long total = 0; +- struct lru_gen_page *lrugen = &lruvec->lrugen; +- struct mem_cgroup *memcg = lruvec_memcg(lruvec); +- DEFINE_MIN_SEQ(lruvec); +- +- /* whether this lruvec is completely out of cold pages */ +- if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { +- *nr_to_scan = 0; +- return true; +- } +- +- for (type = !can_swap; type < ANON_AND_FILE; type++) { +- unsigned long seq; +- +- for (seq = min_seq[type]; seq <= max_seq; seq++) { +- unsigned long size = 0; +- +- gen = lru_gen_from_seq(seq); +- +- for (zone = 0; zone < MAX_NR_ZONES; zone++) +- size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); +- +- total += size; +- if (seq == max_seq) +- young += size; +- else if (seq + MIN_NR_GENS == max_seq) +- old += size; +- } +- } +- +- /* try to scrape all its memory if this memcg was deleted */ +- *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; +- +- /* +- * The aging tries to be lazy to reduce the overhead, while the eviction +- * stalls when the number of generations reaches MIN_NR_GENS. Hence, the +- * ideal number of generations is MIN_NR_GENS+1. +- */ +- if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) +- return false; +- +- /* +- * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) +- * of the total number of pages for each generation. A reasonable range +- * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The +- * aging cares about the upper bound of hot pages, while the eviction +- * cares about the lower bound of cold pages. +- */ +- if (young * MIN_NR_GENS > total) +- return true; +- if (old * (MIN_NR_GENS + 2) < total) +- return true; +- +- return false; +-} +- + static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) + { + int gen, type, zone; +@@ -4828,6 +4766,68 @@ retry: + return scanned; + } + ++static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, ++ struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) ++{ ++ int gen, type, zone; ++ unsigned long old = 0; ++ unsigned long young = 0; ++ unsigned long total = 0; ++ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ DEFINE_MIN_SEQ(lruvec); ++ ++ /* whether this lruvec is completely out of cold pages */ ++ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { ++ *nr_to_scan = 0; ++ return true; ++ } ++ ++ for (type = !can_swap; type < ANON_AND_FILE; type++) { ++ unsigned long seq; ++ ++ for (seq = min_seq[type]; seq <= max_seq; seq++) { ++ unsigned long size = 0; ++ ++ gen = lru_gen_from_seq(seq); ++ ++ for (zone = 0; zone < MAX_NR_ZONES; zone++) ++ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); ++ ++ total += size; ++ if (seq == max_seq) ++ young += size; ++ else if (seq + MIN_NR_GENS == max_seq) ++ old += size; ++ } ++ } ++ ++ /* try to scrape all its memory if this memcg was deleted */ ++ *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; ++ ++ /* ++ * The aging tries to be lazy to reduce the overhead, while the eviction ++ * stalls when the number of generations reaches MIN_NR_GENS. Hence, the ++ * ideal number of generations is MIN_NR_GENS+1. ++ */ ++ if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) ++ return false; ++ ++ /* ++ * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) ++ * of the total number of pages for each generation. A reasonable range ++ * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The ++ * aging cares about the upper bound of hot pages, while the eviction ++ * cares about the lower bound of cold pages. ++ */ ++ if (young * MIN_NR_GENS > total) ++ return true; ++ if (old * (MIN_NR_GENS + 2) < total) ++ return true; ++ ++ return false; ++} ++ + /* + * For future optimizations: + * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg diff --git a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch new file mode 100644 index 00000000000..f54e828de10 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch @@ -0,0 +1,868 @@ +From fa6363828d314e837c5f79e97ea5e8c0d2f7f062 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:04 -0700 +Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_page lists + +For each node, memcgs are divided into two generations: the old and +the young. For each generation, memcgs are randomly sharded into +multiple bins to improve scalability. For each bin, an RCU hlist_nulls +is virtually divided into three segments: the head, the tail and the +default. + +An onlining memcg is added to the tail of a random bin in the old +generation. The eviction starts at the head of a random bin in the old +generation. The per-node memcg generation counter, whose reminder (mod +2) indexes the old generation, is incremented when all its bins become +empty. + +There are four operations: +1. MEMCG_LRU_HEAD, which moves an memcg to the head of a random bin in + its current generation (old or young) and updates its "seg" to + "head"; +2. MEMCG_LRU_TAIL, which moves an memcg to the tail of a random bin in + its current generation (old or young) and updates its "seg" to + "tail"; +3. MEMCG_LRU_OLD, which moves an memcg to the head of a random bin in + the old generation, updates its "gen" to "old" and resets its "seg" + to "default"; +4. MEMCG_LRU_YOUNG, which moves an memcg to the tail of a random bin + in the young generation, updates its "gen" to "young" and resets + its "seg" to "default". + +The events that trigger the above operations are: +1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; +2. The first attempt to reclaim an memcg below low, which triggers + MEMCG_LRU_TAIL; +3. The first attempt to reclaim an memcg below reclaimable size + threshold, which triggers MEMCG_LRU_TAIL; +4. The second attempt to reclaim an memcg below reclaimable size + threshold, which triggers MEMCG_LRU_YOUNG; +5. Attempting to reclaim an memcg below min, which triggers + MEMCG_LRU_YOUNG; +6. Finishing the aging on the eviction path, which triggers + MEMCG_LRU_YOUNG; +7. Offlining an memcg, which triggers MEMCG_LRU_OLD. + +Note that memcg LRU only applies to global reclaim, and the +round-robin incrementing of their max_seq counters ensures the +eventual fairness to all eligible memcgs. For memcg reclaim, it still +relies on mem_cgroup_iter(). + +Link: https://lkml.kernel.org/r/20221222041905.2431096-7-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/memcontrol.h | 10 + + include/linux/mm_inline.h | 17 ++ + include/linux/mmzone.h | 117 +++++++++++- + mm/memcontrol.c | 16 ++ + mm/page_alloc.c | 1 + + mm/vmscan.c | 373 +++++++++++++++++++++++++++++++++---- + 6 files changed, 499 insertions(+), 35 deletions(-) + +--- a/include/linux/memcontrol.h ++++ b/include/linux/memcontrol.h +@@ -818,6 +818,11 @@ static inline void obj_cgroup_put(struct + percpu_ref_put(&objcg->refcnt); + } + ++static inline bool mem_cgroup_tryget(struct mem_cgroup *memcg) ++{ ++ return !memcg || css_tryget(&memcg->css); ++} ++ + static inline void mem_cgroup_put(struct mem_cgroup *memcg) + { + if (memcg) +@@ -1283,6 +1288,11 @@ struct mem_cgroup *mem_cgroup_from_css(s + return NULL; + } + ++static inline bool mem_cgroup_tryget(struct mem_cgroup *memcg) ++{ ++ return true; ++} ++ + static inline void mem_cgroup_put(struct mem_cgroup *memcg) + { + } +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -112,6 +112,18 @@ static inline bool lru_gen_in_fault(void + return current->in_lru_fault; + } + ++#ifdef CONFIG_MEMCG ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return READ_ONCE(lruvec->lrugen.seg); ++} ++#else ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return 0; ++} ++#endif ++ + static inline int lru_gen_from_seq(unsigned long seq) + { + return seq % MAX_NR_GENS; +@@ -287,6 +299,11 @@ static inline bool lru_gen_in_fault(void + return false; + } + ++static inline int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return 0; ++} ++ + static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) + { + return false; +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -7,6 +7,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -357,6 +358,15 @@ struct page_vma_mapped_walk; + #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) + #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) + ++/* see the comment on MEMCG_NR_GENS */ ++enum { ++ MEMCG_LRU_NOP, ++ MEMCG_LRU_HEAD, ++ MEMCG_LRU_TAIL, ++ MEMCG_LRU_OLD, ++ MEMCG_LRU_YOUNG, ++}; ++ + #ifdef CONFIG_LRU_GEN + + enum { +@@ -416,6 +426,14 @@ struct lru_gen_page { + atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; + /* whether the multi-gen LRU is enabled */ + bool enabled; ++#ifdef CONFIG_MEMCG ++ /* the memcg generation this lru_gen_page belongs to */ ++ u8 gen; ++ /* the list segment this lru_gen_page belongs to */ ++ u8 seg; ++ /* per-node lru_gen_page list for global reclaim */ ++ struct hlist_nulls_node list; ++#endif + }; + + enum { +@@ -469,12 +487,87 @@ void lru_gen_init_lruvec(struct lruvec * + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); + + #ifdef CONFIG_MEMCG ++ ++/* ++ * For each node, memcgs are divided into two generations: the old and the ++ * young. For each generation, memcgs are randomly sharded into multiple bins ++ * to improve scalability. For each bin, the hlist_nulls is virtually divided ++ * into three segments: the head, the tail and the default. ++ * ++ * An onlining memcg is added to the tail of a random bin in the old generation. ++ * The eviction starts at the head of a random bin in the old generation. The ++ * per-node memcg generation counter, whose reminder (mod MEMCG_NR_GENS) indexes ++ * the old generation, is incremented when all its bins become empty. ++ * ++ * There are four operations: ++ * 1. MEMCG_LRU_HEAD, which moves an memcg to the head of a random bin in its ++ * current generation (old or young) and updates its "seg" to "head"; ++ * 2. MEMCG_LRU_TAIL, which moves an memcg to the tail of a random bin in its ++ * current generation (old or young) and updates its "seg" to "tail"; ++ * 3. MEMCG_LRU_OLD, which moves an memcg to the head of a random bin in the old ++ * generation, updates its "gen" to "old" and resets its "seg" to "default"; ++ * 4. MEMCG_LRU_YOUNG, which moves an memcg to the tail of a random bin in the ++ * young generation, updates its "gen" to "young" and resets its "seg" to ++ * "default". ++ * ++ * The events that trigger the above operations are: ++ * 1. Exceeding the soft limit, which triggers MEMCG_LRU_HEAD; ++ * 2. The first attempt to reclaim an memcg below low, which triggers ++ * MEMCG_LRU_TAIL; ++ * 3. The first attempt to reclaim an memcg below reclaimable size threshold, ++ * which triggers MEMCG_LRU_TAIL; ++ * 4. The second attempt to reclaim an memcg below reclaimable size threshold, ++ * which triggers MEMCG_LRU_YOUNG; ++ * 5. Attempting to reclaim an memcg below min, which triggers MEMCG_LRU_YOUNG; ++ * 6. Finishing the aging on the eviction path, which triggers MEMCG_LRU_YOUNG; ++ * 7. Offlining an memcg, which triggers MEMCG_LRU_OLD. ++ * ++ * Note that memcg LRU only applies to global reclaim, and the round-robin ++ * incrementing of their max_seq counters ensures the eventual fairness to all ++ * eligible memcgs. For memcg reclaim, it still relies on mem_cgroup_iter(). ++ */ ++#define MEMCG_NR_GENS 2 ++#define MEMCG_NR_BINS 8 ++ ++struct lru_gen_memcg { ++ /* the per-node memcg generation counter */ ++ unsigned long seq; ++ /* each memcg has one lru_gen_page per node */ ++ unsigned long nr_memcgs[MEMCG_NR_GENS]; ++ /* per-node lru_gen_page list for global reclaim */ ++ struct hlist_nulls_head fifo[MEMCG_NR_GENS][MEMCG_NR_BINS]; ++ /* protects the above */ ++ spinlock_t lock; ++}; ++ ++void lru_gen_init_pgdat(struct pglist_data *pgdat); ++ + void lru_gen_init_memcg(struct mem_cgroup *memcg); + void lru_gen_exit_memcg(struct mem_cgroup *memcg); +-#endif ++void lru_gen_online_memcg(struct mem_cgroup *memcg); ++void lru_gen_offline_memcg(struct mem_cgroup *memcg); ++void lru_gen_release_memcg(struct mem_cgroup *memcg); ++void lru_gen_rotate_memcg(struct lruvec *lruvec, int op); ++ ++#else /* !CONFIG_MEMCG */ ++ ++#define MEMCG_NR_GENS 1 ++ ++struct lru_gen_memcg { ++}; ++ ++static inline void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++} ++ ++#endif /* CONFIG_MEMCG */ + + #else /* !CONFIG_LRU_GEN */ + ++static inline void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++} ++ + static inline void lru_gen_init_lruvec(struct lruvec *lruvec) + { + } +@@ -484,6 +577,7 @@ static inline void lru_gen_look_around(s + } + + #ifdef CONFIG_MEMCG ++ + static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) + { + } +@@ -491,7 +585,24 @@ static inline void lru_gen_init_memcg(st + static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) + { + } +-#endif ++ ++static inline void lru_gen_online_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_offline_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) ++{ ++} ++ ++static inline void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++{ ++} ++ ++#endif /* CONFIG_MEMCG */ + + #endif /* CONFIG_LRU_GEN */ + +@@ -1105,6 +1216,8 @@ typedef struct pglist_data { + #ifdef CONFIG_LRU_GEN + /* kswap mm walk data */ + struct lru_gen_mm_walk mm_walk; ++ /* lru_gen_page list */ ++ struct lru_gen_memcg memcg_lru; + #endif + + ZONE_PADDING(_pad2_) +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -549,6 +549,16 @@ static void mem_cgroup_update_tree(struc + struct mem_cgroup_per_node *mz; + struct mem_cgroup_tree_per_node *mctz; + ++ if (lru_gen_enabled()) { ++ struct lruvec *lruvec = &mem_cgroup_page_nodeinfo(memcg, page)->lruvec; ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (soft_limit_excess(memcg) && lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_HEAD); ++ ++ return; ++ } ++ + mctz = soft_limit_tree_from_page(page); + if (!mctz) + return; +@@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_recl + unsigned long excess; + unsigned long nr_scanned; + ++ if (lru_gen_enabled()) ++ return 0; ++ + if (order > 0) + return 0; + +@@ -5321,6 +5334,7 @@ static int mem_cgroup_css_online(struct + if (unlikely(mem_cgroup_is_root(memcg))) + queue_delayed_work(system_unbound_wq, &stats_flush_dwork, + 2UL*HZ); ++ lru_gen_online_memcg(memcg); + return 0; + } + +@@ -5347,6 +5361,7 @@ static void mem_cgroup_css_offline(struc + memcg_offline_kmem(memcg); + reparent_shrinker_deferred(memcg); + wb_memcg_offline(memcg); ++ lru_gen_offline_memcg(memcg); + + drain_all_stock(memcg); + +@@ -5358,6 +5373,7 @@ static void mem_cgroup_css_released(stru + struct mem_cgroup *memcg = mem_cgroup_from_css(css); + + invalidate_reclaim_iterators(memcg); ++ lru_gen_release_memcg(memcg); + } + + static void mem_cgroup_css_free(struct cgroup_subsys_state *css) +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -7661,6 +7661,7 @@ static void __init free_area_init_node(i + pgdat_set_deferred_range(pgdat); + + free_area_init_core(pgdat); ++ lru_gen_init_pgdat(pgdat); + } + + void __init free_area_init_memoryless_node(int nid) +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -54,6 +54,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -129,11 +131,6 @@ struct scan_control { + /* Always discard instead of demoting to lower tier memory */ + unsigned int no_demotion:1; + +-#ifdef CONFIG_LRU_GEN +- /* help kswapd make better choices among multiple memcgs */ +- unsigned long last_reclaimed; +-#endif +- + /* Allocation order */ + s8 order; + +@@ -2880,6 +2877,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_ca + for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ + for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) + ++#define get_memcg_gen(seq) ((seq) % MEMCG_NR_GENS) ++#define get_memcg_bin(bin) ((bin) % MEMCG_NR_BINS) ++ + static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) + { + struct pglist_data *pgdat = NODE_DATA(nid); +@@ -4169,8 +4169,7 @@ done: + if (sc->priority <= DEF_PRIORITY - 2) + wait_event_killable(lruvec->mm_state.wait, + max_seq < READ_ONCE(lrugen->max_seq)); +- +- return max_seq < READ_ONCE(lrugen->max_seq); ++ return false; + } + + VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); +@@ -4243,8 +4242,6 @@ static void lru_gen_age_node(struct pgli + + VM_WARN_ON_ONCE(!current_is_kswapd()); + +- sc->last_reclaimed = sc->nr_reclaimed; +- + /* check the order to exclude compaction-induced reclaim */ + if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) + return; +@@ -4833,8 +4830,7 @@ static bool should_run_aging(struct lruv + * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg + * reclaim. + */ +-static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, +- bool can_swap) ++static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool can_swap) + { + unsigned long nr_to_scan; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); +@@ -4851,10 +4847,8 @@ static unsigned long get_nr_to_scan(stru + if (sc->priority == DEF_PRIORITY) + return nr_to_scan; + +- try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); +- + /* skip this lruvec as it's low on cold pages */ +- return 0; ++ return try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false) ? -1 : 0; + } + + static unsigned long get_nr_to_reclaim(struct scan_control *sc) +@@ -4863,29 +4857,18 @@ static unsigned long get_nr_to_reclaim(s + if (!global_reclaim(sc)) + return -1; + +- /* discount the previous progress for kswapd */ +- if (current_is_kswapd()) +- return sc->nr_to_reclaim + sc->last_reclaimed; +- + return max(sc->nr_to_reclaim, compact_gap(sc->order)); + } + +-static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) + { +- struct blk_plug plug; ++ long nr_to_scan; + unsigned long scanned = 0; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + +- lru_add_drain(); +- +- blk_start_plug(&plug); +- +- set_mm_walk(lruvec_pgdat(lruvec)); +- + while (true) { + int delta; + int swappiness; +- unsigned long nr_to_scan; + + if (sc->may_swap) + swappiness = get_swappiness(lruvec, sc); +@@ -4895,7 +4878,7 @@ static void lru_gen_shrink_lruvec(struct + swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); +- if (!nr_to_scan) ++ if (nr_to_scan <= 0) + break; + + delta = evict_pages(lruvec, sc, swappiness); +@@ -4912,10 +4895,250 @@ static void lru_gen_shrink_lruvec(struct + cond_resched(); + } + ++ /* whether try_to_inc_max_seq() was successful */ ++ return nr_to_scan < 0; ++} ++ ++static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ bool success; ++ unsigned long scanned = sc->nr_scanned; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ int seg = lru_gen_memcg_seg(lruvec); ++ struct mem_cgroup *memcg = lruvec_memcg(lruvec); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (!lruvec_is_sizable(lruvec, sc)) ++ return seg != MEMCG_LRU_TAIL ? MEMCG_LRU_TAIL : MEMCG_LRU_YOUNG; ++ ++ mem_cgroup_calculate_protection(NULL, memcg); ++ ++ if (mem_cgroup_below_min(memcg)) ++ return MEMCG_LRU_YOUNG; ++ ++ if (mem_cgroup_below_low(memcg)) { ++ /* see the comment on MEMCG_NR_GENS */ ++ if (seg != MEMCG_LRU_TAIL) ++ return MEMCG_LRU_TAIL; ++ ++ memcg_memory_event(memcg, MEMCG_LOW); ++ } ++ ++ success = try_to_shrink_lruvec(lruvec, sc); ++ ++ shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority); ++ ++ vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned, ++ sc->nr_reclaimed - reclaimed); ++ ++ sc->nr_reclaimed += current->reclaim_state->reclaimed_slab; ++ current->reclaim_state->reclaimed_slab = 0; ++ ++ return success ? MEMCG_LRU_YOUNG : 0; ++} ++ ++#ifdef CONFIG_MEMCG ++ ++static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ int gen; ++ int bin; ++ int first_bin; ++ struct lruvec *lruvec; ++ struct lru_gen_page *lrugen; ++ const struct hlist_nulls_node *pos; ++ int op = 0; ++ struct mem_cgroup *memcg = NULL; ++ unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); ++ ++ bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); ++restart: ++ gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); ++ ++ rcu_read_lock(); ++ ++ hlist_nulls_for_each_entry_rcu(lrugen, pos, &pgdat->memcg_lru.fifo[gen][bin], list) { ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++ ++ lruvec = container_of(lrugen, struct lruvec, lrugen); ++ memcg = lruvec_memcg(lruvec); ++ ++ if (!mem_cgroup_tryget(memcg)) { ++ op = 0; ++ memcg = NULL; ++ continue; ++ } ++ ++ rcu_read_unlock(); ++ ++ op = shrink_one(lruvec, sc); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ goto success; ++ ++ rcu_read_lock(); ++ } ++ ++ rcu_read_unlock(); ++ ++ /* restart if raced with lru_gen_rotate_memcg() */ ++ if (gen != get_nulls_value(pos)) ++ goto restart; ++ ++ /* try the rest of the bins of the current generation */ ++ bin = get_memcg_bin(bin + 1); ++ if (bin != first_bin) ++ goto restart; ++success: ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ ++ VM_WARN_ON_ONCE(global_reclaim(sc)); ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ set_mm_walk(lruvec_pgdat(lruvec)); ++ ++ if (try_to_shrink_lruvec(lruvec, sc)) ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); ++ ++ clear_mm_walk(); ++ ++ blk_finish_plug(&plug); ++} ++ ++#else /* !CONFIG_MEMCG */ ++ ++static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ BUILD_BUG(); ++} ++ ++static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) ++{ ++ BUILD_BUG(); ++} ++ ++#endif ++ ++static void set_initial_priority(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ int priority; ++ unsigned long reclaimable; ++ struct lruvec *lruvec = mem_cgroup_lruvec(NULL, pgdat); ++ ++ if (sc->priority != DEF_PRIORITY || sc->nr_to_reclaim < MIN_LRU_BATCH) ++ return; ++ /* ++ * Determine the initial priority based on ((total / MEMCG_NR_GENS) >> ++ * priority) * reclaimed_to_scanned_ratio = nr_to_reclaim, where the ++ * estimated reclaimed_to_scanned_ratio = inactive / total. ++ */ ++ reclaimable = node_page_state(pgdat, NR_INACTIVE_FILE); ++ if (get_swappiness(lruvec, sc)) ++ reclaimable += node_page_state(pgdat, NR_INACTIVE_ANON); ++ ++ reclaimable /= MEMCG_NR_GENS; ++ ++ /* round down reclaimable and round up sc->nr_to_reclaim */ ++ priority = fls_long(reclaimable) - 1 - fls_long(sc->nr_to_reclaim - 1); ++ ++ sc->priority = clamp(priority, 0, DEF_PRIORITY); ++} ++ ++static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++ struct blk_plug plug; ++ unsigned long reclaimed = sc->nr_reclaimed; ++ ++ VM_WARN_ON_ONCE(!global_reclaim(sc)); ++ ++ lru_add_drain(); ++ ++ blk_start_plug(&plug); ++ ++ set_mm_walk(pgdat); ++ ++ set_initial_priority(pgdat, sc); ++ ++ if (current_is_kswapd()) ++ sc->nr_reclaimed = 0; ++ ++ if (mem_cgroup_disabled()) ++ shrink_one(&pgdat->__lruvec, sc); ++ else ++ shrink_many(pgdat, sc); ++ ++ if (current_is_kswapd()) ++ sc->nr_reclaimed += reclaimed; ++ + clear_mm_walk(); + + blk_finish_plug(&plug); ++ ++ /* kswapd should never fail */ ++ pgdat->kswapd_failures = 0; ++} ++ ++#ifdef CONFIG_MEMCG ++void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++{ ++ int seg; ++ int old, new; ++ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ seg = 0; ++ new = old = lruvec->lrugen.gen; ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (op == MEMCG_LRU_HEAD) ++ seg = MEMCG_LRU_HEAD; ++ else if (op == MEMCG_LRU_TAIL) ++ seg = MEMCG_LRU_TAIL; ++ else if (op == MEMCG_LRU_OLD) ++ new = get_memcg_gen(pgdat->memcg_lru.seq); ++ else if (op == MEMCG_LRU_YOUNG) ++ new = get_memcg_gen(pgdat->memcg_lru.seq + 1); ++ else ++ VM_WARN_ON_ONCE(true); ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ ++ if (op == MEMCG_LRU_HEAD || op == MEMCG_LRU_OLD) ++ hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ else ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ ++ pgdat->memcg_lru.nr_memcgs[old]--; ++ pgdat->memcg_lru.nr_memcgs[new]++; ++ ++ lruvec->lrugen.gen = new; ++ WRITE_ONCE(lruvec->lrugen.seg, seg); ++ ++ if (!pgdat->memcg_lru.nr_memcgs[old] && old == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); + } ++#endif + + /****************************************************************************** + * state change +@@ -5370,11 +5593,11 @@ static int run_cmd(char cmd, int memcg_i + + if (!mem_cgroup_disabled()) { + rcu_read_lock(); ++ + memcg = mem_cgroup_from_id(memcg_id); +-#ifdef CONFIG_MEMCG +- if (memcg && !css_tryget(&memcg->css)) ++ if (!mem_cgroup_tryget(memcg)) + memcg = NULL; +-#endif ++ + rcu_read_unlock(); + + if (!memcg) +@@ -5521,6 +5744,19 @@ void lru_gen_init_lruvec(struct lruvec * + } + + #ifdef CONFIG_MEMCG ++ ++void lru_gen_init_pgdat(struct pglist_data *pgdat) ++{ ++ int i, j; ++ ++ spin_lock_init(&pgdat->memcg_lru.lock); ++ ++ for (i = 0; i < MEMCG_NR_GENS; i++) { ++ for (j = 0; j < MEMCG_NR_BINS; j++) ++ INIT_HLIST_NULLS_HEAD(&pgdat->memcg_lru.fifo[i][j], i); ++ } ++} ++ + void lru_gen_init_memcg(struct mem_cgroup *memcg) + { + INIT_LIST_HEAD(&memcg->mm_list.fifo); +@@ -5544,7 +5780,69 @@ void lru_gen_exit_memcg(struct mem_cgrou + } + } + } +-#endif ++ ++void lru_gen_online_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(!hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = get_memcg_gen(pgdat->memcg_lru.seq); ++ ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[gen][bin]); ++ pgdat->memcg_lru.nr_memcgs[gen]++; ++ ++ lruvec->lrugen.gen = gen; ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++void lru_gen_offline_memcg(struct mem_cgroup *memcg) ++{ ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD); ++ } ++} ++ ++void lru_gen_release_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = lruvec->lrugen.gen; ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ pgdat->memcg_lru.nr_memcgs[gen]--; ++ ++ if (!pgdat->memcg_lru.nr_memcgs[gen] && gen == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++#endif /* CONFIG_MEMCG */ + + static int __init init_lru_gen(void) + { +@@ -5571,6 +5869,10 @@ static void lru_gen_shrink_lruvec(struct + { + } + ++static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control *sc) ++{ ++} ++ + #endif /* CONFIG_LRU_GEN */ + + static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +@@ -5584,7 +5886,7 @@ static void shrink_lruvec(struct lruvec + bool proportional_reclaim; + struct blk_plug plug; + +- if (lru_gen_enabled()) { ++ if (lru_gen_enabled() && !global_reclaim(sc)) { + lru_gen_shrink_lruvec(lruvec, sc); + return; + } +@@ -5826,6 +6128,11 @@ static void shrink_node(pg_data_t *pgdat + struct lruvec *target_lruvec; + bool reclaimable = false; + ++ if (lru_gen_enabled() && global_reclaim(sc)) { ++ lru_gen_shrink_node(pgdat, sc); ++ return; ++ } ++ + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); + + again: diff --git a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch new file mode 100644 index 00000000000..882f29e9892 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -0,0 +1,196 @@ +From 93147736b5b3a21bea24313bfc7a696829932009 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:05 -0700 +Subject: [PATCH 27/29] mm: multi-gen LRU: clarify scan_control flags + +Among the flags in scan_control: +1. sc->may_swap, which indicates swap constraint due to memsw.max, is + supported as usual. +2. sc->proactive, which indicates reclaim by memory.reclaim, may not + opportunistically skip the aging path, since it is considered less + latency sensitive. +3. !(sc->gfp_mask & __GFP_IO), which indicates IO constraint, lowers + swappiness to prioritize file LRU, since clean file pages are more + likely to exist. +4. sc->may_writepage and sc->may_unmap, which indicates opportunistic + reclaim, are rejected, since unmapped clean pages are already + prioritized. Scanning for more of them is likely futile and can + cause high reclaim latency when there is a large number of memcgs. + +The rest are handled by the existing code. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-8-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 55 +++++++++++++++++++++++++++-------------------------- + 1 file changed, 28 insertions(+), 27 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2905,6 +2905,9 @@ static int get_swappiness(struct lruvec + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + ++ if (!sc->may_swap) ++ return 0; ++ + if (!can_demote(pgdat->node_id, sc) && + mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + return 0; +@@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruve + } while (err == -EAGAIN); + } + +-static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) ++static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat, bool force_alloc) + { + struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; + +@@ -3960,7 +3963,7 @@ static struct lru_gen_mm_walk *set_mm_wa + VM_WARN_ON_ONCE(walk); + + walk = &pgdat->mm_walk; +- } else if (!pgdat && !walk) { ++ } else if (!walk && force_alloc) { + VM_WARN_ON_ONCE(current_is_kswapd()); + + walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +@@ -4146,7 +4149,7 @@ static bool try_to_inc_max_seq(struct lr + goto done; + } + +- walk = set_mm_walk(NULL); ++ walk = set_mm_walk(NULL, true); + if (!walk) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; +@@ -4215,8 +4218,6 @@ static bool lruvec_is_reclaimable(struct + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MIN_SEQ(lruvec); + +- VM_WARN_ON_ONCE(sc->memcg_low_reclaim); +- + /* see the comment on lru_gen_page */ + gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); +@@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec * + { + bool success; + +- /* unmapping inhibited */ +- if (!sc->may_unmap && page_mapped(page)) +- return false; +- + /* swapping inhibited */ +- if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && ++ if (!(sc->gfp_mask & __GFP_IO) && + (PageDirty(page) || + (PageAnon(page) && !PageSwapCache(page)))) + return false; +@@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lru + __count_vm_events(PGSCAN_ANON + type, isolated); + + /* +- * There might not be eligible pages due to reclaim_idx, may_unmap and +- * may_writepage. Check the remaining to prevent livelock if it's not +- * making progress. ++ * There might not be eligible pages due to reclaim_idx. Check the ++ * remaining to prevent livelock if it's not making progress. + */ + return isolated || !remaining ? scanned : 0; + } +@@ -4836,8 +4832,7 @@ static long get_nr_to_scan(struct lruvec + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MAX_SEQ(lruvec); + +- if (mem_cgroup_below_min(memcg) || +- (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) ++ if (mem_cgroup_below_min(memcg)) + return 0; + + if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) +@@ -4865,17 +4860,14 @@ static bool try_to_shrink_lruvec(struct + long nr_to_scan; + unsigned long scanned = 0; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); ++ int swappiness = get_swappiness(lruvec, sc); ++ ++ /* clean file pages are more likely to exist */ ++ if (swappiness && !(sc->gfp_mask & __GFP_IO)) ++ swappiness = 1; + + while (true) { + int delta; +- int swappiness; +- +- if (sc->may_swap) +- swappiness = get_swappiness(lruvec, sc); +- else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) +- swappiness = 1; +- else +- swappiness = 0; + + nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); + if (nr_to_scan <= 0) +@@ -5005,12 +4997,13 @@ static void lru_gen_shrink_lruvec(struct + struct blk_plug plug; + + VM_WARN_ON_ONCE(global_reclaim(sc)); ++ VM_WARN_ON_ONCE(!sc->may_writepage || !sc->may_unmap); + + lru_add_drain(); + + blk_start_plug(&plug); + +- set_mm_walk(lruvec_pgdat(lruvec)); ++ set_mm_walk(NULL, false); + + if (try_to_shrink_lruvec(lruvec, sc)) + lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); +@@ -5066,11 +5059,19 @@ static void lru_gen_shrink_node(struct p + + VM_WARN_ON_ONCE(!global_reclaim(sc)); + ++ /* ++ * Unmapped clean pages are already prioritized. Scanning for more of ++ * them is likely futile and can cause high reclaim latency when there ++ * is a large number of memcgs. ++ */ ++ if (!sc->may_writepage || !sc->may_unmap) ++ goto done; ++ + lru_add_drain(); + + blk_start_plug(&plug); + +- set_mm_walk(pgdat); ++ set_mm_walk(pgdat, false); + + set_initial_priority(pgdat, sc); + +@@ -5088,7 +5089,7 @@ static void lru_gen_shrink_node(struct p + clear_mm_walk(); + + blk_finish_plug(&plug); +- ++done: + /* kswapd should never fail */ + pgdat->kswapd_failures = 0; + } +@@ -5656,7 +5657,7 @@ static ssize_t lru_gen_seq_write(struct + set_task_reclaim_state(current, &sc.reclaim_state); + flags = memalloc_noreclaim_save(); + blk_start_plug(&plug); +- if (!set_mm_walk(NULL)) { ++ if (!set_mm_walk(NULL, true)) { + err = -ENOMEM; + goto done; + } diff --git a/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch b/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch new file mode 100644 index 00000000000..38d0e5496cc --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch @@ -0,0 +1,34 @@ +From cf3297e4c7a928da8b2b2f0baff2f9c69ea57952 Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Wed, 21 Dec 2022 21:19:06 -0700 +Subject: [PATCH 28/29] mm: multi-gen LRU: simplify arch_has_hw_pte_young() + check + +Scanning page tables when hardware does not set the accessed bit has +no real use cases. + +Link: https://lkml.kernel.org/r/20221222041905.2431096-9-yuzhao@google.com +Signed-off-by: Yu Zhao +Cc: Johannes Weiner +Cc: Jonathan Corbet +Cc: Michael Larabel +Cc: Michal Hocko +Cc: Mike Rapoport +Cc: Roman Gushchin +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4144,7 +4144,7 @@ static bool try_to_inc_max_seq(struct lr + * handful of PTEs. Spreading the work out over a period of time usually + * is less efficient, but it avoids bursty page faults. + */ +- if (!force_scan && !(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { ++ if (!arch_has_hw_pte_young() || !get_cap(LRU_GEN_MM_WALK)) { + success = iterate_mm_list_nowalk(lruvec, max_seq); + goto done; + } diff --git a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch new file mode 100644 index 00000000000..2d19d0d7da1 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -0,0 +1,88 @@ +From cc67f962cc53f6e1dfa92eb85b7b26fe83a3c66f Mon Sep 17 00:00:00 2001 +From: Yu Zhao +Date: Mon, 13 Feb 2023 00:53:22 -0700 +Subject: [PATCH 29/29] mm: multi-gen LRU: avoid futile retries + +Recall that the per-node memcg LRU has two generations and they alternate +when the last memcg (of a given node) is moved from one to the other. +Each generation is also sharded into multiple bins to improve scalability. +A reclaimer starts with a random bin (in the old generation) and, if it +fails, it will retry, i.e., to try the rest of the bins. + +If a reclaimer fails with the last memcg, it should move this memcg to the +young generation first, which causes the generations to alternate, and +then retry. Otherwise, the retries will be futile because all other bins +are empty. + +Link: https://lkml.kernel.org/r/20230213075322.1416966-1-yuzhao@google.com +Fixes: e4dde56cd208 ("mm: multi-gen LRU: per-node lru_gen_folio lists") +Signed-off-by: Yu Zhao +Reported-by: T.J. Mercier +Signed-off-by: Andrew Morton +--- + mm/vmscan.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4934,18 +4934,20 @@ static int shrink_one(struct lruvec *lru + + static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) + { ++ int op; + int gen; + int bin; + int first_bin; + struct lruvec *lruvec; + struct lru_gen_page *lrugen; ++ struct mem_cgroup *memcg; + const struct hlist_nulls_node *pos; +- int op = 0; +- struct mem_cgroup *memcg = NULL; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + + bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); + restart: ++ op = 0; ++ memcg = NULL; + gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); + + rcu_read_lock(); +@@ -4969,14 +4971,22 @@ restart: + + op = shrink_one(lruvec, sc); + +- if (sc->nr_reclaimed >= nr_to_reclaim) +- goto success; +- + rcu_read_lock(); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ break; + } + + rcu_read_unlock(); + ++ if (op) ++ lru_gen_rotate_memcg(lruvec, op); ++ ++ mem_cgroup_put(memcg); ++ ++ if (sc->nr_reclaimed >= nr_to_reclaim) ++ return; ++ + /* restart if raced with lru_gen_rotate_memcg() */ + if (gen != get_nulls_value(pos)) + goto restart; +@@ -4985,11 +4995,6 @@ restart: + bin = get_memcg_bin(bin + 1); + if (bin != first_bin) + goto restart; +-success: +- if (op) +- lru_gen_rotate_memcg(lruvec, op); +- +- mem_cgroup_put(memcg); + } + + static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) diff --git a/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch b/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch new file mode 100644 index 00000000000..82feb7421d5 --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch @@ -0,0 +1,65 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:02 +0200 +Subject: [PATCH] MIPS: uasm: Enable muhu opcode for MIPS R6 + +Enable the 'muhu' instruction, complementing the existing 'mulu', needed +to implement a MIPS32 BPF JIT. + +Also fix a typo in the existing definition of 'dmulu'. + +Signed-off-by: Tony Ambardar + +This patch is a dependency for my 32-bit MIPS eBPF JIT. + +Signed-off-by: Johan Almbladh +--- + +--- a/arch/mips/include/asm/uasm.h ++++ b/arch/mips/include/asm/uasm.h +@@ -145,6 +145,7 @@ Ip_u1(_mtlo); + Ip_u3u1u2(_mul); + Ip_u1u2(_multu); + Ip_u3u1u2(_mulu); ++Ip_u3u1u2(_muhu); + Ip_u3u1u2(_nor); + Ip_u3u1u2(_or); + Ip_u2u1u3(_ori); +--- a/arch/mips/mm/uasm-mips.c ++++ b/arch/mips/mm/uasm-mips.c +@@ -90,7 +90,7 @@ static const struct insn insn_table[insn + RS | RT | RD}, + [insn_dmtc0] = {M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, + [insn_dmultu] = {M(spec_op, 0, 0, 0, 0, dmultu_op), RS | RT}, +- [insn_dmulu] = {M(spec_op, 0, 0, 0, dmult_dmul_op, dmultu_op), ++ [insn_dmulu] = {M(spec_op, 0, 0, 0, dmultu_dmulu_op, dmultu_op), + RS | RT | RD}, + [insn_drotr] = {M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE}, + [insn_drotr32] = {M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE}, +@@ -150,6 +150,8 @@ static const struct insn insn_table[insn + [insn_mtlo] = {M(spec_op, 0, 0, 0, 0, mtlo_op), RS}, + [insn_mulu] = {M(spec_op, 0, 0, 0, multu_mulu_op, multu_op), + RS | RT | RD}, ++ [insn_muhu] = {M(spec_op, 0, 0, 0, multu_muhu_op, multu_op), ++ RS | RT | RD}, + #ifndef CONFIG_CPU_MIPSR6 + [insn_mul] = {M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD}, + #else +--- a/arch/mips/mm/uasm.c ++++ b/arch/mips/mm/uasm.c +@@ -59,7 +59,7 @@ enum opcode { + insn_lddir, insn_ldpte, insn_ldx, insn_lh, insn_lhu, insn_ll, insn_lld, + insn_lui, insn_lw, insn_lwu, insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi, + insn_mflo, insn_modu, insn_movn, insn_movz, insn_mtc0, insn_mthc0, +- insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_nor, ++ insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_muhu, insn_nor, + insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb, insn_sc, + insn_scd, insn_seleqz, insn_selnez, insn_sd, insn_sh, insn_sll, + insn_sllv, insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra, +@@ -344,6 +344,7 @@ I_u1(_mtlo) + I_u3u1u2(_mul) + I_u1u2(_multu) + I_u3u1u2(_mulu) ++I_u3u1u2(_muhu) + I_u3u1u2(_nor) + I_u3u1u2(_or) + I_u2u1u3(_ori) diff --git a/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch b/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch new file mode 100644 index 00000000000..3a4d573f80a --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch @@ -0,0 +1,31 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:03 +0200 +Subject: [PATCH] mips: uasm: Add workaround for Loongson-2F nop CPU errata + +This patch implements a workaround for the Loongson-2F nop in generated, +code, if the existing option CONFIG_CPU_NOP_WORKAROUND is set. Before, +the binutils option -mfix-loongson2f-nop was enabled, but no workaround +was done when emitting MIPS code. Now, the nop pseudo instruction is +emitted as "or ax,ax,zero" instead of the default "sll zero,zero,0". This +is consistent with the workaround implemented by binutils. + +Link: https://sourceware.org/legacy-ml/binutils/2009-11/msg00387.html + +Signed-off-by: Johan Almbladh +Reviewed-by: Jiaxun Yang +--- + +--- a/arch/mips/include/asm/uasm.h ++++ b/arch/mips/include/asm/uasm.h +@@ -249,7 +249,11 @@ static inline void uasm_l##lb(struct uas + #define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off) + #define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3) + #define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b) ++#ifdef CONFIG_CPU_NOP_WORKAROUNDS ++#define uasm_i_nop(buf) uasm_i_or(buf, 1, 1, 0) ++#else + #define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0) ++#endif + #define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1) + + static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1, diff --git a/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch b/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch new file mode 100644 index 00000000000..79806599612 --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch @@ -0,0 +1,3078 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:04 +0200 +Subject: [PATCH] mips: bpf: Add eBPF JIT for 32-bit MIPS + +This is an implementation of an eBPF JIT for 32-bit MIPS I-V and MIPS32. +The implementation supports all 32-bit and 64-bit ALU and JMP operations, +including the recently-added atomics. 64-bit div/mod and 64-bit atomics +are implemented using function calls to math64 and atomic64 functions, +respectively. All 32-bit operations are implemented natively by the JIT, +except if the CPU lacks ll/sc instructions. + +Register mapping +================ +All 64-bit eBPF registers are mapped to native 32-bit MIPS register pairs, +and does not use any stack scratch space for register swapping. This means +that all eBPF register data is kept in CPU registers all the time, and +this simplifies the register management a lot. It also reduces the JIT's +pressure on temporary registers since we do not have to move data around. + +Native register pairs are ordered according to CPU endiannes, following +the O32 calling convention for passing 64-bit arguments and return values. +The eBPF return value, arguments and callee-saved registers are mapped to +their native MIPS equivalents. + +Since the 32 highest bits in the eBPF FP (frame pointer) register are +always zero, only one general-purpose register is actually needed for the +mapping. The MIPS fp register is used for this purpose. The high bits are +mapped to MIPS register r0. This saves us one CPU register, which is much +needed for temporaries, while still allowing us to treat the R10 (FP) +register just like any other eBPF register in the JIT. + +The MIPS gp (global pointer) and at (assembler temporary) registers are +used as internal temporary registers for constant blinding. CPU registers +t6-t9 are used internally by the JIT when constructing more complex 64-bit +operations. This is precisely what is needed - two registers to store an +operand value, and two more as scratch registers when performing the +operation. + +The register mapping is shown below. + + R0 - $v1, $v0 return value + R1 - $a1, $a0 argument 1, passed in registers + R2 - $a3, $a2 argument 2, passed in registers + R3 - $t1, $t0 argument 3, passed on stack + R4 - $t3, $t2 argument 4, passed on stack + R5 - $t4, $t3 argument 5, passed on stack + R6 - $s1, $s0 callee-saved + R7 - $s3, $s2 callee-saved + R8 - $s5, $s4 callee-saved + R9 - $s7, $s6 callee-saved + FP - $r0, $fp 32-bit frame pointer + AX - $gp, $at constant-blinding + $t6 - $t9 unallocated, JIT temporaries + +Jump offsets +============ +The JIT tries to map all conditional JMP operations to MIPS conditional +PC-relative branches. The MIPS branch offset field is 18 bits, in bytes, +which is equivalent to the eBPF 16-bit instruction offset. However, since +the JIT may emit more than one CPU instruction per eBPF instruction, the +field width may overflow. If that happens, the JIT converts the long +conditional jump to a short PC-relative branch with the condition +inverted, jumping over a long unconditional absolute jmp (j). + +This conversion will change the instruction offset mapping used for jumps, +and may in turn result in more branch offset overflows. The JIT therefore +dry-runs the translation until no more branches are converted and the +offsets do not change anymore. There is an upper bound on this of course, +and if the JIT hits that limit, the last two iterations are run with all +branches being converted. + +Tail call count +=============== +The current tail call count is stored in the 16-byte area of the caller's +stack frame that is reserved for the callee in the o32 ABI. The value is +initialized in the prologue, and propagated to the tail-callee by skipping +the initialization instructions when emitting the tail call. + +Signed-off-by: Johan Almbladh +--- + create mode 100644 arch/mips/net/bpf_jit_comp.c + create mode 100644 arch/mips/net/bpf_jit_comp.h + create mode 100644 arch/mips/net/bpf_jit_comp32.c + +--- a/arch/mips/net/Makefile ++++ b/arch/mips/net/Makefile +@@ -2,4 +2,9 @@ + # MIPS networking code + + obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o +-obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o ++ ++ifeq ($(CONFIG_32BIT),y) ++ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o bpf_jit_comp32.o ++else ++ obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o ++endif +--- /dev/null ++++ b/arch/mips/net/bpf_jit_comp.c +@@ -0,0 +1,1020 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Just-In-Time compiler for eBPF bytecode on MIPS. ++ * Implementation of JIT functions common to 32-bit and 64-bit CPUs. ++ * ++ * Copyright (c) 2021 Anyfi Networks AB. ++ * Author: Johan Almbladh ++ * ++ * Based on code and ideas from ++ * Copyright (c) 2017 Cavium, Inc. ++ * Copyright (c) 2017 Shubham Bansal ++ * Copyright (c) 2011 Mircea Gherzan ++ */ ++ ++/* ++ * Code overview ++ * ============= ++ * ++ * - bpf_jit_comp.h ++ * Common definitions and utilities. ++ * ++ * - bpf_jit_comp.c ++ * Implementation of JIT top-level logic and exported JIT API functions. ++ * Implementation of internal operations shared by 32-bit and 64-bit code. ++ * JMP and ALU JIT control code, register control code, shared ALU and ++ * JMP/JMP32 JIT operations. ++ * ++ * - bpf_jit_comp32.c ++ * Implementation of functions to JIT prologue, epilogue and a single eBPF ++ * instruction for 32-bit MIPS CPUs. The functions use shared operations ++ * where possible, and implement the rest for 32-bit MIPS such as ALU64 ++ * operations. ++ * ++ * - bpf_jit_comp64.c ++ * Ditto, for 64-bit MIPS CPUs. ++ * ++ * Zero and sign extension ++ * ======================== ++ * 32-bit MIPS instructions on 64-bit MIPS registers use sign extension, ++ * but the eBPF instruction set mandates zero extension. We let the verifier ++ * insert explicit zero-extensions after 32-bit ALU operations, both for ++ * 32-bit and 64-bit MIPS JITs. Conditional JMP32 operations on 64-bit MIPs ++ * are JITed with sign extensions inserted when so expected. ++ * ++ * ALU operations ++ * ============== ++ * ALU operations on 32/64-bit MIPS and ALU64 operations on 64-bit MIPS are ++ * JITed in the following steps. ALU64 operations on 32-bit MIPS are more ++ * complicated and therefore only processed by special implementations in ++ * step (3). ++ * ++ * 1) valid_alu_i: ++ * Determine if an immediate operation can be emitted as such, or if ++ * we must fall back to the register version. ++ * ++ * 2) rewrite_alu_i: ++ * Convert BPF operation and immediate value to a canonical form for ++ * JITing. In some degenerate cases this form may be a no-op. ++ * ++ * 3) emit_alu_{i,i64,r,64}: ++ * Emit instructions for an ALU or ALU64 immediate or register operation. ++ * ++ * JMP operations ++ * ============== ++ * JMP and JMP32 operations require an JIT instruction offset table for ++ * translating the jump offset. This table is computed by dry-running the ++ * JIT without actually emitting anything. However, the computed PC-relative ++ * offset may overflow the 18-bit offset field width of the native MIPS ++ * branch instruction. In such cases, the long jump is converted into the ++ * following sequence. ++ * ++ * ! +2 Inverted PC-relative branch ++ * nop Delay slot ++ * j Unconditional absolute long jump ++ * nop Delay slot ++ * ++ * Since this converted sequence alters the offset table, all offsets must ++ * be re-calculated. This may in turn trigger new branch conversions, so ++ * the process is repeated until no further changes are made. Normally it ++ * completes in 1-2 iterations. If JIT_MAX_ITERATIONS should reached, we ++ * fall back to converting every remaining jump operation. The branch ++ * conversion is independent of how the JMP or JMP32 condition is JITed. ++ * ++ * JMP32 and JMP operations are JITed as follows. ++ * ++ * 1) setup_jmp_{i,r}: ++ * Convert jump conditional and offset into a form that can be JITed. ++ * This form may be a no-op, a canonical form, or an inverted PC-relative ++ * jump if branch conversion is necessary. ++ * ++ * 2) valid_jmp_i: ++ * Determine if an immediate operations can be emitted as such, or if ++ * we must fall back to the register version. Applies to JMP32 for 32-bit ++ * MIPS, and both JMP and JMP32 for 64-bit MIPS. ++ * ++ * 3) emit_jmp_{i,i64,r,r64}: ++ * Emit instructions for an JMP or JMP32 immediate or register operation. ++ * ++ * 4) finish_jmp_{i,r}: ++ * Emit any instructions needed to finish the jump. This includes a nop ++ * for the delay slot if a branch was emitted, and a long absolute jump ++ * if the branch was converted. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bpf_jit_comp.h" ++ ++/* Convenience macros for descriptor access */ ++#define CONVERTED(desc) ((desc) & JIT_DESC_CONVERT) ++#define INDEX(desc) ((desc) & ~JIT_DESC_CONVERT) ++ ++/* ++ * Push registers on the stack, starting at a given depth from the stack ++ * pointer and increasing. The next depth to be written is returned. ++ */ ++int push_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth) ++{ ++ int reg; ++ ++ for (reg = 0; reg < BITS_PER_BYTE * sizeof(mask); reg++) ++ if (mask & BIT(reg)) { ++ if ((excl & BIT(reg)) == 0) { ++ if (sizeof(long) == 4) ++ emit(ctx, sw, reg, depth, MIPS_R_SP); ++ else /* sizeof(long) == 8 */ ++ emit(ctx, sd, reg, depth, MIPS_R_SP); ++ } ++ depth += sizeof(long); ++ } ++ ++ ctx->stack_used = max((int)ctx->stack_used, depth); ++ return depth; ++} ++ ++/* ++ * Pop registers from the stack, starting at a given depth from the stack ++ * pointer and increasing. The next depth to be read is returned. ++ */ ++int pop_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth) ++{ ++ int reg; ++ ++ for (reg = 0; reg < BITS_PER_BYTE * sizeof(mask); reg++) ++ if (mask & BIT(reg)) { ++ if ((excl & BIT(reg)) == 0) { ++ if (sizeof(long) == 4) ++ emit(ctx, lw, reg, depth, MIPS_R_SP); ++ else /* sizeof(long) == 8 */ ++ emit(ctx, ld, reg, depth, MIPS_R_SP); ++ } ++ depth += sizeof(long); ++ } ++ ++ return depth; ++} ++ ++/* Compute the 28-bit jump target address from a BPF program location */ ++int get_target(struct jit_context *ctx, u32 loc) ++{ ++ u32 index = INDEX(ctx->descriptors[loc]); ++ unsigned long pc = (unsigned long)&ctx->target[ctx->jit_index]; ++ unsigned long addr = (unsigned long)&ctx->target[index]; ++ ++ if (!ctx->target) ++ return 0; ++ ++ if ((addr ^ pc) & ~MIPS_JMP_MASK) ++ return -1; ++ ++ return addr & MIPS_JMP_MASK; ++} ++ ++/* Compute the PC-relative offset to relative BPF program offset */ ++int get_offset(const struct jit_context *ctx, int off) ++{ ++ return (INDEX(ctx->descriptors[ctx->bpf_index + off]) - ++ ctx->jit_index - 1) * sizeof(u32); ++} ++ ++/* dst = imm (register width) */ ++void emit_mov_i(struct jit_context *ctx, u8 dst, s32 imm) ++{ ++ if (imm >= -0x8000 && imm <= 0x7fff) { ++ emit(ctx, addiu, dst, MIPS_R_ZERO, imm); ++ } else { ++ emit(ctx, lui, dst, (s16)((u32)imm >> 16)); ++ emit(ctx, ori, dst, dst, (u16)(imm & 0xffff)); ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* dst = src (register width) */ ++void emit_mov_r(struct jit_context *ctx, u8 dst, u8 src) ++{ ++ emit(ctx, ori, dst, src, 0); ++ clobber_reg(ctx, dst); ++} ++ ++/* Validate ALU immediate range */ ++bool valid_alu_i(u8 op, s32 imm) ++{ ++ switch (BPF_OP(op)) { ++ case BPF_NEG: ++ case BPF_LSH: ++ case BPF_RSH: ++ case BPF_ARSH: ++ /* All legal eBPF values are valid */ ++ return true; ++ case BPF_ADD: ++ /* imm must be 16 bits */ ++ return imm >= -0x8000 && imm <= 0x7fff; ++ case BPF_SUB: ++ /* -imm must be 16 bits */ ++ return imm >= -0x7fff && imm <= 0x8000; ++ case BPF_AND: ++ case BPF_OR: ++ case BPF_XOR: ++ /* imm must be 16 bits unsigned */ ++ return imm >= 0 && imm <= 0xffff; ++ case BPF_MUL: ++ /* imm must be zero or a positive power of two */ ++ return imm == 0 || (imm > 0 && is_power_of_2(imm)); ++ case BPF_DIV: ++ case BPF_MOD: ++ /* imm must be an 17-bit power of two */ ++ return (u32)imm <= 0x10000 && is_power_of_2((u32)imm); ++ } ++ return false; ++} ++ ++/* Rewrite ALU immediate operation */ ++bool rewrite_alu_i(u8 op, s32 imm, u8 *alu, s32 *val) ++{ ++ bool act = true; ++ ++ switch (BPF_OP(op)) { ++ case BPF_LSH: ++ case BPF_RSH: ++ case BPF_ARSH: ++ case BPF_ADD: ++ case BPF_SUB: ++ case BPF_OR: ++ case BPF_XOR: ++ /* imm == 0 is a no-op */ ++ act = imm != 0; ++ break; ++ case BPF_MUL: ++ if (imm == 1) { ++ /* dst * 1 is a no-op */ ++ act = false; ++ } else if (imm == 0) { ++ /* dst * 0 is dst & 0 */ ++ op = BPF_AND; ++ } else { ++ /* dst * (1 << n) is dst << n */ ++ op = BPF_LSH; ++ imm = ilog2(abs(imm)); ++ } ++ break; ++ case BPF_DIV: ++ if (imm == 1) { ++ /* dst / 1 is a no-op */ ++ act = false; ++ } else { ++ /* dst / (1 << n) is dst >> n */ ++ op = BPF_RSH; ++ imm = ilog2(imm); ++ } ++ break; ++ case BPF_MOD: ++ /* dst % (1 << n) is dst & ((1 << n) - 1) */ ++ op = BPF_AND; ++ imm--; ++ break; ++ } ++ ++ *alu = op; ++ *val = imm; ++ return act; ++} ++ ++/* ALU immediate operation (32-bit) */ ++void emit_alu_i(struct jit_context *ctx, u8 dst, s32 imm, u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = -dst */ ++ case BPF_NEG: ++ emit(ctx, subu, dst, MIPS_R_ZERO, dst); ++ break; ++ /* dst = dst & imm */ ++ case BPF_AND: ++ emit(ctx, andi, dst, dst, (u16)imm); ++ break; ++ /* dst = dst | imm */ ++ case BPF_OR: ++ emit(ctx, ori, dst, dst, (u16)imm); ++ break; ++ /* dst = dst ^ imm */ ++ case BPF_XOR: ++ emit(ctx, xori, dst, dst, (u16)imm); ++ break; ++ /* dst = dst << imm */ ++ case BPF_LSH: ++ emit(ctx, sll, dst, dst, imm); ++ break; ++ /* dst = dst >> imm */ ++ case BPF_RSH: ++ emit(ctx, srl, dst, dst, imm); ++ break; ++ /* dst = dst >> imm (arithmetic) */ ++ case BPF_ARSH: ++ emit(ctx, sra, dst, dst, imm); ++ break; ++ /* dst = dst + imm */ ++ case BPF_ADD: ++ emit(ctx, addiu, dst, dst, imm); ++ break; ++ /* dst = dst - imm */ ++ case BPF_SUB: ++ emit(ctx, addiu, dst, dst, -imm); ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* ALU register operation (32-bit) */ ++void emit_alu_r(struct jit_context *ctx, u8 dst, u8 src, u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = dst & src */ ++ case BPF_AND: ++ emit(ctx, and, dst, dst, src); ++ break; ++ /* dst = dst | src */ ++ case BPF_OR: ++ emit(ctx, or, dst, dst, src); ++ break; ++ /* dst = dst ^ src */ ++ case BPF_XOR: ++ emit(ctx, xor, dst, dst, src); ++ break; ++ /* dst = dst << src */ ++ case BPF_LSH: ++ emit(ctx, sllv, dst, dst, src); ++ break; ++ /* dst = dst >> src */ ++ case BPF_RSH: ++ emit(ctx, srlv, dst, dst, src); ++ break; ++ /* dst = dst >> src (arithmetic) */ ++ case BPF_ARSH: ++ emit(ctx, srav, dst, dst, src); ++ break; ++ /* dst = dst + src */ ++ case BPF_ADD: ++ emit(ctx, addu, dst, dst, src); ++ break; ++ /* dst = dst - src */ ++ case BPF_SUB: ++ emit(ctx, subu, dst, dst, src); ++ break; ++ /* dst = dst * src */ ++ case BPF_MUL: ++ if (cpu_has_mips32r1 || cpu_has_mips32r6) { ++ emit(ctx, mul, dst, dst, src); ++ } else { ++ emit(ctx, multu, dst, src); ++ emit(ctx, mflo, dst); ++ } ++ break; ++ /* dst = dst / src */ ++ case BPF_DIV: ++ if (cpu_has_mips32r6) { ++ emit(ctx, divu_r6, dst, dst, src); ++ } else { ++ emit(ctx, divu, dst, src); ++ emit(ctx, mflo, dst); ++ } ++ break; ++ /* dst = dst % src */ ++ case BPF_MOD: ++ if (cpu_has_mips32r6) { ++ emit(ctx, modu, dst, dst, src); ++ } else { ++ emit(ctx, divu, dst, src); ++ emit(ctx, mfhi, dst); ++ } ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Atomic read-modify-write (32-bit) */ ++void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code) ++{ ++ emit(ctx, ll, MIPS_R_T9, off, dst); ++ switch (code) { ++ case BPF_ADD: ++ emit(ctx, addu, MIPS_R_T8, MIPS_R_T9, src); ++ break; ++ case BPF_AND: ++ emit(ctx, and, MIPS_R_T8, MIPS_R_T9, src); ++ break; ++ case BPF_OR: ++ emit(ctx, or, MIPS_R_T8, MIPS_R_T9, src); ++ break; ++ case BPF_XOR: ++ emit(ctx, xor, MIPS_R_T8, MIPS_R_T9, src); ++ break; ++ } ++ emit(ctx, sc, MIPS_R_T8, off, dst); ++ emit(ctx, beqz, MIPS_R_T8, -16); ++ emit(ctx, nop); /* Delay slot */ ++} ++ ++/* Atomic compare-and-exchange (32-bit) */ ++void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off) ++{ ++ emit(ctx, ll, MIPS_R_T9, off, dst); ++ emit(ctx, bne, MIPS_R_T9, res, 12); ++ emit(ctx, move, MIPS_R_T8, src); /* Delay slot */ ++ emit(ctx, sc, MIPS_R_T8, off, dst); ++ emit(ctx, beqz, MIPS_R_T8, -20); ++ emit(ctx, move, res, MIPS_R_T9); /* Delay slot */ ++ clobber_reg(ctx, res); ++} ++ ++/* Swap bytes and truncate a register word or half word */ ++void emit_bswap_r(struct jit_context *ctx, u8 dst, u32 width) ++{ ++ u8 tmp = MIPS_R_T8; ++ u8 msk = MIPS_R_T9; ++ ++ switch (width) { ++ /* Swap bytes in a word */ ++ case 32: ++ if (cpu_has_mips32r2 || cpu_has_mips32r6) { ++ emit(ctx, wsbh, dst, dst); ++ emit(ctx, rotr, dst, dst, 16); ++ } else { ++ emit(ctx, sll, tmp, dst, 16); /* tmp = dst << 16 */ ++ emit(ctx, srl, dst, dst, 16); /* dst = dst >> 16 */ ++ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ ++ ++ emit(ctx, lui, msk, 0xff); /* msk = 0x00ff0000 */ ++ emit(ctx, ori, msk, msk, 0xff); /* msk = msk | 0xff */ ++ ++ emit(ctx, and, tmp, dst, msk); /* tmp = dst & msk */ ++ emit(ctx, sll, tmp, tmp, 8); /* tmp = tmp << 8 */ ++ emit(ctx, srl, dst, dst, 8); /* dst = dst >> 8 */ ++ emit(ctx, and, dst, dst, msk); /* dst = dst & msk */ ++ emit(ctx, or, dst, dst, tmp); /* reg = dst | tmp */ ++ } ++ break; ++ /* Swap bytes in a half word */ ++ case 16: ++ if (cpu_has_mips32r2 || cpu_has_mips32r6) { ++ emit(ctx, wsbh, dst, dst); ++ emit(ctx, andi, dst, dst, 0xffff); ++ } else { ++ emit(ctx, andi, tmp, dst, 0xff00); /* t = d & 0xff00 */ ++ emit(ctx, srl, tmp, tmp, 8); /* t = t >> 8 */ ++ emit(ctx, andi, dst, dst, 0x00ff); /* d = d & 0x00ff */ ++ emit(ctx, sll, dst, dst, 8); /* d = d << 8 */ ++ emit(ctx, or, dst, dst, tmp); /* d = d | t */ ++ } ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Validate jump immediate range */ ++bool valid_jmp_i(u8 op, s32 imm) ++{ ++ switch (op) { ++ case JIT_JNOP: ++ /* Immediate value not used */ ++ return true; ++ case BPF_JEQ: ++ case BPF_JNE: ++ /* No immediate operation */ ++ return false; ++ case BPF_JSET: ++ case JIT_JNSET: ++ /* imm must be 16 bits unsigned */ ++ return imm >= 0 && imm <= 0xffff; ++ case BPF_JGE: ++ case BPF_JLT: ++ case BPF_JSGE: ++ case BPF_JSLT: ++ /* imm must be 16 bits */ ++ return imm >= -0x8000 && imm <= 0x7fff; ++ case BPF_JGT: ++ case BPF_JLE: ++ case BPF_JSGT: ++ case BPF_JSLE: ++ /* imm + 1 must be 16 bits */ ++ return imm >= -0x8001 && imm <= 0x7ffe; ++ } ++ return false; ++} ++ ++/* Invert a conditional jump operation */ ++static u8 invert_jmp(u8 op) ++{ ++ switch (op) { ++ case BPF_JA: return JIT_JNOP; ++ case BPF_JEQ: return BPF_JNE; ++ case BPF_JNE: return BPF_JEQ; ++ case BPF_JSET: return JIT_JNSET; ++ case BPF_JGT: return BPF_JLE; ++ case BPF_JGE: return BPF_JLT; ++ case BPF_JLT: return BPF_JGE; ++ case BPF_JLE: return BPF_JGT; ++ case BPF_JSGT: return BPF_JSLE; ++ case BPF_JSGE: return BPF_JSLT; ++ case BPF_JSLT: return BPF_JSGE; ++ case BPF_JSLE: return BPF_JSGT; ++ } ++ return 0; ++} ++ ++/* Prepare a PC-relative jump operation */ ++static void setup_jmp(struct jit_context *ctx, u8 bpf_op, ++ s16 bpf_off, u8 *jit_op, s32 *jit_off) ++{ ++ u32 *descp = &ctx->descriptors[ctx->bpf_index]; ++ int op = bpf_op; ++ int offset = 0; ++ ++ /* Do not compute offsets on the first pass */ ++ if (INDEX(*descp) == 0) ++ goto done; ++ ++ /* Skip jumps never taken */ ++ if (bpf_op == JIT_JNOP) ++ goto done; ++ ++ /* Convert jumps always taken */ ++ if (bpf_op == BPF_JA) ++ *descp |= JIT_DESC_CONVERT; ++ ++ /* ++ * Current ctx->jit_index points to the start of the branch preamble. ++ * Since the preamble differs among different branch conditionals, ++ * the current index cannot be used to compute the branch offset. ++ * Instead, we use the offset table value for the next instruction, ++ * which gives the index immediately after the branch delay slot. ++ */ ++ if (!CONVERTED(*descp)) { ++ int target = ctx->bpf_index + bpf_off + 1; ++ int origin = ctx->bpf_index + 1; ++ ++ offset = (INDEX(ctx->descriptors[target]) - ++ INDEX(ctx->descriptors[origin]) + 1) * sizeof(u32); ++ } ++ ++ /* ++ * The PC-relative branch offset field on MIPS is 18 bits signed, ++ * so if the computed offset is larger than this we generate a an ++ * absolute jump that we skip with an inverted conditional branch. ++ */ ++ if (CONVERTED(*descp) || offset < -0x20000 || offset > 0x1ffff) { ++ offset = 3 * sizeof(u32); ++ op = invert_jmp(bpf_op); ++ ctx->changes += !CONVERTED(*descp); ++ *descp |= JIT_DESC_CONVERT; ++ } ++ ++done: ++ *jit_off = offset; ++ *jit_op = op; ++} ++ ++/* Prepare a PC-relative jump operation with immediate conditional */ ++void setup_jmp_i(struct jit_context *ctx, s32 imm, u8 width, ++ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off) ++{ ++ bool always = false; ++ bool never = false; ++ ++ switch (bpf_op) { ++ case BPF_JEQ: ++ case BPF_JNE: ++ break; ++ case BPF_JSET: ++ case BPF_JLT: ++ never = imm == 0; ++ break; ++ case BPF_JGE: ++ always = imm == 0; ++ break; ++ case BPF_JGT: ++ never = (u32)imm == U32_MAX; ++ break; ++ case BPF_JLE: ++ always = (u32)imm == U32_MAX; ++ break; ++ case BPF_JSGT: ++ never = imm == S32_MAX && width == 32; ++ break; ++ case BPF_JSGE: ++ always = imm == S32_MIN && width == 32; ++ break; ++ case BPF_JSLT: ++ never = imm == S32_MIN && width == 32; ++ break; ++ case BPF_JSLE: ++ always = imm == S32_MAX && width == 32; ++ break; ++ } ++ ++ if (never) ++ bpf_op = JIT_JNOP; ++ if (always) ++ bpf_op = BPF_JA; ++ setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off); ++} ++ ++/* Prepare a PC-relative jump operation with register conditional */ ++void setup_jmp_r(struct jit_context *ctx, bool same_reg, ++ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off) ++{ ++ switch (bpf_op) { ++ case BPF_JSET: ++ break; ++ case BPF_JEQ: ++ case BPF_JGE: ++ case BPF_JLE: ++ case BPF_JSGE: ++ case BPF_JSLE: ++ if (same_reg) ++ bpf_op = BPF_JA; ++ break; ++ case BPF_JNE: ++ case BPF_JLT: ++ case BPF_JGT: ++ case BPF_JSGT: ++ case BPF_JSLT: ++ if (same_reg) ++ bpf_op = JIT_JNOP; ++ break; ++ } ++ setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off); ++} ++ ++/* Finish a PC-relative jump operation */ ++int finish_jmp(struct jit_context *ctx, u8 jit_op, s16 bpf_off) ++{ ++ /* Emit conditional branch delay slot */ ++ if (jit_op != JIT_JNOP) ++ emit(ctx, nop); ++ /* ++ * Emit an absolute long jump with delay slot, ++ * if the PC-relative branch was converted. ++ */ ++ if (CONVERTED(ctx->descriptors[ctx->bpf_index])) { ++ int target = get_target(ctx, ctx->bpf_index + bpf_off + 1); ++ ++ if (target < 0) ++ return -1; ++ emit(ctx, j, target); ++ emit(ctx, nop); ++ } ++ return 0; ++} ++ ++/* Jump immediate (32-bit) */ ++void emit_jmp_i(struct jit_context *ctx, u8 dst, s32 imm, s32 off, u8 op) ++{ ++ switch (op) { ++ /* No-op, used internally for branch optimization */ ++ case JIT_JNOP: ++ break; ++ /* PC += off if dst & imm */ ++ case BPF_JSET: ++ emit(ctx, andi, MIPS_R_T9, dst, (u16)imm); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ ++ case JIT_JNSET: ++ emit(ctx, andi, MIPS_R_T9, dst, (u16)imm); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst > imm */ ++ case BPF_JGT: ++ emit(ctx, sltiu, MIPS_R_T9, dst, imm + 1); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst >= imm */ ++ case BPF_JGE: ++ emit(ctx, sltiu, MIPS_R_T9, dst, imm); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst < imm */ ++ case BPF_JLT: ++ emit(ctx, sltiu, MIPS_R_T9, dst, imm); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst <= imm */ ++ case BPF_JLE: ++ emit(ctx, sltiu, MIPS_R_T9, dst, imm + 1); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst > imm (signed) */ ++ case BPF_JSGT: ++ emit(ctx, slti, MIPS_R_T9, dst, imm + 1); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst >= imm (signed) */ ++ case BPF_JSGE: ++ emit(ctx, slti, MIPS_R_T9, dst, imm); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst < imm (signed) */ ++ case BPF_JSLT: ++ emit(ctx, slti, MIPS_R_T9, dst, imm); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JSLE: ++ emit(ctx, slti, MIPS_R_T9, dst, imm + 1); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ } ++} ++ ++/* Jump register (32-bit) */ ++void emit_jmp_r(struct jit_context *ctx, u8 dst, u8 src, s32 off, u8 op) ++{ ++ switch (op) { ++ /* No-op, used internally for branch optimization */ ++ case JIT_JNOP: ++ break; ++ /* PC += off if dst == src */ ++ case BPF_JEQ: ++ emit(ctx, beq, dst, src, off); ++ break; ++ /* PC += off if dst != src */ ++ case BPF_JNE: ++ emit(ctx, bne, dst, src, off); ++ break; ++ /* PC += off if dst & src */ ++ case BPF_JSET: ++ emit(ctx, and, MIPS_R_T9, dst, src); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ ++ case JIT_JNSET: ++ emit(ctx, and, MIPS_R_T9, dst, src); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst > src */ ++ case BPF_JGT: ++ emit(ctx, sltu, MIPS_R_T9, src, dst); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst >= src */ ++ case BPF_JGE: ++ emit(ctx, sltu, MIPS_R_T9, dst, src); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst < src */ ++ case BPF_JLT: ++ emit(ctx, sltu, MIPS_R_T9, dst, src); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst <= src */ ++ case BPF_JLE: ++ emit(ctx, sltu, MIPS_R_T9, src, dst); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst > src (signed) */ ++ case BPF_JSGT: ++ emit(ctx, slt, MIPS_R_T9, src, dst); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst >= src (signed) */ ++ case BPF_JSGE: ++ emit(ctx, slt, MIPS_R_T9, dst, src); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst < src (signed) */ ++ case BPF_JSLT: ++ emit(ctx, slt, MIPS_R_T9, dst, src); ++ emit(ctx, bnez, MIPS_R_T9, off); ++ break; ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JSLE: ++ emit(ctx, slt, MIPS_R_T9, src, dst); ++ emit(ctx, beqz, MIPS_R_T9, off); ++ break; ++ } ++} ++ ++/* Jump always */ ++int emit_ja(struct jit_context *ctx, s16 off) ++{ ++ int target = get_target(ctx, ctx->bpf_index + off + 1); ++ ++ if (target < 0) ++ return -1; ++ emit(ctx, j, target); ++ emit(ctx, nop); ++ return 0; ++} ++ ++/* Jump to epilogue */ ++int emit_exit(struct jit_context *ctx) ++{ ++ int target = get_target(ctx, ctx->program->len); ++ ++ if (target < 0) ++ return -1; ++ emit(ctx, j, target); ++ emit(ctx, nop); ++ return 0; ++} ++ ++/* Build the program body from eBPF bytecode */ ++static int build_body(struct jit_context *ctx) ++{ ++ const struct bpf_prog *prog = ctx->program; ++ unsigned int i; ++ ++ ctx->stack_used = 0; ++ for (i = 0; i < prog->len; i++) { ++ const struct bpf_insn *insn = &prog->insnsi[i]; ++ u32 *descp = &ctx->descriptors[i]; ++ int ret; ++ ++ access_reg(ctx, insn->src_reg); ++ access_reg(ctx, insn->dst_reg); ++ ++ ctx->bpf_index = i; ++ if (ctx->target == NULL) { ++ ctx->changes += INDEX(*descp) != ctx->jit_index; ++ *descp &= JIT_DESC_CONVERT; ++ *descp |= ctx->jit_index; ++ } ++ ++ ret = build_insn(insn, ctx); ++ if (ret < 0) ++ return ret; ++ ++ if (ret > 0) { ++ i++; ++ if (ctx->target == NULL) ++ descp[1] = ctx->jit_index; ++ } ++ } ++ ++ /* Store the end offset, where the epilogue begins */ ++ ctx->descriptors[prog->len] = ctx->jit_index; ++ return 0; ++} ++ ++/* Set the branch conversion flag on all instructions */ ++static void set_convert_flag(struct jit_context *ctx, bool enable) ++{ ++ const struct bpf_prog *prog = ctx->program; ++ u32 flag = enable ? JIT_DESC_CONVERT : 0; ++ unsigned int i; ++ ++ for (i = 0; i <= prog->len; i++) ++ ctx->descriptors[i] = INDEX(ctx->descriptors[i]) | flag; ++} ++ ++static void jit_fill_hole(void *area, unsigned int size) ++{ ++ u32 *p; ++ ++ /* We are guaranteed to have aligned memory. */ ++ for (p = area; size >= sizeof(u32); size -= sizeof(u32)) ++ uasm_i_break(&p, BRK_BUG); /* Increments p */ ++} ++ ++bool bpf_jit_needs_zext(void) ++{ ++ return true; ++} ++ ++struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) ++{ ++ struct bpf_prog *tmp, *orig_prog = prog; ++ struct bpf_binary_header *header = NULL; ++ struct jit_context ctx; ++ bool tmp_blinded = false; ++ unsigned int tmp_idx; ++ unsigned int image_size; ++ u8 *image_ptr; ++ int tries; ++ ++ /* ++ * If BPF JIT was not enabled then we must fall back to ++ * the interpreter. ++ */ ++ if (!prog->jit_requested) ++ return orig_prog; ++ /* ++ * If constant blinding was enabled and we failed during blinding ++ * then we must fall back to the interpreter. Otherwise, we save ++ * the new JITed code. ++ */ ++ tmp = bpf_jit_blind_constants(prog); ++ if (IS_ERR(tmp)) ++ return orig_prog; ++ if (tmp != prog) { ++ tmp_blinded = true; ++ prog = tmp; ++ } ++ ++ memset(&ctx, 0, sizeof(ctx)); ++ ctx.program = prog; ++ ++ /* ++ * Not able to allocate memory for descriptors[], then ++ * we must fall back to the interpreter ++ */ ++ ctx.descriptors = kcalloc(prog->len + 1, sizeof(*ctx.descriptors), ++ GFP_KERNEL); ++ if (ctx.descriptors == NULL) ++ goto out_err; ++ ++ /* First pass discovers used resources */ ++ if (build_body(&ctx) < 0) ++ goto out_err; ++ /* ++ * Second pass computes instruction offsets. ++ * If any PC-relative branches are out of range, a sequence of ++ * a PC-relative branch + a jump is generated, and we have to ++ * try again from the beginning to generate the new offsets. ++ * This is done until no additional conversions are necessary. ++ * The last two iterations are done with all branches being ++ * converted, to guarantee offset table convergence within a ++ * fixed number of iterations. ++ */ ++ ctx.jit_index = 0; ++ build_prologue(&ctx); ++ tmp_idx = ctx.jit_index; ++ ++ tries = JIT_MAX_ITERATIONS; ++ do { ++ ctx.jit_index = tmp_idx; ++ ctx.changes = 0; ++ if (tries == 2) ++ set_convert_flag(&ctx, true); ++ if (build_body(&ctx) < 0) ++ goto out_err; ++ } while (ctx.changes > 0 && --tries > 0); ++ ++ if (WARN_ONCE(ctx.changes > 0, "JIT offsets failed to converge")) ++ goto out_err; ++ ++ build_epilogue(&ctx, MIPS_R_RA); ++ ++ /* Now we know the size of the structure to make */ ++ image_size = sizeof(u32) * ctx.jit_index; ++ header = bpf_jit_binary_alloc(image_size, &image_ptr, ++ sizeof(u32), jit_fill_hole); ++ /* ++ * Not able to allocate memory for the structure then ++ * we must fall back to the interpretation ++ */ ++ if (header == NULL) ++ goto out_err; ++ ++ /* Actual pass to generate final JIT code */ ++ ctx.target = (u32 *)image_ptr; ++ ctx.jit_index = 0; ++ ++ /* ++ * If building the JITed code fails somehow, ++ * we fall back to the interpretation. ++ */ ++ build_prologue(&ctx); ++ if (build_body(&ctx) < 0) ++ goto out_err; ++ build_epilogue(&ctx, MIPS_R_RA); ++ ++ /* Populate line info meta data */ ++ set_convert_flag(&ctx, false); ++ bpf_prog_fill_jited_linfo(prog, &ctx.descriptors[1]); ++ ++ /* Set as read-only exec and flush instruction cache */ ++ bpf_jit_binary_lock_ro(header); ++ flush_icache_range((unsigned long)header, ++ (unsigned long)&ctx.target[ctx.jit_index]); ++ ++ if (bpf_jit_enable > 1) ++ bpf_jit_dump(prog->len, image_size, 2, ctx.target); ++ ++ prog->bpf_func = (void *)ctx.target; ++ prog->jited = 1; ++ prog->jited_len = image_size; ++ ++out: ++ if (tmp_blinded) ++ bpf_jit_prog_release_other(prog, prog == orig_prog ? ++ tmp : orig_prog); ++ kfree(ctx.descriptors); ++ return prog; ++ ++out_err: ++ prog = orig_prog; ++ if (header) ++ bpf_jit_binary_free(header); ++ goto out; ++} +--- /dev/null ++++ b/arch/mips/net/bpf_jit_comp.h +@@ -0,0 +1,211 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Just-In-Time compiler for eBPF bytecode on 32-bit and 64-bit MIPS. ++ * ++ * Copyright (c) 2021 Anyfi Networks AB. ++ * Author: Johan Almbladh ++ * ++ * Based on code and ideas from ++ * Copyright (c) 2017 Cavium, Inc. ++ * Copyright (c) 2017 Shubham Bansal ++ * Copyright (c) 2011 Mircea Gherzan ++ */ ++ ++#ifndef _BPF_JIT_COMP_H ++#define _BPF_JIT_COMP_H ++ ++/* MIPS registers */ ++#define MIPS_R_ZERO 0 /* Const zero */ ++#define MIPS_R_AT 1 /* Asm temp */ ++#define MIPS_R_V0 2 /* Result */ ++#define MIPS_R_V1 3 /* Result */ ++#define MIPS_R_A0 4 /* Argument */ ++#define MIPS_R_A1 5 /* Argument */ ++#define MIPS_R_A2 6 /* Argument */ ++#define MIPS_R_A3 7 /* Argument */ ++#define MIPS_R_A4 8 /* Arg (n64) */ ++#define MIPS_R_A5 9 /* Arg (n64) */ ++#define MIPS_R_A6 10 /* Arg (n64) */ ++#define MIPS_R_A7 11 /* Arg (n64) */ ++#define MIPS_R_T0 8 /* Temp (o32) */ ++#define MIPS_R_T1 9 /* Temp (o32) */ ++#define MIPS_R_T2 10 /* Temp (o32) */ ++#define MIPS_R_T3 11 /* Temp (o32) */ ++#define MIPS_R_T4 12 /* Temporary */ ++#define MIPS_R_T5 13 /* Temporary */ ++#define MIPS_R_T6 14 /* Temporary */ ++#define MIPS_R_T7 15 /* Temporary */ ++#define MIPS_R_S0 16 /* Saved */ ++#define MIPS_R_S1 17 /* Saved */ ++#define MIPS_R_S2 18 /* Saved */ ++#define MIPS_R_S3 19 /* Saved */ ++#define MIPS_R_S4 20 /* Saved */ ++#define MIPS_R_S5 21 /* Saved */ ++#define MIPS_R_S6 22 /* Saved */ ++#define MIPS_R_S7 23 /* Saved */ ++#define MIPS_R_T8 24 /* Temporary */ ++#define MIPS_R_T9 25 /* Temporary */ ++/* MIPS_R_K0 26 Reserved */ ++/* MIPS_R_K1 27 Reserved */ ++#define MIPS_R_GP 28 /* Global ptr */ ++#define MIPS_R_SP 29 /* Stack ptr */ ++#define MIPS_R_FP 30 /* Frame ptr */ ++#define MIPS_R_RA 31 /* Return */ ++ ++/* ++ * Jump address mask for immediate jumps. The four most significant bits ++ * must be equal to PC. ++ */ ++#define MIPS_JMP_MASK 0x0fffffffUL ++ ++/* Maximum number of iterations in offset table computation */ ++#define JIT_MAX_ITERATIONS 8 ++ ++/* ++ * Jump pseudo-instructions used internally ++ * for branch conversion and branch optimization. ++ */ ++#define JIT_JNSET 0xe0 ++#define JIT_JNOP 0xf0 ++ ++/* Descriptor flag for PC-relative branch conversion */ ++#define JIT_DESC_CONVERT BIT(31) ++ ++/* JIT context for an eBPF program */ ++struct jit_context { ++ struct bpf_prog *program; /* The eBPF program being JITed */ ++ u32 *descriptors; /* eBPF to JITed CPU insn descriptors */ ++ u32 *target; /* JITed code buffer */ ++ u32 bpf_index; /* Index of current BPF program insn */ ++ u32 jit_index; /* Index of current JIT target insn */ ++ u32 changes; /* Number of PC-relative branch conv */ ++ u32 accessed; /* Bit mask of read eBPF registers */ ++ u32 clobbered; /* Bit mask of modified CPU registers */ ++ u32 stack_size; /* Total allocated stack size in bytes */ ++ u32 saved_size; /* Size of callee-saved registers */ ++ u32 stack_used; /* Stack size used for function calls */ ++}; ++ ++/* Emit the instruction if the JIT memory space has been allocated */ ++#define emit(ctx, func, ...) \ ++do { \ ++ if ((ctx)->target != NULL) { \ ++ u32 *p = &(ctx)->target[ctx->jit_index]; \ ++ uasm_i_##func(&p, ##__VA_ARGS__); \ ++ } \ ++ (ctx)->jit_index++; \ ++} while (0) ++ ++/* ++ * Mark a BPF register as accessed, it needs to be ++ * initialized by the program if expected, e.g. FP. ++ */ ++static inline void access_reg(struct jit_context *ctx, u8 reg) ++{ ++ ctx->accessed |= BIT(reg); ++} ++ ++/* ++ * Mark a CPU register as clobbered, it needs to be ++ * saved/restored by the program if callee-saved. ++ */ ++static inline void clobber_reg(struct jit_context *ctx, u8 reg) ++{ ++ ctx->clobbered |= BIT(reg); ++} ++ ++/* ++ * Push registers on the stack, starting at a given depth from the stack ++ * pointer and increasing. The next depth to be written is returned. ++ */ ++int push_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth); ++ ++/* ++ * Pop registers from the stack, starting at a given depth from the stack ++ * pointer and increasing. The next depth to be read is returned. ++ */ ++int pop_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth); ++ ++/* Compute the 28-bit jump target address from a BPF program location */ ++int get_target(struct jit_context *ctx, u32 loc); ++ ++/* Compute the PC-relative offset to relative BPF program offset */ ++int get_offset(const struct jit_context *ctx, int off); ++ ++/* dst = imm (32-bit) */ ++void emit_mov_i(struct jit_context *ctx, u8 dst, s32 imm); ++ ++/* dst = src (32-bit) */ ++void emit_mov_r(struct jit_context *ctx, u8 dst, u8 src); ++ ++/* Validate ALU/ALU64 immediate range */ ++bool valid_alu_i(u8 op, s32 imm); ++ ++/* Rewrite ALU/ALU64 immediate operation */ ++bool rewrite_alu_i(u8 op, s32 imm, u8 *alu, s32 *val); ++ ++/* ALU immediate operation (32-bit) */ ++void emit_alu_i(struct jit_context *ctx, u8 dst, s32 imm, u8 op); ++ ++/* ALU register operation (32-bit) */ ++void emit_alu_r(struct jit_context *ctx, u8 dst, u8 src, u8 op); ++ ++/* Atomic read-modify-write (32-bit) */ ++void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code); ++ ++/* Atomic compare-and-exchange (32-bit) */ ++void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off); ++ ++/* Swap bytes and truncate a register word or half word */ ++void emit_bswap_r(struct jit_context *ctx, u8 dst, u32 width); ++ ++/* Validate JMP/JMP32 immediate range */ ++bool valid_jmp_i(u8 op, s32 imm); ++ ++/* Prepare a PC-relative jump operation with immediate conditional */ ++void setup_jmp_i(struct jit_context *ctx, s32 imm, u8 width, ++ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off); ++ ++/* Prepare a PC-relative jump operation with register conditional */ ++void setup_jmp_r(struct jit_context *ctx, bool same_reg, ++ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off); ++ ++/* Finish a PC-relative jump operation */ ++int finish_jmp(struct jit_context *ctx, u8 jit_op, s16 bpf_off); ++ ++/* Conditional JMP/JMP32 immediate */ ++void emit_jmp_i(struct jit_context *ctx, u8 dst, s32 imm, s32 off, u8 op); ++ ++/* Conditional JMP/JMP32 register */ ++void emit_jmp_r(struct jit_context *ctx, u8 dst, u8 src, s32 off, u8 op); ++ ++/* Jump always */ ++int emit_ja(struct jit_context *ctx, s16 off); ++ ++/* Jump to epilogue */ ++int emit_exit(struct jit_context *ctx); ++ ++/* ++ * Build program prologue to set up the stack and registers. ++ * This function is implemented separately for 32-bit and 64-bit JITs. ++ */ ++void build_prologue(struct jit_context *ctx); ++ ++/* ++ * Build the program epilogue to restore the stack and registers. ++ * This function is implemented separately for 32-bit and 64-bit JITs. ++ */ ++void build_epilogue(struct jit_context *ctx, int dest_reg); ++ ++/* ++ * Convert an eBPF instruction to native instruction, i.e ++ * JITs an eBPF instruction. ++ * Returns : ++ * 0 - Successfully JITed an 8-byte eBPF instruction ++ * >0 - Successfully JITed a 16-byte eBPF instruction ++ * <0 - Failed to JIT. ++ * This function is implemented separately for 32-bit and 64-bit JITs. ++ */ ++int build_insn(const struct bpf_insn *insn, struct jit_context *ctx); ++ ++#endif /* _BPF_JIT_COMP_H */ +--- /dev/null ++++ b/arch/mips/net/bpf_jit_comp32.c +@@ -0,0 +1,1741 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Just-In-Time compiler for eBPF bytecode on MIPS. ++ * Implementation of JIT functions for 32-bit CPUs. ++ * ++ * Copyright (c) 2021 Anyfi Networks AB. ++ * Author: Johan Almbladh ++ * ++ * Based on code and ideas from ++ * Copyright (c) 2017 Cavium, Inc. ++ * Copyright (c) 2017 Shubham Bansal ++ * Copyright (c) 2011 Mircea Gherzan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bpf_jit_comp.h" ++ ++/* MIPS a4-a7 are not available in the o32 ABI */ ++#undef MIPS_R_A4 ++#undef MIPS_R_A5 ++#undef MIPS_R_A6 ++#undef MIPS_R_A7 ++ ++/* Stack is 8-byte aligned in o32 ABI */ ++#define MIPS_STACK_ALIGNMENT 8 ++ ++/* ++ * The top 16 bytes of a stack frame is reserved for the callee in O32 ABI. ++ * This corresponds to stack space for register arguments a0-a3. ++ */ ++#define JIT_RESERVED_STACK 16 ++ ++/* Temporary 64-bit register used by JIT */ ++#define JIT_REG_TMP MAX_BPF_JIT_REG ++ ++/* ++ * Number of prologue bytes to skip when doing a tail call. ++ * Tail call count (TCC) initialization (8 bytes) always, plus ++ * R0-to-v0 assignment (4 bytes) if big endian. ++ */ ++#ifdef __BIG_ENDIAN ++#define JIT_TCALL_SKIP 12 ++#else ++#define JIT_TCALL_SKIP 8 ++#endif ++ ++/* CPU registers holding the callee return value */ ++#define JIT_RETURN_REGS \ ++ (BIT(MIPS_R_V0) | \ ++ BIT(MIPS_R_V1)) ++ ++/* CPU registers arguments passed to callee directly */ ++#define JIT_ARG_REGS \ ++ (BIT(MIPS_R_A0) | \ ++ BIT(MIPS_R_A1) | \ ++ BIT(MIPS_R_A2) | \ ++ BIT(MIPS_R_A3)) ++ ++/* CPU register arguments passed to callee on stack */ ++#define JIT_STACK_REGS \ ++ (BIT(MIPS_R_T0) | \ ++ BIT(MIPS_R_T1) | \ ++ BIT(MIPS_R_T2) | \ ++ BIT(MIPS_R_T3) | \ ++ BIT(MIPS_R_T4) | \ ++ BIT(MIPS_R_T5)) ++ ++/* Caller-saved CPU registers */ ++#define JIT_CALLER_REGS \ ++ (JIT_RETURN_REGS | \ ++ JIT_ARG_REGS | \ ++ JIT_STACK_REGS) ++ ++/* Callee-saved CPU registers */ ++#define JIT_CALLEE_REGS \ ++ (BIT(MIPS_R_S0) | \ ++ BIT(MIPS_R_S1) | \ ++ BIT(MIPS_R_S2) | \ ++ BIT(MIPS_R_S3) | \ ++ BIT(MIPS_R_S4) | \ ++ BIT(MIPS_R_S5) | \ ++ BIT(MIPS_R_S6) | \ ++ BIT(MIPS_R_S7) | \ ++ BIT(MIPS_R_GP) | \ ++ BIT(MIPS_R_FP) | \ ++ BIT(MIPS_R_RA)) ++ ++/* ++ * Mapping of 64-bit eBPF registers to 32-bit native MIPS registers. ++ * ++ * 1) Native register pairs are ordered according to CPU endiannes, following ++ * the MIPS convention for passing 64-bit arguments and return values. ++ * 2) The eBPF return value, arguments and callee-saved registers are mapped ++ * to their native MIPS equivalents. ++ * 3) Since the 32 highest bits in the eBPF FP register are always zero, ++ * only one general-purpose register is actually needed for the mapping. ++ * We use the fp register for this purpose, and map the highest bits to ++ * the MIPS register r0 (zero). ++ * 4) We use the MIPS gp and at registers as internal temporary registers ++ * for constant blinding. The gp register is callee-saved. ++ * 5) One 64-bit temporary register is mapped for use when sign-extending ++ * immediate operands. MIPS registers t6-t9 are available to the JIT ++ * for as temporaries when implementing complex 64-bit operations. ++ * ++ * With this scheme all eBPF registers are being mapped to native MIPS ++ * registers without having to use any stack scratch space. The direct ++ * register mapping (2) simplifies the handling of function calls. ++ */ ++static const u8 bpf2mips32[][2] = { ++ /* Return value from in-kernel function, and exit value from eBPF */ ++ [BPF_REG_0] = {MIPS_R_V1, MIPS_R_V0}, ++ /* Arguments from eBPF program to in-kernel function */ ++ [BPF_REG_1] = {MIPS_R_A1, MIPS_R_A0}, ++ [BPF_REG_2] = {MIPS_R_A3, MIPS_R_A2}, ++ /* Remaining arguments, to be passed on the stack per O32 ABI */ ++ [BPF_REG_3] = {MIPS_R_T1, MIPS_R_T0}, ++ [BPF_REG_4] = {MIPS_R_T3, MIPS_R_T2}, ++ [BPF_REG_5] = {MIPS_R_T5, MIPS_R_T4}, ++ /* Callee-saved registers that in-kernel function will preserve */ ++ [BPF_REG_6] = {MIPS_R_S1, MIPS_R_S0}, ++ [BPF_REG_7] = {MIPS_R_S3, MIPS_R_S2}, ++ [BPF_REG_8] = {MIPS_R_S5, MIPS_R_S4}, ++ [BPF_REG_9] = {MIPS_R_S7, MIPS_R_S6}, ++ /* Read-only frame pointer to access the eBPF stack */ ++#ifdef __BIG_ENDIAN ++ [BPF_REG_FP] = {MIPS_R_FP, MIPS_R_ZERO}, ++#else ++ [BPF_REG_FP] = {MIPS_R_ZERO, MIPS_R_FP}, ++#endif ++ /* Temporary register for blinding constants */ ++ [BPF_REG_AX] = {MIPS_R_GP, MIPS_R_AT}, ++ /* Temporary register for internal JIT use */ ++ [JIT_REG_TMP] = {MIPS_R_T7, MIPS_R_T6}, ++}; ++ ++/* Get low CPU register for a 64-bit eBPF register mapping */ ++static inline u8 lo(const u8 reg[]) ++{ ++#ifdef __BIG_ENDIAN ++ return reg[0]; ++#else ++ return reg[1]; ++#endif ++} ++ ++/* Get high CPU register for a 64-bit eBPF register mapping */ ++static inline u8 hi(const u8 reg[]) ++{ ++#ifdef __BIG_ENDIAN ++ return reg[1]; ++#else ++ return reg[0]; ++#endif ++} ++ ++/* ++ * Mark a 64-bit CPU register pair as clobbered, it needs to be ++ * saved/restored by the program if callee-saved. ++ */ ++static void clobber_reg64(struct jit_context *ctx, const u8 reg[]) ++{ ++ clobber_reg(ctx, reg[0]); ++ clobber_reg(ctx, reg[1]); ++} ++ ++/* dst = imm (sign-extended) */ ++static void emit_mov_se_i64(struct jit_context *ctx, const u8 dst[], s32 imm) ++{ ++ emit_mov_i(ctx, lo(dst), imm); ++ if (imm < 0) ++ emit(ctx, addiu, hi(dst), MIPS_R_ZERO, -1); ++ else ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ clobber_reg64(ctx, dst); ++} ++ ++/* Zero extension, if verifier does not do it for us */ ++static void emit_zext_ver(struct jit_context *ctx, const u8 dst[]) ++{ ++ if (!ctx->program->aux->verifier_zext) { ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ clobber_reg(ctx, hi(dst)); ++ } ++} ++ ++/* Load delay slot, if ISA mandates it */ ++static void emit_load_delay(struct jit_context *ctx) ++{ ++ if (!cpu_has_mips_2_3_4_5_r) ++ emit(ctx, nop); ++} ++ ++/* ALU immediate operation (64-bit) */ ++static void emit_alu_i64(struct jit_context *ctx, ++ const u8 dst[], s32 imm, u8 op) ++{ ++ u8 src = MIPS_R_T6; ++ ++ /* ++ * ADD/SUB with all but the max negative imm can be handled by ++ * inverting the operation and the imm value, saving one insn. ++ */ ++ if (imm > S32_MIN && imm < 0) ++ switch (op) { ++ case BPF_ADD: ++ op = BPF_SUB; ++ imm = -imm; ++ break; ++ case BPF_SUB: ++ op = BPF_ADD; ++ imm = -imm; ++ break; ++ } ++ ++ /* Move immediate to temporary register */ ++ emit_mov_i(ctx, src, imm); ++ ++ switch (op) { ++ /* dst = dst + imm */ ++ case BPF_ADD: ++ emit(ctx, addu, lo(dst), lo(dst), src); ++ emit(ctx, sltu, MIPS_R_T9, lo(dst), src); ++ emit(ctx, addu, hi(dst), hi(dst), MIPS_R_T9); ++ if (imm < 0) ++ emit(ctx, addiu, hi(dst), hi(dst), -1); ++ break; ++ /* dst = dst - imm */ ++ case BPF_SUB: ++ emit(ctx, sltu, MIPS_R_T9, lo(dst), src); ++ emit(ctx, subu, lo(dst), lo(dst), src); ++ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); ++ if (imm < 0) ++ emit(ctx, addiu, hi(dst), hi(dst), 1); ++ break; ++ /* dst = dst | imm */ ++ case BPF_OR: ++ emit(ctx, or, lo(dst), lo(dst), src); ++ if (imm < 0) ++ emit(ctx, addiu, hi(dst), MIPS_R_ZERO, -1); ++ break; ++ /* dst = dst & imm */ ++ case BPF_AND: ++ emit(ctx, and, lo(dst), lo(dst), src); ++ if (imm >= 0) ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ break; ++ /* dst = dst ^ imm */ ++ case BPF_XOR: ++ emit(ctx, xor, lo(dst), lo(dst), src); ++ if (imm < 0) { ++ emit(ctx, subu, hi(dst), MIPS_R_ZERO, hi(dst)); ++ emit(ctx, addiu, hi(dst), hi(dst), -1); ++ } ++ break; ++ } ++ clobber_reg64(ctx, dst); ++} ++ ++/* ALU register operation (64-bit) */ ++static void emit_alu_r64(struct jit_context *ctx, ++ const u8 dst[], const u8 src[], u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = dst + src */ ++ case BPF_ADD: ++ if (src == dst) { ++ emit(ctx, srl, MIPS_R_T9, lo(dst), 31); ++ emit(ctx, addu, lo(dst), lo(dst), lo(dst)); ++ } else { ++ emit(ctx, addu, lo(dst), lo(dst), lo(src)); ++ emit(ctx, sltu, MIPS_R_T9, lo(dst), lo(src)); ++ } ++ emit(ctx, addu, hi(dst), hi(dst), hi(src)); ++ emit(ctx, addu, hi(dst), hi(dst), MIPS_R_T9); ++ break; ++ /* dst = dst - src */ ++ case BPF_SUB: ++ emit(ctx, sltu, MIPS_R_T9, lo(dst), lo(src)); ++ emit(ctx, subu, lo(dst), lo(dst), lo(src)); ++ emit(ctx, subu, hi(dst), hi(dst), hi(src)); ++ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); ++ break; ++ /* dst = dst | src */ ++ case BPF_OR: ++ emit(ctx, or, lo(dst), lo(dst), lo(src)); ++ emit(ctx, or, hi(dst), hi(dst), hi(src)); ++ break; ++ /* dst = dst & src */ ++ case BPF_AND: ++ emit(ctx, and, lo(dst), lo(dst), lo(src)); ++ emit(ctx, and, hi(dst), hi(dst), hi(src)); ++ break; ++ /* dst = dst ^ src */ ++ case BPF_XOR: ++ emit(ctx, xor, lo(dst), lo(dst), lo(src)); ++ emit(ctx, xor, hi(dst), hi(dst), hi(src)); ++ break; ++ } ++ clobber_reg64(ctx, dst); ++} ++ ++/* ALU invert (64-bit) */ ++static void emit_neg_i64(struct jit_context *ctx, const u8 dst[]) ++{ ++ emit(ctx, sltu, MIPS_R_T9, MIPS_R_ZERO, lo(dst)); ++ emit(ctx, subu, lo(dst), MIPS_R_ZERO, lo(dst)); ++ emit(ctx, subu, hi(dst), MIPS_R_ZERO, hi(dst)); ++ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); ++ ++ clobber_reg64(ctx, dst); ++} ++ ++/* ALU shift immediate (64-bit) */ ++static void emit_shift_i64(struct jit_context *ctx, ++ const u8 dst[], u32 imm, u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = dst << imm */ ++ case BPF_LSH: ++ if (imm < 32) { ++ emit(ctx, srl, MIPS_R_T9, lo(dst), 32 - imm); ++ emit(ctx, sll, lo(dst), lo(dst), imm); ++ emit(ctx, sll, hi(dst), hi(dst), imm); ++ emit(ctx, or, hi(dst), hi(dst), MIPS_R_T9); ++ } else { ++ emit(ctx, sll, hi(dst), lo(dst), imm - 32); ++ emit(ctx, move, lo(dst), MIPS_R_ZERO); ++ } ++ break; ++ /* dst = dst >> imm */ ++ case BPF_RSH: ++ if (imm < 32) { ++ emit(ctx, sll, MIPS_R_T9, hi(dst), 32 - imm); ++ emit(ctx, srl, lo(dst), lo(dst), imm); ++ emit(ctx, srl, hi(dst), hi(dst), imm); ++ emit(ctx, or, lo(dst), lo(dst), MIPS_R_T9); ++ } else { ++ emit(ctx, srl, lo(dst), hi(dst), imm - 32); ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ } ++ break; ++ /* dst = dst >> imm (arithmetic) */ ++ case BPF_ARSH: ++ if (imm < 32) { ++ emit(ctx, sll, MIPS_R_T9, hi(dst), 32 - imm); ++ emit(ctx, srl, lo(dst), lo(dst), imm); ++ emit(ctx, sra, hi(dst), hi(dst), imm); ++ emit(ctx, or, lo(dst), lo(dst), MIPS_R_T9); ++ } else { ++ emit(ctx, sra, lo(dst), hi(dst), imm - 32); ++ emit(ctx, sra, hi(dst), hi(dst), 31); ++ } ++ break; ++ } ++ clobber_reg64(ctx, dst); ++} ++ ++/* ALU shift register (64-bit) */ ++static void emit_shift_r64(struct jit_context *ctx, ++ const u8 dst[], u8 src, u8 op) ++{ ++ u8 t1 = MIPS_R_T8; ++ u8 t2 = MIPS_R_T9; ++ ++ emit(ctx, andi, t1, src, 32); /* t1 = src & 32 */ ++ emit(ctx, beqz, t1, 16); /* PC += 16 if t1 == 0 */ ++ emit(ctx, nor, t2, src, MIPS_R_ZERO); /* t2 = ~src (delay slot) */ ++ ++ switch (BPF_OP(op)) { ++ /* dst = dst << src */ ++ case BPF_LSH: ++ /* Next: shift >= 32 */ ++ emit(ctx, sllv, hi(dst), lo(dst), src); /* dh = dl << src */ ++ emit(ctx, move, lo(dst), MIPS_R_ZERO); /* dl = 0 */ ++ emit(ctx, b, 20); /* PC += 20 */ ++ /* +16: shift < 32 */ ++ emit(ctx, srl, t1, lo(dst), 1); /* t1 = dl >> 1 */ ++ emit(ctx, srlv, t1, t1, t2); /* t1 = t1 >> t2 */ ++ emit(ctx, sllv, lo(dst), lo(dst), src); /* dl = dl << src */ ++ emit(ctx, sllv, hi(dst), hi(dst), src); /* dh = dh << src */ ++ emit(ctx, or, hi(dst), hi(dst), t1); /* dh = dh | t1 */ ++ break; ++ /* dst = dst >> src */ ++ case BPF_RSH: ++ /* Next: shift >= 32 */ ++ emit(ctx, srlv, lo(dst), hi(dst), src); /* dl = dh >> src */ ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); /* dh = 0 */ ++ emit(ctx, b, 20); /* PC += 20 */ ++ /* +16: shift < 32 */ ++ emit(ctx, sll, t1, hi(dst), 1); /* t1 = dl << 1 */ ++ emit(ctx, sllv, t1, t1, t2); /* t1 = t1 << t2 */ ++ emit(ctx, srlv, lo(dst), lo(dst), src); /* dl = dl >> src */ ++ emit(ctx, srlv, hi(dst), hi(dst), src); /* dh = dh >> src */ ++ emit(ctx, or, lo(dst), lo(dst), t1); /* dl = dl | t1 */ ++ break; ++ /* dst = dst >> src (arithmetic) */ ++ case BPF_ARSH: ++ /* Next: shift >= 32 */ ++ emit(ctx, srav, lo(dst), hi(dst), src); /* dl = dh >>a src */ ++ emit(ctx, sra, hi(dst), hi(dst), 31); /* dh = dh >>a 31 */ ++ emit(ctx, b, 20); /* PC += 20 */ ++ /* +16: shift < 32 */ ++ emit(ctx, sll, t1, hi(dst), 1); /* t1 = dl << 1 */ ++ emit(ctx, sllv, t1, t1, t2); /* t1 = t1 << t2 */ ++ emit(ctx, srlv, lo(dst), lo(dst), src); /* dl = dl >>a src */ ++ emit(ctx, srav, hi(dst), hi(dst), src); /* dh = dh >> src */ ++ emit(ctx, or, lo(dst), lo(dst), t1); /* dl = dl | t1 */ ++ break; ++ } ++ ++ /* +20: Done */ ++ clobber_reg64(ctx, dst); ++} ++ ++/* ALU mul immediate (64x32-bit) */ ++static void emit_mul_i64(struct jit_context *ctx, const u8 dst[], s32 imm) ++{ ++ u8 src = MIPS_R_T6; ++ u8 tmp = MIPS_R_T9; ++ ++ switch (imm) { ++ /* dst = dst * 1 is a no-op */ ++ case 1: ++ break; ++ /* dst = dst * -1 */ ++ case -1: ++ emit_neg_i64(ctx, dst); ++ break; ++ case 0: ++ emit_mov_r(ctx, lo(dst), MIPS_R_ZERO); ++ emit_mov_r(ctx, hi(dst), MIPS_R_ZERO); ++ break; ++ /* Full 64x32 multiply */ ++ default: ++ /* hi(dst) = hi(dst) * src(imm) */ ++ emit_mov_i(ctx, src, imm); ++ if (cpu_has_mips32r1 || cpu_has_mips32r6) { ++ emit(ctx, mul, hi(dst), hi(dst), src); ++ } else { ++ emit(ctx, multu, hi(dst), src); ++ emit(ctx, mflo, hi(dst)); ++ } ++ ++ /* hi(dst) = hi(dst) - lo(dst) */ ++ if (imm < 0) ++ emit(ctx, subu, hi(dst), hi(dst), lo(dst)); ++ ++ /* tmp = lo(dst) * src(imm) >> 32 */ ++ /* lo(dst) = lo(dst) * src(imm) */ ++ if (cpu_has_mips32r6) { ++ emit(ctx, muhu, tmp, lo(dst), src); ++ emit(ctx, mulu, lo(dst), lo(dst), src); ++ } else { ++ emit(ctx, multu, lo(dst), src); ++ emit(ctx, mflo, lo(dst)); ++ emit(ctx, mfhi, tmp); ++ } ++ ++ /* hi(dst) += tmp */ ++ emit(ctx, addu, hi(dst), hi(dst), tmp); ++ clobber_reg64(ctx, dst); ++ break; ++ } ++} ++ ++/* ALU mul register (64x64-bit) */ ++static void emit_mul_r64(struct jit_context *ctx, ++ const u8 dst[], const u8 src[]) ++{ ++ u8 acc = MIPS_R_T8; ++ u8 tmp = MIPS_R_T9; ++ ++ /* acc = hi(dst) * lo(src) */ ++ if (cpu_has_mips32r1 || cpu_has_mips32r6) { ++ emit(ctx, mul, acc, hi(dst), lo(src)); ++ } else { ++ emit(ctx, multu, hi(dst), lo(src)); ++ emit(ctx, mflo, acc); ++ } ++ ++ /* tmp = lo(dst) * hi(src) */ ++ if (cpu_has_mips32r1 || cpu_has_mips32r6) { ++ emit(ctx, mul, tmp, lo(dst), hi(src)); ++ } else { ++ emit(ctx, multu, lo(dst), hi(src)); ++ emit(ctx, mflo, tmp); ++ } ++ ++ /* acc += tmp */ ++ emit(ctx, addu, acc, acc, tmp); ++ ++ /* tmp = lo(dst) * lo(src) >> 32 */ ++ /* lo(dst) = lo(dst) * lo(src) */ ++ if (cpu_has_mips32r6) { ++ emit(ctx, muhu, tmp, lo(dst), lo(src)); ++ emit(ctx, mulu, lo(dst), lo(dst), lo(src)); ++ } else { ++ emit(ctx, multu, lo(dst), lo(src)); ++ emit(ctx, mflo, lo(dst)); ++ emit(ctx, mfhi, tmp); ++ } ++ ++ /* hi(dst) = acc + tmp */ ++ emit(ctx, addu, hi(dst), acc, tmp); ++ clobber_reg64(ctx, dst); ++} ++ ++/* Helper function for 64-bit modulo */ ++static u64 jit_mod64(u64 a, u64 b) ++{ ++ u64 rem; ++ ++ div64_u64_rem(a, b, &rem); ++ return rem; ++} ++ ++/* ALU div/mod register (64-bit) */ ++static void emit_divmod_r64(struct jit_context *ctx, ++ const u8 dst[], const u8 src[], u8 op) ++{ ++ const u8 *r0 = bpf2mips32[BPF_REG_0]; /* Mapped to v0-v1 */ ++ const u8 *r1 = bpf2mips32[BPF_REG_1]; /* Mapped to a0-a1 */ ++ const u8 *r2 = bpf2mips32[BPF_REG_2]; /* Mapped to a2-a3 */ ++ int exclude, k; ++ u32 addr = 0; ++ ++ /* Push caller-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ 0, JIT_RESERVED_STACK); ++ ++ /* Put 64-bit arguments 1 and 2 in registers a0-a3 */ ++ for (k = 0; k < 2; k++) { ++ emit(ctx, move, MIPS_R_T9, src[k]); ++ emit(ctx, move, r1[k], dst[k]); ++ emit(ctx, move, r2[k], MIPS_R_T9); ++ } ++ ++ /* Emit function call */ ++ switch (BPF_OP(op)) { ++ /* dst = dst / src */ ++ case BPF_DIV: ++ addr = (u32)&div64_u64; ++ break; ++ /* dst = dst % src */ ++ case BPF_MOD: ++ addr = (u32)&jit_mod64; ++ break; ++ } ++ emit_mov_i(ctx, MIPS_R_T9, addr); ++ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* Store the 64-bit result in dst */ ++ emit(ctx, move, dst[0], r0[0]); ++ emit(ctx, move, dst[1], r0[1]); ++ ++ /* Restore caller-saved registers, excluding the computed result */ ++ exclude = BIT(lo(dst)) | BIT(hi(dst)); ++ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ exclude, JIT_RESERVED_STACK); ++ emit_load_delay(ctx); ++ ++ clobber_reg64(ctx, dst); ++ clobber_reg(ctx, MIPS_R_V0); ++ clobber_reg(ctx, MIPS_R_V1); ++ clobber_reg(ctx, MIPS_R_RA); ++} ++ ++/* Swap bytes in a register word */ ++static void emit_swap8_r(struct jit_context *ctx, u8 dst, u8 src, u8 mask) ++{ ++ u8 tmp = MIPS_R_T9; ++ ++ emit(ctx, and, tmp, src, mask); /* tmp = src & 0x00ff00ff */ ++ emit(ctx, sll, tmp, tmp, 8); /* tmp = tmp << 8 */ ++ emit(ctx, srl, dst, src, 8); /* dst = src >> 8 */ ++ emit(ctx, and, dst, dst, mask); /* dst = dst & 0x00ff00ff */ ++ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ ++} ++ ++/* Swap half words in a register word */ ++static void emit_swap16_r(struct jit_context *ctx, u8 dst, u8 src) ++{ ++ u8 tmp = MIPS_R_T9; ++ ++ emit(ctx, sll, tmp, src, 16); /* tmp = src << 16 */ ++ emit(ctx, srl, dst, src, 16); /* dst = src >> 16 */ ++ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ ++} ++ ++/* Swap bytes and truncate a register double word, word or half word */ ++static void emit_bswap_r64(struct jit_context *ctx, const u8 dst[], u32 width) ++{ ++ u8 tmp = MIPS_R_T8; ++ ++ switch (width) { ++ /* Swap bytes in a double word */ ++ case 64: ++ if (cpu_has_mips32r2 || cpu_has_mips32r6) { ++ emit(ctx, rotr, tmp, hi(dst), 16); ++ emit(ctx, rotr, hi(dst), lo(dst), 16); ++ emit(ctx, wsbh, lo(dst), tmp); ++ emit(ctx, wsbh, hi(dst), hi(dst)); ++ } else { ++ emit_swap16_r(ctx, tmp, lo(dst)); ++ emit_swap16_r(ctx, lo(dst), hi(dst)); ++ emit(ctx, move, hi(dst), tmp); ++ ++ emit(ctx, lui, tmp, 0xff); /* tmp = 0x00ff0000 */ ++ emit(ctx, ori, tmp, tmp, 0xff); /* tmp = 0x00ff00ff */ ++ emit_swap8_r(ctx, lo(dst), lo(dst), tmp); ++ emit_swap8_r(ctx, hi(dst), hi(dst), tmp); ++ } ++ break; ++ /* Swap bytes in a word */ ++ /* Swap bytes in a half word */ ++ case 32: ++ case 16: ++ emit_bswap_r(ctx, lo(dst), width); ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ break; ++ } ++ clobber_reg64(ctx, dst); ++} ++ ++/* Truncate a register double word, word or half word */ ++static void emit_trunc_r64(struct jit_context *ctx, const u8 dst[], u32 width) ++{ ++ switch (width) { ++ case 64: ++ break; ++ /* Zero-extend a word */ ++ case 32: ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ clobber_reg(ctx, hi(dst)); ++ break; ++ /* Zero-extend a half word */ ++ case 16: ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ emit(ctx, andi, lo(dst), lo(dst), 0xffff); ++ clobber_reg64(ctx, dst); ++ break; ++ } ++} ++ ++/* Load operation: dst = *(size*)(src + off) */ ++static void emit_ldx(struct jit_context *ctx, ++ const u8 dst[], u8 src, s16 off, u8 size) ++{ ++ switch (size) { ++ /* Load a byte */ ++ case BPF_B: ++ emit(ctx, lbu, lo(dst), off, src); ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ break; ++ /* Load a half word */ ++ case BPF_H: ++ emit(ctx, lhu, lo(dst), off, src); ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ break; ++ /* Load a word */ ++ case BPF_W: ++ emit(ctx, lw, lo(dst), off, src); ++ emit(ctx, move, hi(dst), MIPS_R_ZERO); ++ break; ++ /* Load a double word */ ++ case BPF_DW: ++ if (dst[1] == src) { ++ emit(ctx, lw, dst[0], off + 4, src); ++ emit(ctx, lw, dst[1], off, src); ++ } else { ++ emit(ctx, lw, dst[1], off, src); ++ emit(ctx, lw, dst[0], off + 4, src); ++ } ++ emit_load_delay(ctx); ++ break; ++ } ++ clobber_reg64(ctx, dst); ++} ++ ++/* Store operation: *(size *)(dst + off) = src */ ++static void emit_stx(struct jit_context *ctx, ++ const u8 dst, const u8 src[], s16 off, u8 size) ++{ ++ switch (size) { ++ /* Store a byte */ ++ case BPF_B: ++ emit(ctx, sb, lo(src), off, dst); ++ break; ++ /* Store a half word */ ++ case BPF_H: ++ emit(ctx, sh, lo(src), off, dst); ++ break; ++ /* Store a word */ ++ case BPF_W: ++ emit(ctx, sw, lo(src), off, dst); ++ break; ++ /* Store a double word */ ++ case BPF_DW: ++ emit(ctx, sw, src[1], off, dst); ++ emit(ctx, sw, src[0], off + 4, dst); ++ break; ++ } ++} ++ ++/* Atomic read-modify-write (32-bit, non-ll/sc fallback) */ ++static void emit_atomic_r32(struct jit_context *ctx, ++ u8 dst, u8 src, s16 off, u8 code) ++{ ++ u32 exclude = 0; ++ u32 addr = 0; ++ ++ /* Push caller-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ 0, JIT_RESERVED_STACK); ++ /* ++ * Argument 1: dst+off if xchg, otherwise src, passed in register a0 ++ * Argument 2: src if xchg, othersize dst+off, passed in register a1 ++ */ ++ emit(ctx, move, MIPS_R_T9, dst); ++ emit(ctx, move, MIPS_R_A0, src); ++ emit(ctx, addiu, MIPS_R_A1, MIPS_R_T9, off); ++ ++ /* Emit function call */ ++ switch (code) { ++ case BPF_ADD: ++ addr = (u32)&atomic_add; ++ break; ++ case BPF_SUB: ++ addr = (u32)&atomic_sub; ++ break; ++ case BPF_OR: ++ addr = (u32)&atomic_or; ++ break; ++ case BPF_AND: ++ addr = (u32)&atomic_and; ++ break; ++ case BPF_XOR: ++ addr = (u32)&atomic_xor; ++ break; ++ } ++ emit_mov_i(ctx, MIPS_R_T9, addr); ++ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* Restore caller-saved registers, except any fetched value */ ++ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ exclude, JIT_RESERVED_STACK); ++ emit_load_delay(ctx); ++ clobber_reg(ctx, MIPS_R_RA); ++} ++ ++/* Atomic read-modify-write (64-bit) */ ++static void emit_atomic_r64(struct jit_context *ctx, ++ u8 dst, const u8 src[], s16 off, u8 code) ++{ ++ const u8 *r1 = bpf2mips32[BPF_REG_1]; /* Mapped to a0-a1 */ ++ u32 exclude = 0; ++ u32 addr = 0; ++ ++ /* Push caller-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ 0, JIT_RESERVED_STACK); ++ /* ++ * Argument 1: 64-bit src, passed in registers a0-a1 ++ * Argument 2: 32-bit dst+off, passed in register a2 ++ */ ++ emit(ctx, move, MIPS_R_T9, dst); ++ emit(ctx, move, r1[0], src[0]); ++ emit(ctx, move, r1[1], src[1]); ++ emit(ctx, addiu, MIPS_R_A2, MIPS_R_T9, off); ++ ++ /* Emit function call */ ++ switch (code) { ++ case BPF_ADD: ++ addr = (u32)&atomic64_add; ++ break; ++ case BPF_SUB: ++ addr = (u32)&atomic64_sub; ++ break; ++ case BPF_OR: ++ addr = (u32)&atomic64_or; ++ break; ++ case BPF_AND: ++ addr = (u32)&atomic64_and; ++ break; ++ case BPF_XOR: ++ addr = (u32)&atomic64_xor; ++ break; ++ } ++ emit_mov_i(ctx, MIPS_R_T9, addr); ++ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* Restore caller-saved registers, except any fetched value */ ++ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, ++ exclude, JIT_RESERVED_STACK); ++ emit_load_delay(ctx); ++ clobber_reg(ctx, MIPS_R_RA); ++} ++ ++/* ++ * Conditional movz or an emulated equivalent. ++ * Note that the rs register may be modified. ++ */ ++static void emit_movz_r(struct jit_context *ctx, u8 rd, u8 rs, u8 rt) ++{ ++ if (cpu_has_mips_2) { ++ emit(ctx, movz, rd, rs, rt); /* rd = rt ? rd : rs */ ++ } else if (cpu_has_mips32r6) { ++ if (rs != MIPS_R_ZERO) ++ emit(ctx, seleqz, rs, rs, rt); /* rs = 0 if rt == 0 */ ++ emit(ctx, selnez, rd, rd, rt); /* rd = 0 if rt != 0 */ ++ if (rs != MIPS_R_ZERO) ++ emit(ctx, or, rd, rd, rs); /* rd = rd | rs */ ++ } else { ++ emit(ctx, bnez, rt, 8); /* PC += 8 if rd != 0 */ ++ emit(ctx, nop); /* +0: delay slot */ ++ emit(ctx, or, rd, rs, MIPS_R_ZERO); /* +4: rd = rs */ ++ } ++ clobber_reg(ctx, rd); ++ clobber_reg(ctx, rs); ++} ++ ++/* ++ * Conditional movn or an emulated equivalent. ++ * Note that the rs register may be modified. ++ */ ++static void emit_movn_r(struct jit_context *ctx, u8 rd, u8 rs, u8 rt) ++{ ++ if (cpu_has_mips_2) { ++ emit(ctx, movn, rd, rs, rt); /* rd = rt ? rs : rd */ ++ } else if (cpu_has_mips32r6) { ++ if (rs != MIPS_R_ZERO) ++ emit(ctx, selnez, rs, rs, rt); /* rs = 0 if rt == 0 */ ++ emit(ctx, seleqz, rd, rd, rt); /* rd = 0 if rt != 0 */ ++ if (rs != MIPS_R_ZERO) ++ emit(ctx, or, rd, rd, rs); /* rd = rd | rs */ ++ } else { ++ emit(ctx, beqz, rt, 8); /* PC += 8 if rd == 0 */ ++ emit(ctx, nop); /* +0: delay slot */ ++ emit(ctx, or, rd, rs, MIPS_R_ZERO); /* +4: rd = rs */ ++ } ++ clobber_reg(ctx, rd); ++ clobber_reg(ctx, rs); ++} ++ ++/* Emulation of 64-bit sltiu rd, rs, imm, where imm may be S32_MAX + 1 */ ++static void emit_sltiu_r64(struct jit_context *ctx, u8 rd, ++ const u8 rs[], s64 imm) ++{ ++ u8 tmp = MIPS_R_T9; ++ ++ if (imm < 0) { ++ emit_mov_i(ctx, rd, imm); /* rd = imm */ ++ emit(ctx, sltu, rd, lo(rs), rd); /* rd = rsl < rd */ ++ emit(ctx, sltiu, tmp, hi(rs), -1); /* tmp = rsh < ~0U */ ++ emit(ctx, or, rd, rd, tmp); /* rd = rd | tmp */ ++ } else { /* imm >= 0 */ ++ if (imm > 0x7fff) { ++ emit_mov_i(ctx, rd, (s32)imm); /* rd = imm */ ++ emit(ctx, sltu, rd, lo(rs), rd); /* rd = rsl < rd */ ++ } else { ++ emit(ctx, sltiu, rd, lo(rs), imm); /* rd = rsl < imm */ ++ } ++ emit_movn_r(ctx, rd, MIPS_R_ZERO, hi(rs)); /* rd = 0 if rsh */ ++ } ++} ++ ++/* Emulation of 64-bit sltu rd, rs, rt */ ++static void emit_sltu_r64(struct jit_context *ctx, u8 rd, ++ const u8 rs[], const u8 rt[]) ++{ ++ u8 tmp = MIPS_R_T9; ++ ++ emit(ctx, sltu, rd, lo(rs), lo(rt)); /* rd = rsl < rtl */ ++ emit(ctx, subu, tmp, hi(rs), hi(rt)); /* tmp = rsh - rth */ ++ emit_movn_r(ctx, rd, MIPS_R_ZERO, tmp); /* rd = 0 if tmp != 0 */ ++ emit(ctx, sltu, tmp, hi(rs), hi(rt)); /* tmp = rsh < rth */ ++ emit(ctx, or, rd, rd, tmp); /* rd = rd | tmp */ ++} ++ ++/* Emulation of 64-bit slti rd, rs, imm, where imm may be S32_MAX + 1 */ ++static void emit_slti_r64(struct jit_context *ctx, u8 rd, ++ const u8 rs[], s64 imm) ++{ ++ u8 t1 = MIPS_R_T8; ++ u8 t2 = MIPS_R_T9; ++ u8 cmp; ++ ++ /* ++ * if ((rs < 0) ^ (imm < 0)) t1 = imm >u rsl ++ * else t1 = rsl > 31 */ ++ if (imm < 0) ++ emit_movz_r(ctx, t1, t2, rd); /* t1 = rd ? t1 : t2 */ ++ else ++ emit_movn_r(ctx, t1, t2, rd); /* t1 = rd ? t2 : t1 */ ++ /* ++ * if ((imm < 0 && rsh != 0xffffffff) || ++ * (imm >= 0 && rsh != 0)) ++ * t1 = 0 ++ */ ++ if (imm < 0) { ++ emit(ctx, addiu, rd, hi(rs), 1); /* rd = rsh + 1 */ ++ cmp = rd; ++ } else { /* imm >= 0 */ ++ cmp = hi(rs); ++ } ++ emit_movn_r(ctx, t1, MIPS_R_ZERO, cmp); /* t1 = 0 if cmp != 0 */ ++ ++ /* ++ * if (imm < 0) rd = rsh < -1 ++ * else rd = rsh != 0 ++ * rd = rd | t1 ++ */ ++ emit(ctx, slti, rd, hi(rs), imm < 0 ? -1 : 0); /* rd = rsh < hi(imm) */ ++ emit(ctx, or, rd, rd, t1); /* rd = rd | t1 */ ++} ++ ++/* Emulation of 64-bit(slt rd, rs, rt) */ ++static void emit_slt_r64(struct jit_context *ctx, u8 rd, ++ const u8 rs[], const u8 rt[]) ++{ ++ u8 t1 = MIPS_R_T7; ++ u8 t2 = MIPS_R_T8; ++ u8 t3 = MIPS_R_T9; ++ ++ /* ++ * if ((rs < 0) ^ (rt < 0)) t1 = rtl > 31 */ ++ emit_movn_r(ctx, t1, t2, rd); /* t1 = rd ? t2 : t1 */ ++ emit_movn_r(ctx, t1, MIPS_R_ZERO, t3); /* t1 = 0 if t3 != 0 */ ++ ++ /* rd = (rsh < rth) | t1 */ ++ emit(ctx, slt, rd, hi(rs), hi(rt)); /* rd = rsh = -0x7fff && imm <= 0x8000) { ++ emit(ctx, addiu, tmp, lo(dst), -imm); ++ } else if ((u32)imm <= 0xffff) { ++ emit(ctx, xori, tmp, lo(dst), imm); ++ } else { /* Register fallback */ ++ emit_mov_i(ctx, tmp, imm); ++ emit(ctx, xor, tmp, lo(dst), tmp); ++ } ++ if (imm < 0) { /* Compare sign extension */ ++ emit(ctx, addu, MIPS_R_T9, hi(dst), 1); ++ emit(ctx, or, tmp, tmp, MIPS_R_T9); ++ } else { /* Compare zero extension */ ++ emit(ctx, or, tmp, tmp, hi(dst)); ++ } ++ if (op == BPF_JEQ) ++ emit(ctx, beqz, tmp, off); ++ else /* BPF_JNE */ ++ emit(ctx, bnez, tmp, off); ++ break; ++ /* PC += off if dst & imm */ ++ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ ++ case BPF_JSET: ++ case JIT_JNSET: ++ if ((u32)imm <= 0xffff) { ++ emit(ctx, andi, tmp, lo(dst), imm); ++ } else { /* Register fallback */ ++ emit_mov_i(ctx, tmp, imm); ++ emit(ctx, and, tmp, lo(dst), tmp); ++ } ++ if (imm < 0) /* Sign-extension pulls in high word */ ++ emit(ctx, or, tmp, tmp, hi(dst)); ++ if (op == BPF_JSET) ++ emit(ctx, bnez, tmp, off); ++ else /* JIT_JNSET */ ++ emit(ctx, beqz, tmp, off); ++ break; ++ /* PC += off if dst > imm */ ++ case BPF_JGT: ++ emit_sltiu_r64(ctx, tmp, dst, (s64)imm + 1); ++ emit(ctx, beqz, tmp, off); ++ break; ++ /* PC += off if dst >= imm */ ++ case BPF_JGE: ++ emit_sltiu_r64(ctx, tmp, dst, imm); ++ emit(ctx, beqz, tmp, off); ++ break; ++ /* PC += off if dst < imm */ ++ case BPF_JLT: ++ emit_sltiu_r64(ctx, tmp, dst, imm); ++ emit(ctx, bnez, tmp, off); ++ break; ++ /* PC += off if dst <= imm */ ++ case BPF_JLE: ++ emit_sltiu_r64(ctx, tmp, dst, (s64)imm + 1); ++ emit(ctx, bnez, tmp, off); ++ break; ++ /* PC += off if dst > imm (signed) */ ++ case BPF_JSGT: ++ emit_slti_r64(ctx, tmp, dst, (s64)imm + 1); ++ emit(ctx, beqz, tmp, off); ++ break; ++ /* PC += off if dst >= imm (signed) */ ++ case BPF_JSGE: ++ emit_slti_r64(ctx, tmp, dst, imm); ++ emit(ctx, beqz, tmp, off); ++ break; ++ /* PC += off if dst < imm (signed) */ ++ case BPF_JSLT: ++ emit_slti_r64(ctx, tmp, dst, imm); ++ emit(ctx, bnez, tmp, off); ++ break; ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JSLE: ++ emit_slti_r64(ctx, tmp, dst, (s64)imm + 1); ++ emit(ctx, bnez, tmp, off); ++ break; ++ } ++} ++ ++/* Jump register (64-bit) */ ++static void emit_jmp_r64(struct jit_context *ctx, ++ const u8 dst[], const u8 src[], s32 off, u8 op) ++{ ++ u8 t1 = MIPS_R_T6; ++ u8 t2 = MIPS_R_T7; ++ ++ switch (op) { ++ /* No-op, used internally for branch optimization */ ++ case JIT_JNOP: ++ break; ++ /* PC += off if dst == src */ ++ /* PC += off if dst != src */ ++ case BPF_JEQ: ++ case BPF_JNE: ++ emit(ctx, subu, t1, lo(dst), lo(src)); ++ emit(ctx, subu, t2, hi(dst), hi(src)); ++ emit(ctx, or, t1, t1, t2); ++ if (op == BPF_JEQ) ++ emit(ctx, beqz, t1, off); ++ else /* BPF_JNE */ ++ emit(ctx, bnez, t1, off); ++ break; ++ /* PC += off if dst & src */ ++ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ ++ case BPF_JSET: ++ case JIT_JNSET: ++ emit(ctx, and, t1, lo(dst), lo(src)); ++ emit(ctx, and, t2, hi(dst), hi(src)); ++ emit(ctx, or, t1, t1, t2); ++ if (op == BPF_JSET) ++ emit(ctx, bnez, t1, off); ++ else /* JIT_JNSET */ ++ emit(ctx, beqz, t1, off); ++ break; ++ /* PC += off if dst > src */ ++ case BPF_JGT: ++ emit_sltu_r64(ctx, t1, src, dst); ++ emit(ctx, bnez, t1, off); ++ break; ++ /* PC += off if dst >= src */ ++ case BPF_JGE: ++ emit_sltu_r64(ctx, t1, dst, src); ++ emit(ctx, beqz, t1, off); ++ break; ++ /* PC += off if dst < src */ ++ case BPF_JLT: ++ emit_sltu_r64(ctx, t1, dst, src); ++ emit(ctx, bnez, t1, off); ++ break; ++ /* PC += off if dst <= src */ ++ case BPF_JLE: ++ emit_sltu_r64(ctx, t1, src, dst); ++ emit(ctx, beqz, t1, off); ++ break; ++ /* PC += off if dst > src (signed) */ ++ case BPF_JSGT: ++ emit_slt_r64(ctx, t1, src, dst); ++ emit(ctx, bnez, t1, off); ++ break; ++ /* PC += off if dst >= src (signed) */ ++ case BPF_JSGE: ++ emit_slt_r64(ctx, t1, dst, src); ++ emit(ctx, beqz, t1, off); ++ break; ++ /* PC += off if dst < src (signed) */ ++ case BPF_JSLT: ++ emit_slt_r64(ctx, t1, dst, src); ++ emit(ctx, bnez, t1, off); ++ break; ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JSLE: ++ emit_slt_r64(ctx, t1, src, dst); ++ emit(ctx, beqz, t1, off); ++ break; ++ } ++} ++ ++/* Function call */ ++static int emit_call(struct jit_context *ctx, const struct bpf_insn *insn) ++{ ++ bool fixed; ++ u64 addr; ++ ++ /* Decode the call address */ ++ if (bpf_jit_get_func_addr(ctx->program, insn, false, ++ &addr, &fixed) < 0) ++ return -1; ++ if (!fixed) ++ return -1; ++ ++ /* Push stack arguments */ ++ push_regs(ctx, JIT_STACK_REGS, 0, JIT_RESERVED_STACK); ++ ++ /* Emit function call */ ++ emit_mov_i(ctx, MIPS_R_T9, addr); ++ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); ++ emit(ctx, nop); /* Delay slot */ ++ ++ clobber_reg(ctx, MIPS_R_RA); ++ clobber_reg(ctx, MIPS_R_V0); ++ clobber_reg(ctx, MIPS_R_V1); ++ return 0; ++} ++ ++/* Function tail call */ ++static int emit_tail_call(struct jit_context *ctx) ++{ ++ u8 ary = lo(bpf2mips32[BPF_REG_2]); ++ u8 ind = lo(bpf2mips32[BPF_REG_3]); ++ u8 t1 = MIPS_R_T8; ++ u8 t2 = MIPS_R_T9; ++ int off; ++ ++ /* ++ * Tail call: ++ * eBPF R1 - function argument (context ptr), passed in a0-a1 ++ * eBPF R2 - ptr to object with array of function entry points ++ * eBPF R3 - array index of function to be called ++ * stack[sz] - remaining tail call count, initialized in prologue ++ */ ++ ++ /* if (ind >= ary->map.max_entries) goto out */ ++ off = offsetof(struct bpf_array, map.max_entries); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, lw, t1, off, ary); /* t1 = ary->map.max_entries*/ ++ emit_load_delay(ctx); /* Load delay slot */ ++ emit(ctx, sltu, t1, ind, t1); /* t1 = ind < t1 */ ++ emit(ctx, beqz, t1, get_offset(ctx, 1)); /* PC += off(1) if t1 == 0 */ ++ /* (next insn delay slot) */ ++ /* if (TCC-- <= 0) goto out */ ++ emit(ctx, lw, t2, ctx->stack_size, MIPS_R_SP); /* t2 = *(SP + size) */ ++ emit_load_delay(ctx); /* Load delay slot */ ++ emit(ctx, blez, t2, get_offset(ctx, 1)); /* PC += off(1) if t2 < 0 */ ++ emit(ctx, addiu, t2, t2, -1); /* t2-- (delay slot) */ ++ emit(ctx, sw, t2, ctx->stack_size, MIPS_R_SP); /* *(SP + size) = t2 */ ++ ++ /* prog = ary->ptrs[ind] */ ++ off = offsetof(struct bpf_array, ptrs); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, sll, t1, ind, 2); /* t1 = ind << 2 */ ++ emit(ctx, addu, t1, t1, ary); /* t1 += ary */ ++ emit(ctx, lw, t2, off, t1); /* t2 = *(t1 + off) */ ++ emit_load_delay(ctx); /* Load delay slot */ ++ ++ /* if (prog == 0) goto out */ ++ emit(ctx, beqz, t2, get_offset(ctx, 1)); /* PC += off(1) if t2 == 0 */ ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* func = prog->bpf_func + 8 (prologue skip offset) */ ++ off = offsetof(struct bpf_prog, bpf_func); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, lw, t1, off, t2); /* t1 = *(t2 + off) */ ++ emit_load_delay(ctx); /* Load delay slot */ ++ emit(ctx, addiu, t1, t1, JIT_TCALL_SKIP); /* t1 += skip (8 or 12) */ ++ ++ /* goto func */ ++ build_epilogue(ctx, t1); ++ return 0; ++} ++ ++/* ++ * Stack frame layout for a JITed program (stack grows down). ++ * ++ * Higher address : Caller's stack frame : ++ * :----------------------------: ++ * : 64-bit eBPF args r3-r5 : ++ * :----------------------------: ++ * : Reserved / tail call count : ++ * +============================+ <--- MIPS sp before call ++ * | Callee-saved registers, | ++ * | including RA and FP | ++ * +----------------------------+ <--- eBPF FP (MIPS zero,fp) ++ * | Local eBPF variables | ++ * | allocated by program | ++ * +----------------------------+ ++ * | Reserved for caller-saved | ++ * | registers | ++ * +----------------------------+ ++ * | Reserved for 64-bit eBPF | ++ * | args r3-r5 & args passed | ++ * | on stack in kernel calls | ++ * Lower address +============================+ <--- MIPS sp ++ */ ++ ++/* Build program prologue to set up the stack and registers */ ++void build_prologue(struct jit_context *ctx) ++{ ++ const u8 *r1 = bpf2mips32[BPF_REG_1]; ++ const u8 *fp = bpf2mips32[BPF_REG_FP]; ++ int stack, saved, locals, reserved; ++ ++ /* ++ * The first two instructions initialize TCC in the reserved (for us) ++ * 16-byte area in the parent's stack frame. On a tail call, the ++ * calling function jumps into the prologue after these instructions. ++ */ ++ emit(ctx, ori, MIPS_R_T9, MIPS_R_ZERO, ++ min(MAX_TAIL_CALL_CNT + 1, 0xffff)); ++ emit(ctx, sw, MIPS_R_T9, 0, MIPS_R_SP); ++ ++ /* ++ * Register eBPF R1 contains the 32-bit context pointer argument. ++ * A 32-bit argument is always passed in MIPS register a0, regardless ++ * of CPU endianness. Initialize R1 accordingly and zero-extend. ++ */ ++#ifdef __BIG_ENDIAN ++ emit(ctx, move, lo(r1), MIPS_R_A0); ++#endif ++ ++ /* === Entry-point for tail calls === */ ++ ++ /* Zero-extend the 32-bit argument */ ++ emit(ctx, move, hi(r1), MIPS_R_ZERO); ++ ++ /* If the eBPF frame pointer was accessed it must be saved */ ++ if (ctx->accessed & BIT(BPF_REG_FP)) ++ clobber_reg64(ctx, fp); ++ ++ /* Compute the stack space needed for callee-saved registers */ ++ saved = hweight32(ctx->clobbered & JIT_CALLEE_REGS) * sizeof(u32); ++ saved = ALIGN(saved, MIPS_STACK_ALIGNMENT); ++ ++ /* Stack space used by eBPF program local data */ ++ locals = ALIGN(ctx->program->aux->stack_depth, MIPS_STACK_ALIGNMENT); ++ ++ /* ++ * If we are emitting function calls, reserve extra stack space for ++ * caller-saved registers and function arguments passed on the stack. ++ * The required space is computed automatically during resource ++ * usage discovery (pass 1). ++ */ ++ reserved = ctx->stack_used; ++ ++ /* Allocate the stack frame */ ++ stack = ALIGN(saved + locals + reserved, MIPS_STACK_ALIGNMENT); ++ emit(ctx, addiu, MIPS_R_SP, MIPS_R_SP, -stack); ++ ++ /* Store callee-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, stack - saved); ++ ++ /* Initialize the eBPF frame pointer if accessed */ ++ if (ctx->accessed & BIT(BPF_REG_FP)) ++ emit(ctx, addiu, lo(fp), MIPS_R_SP, stack - saved); ++ ++ ctx->saved_size = saved; ++ ctx->stack_size = stack; ++} ++ ++/* Build the program epilogue to restore the stack and registers */ ++void build_epilogue(struct jit_context *ctx, int dest_reg) ++{ ++ /* Restore callee-saved registers from stack */ ++ pop_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, ++ ctx->stack_size - ctx->saved_size); ++ /* ++ * A 32-bit return value is always passed in MIPS register v0, ++ * but on big-endian targets the low part of R0 is mapped to v1. ++ */ ++#ifdef __BIG_ENDIAN ++ emit(ctx, move, MIPS_R_V0, MIPS_R_V1); ++#endif ++ ++ /* Jump to the return address and adjust the stack pointer */ ++ emit(ctx, jr, dest_reg); ++ emit(ctx, addiu, MIPS_R_SP, MIPS_R_SP, ctx->stack_size); ++} ++ ++/* Build one eBPF instruction */ ++int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) ++{ ++ const u8 *dst = bpf2mips32[insn->dst_reg]; ++ const u8 *src = bpf2mips32[insn->src_reg]; ++ const u8 *tmp = bpf2mips32[JIT_REG_TMP]; ++ u8 code = insn->code; ++ s16 off = insn->off; ++ s32 imm = insn->imm; ++ s32 val, rel; ++ u8 alu, jmp; ++ ++ switch (code) { ++ /* ALU operations */ ++ /* dst = imm */ ++ case BPF_ALU | BPF_MOV | BPF_K: ++ emit_mov_i(ctx, lo(dst), imm); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = src */ ++ case BPF_ALU | BPF_MOV | BPF_X: ++ if (imm == 1) { ++ /* Special mov32 for zext */ ++ emit_mov_i(ctx, hi(dst), 0); ++ } else { ++ emit_mov_r(ctx, lo(dst), lo(src)); ++ emit_zext_ver(ctx, dst); ++ } ++ break; ++ /* dst = -dst */ ++ case BPF_ALU | BPF_NEG: ++ emit_alu_i(ctx, lo(dst), 0, BPF_NEG); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst & imm */ ++ /* dst = dst | imm */ ++ /* dst = dst ^ imm */ ++ /* dst = dst << imm */ ++ /* dst = dst >> imm */ ++ /* dst = dst >> imm (arithmetic) */ ++ /* dst = dst + imm */ ++ /* dst = dst - imm */ ++ /* dst = dst * imm */ ++ /* dst = dst / imm */ ++ /* dst = dst % imm */ ++ case BPF_ALU | BPF_OR | BPF_K: ++ case BPF_ALU | BPF_AND | BPF_K: ++ case BPF_ALU | BPF_XOR | BPF_K: ++ case BPF_ALU | BPF_LSH | BPF_K: ++ case BPF_ALU | BPF_RSH | BPF_K: ++ case BPF_ALU | BPF_ARSH | BPF_K: ++ case BPF_ALU | BPF_ADD | BPF_K: ++ case BPF_ALU | BPF_SUB | BPF_K: ++ case BPF_ALU | BPF_MUL | BPF_K: ++ case BPF_ALU | BPF_DIV | BPF_K: ++ case BPF_ALU | BPF_MOD | BPF_K: ++ if (!valid_alu_i(BPF_OP(code), imm)) { ++ emit_mov_i(ctx, MIPS_R_T6, imm); ++ emit_alu_r(ctx, lo(dst), MIPS_R_T6, BPF_OP(code)); ++ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { ++ emit_alu_i(ctx, lo(dst), val, alu); ++ } ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst & src */ ++ /* dst = dst | src */ ++ /* dst = dst ^ src */ ++ /* dst = dst << src */ ++ /* dst = dst >> src */ ++ /* dst = dst >> src (arithmetic) */ ++ /* dst = dst + src */ ++ /* dst = dst - src */ ++ /* dst = dst * src */ ++ /* dst = dst / src */ ++ /* dst = dst % src */ ++ case BPF_ALU | BPF_AND | BPF_X: ++ case BPF_ALU | BPF_OR | BPF_X: ++ case BPF_ALU | BPF_XOR | BPF_X: ++ case BPF_ALU | BPF_LSH | BPF_X: ++ case BPF_ALU | BPF_RSH | BPF_X: ++ case BPF_ALU | BPF_ARSH | BPF_X: ++ case BPF_ALU | BPF_ADD | BPF_X: ++ case BPF_ALU | BPF_SUB | BPF_X: ++ case BPF_ALU | BPF_MUL | BPF_X: ++ case BPF_ALU | BPF_DIV | BPF_X: ++ case BPF_ALU | BPF_MOD | BPF_X: ++ emit_alu_r(ctx, lo(dst), lo(src), BPF_OP(code)); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = imm (64-bit) */ ++ case BPF_ALU64 | BPF_MOV | BPF_K: ++ emit_mov_se_i64(ctx, dst, imm); ++ break; ++ /* dst = src (64-bit) */ ++ case BPF_ALU64 | BPF_MOV | BPF_X: ++ emit_mov_r(ctx, lo(dst), lo(src)); ++ emit_mov_r(ctx, hi(dst), hi(src)); ++ break; ++ /* dst = -dst (64-bit) */ ++ case BPF_ALU64 | BPF_NEG: ++ emit_neg_i64(ctx, dst); ++ break; ++ /* dst = dst & imm (64-bit) */ ++ case BPF_ALU64 | BPF_AND | BPF_K: ++ emit_alu_i64(ctx, dst, imm, BPF_OP(code)); ++ break; ++ /* dst = dst | imm (64-bit) */ ++ /* dst = dst ^ imm (64-bit) */ ++ /* dst = dst + imm (64-bit) */ ++ /* dst = dst - imm (64-bit) */ ++ case BPF_ALU64 | BPF_OR | BPF_K: ++ case BPF_ALU64 | BPF_XOR | BPF_K: ++ case BPF_ALU64 | BPF_ADD | BPF_K: ++ case BPF_ALU64 | BPF_SUB | BPF_K: ++ if (imm) ++ emit_alu_i64(ctx, dst, imm, BPF_OP(code)); ++ break; ++ /* dst = dst << imm (64-bit) */ ++ /* dst = dst >> imm (64-bit) */ ++ /* dst = dst >> imm (64-bit, arithmetic) */ ++ case BPF_ALU64 | BPF_LSH | BPF_K: ++ case BPF_ALU64 | BPF_RSH | BPF_K: ++ case BPF_ALU64 | BPF_ARSH | BPF_K: ++ if (imm) ++ emit_shift_i64(ctx, dst, imm, BPF_OP(code)); ++ break; ++ /* dst = dst * imm (64-bit) */ ++ case BPF_ALU64 | BPF_MUL | BPF_K: ++ emit_mul_i64(ctx, dst, imm); ++ break; ++ /* dst = dst / imm (64-bit) */ ++ /* dst = dst % imm (64-bit) */ ++ case BPF_ALU64 | BPF_DIV | BPF_K: ++ case BPF_ALU64 | BPF_MOD | BPF_K: ++ /* ++ * Sign-extend the immediate value into a temporary register, ++ * and then do the operation on this register. ++ */ ++ emit_mov_se_i64(ctx, tmp, imm); ++ emit_divmod_r64(ctx, dst, tmp, BPF_OP(code)); ++ break; ++ /* dst = dst & src (64-bit) */ ++ /* dst = dst | src (64-bit) */ ++ /* dst = dst ^ src (64-bit) */ ++ /* dst = dst + src (64-bit) */ ++ /* dst = dst - src (64-bit) */ ++ case BPF_ALU64 | BPF_AND | BPF_X: ++ case BPF_ALU64 | BPF_OR | BPF_X: ++ case BPF_ALU64 | BPF_XOR | BPF_X: ++ case BPF_ALU64 | BPF_ADD | BPF_X: ++ case BPF_ALU64 | BPF_SUB | BPF_X: ++ emit_alu_r64(ctx, dst, src, BPF_OP(code)); ++ break; ++ /* dst = dst << src (64-bit) */ ++ /* dst = dst >> src (64-bit) */ ++ /* dst = dst >> src (64-bit, arithmetic) */ ++ case BPF_ALU64 | BPF_LSH | BPF_X: ++ case BPF_ALU64 | BPF_RSH | BPF_X: ++ case BPF_ALU64 | BPF_ARSH | BPF_X: ++ emit_shift_r64(ctx, dst, lo(src), BPF_OP(code)); ++ break; ++ /* dst = dst * src (64-bit) */ ++ case BPF_ALU64 | BPF_MUL | BPF_X: ++ emit_mul_r64(ctx, dst, src); ++ break; ++ /* dst = dst / src (64-bit) */ ++ /* dst = dst % src (64-bit) */ ++ case BPF_ALU64 | BPF_DIV | BPF_X: ++ case BPF_ALU64 | BPF_MOD | BPF_X: ++ emit_divmod_r64(ctx, dst, src, BPF_OP(code)); ++ break; ++ /* dst = htole(dst) */ ++ /* dst = htobe(dst) */ ++ case BPF_ALU | BPF_END | BPF_FROM_LE: ++ case BPF_ALU | BPF_END | BPF_FROM_BE: ++ if (BPF_SRC(code) == ++#ifdef __BIG_ENDIAN ++ BPF_FROM_LE ++#else ++ BPF_FROM_BE ++#endif ++ ) ++ emit_bswap_r64(ctx, dst, imm); ++ else ++ emit_trunc_r64(ctx, dst, imm); ++ break; ++ /* dst = imm64 */ ++ case BPF_LD | BPF_IMM | BPF_DW: ++ emit_mov_i(ctx, lo(dst), imm); ++ emit_mov_i(ctx, hi(dst), insn[1].imm); ++ return 1; ++ /* LDX: dst = *(size *)(src + off) */ ++ case BPF_LDX | BPF_MEM | BPF_W: ++ case BPF_LDX | BPF_MEM | BPF_H: ++ case BPF_LDX | BPF_MEM | BPF_B: ++ case BPF_LDX | BPF_MEM | BPF_DW: ++ emit_ldx(ctx, dst, lo(src), off, BPF_SIZE(code)); ++ break; ++ /* ST: *(size *)(dst + off) = imm */ ++ case BPF_ST | BPF_MEM | BPF_W: ++ case BPF_ST | BPF_MEM | BPF_H: ++ case BPF_ST | BPF_MEM | BPF_B: ++ case BPF_ST | BPF_MEM | BPF_DW: ++ switch (BPF_SIZE(code)) { ++ case BPF_DW: ++ /* Sign-extend immediate value into temporary reg */ ++ emit_mov_se_i64(ctx, tmp, imm); ++ break; ++ case BPF_W: ++ case BPF_H: ++ case BPF_B: ++ emit_mov_i(ctx, lo(tmp), imm); ++ break; ++ } ++ emit_stx(ctx, lo(dst), tmp, off, BPF_SIZE(code)); ++ break; ++ /* STX: *(size *)(dst + off) = src */ ++ case BPF_STX | BPF_MEM | BPF_W: ++ case BPF_STX | BPF_MEM | BPF_H: ++ case BPF_STX | BPF_MEM | BPF_B: ++ case BPF_STX | BPF_MEM | BPF_DW: ++ emit_stx(ctx, lo(dst), src, off, BPF_SIZE(code)); ++ break; ++ /* Speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ break; ++ /* Atomics */ ++ case BPF_STX | BPF_XADD | BPF_W: ++ switch (imm) { ++ case BPF_ADD: ++ case BPF_AND: ++ case BPF_OR: ++ case BPF_XOR: ++ if (cpu_has_llsc) ++ emit_atomic_r(ctx, lo(dst), lo(src), off, imm); ++ else /* Non-ll/sc fallback */ ++ emit_atomic_r32(ctx, lo(dst), lo(src), ++ off, imm); ++ break; ++ default: ++ goto notyet; ++ } ++ break; ++ /* Atomics (64-bit) */ ++ case BPF_STX | BPF_XADD | BPF_DW: ++ switch (imm) { ++ case BPF_ADD: ++ case BPF_AND: ++ case BPF_OR: ++ case BPF_XOR: ++ emit_atomic_r64(ctx, lo(dst), src, off, imm); ++ break; ++ default: ++ goto notyet; ++ } ++ break; ++ /* PC += off if dst == src */ ++ /* PC += off if dst != src */ ++ /* PC += off if dst & src */ ++ /* PC += off if dst > src */ ++ /* PC += off if dst >= src */ ++ /* PC += off if dst < src */ ++ /* PC += off if dst <= src */ ++ /* PC += off if dst > src (signed) */ ++ /* PC += off if dst >= src (signed) */ ++ /* PC += off if dst < src (signed) */ ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JMP32 | BPF_JEQ | BPF_X: ++ case BPF_JMP32 | BPF_JNE | BPF_X: ++ case BPF_JMP32 | BPF_JSET | BPF_X: ++ case BPF_JMP32 | BPF_JGT | BPF_X: ++ case BPF_JMP32 | BPF_JGE | BPF_X: ++ case BPF_JMP32 | BPF_JLT | BPF_X: ++ case BPF_JMP32 | BPF_JLE | BPF_X: ++ case BPF_JMP32 | BPF_JSGT | BPF_X: ++ case BPF_JMP32 | BPF_JSGE | BPF_X: ++ case BPF_JMP32 | BPF_JSLT | BPF_X: ++ case BPF_JMP32 | BPF_JSLE | BPF_X: ++ if (off == 0) ++ break; ++ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); ++ emit_jmp_r(ctx, lo(dst), lo(src), rel, jmp); ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == imm */ ++ /* PC += off if dst != imm */ ++ /* PC += off if dst & imm */ ++ /* PC += off if dst > imm */ ++ /* PC += off if dst >= imm */ ++ /* PC += off if dst < imm */ ++ /* PC += off if dst <= imm */ ++ /* PC += off if dst > imm (signed) */ ++ /* PC += off if dst >= imm (signed) */ ++ /* PC += off if dst < imm (signed) */ ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JMP32 | BPF_JEQ | BPF_K: ++ case BPF_JMP32 | BPF_JNE | BPF_K: ++ case BPF_JMP32 | BPF_JSET | BPF_K: ++ case BPF_JMP32 | BPF_JGT | BPF_K: ++ case BPF_JMP32 | BPF_JGE | BPF_K: ++ case BPF_JMP32 | BPF_JLT | BPF_K: ++ case BPF_JMP32 | BPF_JLE | BPF_K: ++ case BPF_JMP32 | BPF_JSGT | BPF_K: ++ case BPF_JMP32 | BPF_JSGE | BPF_K: ++ case BPF_JMP32 | BPF_JSLT | BPF_K: ++ case BPF_JMP32 | BPF_JSLE | BPF_K: ++ if (off == 0) ++ break; ++ setup_jmp_i(ctx, imm, 32, BPF_OP(code), off, &jmp, &rel); ++ if (valid_jmp_i(jmp, imm)) { ++ emit_jmp_i(ctx, lo(dst), imm, rel, jmp); ++ } else { ++ /* Move large immediate to register */ ++ emit_mov_i(ctx, MIPS_R_T6, imm); ++ emit_jmp_r(ctx, lo(dst), MIPS_R_T6, rel, jmp); ++ } ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == src */ ++ /* PC += off if dst != src */ ++ /* PC += off if dst & src */ ++ /* PC += off if dst > src */ ++ /* PC += off if dst >= src */ ++ /* PC += off if dst < src */ ++ /* PC += off if dst <= src */ ++ /* PC += off if dst > src (signed) */ ++ /* PC += off if dst >= src (signed) */ ++ /* PC += off if dst < src (signed) */ ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JMP | BPF_JEQ | BPF_X: ++ case BPF_JMP | BPF_JNE | BPF_X: ++ case BPF_JMP | BPF_JSET | BPF_X: ++ case BPF_JMP | BPF_JGT | BPF_X: ++ case BPF_JMP | BPF_JGE | BPF_X: ++ case BPF_JMP | BPF_JLT | BPF_X: ++ case BPF_JMP | BPF_JLE | BPF_X: ++ case BPF_JMP | BPF_JSGT | BPF_X: ++ case BPF_JMP | BPF_JSGE | BPF_X: ++ case BPF_JMP | BPF_JSLT | BPF_X: ++ case BPF_JMP | BPF_JSLE | BPF_X: ++ if (off == 0) ++ break; ++ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); ++ emit_jmp_r64(ctx, dst, src, rel, jmp); ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == imm */ ++ /* PC += off if dst != imm */ ++ /* PC += off if dst & imm */ ++ /* PC += off if dst > imm */ ++ /* PC += off if dst >= imm */ ++ /* PC += off if dst < imm */ ++ /* PC += off if dst <= imm */ ++ /* PC += off if dst > imm (signed) */ ++ /* PC += off if dst >= imm (signed) */ ++ /* PC += off if dst < imm (signed) */ ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JMP | BPF_JEQ | BPF_K: ++ case BPF_JMP | BPF_JNE | BPF_K: ++ case BPF_JMP | BPF_JSET | BPF_K: ++ case BPF_JMP | BPF_JGT | BPF_K: ++ case BPF_JMP | BPF_JGE | BPF_K: ++ case BPF_JMP | BPF_JLT | BPF_K: ++ case BPF_JMP | BPF_JLE | BPF_K: ++ case BPF_JMP | BPF_JSGT | BPF_K: ++ case BPF_JMP | BPF_JSGE | BPF_K: ++ case BPF_JMP | BPF_JSLT | BPF_K: ++ case BPF_JMP | BPF_JSLE | BPF_K: ++ if (off == 0) ++ break; ++ setup_jmp_i(ctx, imm, 64, BPF_OP(code), off, &jmp, &rel); ++ emit_jmp_i64(ctx, dst, imm, rel, jmp); ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off */ ++ case BPF_JMP | BPF_JA: ++ if (off == 0) ++ break; ++ if (emit_ja(ctx, off) < 0) ++ goto toofar; ++ break; ++ /* Tail call */ ++ case BPF_JMP | BPF_TAIL_CALL: ++ if (emit_tail_call(ctx) < 0) ++ goto invalid; ++ break; ++ /* Function call */ ++ case BPF_JMP | BPF_CALL: ++ if (emit_call(ctx, insn) < 0) ++ goto invalid; ++ break; ++ /* Function return */ ++ case BPF_JMP | BPF_EXIT: ++ /* ++ * Optimization: when last instruction is EXIT ++ * simply continue to epilogue. ++ */ ++ if (ctx->bpf_index == ctx->program->len - 1) ++ break; ++ if (emit_exit(ctx) < 0) ++ goto toofar; ++ break; ++ ++ default: ++invalid: ++ pr_err_once("unknown opcode %02x\n", code); ++ return -EINVAL; ++notyet: ++ pr_info_once("*** NOT YET: opcode %02x ***\n", code); ++ return -EFAULT; ++toofar: ++ pr_info_once("*** TOO FAR: jump at %u opcode %02x ***\n", ++ ctx->bpf_index, code); ++ return -E2BIG; ++ } ++ return 0; ++} diff --git a/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch b/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch new file mode 100644 index 00000000000..38b46c0b765 --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch @@ -0,0 +1,1005 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:05 +0200 +Subject: [PATCH] mips: bpf: Add new eBPF JIT for 64-bit MIPS + +This is an implementation on of an eBPF JIT for 64-bit MIPS III-V and +MIPS64r1-r6. It uses the same framework introduced by the 32-bit JIT. + +Signed-off-by: Johan Almbladh +--- + create mode 100644 arch/mips/net/bpf_jit_comp64.c + +--- /dev/null ++++ b/arch/mips/net/bpf_jit_comp64.c +@@ -0,0 +1,991 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Just-In-Time compiler for eBPF bytecode on MIPS. ++ * Implementation of JIT functions for 64-bit CPUs. ++ * ++ * Copyright (c) 2021 Anyfi Networks AB. ++ * Author: Johan Almbladh ++ * ++ * Based on code and ideas from ++ * Copyright (c) 2017 Cavium, Inc. ++ * Copyright (c) 2017 Shubham Bansal ++ * Copyright (c) 2011 Mircea Gherzan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "bpf_jit_comp.h" ++ ++/* MIPS t0-t3 are not available in the n64 ABI */ ++#undef MIPS_R_T0 ++#undef MIPS_R_T1 ++#undef MIPS_R_T2 ++#undef MIPS_R_T3 ++ ++/* Stack is 16-byte aligned in n64 ABI */ ++#define MIPS_STACK_ALIGNMENT 16 ++ ++/* Extra 64-bit eBPF registers used by JIT */ ++#define JIT_REG_TC (MAX_BPF_JIT_REG + 0) ++#define JIT_REG_ZX (MAX_BPF_JIT_REG + 1) ++ ++/* Number of prologue bytes to skip when doing a tail call */ ++#define JIT_TCALL_SKIP 4 ++ ++/* Callee-saved CPU registers that the JIT must preserve */ ++#define JIT_CALLEE_REGS \ ++ (BIT(MIPS_R_S0) | \ ++ BIT(MIPS_R_S1) | \ ++ BIT(MIPS_R_S2) | \ ++ BIT(MIPS_R_S3) | \ ++ BIT(MIPS_R_S4) | \ ++ BIT(MIPS_R_S5) | \ ++ BIT(MIPS_R_S6) | \ ++ BIT(MIPS_R_S7) | \ ++ BIT(MIPS_R_GP) | \ ++ BIT(MIPS_R_FP) | \ ++ BIT(MIPS_R_RA)) ++ ++/* Caller-saved CPU registers available for JIT use */ ++#define JIT_CALLER_REGS \ ++ (BIT(MIPS_R_A5) | \ ++ BIT(MIPS_R_A6) | \ ++ BIT(MIPS_R_A7)) ++/* ++ * Mapping of 64-bit eBPF registers to 64-bit native MIPS registers. ++ * MIPS registers t4 - t7 may be used by the JIT as temporary registers. ++ * MIPS registers t8 - t9 are reserved for single-register common functions. ++ */ ++static const u8 bpf2mips64[] = { ++ /* Return value from in-kernel function, and exit value from eBPF */ ++ [BPF_REG_0] = MIPS_R_V0, ++ /* Arguments from eBPF program to in-kernel function */ ++ [BPF_REG_1] = MIPS_R_A0, ++ [BPF_REG_2] = MIPS_R_A1, ++ [BPF_REG_3] = MIPS_R_A2, ++ [BPF_REG_4] = MIPS_R_A3, ++ [BPF_REG_5] = MIPS_R_A4, ++ /* Callee-saved registers that in-kernel function will preserve */ ++ [BPF_REG_6] = MIPS_R_S0, ++ [BPF_REG_7] = MIPS_R_S1, ++ [BPF_REG_8] = MIPS_R_S2, ++ [BPF_REG_9] = MIPS_R_S3, ++ /* Read-only frame pointer to access the eBPF stack */ ++ [BPF_REG_FP] = MIPS_R_FP, ++ /* Temporary register for blinding constants */ ++ [BPF_REG_AX] = MIPS_R_AT, ++ /* Tail call count register, caller-saved */ ++ [JIT_REG_TC] = MIPS_R_A5, ++ /* Constant for register zero-extension */ ++ [JIT_REG_ZX] = MIPS_R_V1, ++}; ++ ++/* ++ * MIPS 32-bit operations on 64-bit registers generate a sign-extended ++ * result. However, the eBPF ISA mandates zero-extension, so we rely on the ++ * verifier to add that for us (emit_zext_ver). In addition, ALU arithmetic ++ * operations, right shift and byte swap require properly sign-extended ++ * operands or the result is unpredictable. We emit explicit sign-extensions ++ * in those cases. ++ */ ++ ++/* Sign extension */ ++static void emit_sext(struct jit_context *ctx, u8 dst, u8 src) ++{ ++ emit(ctx, sll, dst, src, 0); ++ clobber_reg(ctx, dst); ++} ++ ++/* Zero extension */ ++static void emit_zext(struct jit_context *ctx, u8 dst) ++{ ++ if (cpu_has_mips64r2 || cpu_has_mips64r6) { ++ emit(ctx, dinsu, dst, MIPS_R_ZERO, 32, 32); ++ } else { ++ emit(ctx, and, dst, dst, bpf2mips64[JIT_REG_ZX]); ++ access_reg(ctx, JIT_REG_ZX); /* We need the ZX register */ ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Zero extension, if verifier does not do it for us */ ++static void emit_zext_ver(struct jit_context *ctx, u8 dst) ++{ ++ if (!ctx->program->aux->verifier_zext) ++ emit_zext(ctx, dst); ++} ++ ++/* dst = imm (64-bit) */ ++static void emit_mov_i64(struct jit_context *ctx, u8 dst, u64 imm64) ++{ ++ if (imm64 >= 0xffffffffffff8000ULL || imm64 < 0x8000ULL) { ++ emit(ctx, daddiu, dst, MIPS_R_ZERO, (s16)imm64); ++ } else if (imm64 >= 0xffffffff80000000ULL || ++ (imm64 < 0x80000000 && imm64 > 0xffff)) { ++ emit(ctx, lui, dst, (s16)(imm64 >> 16)); ++ emit(ctx, ori, dst, dst, (u16)imm64 & 0xffff); ++ } else { ++ u8 acc = MIPS_R_ZERO; ++ int k; ++ ++ for (k = 0; k < 4; k++) { ++ u16 half = imm64 >> (48 - 16 * k); ++ ++ if (acc == dst) ++ emit(ctx, dsll, dst, dst, 16); ++ ++ if (half) { ++ emit(ctx, ori, dst, acc, half); ++ acc = dst; ++ } ++ } ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* ALU immediate operation (64-bit) */ ++static void emit_alu_i64(struct jit_context *ctx, u8 dst, s32 imm, u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = dst | imm */ ++ case BPF_OR: ++ emit(ctx, ori, dst, dst, (u16)imm); ++ break; ++ /* dst = dst ^ imm */ ++ case BPF_XOR: ++ emit(ctx, xori, dst, dst, (u16)imm); ++ break; ++ /* dst = -dst */ ++ case BPF_NEG: ++ emit(ctx, dsubu, dst, MIPS_R_ZERO, dst); ++ break; ++ /* dst = dst << imm */ ++ case BPF_LSH: ++ emit(ctx, dsll_safe, dst, dst, imm); ++ break; ++ /* dst = dst >> imm */ ++ case BPF_RSH: ++ emit(ctx, dsrl_safe, dst, dst, imm); ++ break; ++ /* dst = dst >> imm (arithmetic) */ ++ case BPF_ARSH: ++ emit(ctx, dsra_safe, dst, dst, imm); ++ break; ++ /* dst = dst + imm */ ++ case BPF_ADD: ++ emit(ctx, daddiu, dst, dst, imm); ++ break; ++ /* dst = dst - imm */ ++ case BPF_SUB: ++ emit(ctx, daddiu, dst, dst, -imm); ++ break; ++ default: ++ /* Width-generic operations */ ++ emit_alu_i(ctx, dst, imm, op); ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* ALU register operation (64-bit) */ ++static void emit_alu_r64(struct jit_context *ctx, u8 dst, u8 src, u8 op) ++{ ++ switch (BPF_OP(op)) { ++ /* dst = dst << src */ ++ case BPF_LSH: ++ emit(ctx, dsllv, dst, dst, src); ++ break; ++ /* dst = dst >> src */ ++ case BPF_RSH: ++ emit(ctx, dsrlv, dst, dst, src); ++ break; ++ /* dst = dst >> src (arithmetic) */ ++ case BPF_ARSH: ++ emit(ctx, dsrav, dst, dst, src); ++ break; ++ /* dst = dst + src */ ++ case BPF_ADD: ++ emit(ctx, daddu, dst, dst, src); ++ break; ++ /* dst = dst - src */ ++ case BPF_SUB: ++ emit(ctx, dsubu, dst, dst, src); ++ break; ++ /* dst = dst * src */ ++ case BPF_MUL: ++ if (cpu_has_mips64r6) { ++ emit(ctx, dmulu, dst, dst, src); ++ } else { ++ emit(ctx, dmultu, dst, src); ++ emit(ctx, mflo, dst); ++ } ++ break; ++ /* dst = dst / src */ ++ case BPF_DIV: ++ if (cpu_has_mips64r6) { ++ emit(ctx, ddivu_r6, dst, dst, src); ++ } else { ++ emit(ctx, ddivu, dst, src); ++ emit(ctx, mflo, dst); ++ } ++ break; ++ /* dst = dst % src */ ++ case BPF_MOD: ++ if (cpu_has_mips64r6) { ++ emit(ctx, dmodu, dst, dst, src); ++ } else { ++ emit(ctx, ddivu, dst, src); ++ emit(ctx, mfhi, dst); ++ } ++ break; ++ default: ++ /* Width-generic operations */ ++ emit_alu_r(ctx, dst, src, op); ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Swap sub words in a register double word */ ++static void emit_swap_r64(struct jit_context *ctx, u8 dst, u8 mask, u32 bits) ++{ ++ u8 tmp = MIPS_R_T9; ++ ++ emit(ctx, and, tmp, dst, mask); /* tmp = dst & mask */ ++ emit(ctx, dsll, tmp, tmp, bits); /* tmp = tmp << bits */ ++ emit(ctx, dsrl, dst, dst, bits); /* dst = dst >> bits */ ++ emit(ctx, and, dst, dst, mask); /* dst = dst & mask */ ++ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ ++} ++ ++/* Swap bytes and truncate a register double word, word or half word */ ++static void emit_bswap_r64(struct jit_context *ctx, u8 dst, u32 width) ++{ ++ switch (width) { ++ /* Swap bytes in a double word */ ++ case 64: ++ if (cpu_has_mips64r2 || cpu_has_mips64r6) { ++ emit(ctx, dsbh, dst, dst); ++ emit(ctx, dshd, dst, dst); ++ } else { ++ u8 t1 = MIPS_R_T6; ++ u8 t2 = MIPS_R_T7; ++ ++ emit(ctx, dsll32, t2, dst, 0); /* t2 = dst << 32 */ ++ emit(ctx, dsrl32, dst, dst, 0); /* dst = dst >> 32 */ ++ emit(ctx, or, dst, dst, t2); /* dst = dst | t2 */ ++ ++ emit(ctx, ori, t2, MIPS_R_ZERO, 0xffff); ++ emit(ctx, dsll32, t1, t2, 0); /* t1 = t2 << 32 */ ++ emit(ctx, or, t1, t1, t2); /* t1 = t1 | t2 */ ++ emit_swap_r64(ctx, dst, t1, 16);/* dst = swap16(dst) */ ++ ++ emit(ctx, lui, t2, 0xff); /* t2 = 0x00ff0000 */ ++ emit(ctx, ori, t2, t2, 0xff); /* t2 = t2 | 0x00ff */ ++ emit(ctx, dsll32, t1, t2, 0); /* t1 = t2 << 32 */ ++ emit(ctx, or, t1, t1, t2); /* t1 = t1 | t2 */ ++ emit_swap_r64(ctx, dst, t1, 8); /* dst = swap8(dst) */ ++ } ++ break; ++ /* Swap bytes in a half word */ ++ /* Swap bytes in a word */ ++ case 32: ++ case 16: ++ emit_sext(ctx, dst, dst); ++ emit_bswap_r(ctx, dst, width); ++ if (cpu_has_mips64r2 || cpu_has_mips64r6) ++ emit_zext(ctx, dst); ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Truncate a register double word, word or half word */ ++static void emit_trunc_r64(struct jit_context *ctx, u8 dst, u32 width) ++{ ++ switch (width) { ++ case 64: ++ break; ++ /* Zero-extend a word */ ++ case 32: ++ emit_zext(ctx, dst); ++ break; ++ /* Zero-extend a half word */ ++ case 16: ++ emit(ctx, andi, dst, dst, 0xffff); ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Load operation: dst = *(size*)(src + off) */ ++static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) ++{ ++ switch (size) { ++ /* Load a byte */ ++ case BPF_B: ++ emit(ctx, lbu, dst, off, src); ++ break; ++ /* Load a half word */ ++ case BPF_H: ++ emit(ctx, lhu, dst, off, src); ++ break; ++ /* Load a word */ ++ case BPF_W: ++ emit(ctx, lwu, dst, off, src); ++ break; ++ /* Load a double word */ ++ case BPF_DW: ++ emit(ctx, ld, dst, off, src); ++ break; ++ } ++ clobber_reg(ctx, dst); ++} ++ ++/* Store operation: *(size *)(dst + off) = src */ ++static void emit_stx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) ++{ ++ switch (size) { ++ /* Store a byte */ ++ case BPF_B: ++ emit(ctx, sb, src, off, dst); ++ break; ++ /* Store a half word */ ++ case BPF_H: ++ emit(ctx, sh, src, off, dst); ++ break; ++ /* Store a word */ ++ case BPF_W: ++ emit(ctx, sw, src, off, dst); ++ break; ++ /* Store a double word */ ++ case BPF_DW: ++ emit(ctx, sd, src, off, dst); ++ break; ++ } ++} ++ ++/* Atomic read-modify-write */ ++static void emit_atomic_r64(struct jit_context *ctx, ++ u8 dst, u8 src, s16 off, u8 code) ++{ ++ u8 t1 = MIPS_R_T6; ++ u8 t2 = MIPS_R_T7; ++ ++ emit(ctx, lld, t1, off, dst); ++ switch (code) { ++ case BPF_ADD: ++ emit(ctx, daddu, t2, t1, src); ++ break; ++ case BPF_AND: ++ emit(ctx, and, t2, t1, src); ++ break; ++ case BPF_OR: ++ emit(ctx, or, t2, t1, src); ++ break; ++ case BPF_XOR: ++ emit(ctx, xor, t2, t1, src); ++ break; ++ } ++ emit(ctx, scd, t2, off, dst); ++ emit(ctx, beqz, t2, -16); ++ emit(ctx, nop); /* Delay slot */ ++} ++ ++/* Function call */ ++static int emit_call(struct jit_context *ctx, const struct bpf_insn *insn) ++{ ++ u8 zx = bpf2mips64[JIT_REG_ZX]; ++ u8 tmp = MIPS_R_T6; ++ bool fixed; ++ u64 addr; ++ ++ /* Decode the call address */ ++ if (bpf_jit_get_func_addr(ctx->program, insn, false, ++ &addr, &fixed) < 0) ++ return -1; ++ if (!fixed) ++ return -1; ++ ++ /* Push caller-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); ++ ++ /* Emit function call */ ++ emit_mov_i64(ctx, tmp, addr); ++ emit(ctx, jalr, MIPS_R_RA, tmp); ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* Restore caller-saved registers */ ++ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); ++ ++ /* Re-initialize the JIT zero-extension register if accessed */ ++ if (ctx->accessed & BIT(JIT_REG_ZX)) { ++ emit(ctx, daddiu, zx, MIPS_R_ZERO, -1); ++ emit(ctx, dsrl32, zx, zx, 0); ++ } ++ ++ clobber_reg(ctx, MIPS_R_RA); ++ clobber_reg(ctx, MIPS_R_V0); ++ clobber_reg(ctx, MIPS_R_V1); ++ return 0; ++} ++ ++/* Function tail call */ ++static int emit_tail_call(struct jit_context *ctx) ++{ ++ u8 ary = bpf2mips64[BPF_REG_2]; ++ u8 ind = bpf2mips64[BPF_REG_3]; ++ u8 tcc = bpf2mips64[JIT_REG_TC]; ++ u8 tmp = MIPS_R_T6; ++ int off; ++ ++ /* ++ * Tail call: ++ * eBPF R1 - function argument (context ptr), passed in a0-a1 ++ * eBPF R2 - ptr to object with array of function entry points ++ * eBPF R3 - array index of function to be called ++ */ ++ ++ /* if (ind >= ary->map.max_entries) goto out */ ++ off = offsetof(struct bpf_array, map.max_entries); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, lwu, tmp, off, ary); /* tmp = ary->map.max_entrs*/ ++ emit(ctx, sltu, tmp, ind, tmp); /* tmp = ind < t1 */ ++ emit(ctx, beqz, tmp, get_offset(ctx, 1)); /* PC += off(1) if tmp == 0*/ ++ ++ /* if (--TCC < 0) goto out */ ++ emit(ctx, daddiu, tcc, tcc, -1); /* tcc-- (delay slot) */ ++ emit(ctx, bltz, tcc, get_offset(ctx, 1)); /* PC += off(1) if tcc < 0 */ ++ /* (next insn delay slot) */ ++ /* prog = ary->ptrs[ind] */ ++ off = offsetof(struct bpf_array, ptrs); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, dsll, tmp, ind, 3); /* tmp = ind << 3 */ ++ emit(ctx, daddu, tmp, tmp, ary); /* tmp += ary */ ++ emit(ctx, ld, tmp, off, tmp); /* tmp = *(tmp + off) */ ++ ++ /* if (prog == 0) goto out */ ++ emit(ctx, beqz, tmp, get_offset(ctx, 1)); /* PC += off(1) if tmp == 0*/ ++ emit(ctx, nop); /* Delay slot */ ++ ++ /* func = prog->bpf_func + 8 (prologue skip offset) */ ++ off = offsetof(struct bpf_prog, bpf_func); ++ if (off > 0x7fff) ++ return -1; ++ emit(ctx, ld, tmp, off, tmp); /* tmp = *(tmp + off) */ ++ emit(ctx, daddiu, tmp, tmp, JIT_TCALL_SKIP); /* tmp += skip (4) */ ++ ++ /* goto func */ ++ build_epilogue(ctx, tmp); ++ access_reg(ctx, JIT_REG_TC); ++ return 0; ++} ++ ++/* ++ * Stack frame layout for a JITed program (stack grows down). ++ * ++ * Higher address : Previous stack frame : ++ * +===========================+ <--- MIPS sp before call ++ * | Callee-saved registers, | ++ * | including RA and FP | ++ * +---------------------------+ <--- eBPF FP (MIPS fp) ++ * | Local eBPF variables | ++ * | allocated by program | ++ * +---------------------------+ ++ * | Reserved for caller-saved | ++ * | registers | ++ * Lower address +===========================+ <--- MIPS sp ++ */ ++ ++/* Build program prologue to set up the stack and registers */ ++void build_prologue(struct jit_context *ctx) ++{ ++ u8 fp = bpf2mips64[BPF_REG_FP]; ++ u8 tc = bpf2mips64[JIT_REG_TC]; ++ u8 zx = bpf2mips64[JIT_REG_ZX]; ++ int stack, saved, locals, reserved; ++ ++ /* ++ * The first instruction initializes the tail call count register. ++ * On a tail call, the calling function jumps into the prologue ++ * after this instruction. ++ */ ++ emit(ctx, addiu, tc, MIPS_R_ZERO, min(MAX_TAIL_CALL_CNT + 1, 0xffff)); ++ ++ /* === Entry-point for tail calls === */ ++ ++ /* ++ * If the eBPF frame pointer and tail call count registers were ++ * accessed they must be preserved. Mark them as clobbered here ++ * to save and restore them on the stack as needed. ++ */ ++ if (ctx->accessed & BIT(BPF_REG_FP)) ++ clobber_reg(ctx, fp); ++ if (ctx->accessed & BIT(JIT_REG_TC)) ++ clobber_reg(ctx, tc); ++ if (ctx->accessed & BIT(JIT_REG_ZX)) ++ clobber_reg(ctx, zx); ++ ++ /* Compute the stack space needed for callee-saved registers */ ++ saved = hweight32(ctx->clobbered & JIT_CALLEE_REGS) * sizeof(u64); ++ saved = ALIGN(saved, MIPS_STACK_ALIGNMENT); ++ ++ /* Stack space used by eBPF program local data */ ++ locals = ALIGN(ctx->program->aux->stack_depth, MIPS_STACK_ALIGNMENT); ++ ++ /* ++ * If we are emitting function calls, reserve extra stack space for ++ * caller-saved registers needed by the JIT. The required space is ++ * computed automatically during resource usage discovery (pass 1). ++ */ ++ reserved = ctx->stack_used; ++ ++ /* Allocate the stack frame */ ++ stack = ALIGN(saved + locals + reserved, MIPS_STACK_ALIGNMENT); ++ if (stack) ++ emit(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, -stack); ++ ++ /* Store callee-saved registers on stack */ ++ push_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, stack - saved); ++ ++ /* Initialize the eBPF frame pointer if accessed */ ++ if (ctx->accessed & BIT(BPF_REG_FP)) ++ emit(ctx, daddiu, fp, MIPS_R_SP, stack - saved); ++ ++ /* Initialize the ePF JIT zero-extension register if accessed */ ++ if (ctx->accessed & BIT(JIT_REG_ZX)) { ++ emit(ctx, daddiu, zx, MIPS_R_ZERO, -1); ++ emit(ctx, dsrl32, zx, zx, 0); ++ } ++ ++ ctx->saved_size = saved; ++ ctx->stack_size = stack; ++} ++ ++/* Build the program epilogue to restore the stack and registers */ ++void build_epilogue(struct jit_context *ctx, int dest_reg) ++{ ++ /* Restore callee-saved registers from stack */ ++ pop_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, ++ ctx->stack_size - ctx->saved_size); ++ ++ /* Release the stack frame */ ++ if (ctx->stack_size) ++ emit(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, ctx->stack_size); ++ ++ /* Jump to return address and sign-extend the 32-bit return value */ ++ emit(ctx, jr, dest_reg); ++ emit(ctx, sll, MIPS_R_V0, MIPS_R_V0, 0); /* Delay slot */ ++} ++ ++/* Build one eBPF instruction */ ++int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) ++{ ++ u8 dst = bpf2mips64[insn->dst_reg]; ++ u8 src = bpf2mips64[insn->src_reg]; ++ u8 code = insn->code; ++ s16 off = insn->off; ++ s32 imm = insn->imm; ++ s32 val, rel; ++ u8 alu, jmp; ++ ++ switch (code) { ++ /* ALU operations */ ++ /* dst = imm */ ++ case BPF_ALU | BPF_MOV | BPF_K: ++ emit_mov_i(ctx, dst, imm); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = src */ ++ case BPF_ALU | BPF_MOV | BPF_X: ++ if (imm == 1) { ++ /* Special mov32 for zext */ ++ emit_zext(ctx, dst); ++ } else { ++ emit_mov_r(ctx, dst, src); ++ emit_zext_ver(ctx, dst); ++ } ++ break; ++ /* dst = -dst */ ++ case BPF_ALU | BPF_NEG: ++ emit_sext(ctx, dst, dst); ++ emit_alu_i(ctx, dst, 0, BPF_NEG); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst & imm */ ++ /* dst = dst | imm */ ++ /* dst = dst ^ imm */ ++ /* dst = dst << imm */ ++ case BPF_ALU | BPF_OR | BPF_K: ++ case BPF_ALU | BPF_AND | BPF_K: ++ case BPF_ALU | BPF_XOR | BPF_K: ++ case BPF_ALU | BPF_LSH | BPF_K: ++ if (!valid_alu_i(BPF_OP(code), imm)) { ++ emit_mov_i(ctx, MIPS_R_T4, imm); ++ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); ++ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { ++ emit_alu_i(ctx, dst, val, alu); ++ } ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst >> imm */ ++ /* dst = dst >> imm (arithmetic) */ ++ /* dst = dst + imm */ ++ /* dst = dst - imm */ ++ /* dst = dst * imm */ ++ /* dst = dst / imm */ ++ /* dst = dst % imm */ ++ case BPF_ALU | BPF_RSH | BPF_K: ++ case BPF_ALU | BPF_ARSH | BPF_K: ++ case BPF_ALU | BPF_ADD | BPF_K: ++ case BPF_ALU | BPF_SUB | BPF_K: ++ case BPF_ALU | BPF_MUL | BPF_K: ++ case BPF_ALU | BPF_DIV | BPF_K: ++ case BPF_ALU | BPF_MOD | BPF_K: ++ if (!valid_alu_i(BPF_OP(code), imm)) { ++ emit_sext(ctx, dst, dst); ++ emit_mov_i(ctx, MIPS_R_T4, imm); ++ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); ++ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { ++ emit_sext(ctx, dst, dst); ++ emit_alu_i(ctx, dst, val, alu); ++ } ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst & src */ ++ /* dst = dst | src */ ++ /* dst = dst ^ src */ ++ /* dst = dst << src */ ++ case BPF_ALU | BPF_AND | BPF_X: ++ case BPF_ALU | BPF_OR | BPF_X: ++ case BPF_ALU | BPF_XOR | BPF_X: ++ case BPF_ALU | BPF_LSH | BPF_X: ++ emit_alu_r(ctx, dst, src, BPF_OP(code)); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = dst >> src */ ++ /* dst = dst >> src (arithmetic) */ ++ /* dst = dst + src */ ++ /* dst = dst - src */ ++ /* dst = dst * src */ ++ /* dst = dst / src */ ++ /* dst = dst % src */ ++ case BPF_ALU | BPF_RSH | BPF_X: ++ case BPF_ALU | BPF_ARSH | BPF_X: ++ case BPF_ALU | BPF_ADD | BPF_X: ++ case BPF_ALU | BPF_SUB | BPF_X: ++ case BPF_ALU | BPF_MUL | BPF_X: ++ case BPF_ALU | BPF_DIV | BPF_X: ++ case BPF_ALU | BPF_MOD | BPF_X: ++ emit_sext(ctx, dst, dst); ++ emit_sext(ctx, MIPS_R_T4, src); ++ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); ++ emit_zext_ver(ctx, dst); ++ break; ++ /* dst = imm (64-bit) */ ++ case BPF_ALU64 | BPF_MOV | BPF_K: ++ emit_mov_i(ctx, dst, imm); ++ break; ++ /* dst = src (64-bit) */ ++ case BPF_ALU64 | BPF_MOV | BPF_X: ++ emit_mov_r(ctx, dst, src); ++ break; ++ /* dst = -dst (64-bit) */ ++ case BPF_ALU64 | BPF_NEG: ++ emit_alu_i64(ctx, dst, 0, BPF_NEG); ++ break; ++ /* dst = dst & imm (64-bit) */ ++ /* dst = dst | imm (64-bit) */ ++ /* dst = dst ^ imm (64-bit) */ ++ /* dst = dst << imm (64-bit) */ ++ /* dst = dst >> imm (64-bit) */ ++ /* dst = dst >> imm ((64-bit, arithmetic) */ ++ /* dst = dst + imm (64-bit) */ ++ /* dst = dst - imm (64-bit) */ ++ /* dst = dst * imm (64-bit) */ ++ /* dst = dst / imm (64-bit) */ ++ /* dst = dst % imm (64-bit) */ ++ case BPF_ALU64 | BPF_AND | BPF_K: ++ case BPF_ALU64 | BPF_OR | BPF_K: ++ case BPF_ALU64 | BPF_XOR | BPF_K: ++ case BPF_ALU64 | BPF_LSH | BPF_K: ++ case BPF_ALU64 | BPF_RSH | BPF_K: ++ case BPF_ALU64 | BPF_ARSH | BPF_K: ++ case BPF_ALU64 | BPF_ADD | BPF_K: ++ case BPF_ALU64 | BPF_SUB | BPF_K: ++ case BPF_ALU64 | BPF_MUL | BPF_K: ++ case BPF_ALU64 | BPF_DIV | BPF_K: ++ case BPF_ALU64 | BPF_MOD | BPF_K: ++ if (!valid_alu_i(BPF_OP(code), imm)) { ++ emit_mov_i(ctx, MIPS_R_T4, imm); ++ emit_alu_r64(ctx, dst, MIPS_R_T4, BPF_OP(code)); ++ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { ++ emit_alu_i64(ctx, dst, val, alu); ++ } ++ break; ++ /* dst = dst & src (64-bit) */ ++ /* dst = dst | src (64-bit) */ ++ /* dst = dst ^ src (64-bit) */ ++ /* dst = dst << src (64-bit) */ ++ /* dst = dst >> src (64-bit) */ ++ /* dst = dst >> src (64-bit, arithmetic) */ ++ /* dst = dst + src (64-bit) */ ++ /* dst = dst - src (64-bit) */ ++ /* dst = dst * src (64-bit) */ ++ /* dst = dst / src (64-bit) */ ++ /* dst = dst % src (64-bit) */ ++ case BPF_ALU64 | BPF_AND | BPF_X: ++ case BPF_ALU64 | BPF_OR | BPF_X: ++ case BPF_ALU64 | BPF_XOR | BPF_X: ++ case BPF_ALU64 | BPF_LSH | BPF_X: ++ case BPF_ALU64 | BPF_RSH | BPF_X: ++ case BPF_ALU64 | BPF_ARSH | BPF_X: ++ case BPF_ALU64 | BPF_ADD | BPF_X: ++ case BPF_ALU64 | BPF_SUB | BPF_X: ++ case BPF_ALU64 | BPF_MUL | BPF_X: ++ case BPF_ALU64 | BPF_DIV | BPF_X: ++ case BPF_ALU64 | BPF_MOD | BPF_X: ++ emit_alu_r64(ctx, dst, src, BPF_OP(code)); ++ break; ++ /* dst = htole(dst) */ ++ /* dst = htobe(dst) */ ++ case BPF_ALU | BPF_END | BPF_FROM_LE: ++ case BPF_ALU | BPF_END | BPF_FROM_BE: ++ if (BPF_SRC(code) == ++#ifdef __BIG_ENDIAN ++ BPF_FROM_LE ++#else ++ BPF_FROM_BE ++#endif ++ ) ++ emit_bswap_r64(ctx, dst, imm); ++ else ++ emit_trunc_r64(ctx, dst, imm); ++ break; ++ /* dst = imm64 */ ++ case BPF_LD | BPF_IMM | BPF_DW: ++ emit_mov_i64(ctx, dst, (u32)imm | ((u64)insn[1].imm << 32)); ++ return 1; ++ /* LDX: dst = *(size *)(src + off) */ ++ case BPF_LDX | BPF_MEM | BPF_W: ++ case BPF_LDX | BPF_MEM | BPF_H: ++ case BPF_LDX | BPF_MEM | BPF_B: ++ case BPF_LDX | BPF_MEM | BPF_DW: ++ emit_ldx(ctx, dst, src, off, BPF_SIZE(code)); ++ break; ++ /* ST: *(size *)(dst + off) = imm */ ++ case BPF_ST | BPF_MEM | BPF_W: ++ case BPF_ST | BPF_MEM | BPF_H: ++ case BPF_ST | BPF_MEM | BPF_B: ++ case BPF_ST | BPF_MEM | BPF_DW: ++ emit_mov_i(ctx, MIPS_R_T4, imm); ++ emit_stx(ctx, dst, MIPS_R_T4, off, BPF_SIZE(code)); ++ break; ++ /* STX: *(size *)(dst + off) = src */ ++ case BPF_STX | BPF_MEM | BPF_W: ++ case BPF_STX | BPF_MEM | BPF_H: ++ case BPF_STX | BPF_MEM | BPF_B: ++ case BPF_STX | BPF_MEM | BPF_DW: ++ emit_stx(ctx, dst, src, off, BPF_SIZE(code)); ++ break; ++ /* Speculation barrier */ ++ case BPF_ST | BPF_NOSPEC: ++ break; ++ /* Atomics */ ++ case BPF_STX | BPF_XADD | BPF_W: ++ case BPF_STX | BPF_XADD | BPF_DW: ++ switch (imm) { ++ case BPF_ADD: ++ case BPF_AND: ++ case BPF_OR: ++ case BPF_XOR: ++ if (BPF_SIZE(code) == BPF_DW) { ++ emit_atomic_r64(ctx, dst, src, off, imm); ++ } else { /* 32-bit, no fetch */ ++ emit_sext(ctx, MIPS_R_T4, src); ++ emit_atomic_r(ctx, dst, MIPS_R_T4, off, imm); ++ } ++ break; ++ default: ++ goto notyet; ++ } ++ break; ++ /* PC += off if dst == src */ ++ /* PC += off if dst != src */ ++ /* PC += off if dst & src */ ++ /* PC += off if dst > src */ ++ /* PC += off if dst >= src */ ++ /* PC += off if dst < src */ ++ /* PC += off if dst <= src */ ++ /* PC += off if dst > src (signed) */ ++ /* PC += off if dst >= src (signed) */ ++ /* PC += off if dst < src (signed) */ ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JMP32 | BPF_JEQ | BPF_X: ++ case BPF_JMP32 | BPF_JNE | BPF_X: ++ case BPF_JMP32 | BPF_JSET | BPF_X: ++ case BPF_JMP32 | BPF_JGT | BPF_X: ++ case BPF_JMP32 | BPF_JGE | BPF_X: ++ case BPF_JMP32 | BPF_JLT | BPF_X: ++ case BPF_JMP32 | BPF_JLE | BPF_X: ++ case BPF_JMP32 | BPF_JSGT | BPF_X: ++ case BPF_JMP32 | BPF_JSGE | BPF_X: ++ case BPF_JMP32 | BPF_JSLT | BPF_X: ++ case BPF_JMP32 | BPF_JSLE | BPF_X: ++ if (off == 0) ++ break; ++ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); ++ emit_sext(ctx, MIPS_R_T4, dst); /* Sign-extended dst */ ++ emit_sext(ctx, MIPS_R_T5, src); /* Sign-extended src */ ++ emit_jmp_r(ctx, MIPS_R_T4, MIPS_R_T5, rel, jmp); ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == imm */ ++ /* PC += off if dst != imm */ ++ /* PC += off if dst & imm */ ++ /* PC += off if dst > imm */ ++ /* PC += off if dst >= imm */ ++ /* PC += off if dst < imm */ ++ /* PC += off if dst <= imm */ ++ /* PC += off if dst > imm (signed) */ ++ /* PC += off if dst >= imm (signed) */ ++ /* PC += off if dst < imm (signed) */ ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JMP32 | BPF_JEQ | BPF_K: ++ case BPF_JMP32 | BPF_JNE | BPF_K: ++ case BPF_JMP32 | BPF_JSET | BPF_K: ++ case BPF_JMP32 | BPF_JGT | BPF_K: ++ case BPF_JMP32 | BPF_JGE | BPF_K: ++ case BPF_JMP32 | BPF_JLT | BPF_K: ++ case BPF_JMP32 | BPF_JLE | BPF_K: ++ case BPF_JMP32 | BPF_JSGT | BPF_K: ++ case BPF_JMP32 | BPF_JSGE | BPF_K: ++ case BPF_JMP32 | BPF_JSLT | BPF_K: ++ case BPF_JMP32 | BPF_JSLE | BPF_K: ++ if (off == 0) ++ break; ++ setup_jmp_i(ctx, imm, 32, BPF_OP(code), off, &jmp, &rel); ++ emit_sext(ctx, MIPS_R_T4, dst); /* Sign-extended dst */ ++ if (valid_jmp_i(jmp, imm)) { ++ emit_jmp_i(ctx, MIPS_R_T4, imm, rel, jmp); ++ } else { ++ /* Move large immediate to register, sign-extended */ ++ emit_mov_i(ctx, MIPS_R_T5, imm); ++ emit_jmp_r(ctx, MIPS_R_T4, MIPS_R_T5, rel, jmp); ++ } ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == src */ ++ /* PC += off if dst != src */ ++ /* PC += off if dst & src */ ++ /* PC += off if dst > src */ ++ /* PC += off if dst >= src */ ++ /* PC += off if dst < src */ ++ /* PC += off if dst <= src */ ++ /* PC += off if dst > src (signed) */ ++ /* PC += off if dst >= src (signed) */ ++ /* PC += off if dst < src (signed) */ ++ /* PC += off if dst <= src (signed) */ ++ case BPF_JMP | BPF_JEQ | BPF_X: ++ case BPF_JMP | BPF_JNE | BPF_X: ++ case BPF_JMP | BPF_JSET | BPF_X: ++ case BPF_JMP | BPF_JGT | BPF_X: ++ case BPF_JMP | BPF_JGE | BPF_X: ++ case BPF_JMP | BPF_JLT | BPF_X: ++ case BPF_JMP | BPF_JLE | BPF_X: ++ case BPF_JMP | BPF_JSGT | BPF_X: ++ case BPF_JMP | BPF_JSGE | BPF_X: ++ case BPF_JMP | BPF_JSLT | BPF_X: ++ case BPF_JMP | BPF_JSLE | BPF_X: ++ if (off == 0) ++ break; ++ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); ++ emit_jmp_r(ctx, dst, src, rel, jmp); ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off if dst == imm */ ++ /* PC += off if dst != imm */ ++ /* PC += off if dst & imm */ ++ /* PC += off if dst > imm */ ++ /* PC += off if dst >= imm */ ++ /* PC += off if dst < imm */ ++ /* PC += off if dst <= imm */ ++ /* PC += off if dst > imm (signed) */ ++ /* PC += off if dst >= imm (signed) */ ++ /* PC += off if dst < imm (signed) */ ++ /* PC += off if dst <= imm (signed) */ ++ case BPF_JMP | BPF_JEQ | BPF_K: ++ case BPF_JMP | BPF_JNE | BPF_K: ++ case BPF_JMP | BPF_JSET | BPF_K: ++ case BPF_JMP | BPF_JGT | BPF_K: ++ case BPF_JMP | BPF_JGE | BPF_K: ++ case BPF_JMP | BPF_JLT | BPF_K: ++ case BPF_JMP | BPF_JLE | BPF_K: ++ case BPF_JMP | BPF_JSGT | BPF_K: ++ case BPF_JMP | BPF_JSGE | BPF_K: ++ case BPF_JMP | BPF_JSLT | BPF_K: ++ case BPF_JMP | BPF_JSLE | BPF_K: ++ if (off == 0) ++ break; ++ setup_jmp_i(ctx, imm, 64, BPF_OP(code), off, &jmp, &rel); ++ if (valid_jmp_i(jmp, imm)) { ++ emit_jmp_i(ctx, dst, imm, rel, jmp); ++ } else { ++ /* Move large immediate to register */ ++ emit_mov_i(ctx, MIPS_R_T4, imm); ++ emit_jmp_r(ctx, dst, MIPS_R_T4, rel, jmp); ++ } ++ if (finish_jmp(ctx, jmp, off) < 0) ++ goto toofar; ++ break; ++ /* PC += off */ ++ case BPF_JMP | BPF_JA: ++ if (off == 0) ++ break; ++ if (emit_ja(ctx, off) < 0) ++ goto toofar; ++ break; ++ /* Tail call */ ++ case BPF_JMP | BPF_TAIL_CALL: ++ if (emit_tail_call(ctx) < 0) ++ goto invalid; ++ break; ++ /* Function call */ ++ case BPF_JMP | BPF_CALL: ++ if (emit_call(ctx, insn) < 0) ++ goto invalid; ++ break; ++ /* Function return */ ++ case BPF_JMP | BPF_EXIT: ++ /* ++ * Optimization: when last instruction is EXIT ++ * simply continue to epilogue. ++ */ ++ if (ctx->bpf_index == ctx->program->len - 1) ++ break; ++ if (emit_exit(ctx) < 0) ++ goto toofar; ++ break; ++ ++ default: ++invalid: ++ pr_err_once("unknown opcode %02x\n", code); ++ return -EINVAL; ++notyet: ++ pr_info_once("*** NOT YET: opcode %02x ***\n", code); ++ return -EFAULT; ++toofar: ++ pr_info_once("*** TOO FAR: jump at %u opcode %02x ***\n", ++ ctx->bpf_index, code); ++ return -E2BIG; ++ } ++ return 0; ++} diff --git a/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch b/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch new file mode 100644 index 00000000000..63553ebe584 --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch @@ -0,0 +1,120 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:06 +0200 +Subject: [PATCH] mips: bpf: Add JIT workarounds for CPU errata + +This patch adds workarounds for the following CPU errata to the MIPS +eBPF JIT, if enabled in the kernel configuration. + + - R10000 ll/sc weak ordering + - Loongson-3 ll/sc weak ordering + - Loongson-2F jump hang + +The Loongson-2F nop errata is implemented in uasm, which the JIT uses, +so no additional mitigations are needed for that. + +Signed-off-by: Johan Almbladh +Reviewed-by: Jiaxun Yang +--- + +--- a/arch/mips/net/bpf_jit_comp.c ++++ b/arch/mips/net/bpf_jit_comp.c +@@ -404,6 +404,7 @@ void emit_alu_r(struct jit_context *ctx, + /* Atomic read-modify-write (32-bit) */ + void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code) + { ++ LLSC_sync(ctx); + emit(ctx, ll, MIPS_R_T9, off, dst); + switch (code) { + case BPF_ADD: +@@ -420,18 +421,19 @@ void emit_atomic_r(struct jit_context *c + break; + } + emit(ctx, sc, MIPS_R_T8, off, dst); +- emit(ctx, beqz, MIPS_R_T8, -16); ++ emit(ctx, LLSC_beqz, MIPS_R_T8, -16 - LLSC_offset); + emit(ctx, nop); /* Delay slot */ + } + + /* Atomic compare-and-exchange (32-bit) */ + void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off) + { ++ LLSC_sync(ctx); + emit(ctx, ll, MIPS_R_T9, off, dst); + emit(ctx, bne, MIPS_R_T9, res, 12); + emit(ctx, move, MIPS_R_T8, src); /* Delay slot */ + emit(ctx, sc, MIPS_R_T8, off, dst); +- emit(ctx, beqz, MIPS_R_T8, -20); ++ emit(ctx, LLSC_beqz, MIPS_R_T8, -20 - LLSC_offset); + emit(ctx, move, res, MIPS_R_T9); /* Delay slot */ + clobber_reg(ctx, res); + } +--- a/arch/mips/net/bpf_jit_comp.h ++++ b/arch/mips/net/bpf_jit_comp.h +@@ -87,7 +87,7 @@ struct jit_context { + }; + + /* Emit the instruction if the JIT memory space has been allocated */ +-#define emit(ctx, func, ...) \ ++#define __emit(ctx, func, ...) \ + do { \ + if ((ctx)->target != NULL) { \ + u32 *p = &(ctx)->target[ctx->jit_index]; \ +@@ -95,6 +95,30 @@ do { \ + } \ + (ctx)->jit_index++; \ + } while (0) ++#define emit(...) __emit(__VA_ARGS__) ++ ++/* Workaround for R10000 ll/sc errata */ ++#ifdef CONFIG_WAR_R10000 ++#define LLSC_beqz beqzl ++#else ++#define LLSC_beqz beqz ++#endif ++ ++/* Workaround for Loongson-3 ll/sc errata */ ++#ifdef CONFIG_CPU_LOONGSON3_WORKAROUNDS ++#define LLSC_sync(ctx) emit(ctx, sync, 0) ++#define LLSC_offset 4 ++#else ++#define LLSC_sync(ctx) ++#define LLSC_offset 0 ++#endif ++ ++/* Workaround for Loongson-2F jump errata */ ++#ifdef CONFIG_CPU_JUMP_WORKAROUNDS ++#define JALR_MASK 0xffffffffcfffffffULL ++#else ++#define JALR_MASK (~0ULL) ++#endif + + /* + * Mark a BPF register as accessed, it needs to be +--- a/arch/mips/net/bpf_jit_comp64.c ++++ b/arch/mips/net/bpf_jit_comp64.c +@@ -375,6 +375,7 @@ static void emit_atomic_r64(struct jit_c + u8 t1 = MIPS_R_T6; + u8 t2 = MIPS_R_T7; + ++ LLSC_sync(ctx); + emit(ctx, lld, t1, off, dst); + switch (code) { + case BPF_ADD: +@@ -391,7 +392,7 @@ static void emit_atomic_r64(struct jit_c + break; + } + emit(ctx, scd, t2, off, dst); +- emit(ctx, beqz, t2, -16); ++ emit(ctx, LLSC_beqz, t2, -16 - LLSC_offset); + emit(ctx, nop); /* Delay slot */ + } + +@@ -414,7 +415,7 @@ static int emit_call(struct jit_context + push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); + + /* Emit function call */ +- emit_mov_i64(ctx, tmp, addr); ++ emit_mov_i64(ctx, tmp, addr & JALR_MASK); + emit(ctx, jalr, MIPS_R_RA, tmp); + emit(ctx, nop); /* Delay slot */ + diff --git a/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch b/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch new file mode 100644 index 00000000000..14763c1211e --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch @@ -0,0 +1,61 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:07 +0200 +Subject: [PATCH] mips: bpf: Enable eBPF JITs + +This patch enables the new eBPF JITs for 32-bit and 64-bit MIPS. It also +disables the old cBPF JIT to so cBPF programs are converted to use the +new JIT. + +Workarounds for R4000 CPU errata are not implemented by the JIT, so the +JIT is disabled if any of those workarounds are configured. + +Signed-off-by: Johan Almbladh +--- + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -3431,6 +3431,7 @@ S: Supported + F: arch/arm64/net/ + + BPF JIT for MIPS (32-BIT AND 64-BIT) ++M: Johan Almbladh + M: Paul Burton + L: netdev@vger.kernel.org + L: bpf@vger.kernel.org +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -57,7 +57,6 @@ config MIPS + select HAVE_ARCH_TRACEHOOK + select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES + select HAVE_ASM_MODVERSIONS +- select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS + select HAVE_CONTEXT_TRACKING + select HAVE_TIF_NOHZ + select HAVE_C_RECORDMCOUNT +@@ -65,7 +64,10 @@ config MIPS + select HAVE_DEBUG_STACKOVERFLOW + select HAVE_DMA_CONTIGUOUS + select HAVE_DYNAMIC_FTRACE +- select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2 ++ select HAVE_EBPF_JIT if !CPU_MICROMIPS && \ ++ !CPU_DADDI_WORKAROUNDS && \ ++ !CPU_R4000_WORKAROUNDS && \ ++ !CPU_R4400_WORKAROUNDS + select HAVE_EXIT_THREAD + select HAVE_FAST_GUP + select HAVE_FTRACE_MCOUNT_RECORD +--- a/arch/mips/net/Makefile ++++ b/arch/mips/net/Makefile +@@ -2,9 +2,10 @@ + # MIPS networking code + + obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o ++obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o + + ifeq ($(CONFIG_32BIT),y) +- obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o bpf_jit_comp32.o ++ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp32.o + else +- obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o ++ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp64.o + endif diff --git a/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch b/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch new file mode 100644 index 00000000000..e25c336831d --- /dev/null +++ b/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch @@ -0,0 +1,387 @@ +From: Johan Almbladh +Date: Tue, 5 Oct 2021 18:54:08 +0200 +Subject: [PATCH] mips: bpf: Remove old BPF JIT implementations + +This patch removes the old 32-bit cBPF and 64-bit eBPF JIT implementations. +They are replaced by a new eBPF implementation that supports both 32-bit +and 64-bit MIPS CPUs. + +Signed-off-by: Johan Almbladh +--- + delete mode 100644 arch/mips/net/bpf_jit.c + delete mode 100644 arch/mips/net/bpf_jit.h + delete mode 100644 arch/mips/net/bpf_jit_asm.S + delete mode 100644 arch/mips/net/ebpf_jit.c + +--- a/arch/mips/net/bpf_jit.h ++++ /dev/null +@@ -1,81 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Just-In-Time compiler for BPF filters on MIPS +- * +- * Copyright (c) 2014 Imagination Technologies Ltd. +- * Author: Markos Chandras +- */ +- +-#ifndef BPF_JIT_MIPS_OP_H +-#define BPF_JIT_MIPS_OP_H +- +-/* Registers used by JIT */ +-#define MIPS_R_ZERO 0 +-#define MIPS_R_V0 2 +-#define MIPS_R_A0 4 +-#define MIPS_R_A1 5 +-#define MIPS_R_T4 12 +-#define MIPS_R_T5 13 +-#define MIPS_R_T6 14 +-#define MIPS_R_T7 15 +-#define MIPS_R_S0 16 +-#define MIPS_R_S1 17 +-#define MIPS_R_S2 18 +-#define MIPS_R_S3 19 +-#define MIPS_R_S4 20 +-#define MIPS_R_S5 21 +-#define MIPS_R_S6 22 +-#define MIPS_R_S7 23 +-#define MIPS_R_SP 29 +-#define MIPS_R_RA 31 +- +-/* Conditional codes */ +-#define MIPS_COND_EQ 0x1 +-#define MIPS_COND_GE (0x1 << 1) +-#define MIPS_COND_GT (0x1 << 2) +-#define MIPS_COND_NE (0x1 << 3) +-#define MIPS_COND_ALL (0x1 << 4) +-/* Conditionals on X register or K immediate */ +-#define MIPS_COND_X (0x1 << 5) +-#define MIPS_COND_K (0x1 << 6) +- +-#define r_ret MIPS_R_V0 +- +-/* +- * Use 2 scratch registers to avoid pipeline interlocks. +- * There is no overhead during epilogue and prologue since +- * any of the $s0-$s6 registers will only be preserved if +- * they are going to actually be used. +- */ +-#define r_skb_hl MIPS_R_S0 /* skb header length */ +-#define r_skb_data MIPS_R_S1 /* skb actual data */ +-#define r_off MIPS_R_S2 +-#define r_A MIPS_R_S3 +-#define r_X MIPS_R_S4 +-#define r_skb MIPS_R_S5 +-#define r_M MIPS_R_S6 +-#define r_skb_len MIPS_R_S7 +-#define r_s0 MIPS_R_T4 /* scratch reg 1 */ +-#define r_s1 MIPS_R_T5 /* scratch reg 2 */ +-#define r_tmp_imm MIPS_R_T6 /* No need to preserve this */ +-#define r_tmp MIPS_R_T7 /* No need to preserve this */ +-#define r_zero MIPS_R_ZERO +-#define r_sp MIPS_R_SP +-#define r_ra MIPS_R_RA +- +-#ifndef __ASSEMBLY__ +- +-/* Declare ASM helpers */ +- +-#define DECLARE_LOAD_FUNC(func) \ +- extern u8 func(unsigned long *skb, int offset); \ +- extern u8 func##_negative(unsigned long *skb, int offset); \ +- extern u8 func##_positive(unsigned long *skb, int offset) +- +-DECLARE_LOAD_FUNC(sk_load_word); +-DECLARE_LOAD_FUNC(sk_load_half); +-DECLARE_LOAD_FUNC(sk_load_byte); +- +-#endif +- +-#endif /* BPF_JIT_MIPS_OP_H */ +--- a/arch/mips/net/bpf_jit_asm.S ++++ /dev/null +@@ -1,285 +0,0 @@ +-/* +- * bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF +- * compiler. +- * +- * Copyright (C) 2015 Imagination Technologies Ltd. +- * Author: Markos Chandras +- * +- * This program is free software; you can redistribute it and/or modify it +- * under the terms of the GNU General Public License as published by the +- * Free Software Foundation; version 2 of the License. +- */ +- +-#include +-#include +-#include +-#include "bpf_jit.h" +- +-/* ABI +- * +- * r_skb_hl skb header length +- * r_skb_data skb data +- * r_off(a1) offset register +- * r_A BPF register A +- * r_X PF register X +- * r_skb(a0) *skb +- * r_M *scratch memory +- * r_skb_le skb length +- * r_s0 Scratch register 0 +- * r_s1 Scratch register 1 +- * +- * On entry: +- * a0: *skb +- * a1: offset (imm or imm + X) +- * +- * All non-BPF-ABI registers are free for use. On return, we only +- * care about r_ret. The BPF-ABI registers are assumed to remain +- * unmodified during the entire filter operation. +- */ +- +-#define skb a0 +-#define offset a1 +-#define SKF_LL_OFF (-0x200000) /* Can't include linux/filter.h in assembly */ +- +- /* We know better :) so prevent assembler reordering etc */ +- .set noreorder +- +-#define is_offset_negative(TYPE) \ +- /* If offset is negative we have more work to do */ \ +- slti t0, offset, 0; \ +- bgtz t0, bpf_slow_path_##TYPE##_neg; \ +- /* Be careful what follows in DS. */ +- +-#define is_offset_in_header(SIZE, TYPE) \ +- /* Reading from header? */ \ +- addiu $r_s0, $r_skb_hl, -SIZE; \ +- slt t0, $r_s0, offset; \ +- bgtz t0, bpf_slow_path_##TYPE; \ +- +-LEAF(sk_load_word) +- is_offset_negative(word) +-FEXPORT(sk_load_word_positive) +- is_offset_in_header(4, word) +- /* Offset within header boundaries */ +- PTR_ADDU t1, $r_skb_data, offset +- .set reorder +- lw $r_A, 0(t1) +- .set noreorder +-#ifdef CONFIG_CPU_LITTLE_ENDIAN +-# if MIPS_ISA_REV >= 2 +- wsbh t0, $r_A +- rotr $r_A, t0, 16 +-# else +- sll t0, $r_A, 24 +- srl t1, $r_A, 24 +- srl t2, $r_A, 8 +- or t0, t0, t1 +- andi t2, t2, 0xff00 +- andi t1, $r_A, 0xff00 +- or t0, t0, t2 +- sll t1, t1, 8 +- or $r_A, t0, t1 +-# endif +-#endif +- jr $r_ra +- move $r_ret, zero +- END(sk_load_word) +- +-LEAF(sk_load_half) +- is_offset_negative(half) +-FEXPORT(sk_load_half_positive) +- is_offset_in_header(2, half) +- /* Offset within header boundaries */ +- PTR_ADDU t1, $r_skb_data, offset +- lhu $r_A, 0(t1) +-#ifdef CONFIG_CPU_LITTLE_ENDIAN +-# if MIPS_ISA_REV >= 2 +- wsbh $r_A, $r_A +-# else +- sll t0, $r_A, 8 +- srl t1, $r_A, 8 +- andi t0, t0, 0xff00 +- or $r_A, t0, t1 +-# endif +-#endif +- jr $r_ra +- move $r_ret, zero +- END(sk_load_half) +- +-LEAF(sk_load_byte) +- is_offset_negative(byte) +-FEXPORT(sk_load_byte_positive) +- is_offset_in_header(1, byte) +- /* Offset within header boundaries */ +- PTR_ADDU t1, $r_skb_data, offset +- lbu $r_A, 0(t1) +- jr $r_ra +- move $r_ret, zero +- END(sk_load_byte) +- +-/* +- * call skb_copy_bits: +- * (prototype in linux/skbuff.h) +- * +- * int skb_copy_bits(sk_buff *skb, int offset, void *to, int len) +- * +- * o32 mandates we leave 4 spaces for argument registers in case +- * the callee needs to use them. Even though we don't care about +- * the argument registers ourselves, we need to allocate that space +- * to remain ABI compliant since the callee may want to use that space. +- * We also allocate 2 more spaces for $r_ra and our return register (*to). +- * +- * n64 is a bit different. The *caller* will allocate the space to preserve +- * the arguments. So in 64-bit kernels, we allocate the 4-arg space for no +- * good reason but it does not matter that much really. +- * +- * (void *to) is returned in r_s0 +- * +- */ +-#ifdef CONFIG_CPU_LITTLE_ENDIAN +-#define DS_OFFSET(SIZE) (4 * SZREG) +-#else +-#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE)) +-#endif +-#define bpf_slow_path_common(SIZE) \ +- /* Quick check. Are we within reasonable boundaries? */ \ +- LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \ +- sltu $r_s0, offset, $r_s1; \ +- beqz $r_s0, fault; \ +- /* Load 4th argument in DS */ \ +- LONG_ADDIU a3, zero, SIZE; \ +- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \ +- PTR_LA t0, skb_copy_bits; \ +- PTR_S $r_ra, (5 * SZREG)($r_sp); \ +- /* Assign low slot to a2 */ \ +- PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \ +- jalr t0; \ +- /* Reset our destination slot (DS but it's ok) */ \ +- INT_S zero, (4 * SZREG)($r_sp); \ +- /* \ +- * skb_copy_bits returns 0 on success and -EFAULT \ +- * on error. Our data live in a2. Do not bother with \ +- * our data if an error has been returned. \ +- */ \ +- /* Restore our frame */ \ +- PTR_L $r_ra, (5 * SZREG)($r_sp); \ +- INT_L $r_s0, (4 * SZREG)($r_sp); \ +- bltz v0, fault; \ +- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \ +- move $r_ret, zero; \ +- +-NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp) +- bpf_slow_path_common(4) +-#ifdef CONFIG_CPU_LITTLE_ENDIAN +-# if MIPS_ISA_REV >= 2 +- wsbh t0, $r_s0 +- jr $r_ra +- rotr $r_A, t0, 16 +-# else +- sll t0, $r_s0, 24 +- srl t1, $r_s0, 24 +- srl t2, $r_s0, 8 +- or t0, t0, t1 +- andi t2, t2, 0xff00 +- andi t1, $r_s0, 0xff00 +- or t0, t0, t2 +- sll t1, t1, 8 +- jr $r_ra +- or $r_A, t0, t1 +-# endif +-#else +- jr $r_ra +- move $r_A, $r_s0 +-#endif +- +- END(bpf_slow_path_word) +- +-NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp) +- bpf_slow_path_common(2) +-#ifdef CONFIG_CPU_LITTLE_ENDIAN +-# if MIPS_ISA_REV >= 2 +- jr $r_ra +- wsbh $r_A, $r_s0 +-# else +- sll t0, $r_s0, 8 +- andi t1, $r_s0, 0xff00 +- andi t0, t0, 0xff00 +- srl t1, t1, 8 +- jr $r_ra +- or $r_A, t0, t1 +-# endif +-#else +- jr $r_ra +- move $r_A, $r_s0 +-#endif +- +- END(bpf_slow_path_half) +- +-NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp) +- bpf_slow_path_common(1) +- jr $r_ra +- move $r_A, $r_s0 +- +- END(bpf_slow_path_byte) +- +-/* +- * Negative entry points +- */ +- .macro bpf_is_end_of_data +- li t0, SKF_LL_OFF +- /* Reading link layer data? */ +- slt t1, offset, t0 +- bgtz t1, fault +- /* Be careful what follows in DS. */ +- .endm +-/* +- * call skb_copy_bits: +- * (prototype in linux/filter.h) +- * +- * void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, +- * int k, unsigned int size) +- * +- * see above (bpf_slow_path_common) for ABI restrictions +- */ +-#define bpf_negative_common(SIZE) \ +- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \ +- PTR_LA t0, bpf_internal_load_pointer_neg_helper; \ +- PTR_S $r_ra, (5 * SZREG)($r_sp); \ +- jalr t0; \ +- li a2, SIZE; \ +- PTR_L $r_ra, (5 * SZREG)($r_sp); \ +- /* Check return pointer */ \ +- beqz v0, fault; \ +- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \ +- /* Preserve our pointer */ \ +- move $r_s0, v0; \ +- /* Set return value */ \ +- move $r_ret, zero; \ +- +-bpf_slow_path_word_neg: +- bpf_is_end_of_data +-NESTED(sk_load_word_negative, (6 * SZREG), $r_sp) +- bpf_negative_common(4) +- jr $r_ra +- lw $r_A, 0($r_s0) +- END(sk_load_word_negative) +- +-bpf_slow_path_half_neg: +- bpf_is_end_of_data +-NESTED(sk_load_half_negative, (6 * SZREG), $r_sp) +- bpf_negative_common(2) +- jr $r_ra +- lhu $r_A, 0($r_s0) +- END(sk_load_half_negative) +- +-bpf_slow_path_byte_neg: +- bpf_is_end_of_data +-NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp) +- bpf_negative_common(1) +- jr $r_ra +- lbu $r_A, 0($r_s0) +- END(sk_load_byte_negative) +- +-fault: +- jr $r_ra +- addiu $r_ret, zero, 1 diff --git a/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch b/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch new file mode 100644 index 00000000000..51c23b6e349 --- /dev/null +++ b/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch @@ -0,0 +1,105 @@ +From 815f0e738a8d5663a02350e2580706829144a722 Mon Sep 17 00:00:00 2001 +From: Horatiu Vultur +Date: Wed, 3 Nov 2021 09:50:59 +0100 +Subject: [PATCH] clk: gate: Add devm_clk_hw_register_gate() + +Add devm_clk_hw_register_gate() - devres-managed version of +clk_hw_register_gate() + +Suggested-by: Stephen Boyd +Signed-off-by: Horatiu Vultur +Acked-by: Nicolas Ferre +Signed-off-by: Nicolas Ferre +Link: https://lore.kernel.org/r/20211103085102.1656081-2-horatiu.vultur@microchip.com +--- + drivers/clk/clk-gate.c | 35 +++++++++++++++++++++++++++++++++++ + include/linux/clk-provider.h | 23 +++++++++++++++++++++++ + 2 files changed, 58 insertions(+) + +--- a/drivers/clk/clk-gate.c ++++ b/drivers/clk/clk-gate.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -222,3 +223,37 @@ void clk_hw_unregister_gate(struct clk_h + kfree(gate); + } + EXPORT_SYMBOL_GPL(clk_hw_unregister_gate); ++ ++static void devm_clk_hw_release_gate(struct device *dev, void *res) ++{ ++ clk_hw_unregister_gate(*(struct clk_hw **)res); ++} ++ ++struct clk_hw *__devm_clk_hw_register_gate(struct device *dev, ++ struct device_node *np, const char *name, ++ const char *parent_name, const struct clk_hw *parent_hw, ++ const struct clk_parent_data *parent_data, ++ unsigned long flags, ++ void __iomem *reg, u8 bit_idx, ++ u8 clk_gate_flags, spinlock_t *lock) ++{ ++ struct clk_hw **ptr, *hw; ++ ++ ptr = devres_alloc(devm_clk_hw_release_gate, sizeof(*ptr), GFP_KERNEL); ++ if (!ptr) ++ return ERR_PTR(-ENOMEM); ++ ++ hw = __clk_hw_register_gate(dev, np, name, parent_name, parent_hw, ++ parent_data, flags, reg, bit_idx, ++ clk_gate_flags, lock); ++ ++ if (!IS_ERR(hw)) { ++ *ptr = hw; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ ++ return hw; ++} ++EXPORT_SYMBOL_GPL(__devm_clk_hw_register_gate); +--- a/include/linux/clk-provider.h ++++ b/include/linux/clk-provider.h +@@ -490,6 +490,13 @@ struct clk_hw *__clk_hw_register_gate(st + unsigned long flags, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags, spinlock_t *lock); ++struct clk_hw *__devm_clk_hw_register_gate(struct device *dev, ++ struct device_node *np, const char *name, ++ const char *parent_name, const struct clk_hw *parent_hw, ++ const struct clk_parent_data *parent_data, ++ unsigned long flags, ++ void __iomem *reg, u8 bit_idx, ++ u8 clk_gate_flags, spinlock_t *lock); + struct clk *clk_register_gate(struct device *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 bit_idx, +@@ -544,6 +551,22 @@ struct clk *clk_register_gate(struct dev + __clk_hw_register_gate((dev), NULL, (name), NULL, NULL, (parent_data), \ + (flags), (reg), (bit_idx), \ + (clk_gate_flags), (lock)) ++/** ++ * devm_clk_hw_register_gate - register a gate clock with the clock framework ++ * @dev: device that is registering this clock ++ * @name: name of this clock ++ * @parent_name: name of this clock's parent ++ * @flags: framework-specific flags for this clock ++ * @reg: register address to control gating of this clock ++ * @bit_idx: which bit in the register controls gating of this clock ++ * @clk_gate_flags: gate-specific flags for this clock ++ * @lock: shared register lock for this clock ++ */ ++#define devm_clk_hw_register_gate(dev, name, parent_name, flags, reg, bit_idx,\ ++ clk_gate_flags, lock) \ ++ __devm_clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL, \ ++ NULL, (flags), (reg), (bit_idx), \ ++ (clk_gate_flags), (lock)) + void clk_unregister_gate(struct clk *clk); + void clk_hw_unregister_gate(struct clk_hw *hw); + int clk_gate_is_enabled(struct clk_hw *hw); diff --git a/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch b/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch new file mode 100644 index 00000000000..e4c0833ae75 --- /dev/null +++ b/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch @@ -0,0 +1,52 @@ +From 02d6fdecb9c38de19065f6bed8d5214556fd061d Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 4 Nov 2021 16:00:40 +0100 +Subject: regmap: allow to define reg_update_bits for no bus configuration + +Some device requires a special handling for reg_update_bits and can't use +the normal regmap read write logic. An example is when locking is +handled by the device and rmw operations requires to do atomic operations. +Allow to declare a dedicated function in regmap_config for +reg_update_bits in no bus configuration. + +Signed-off-by: Ansuel Smith +Link: https://lore.kernel.org/r/20211104150040.1260-1-ansuelsmth@gmail.com +Signed-off-by: Mark Brown +--- + drivers/base/regmap/regmap.c | 1 + + include/linux/regmap.h | 7 +++++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -877,6 +877,7 @@ struct regmap *__regmap_init(struct devi + if (!bus) { + map->reg_read = config->reg_read; + map->reg_write = config->reg_write; ++ map->reg_update_bits = config->reg_update_bits; + + map->defer_caching = false; + goto skip_format_initialization; +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -290,6 +290,11 @@ typedef void (*regmap_unlock)(void *); + * read operation on a bus such as SPI, I2C, etc. Most of the + * devices do not need this. + * @reg_write: Same as above for writing. ++ * @reg_update_bits: Optional callback that if filled will be used to perform ++ * all the update_bits(rmw) operation. Should only be provided ++ * if the function require special handling with lock and reg ++ * handling and the operation cannot be represented as a simple ++ * update_bits operation on a bus such as SPI, I2C, etc. + * @fast_io: Register IO is fast. Use a spinlock instead of a mutex + * to perform locking. This field is ignored if custom lock/unlock + * functions are used (see fields lock/unlock of struct regmap_config). +@@ -372,6 +377,8 @@ struct regmap_config { + + int (*reg_read)(void *context, unsigned int reg, unsigned int *val); + int (*reg_write)(void *context, unsigned int reg, unsigned int val); ++ int (*reg_update_bits)(void *context, unsigned int reg, ++ unsigned int mask, unsigned int val); + + bool fast_io; + diff --git a/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch b/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch new file mode 100644 index 00000000000..7de3cbbda07 --- /dev/null +++ b/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch @@ -0,0 +1,37 @@ +From 0dc0da881b4574d1e04a079ab2ea75da61f5ad2e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 11 Mar 2022 10:32:33 +0100 +Subject: [PATCH] tty: serial: bcm63xx: use more precise Kconfig symbol +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Patches lowering SERIAL_BCM63XX dependencies led to a discussion and +documentation change regarding "depends" usage. Adjust Kconfig entry to +match current guidelines. Make this symbol available for relevant +architectures only. + +Cc: Geert Uytterhoeven +Reviewed-by: Geert Uytterhoeven +Acked-by: Florian Fainelli +Signed-off-by: Rafał Miłecki +Ref: f35a07f92616 ("tty: serial: bcm63xx: lower driver dependencies") +Ref: 18084e435ff6 ("Documentation/kbuild: Document platform dependency practises") +Link: https://lore.kernel.org/r/20220311093233.10012-1-zajec5@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/tty/serial/Kconfig | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1098,7 +1098,8 @@ config SERIAL_TIMBERDALE + config SERIAL_BCM63XX + tristate "Broadcom BCM63xx/BCM33xx UART support" + select SERIAL_CORE +- depends on COMMON_CLK ++ depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST ++ default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC + help + This enables the driver for the onchip UART core found on + the following chipsets: diff --git a/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch b/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch new file mode 100644 index 00000000000..caec8db5d69 --- /dev/null +++ b/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch @@ -0,0 +1,49 @@ +From cdbc4e3399ed8cdcf234a85f7a2482b622379e82 Mon Sep 17 00:00:00 2001 +From: Connor O'Brien +Date: Wed, 12 Jan 2022 00:25:03 +0000 +Subject: [PATCH] tools/resolve_btfids: Build with host flags + +resolve_btfids is built using $(HOSTCC) and $(HOSTLD) but does not +pick up the corresponding flags. As a result, host-specific settings +(such as a sysroot specified via HOSTCFLAGS=--sysroot=..., or a linker +specified via HOSTLDFLAGS=-fuse-ld=...) will not be respected. + +Fix this by setting CFLAGS to KBUILD_HOSTCFLAGS and LDFLAGS to +KBUILD_HOSTLDFLAGS. + +Also pass the cflags through to libbpf via EXTRA_CFLAGS to ensure that +the host libbpf is built with flags consistent with resolve_btfids. + +Signed-off-by: Connor O'Brien +Signed-off-by: Andrii Nakryiko +Acked-by: Song Liu +Link: https://lore.kernel.org/bpf/20220112002503.115968-1-connoro@google.com +(cherry picked from commit 0e3a1c902ffb56e9fe4416f0cd382c97b09ecbf6) +Signed-off-by: Stijn Tintel +--- + tools/bpf/resolve_btfids/Makefile | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/tools/bpf/resolve_btfids/Makefile ++++ b/tools/bpf/resolve_btfids/Makefile +@@ -23,6 +23,8 @@ CC = $(HOSTCC) + LD = $(HOSTLD) + ARCH = $(HOSTARCH) + RM ?= rm ++CFLAGS := $(KBUILD_HOSTCFLAGS) ++LDFLAGS := $(KBUILD_HOSTLDFLAGS) + + OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/ + +@@ -45,9 +47,9 @@ $(SUBCMDOBJ): fixdep FORCE | $(OUTPUT)/l + $(Q)$(MAKE) -C $(SUBCMD_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@) + + $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf +- $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@) ++ $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(abspath $(dir $@))/ EXTRA_CFLAGS="$(CFLAGS)" $(abspath $@) + +-CFLAGS := -g \ ++CFLAGS += -g \ + -I$(srctree)/tools/include \ + -I$(srctree)/tools/include/uapi \ + -I$(LIBBPF_SRC) \ diff --git a/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch b/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch new file mode 100644 index 00000000000..d1bef74f327 --- /dev/null +++ b/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch @@ -0,0 +1,997 @@ +From a77725a9a3c5924e2fd4cd5b3557dd92a8e46f87 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Mon, 25 Oct 2021 11:05:45 -0500 +Subject: [PATCH 1/1] scripts/dtc: Update to upstream version + v1.6.1-19-g0a3a9d3449c8 + +This adds the following commits from upstream: + +0a3a9d3449c8 checks: Add an interrupt-map check +8fd24744e361 checks: Ensure '#interrupt-cells' only exists in interrupt providers +d8d1a9a77863 checks: Drop interrupt provider '#address-cells' check +52a16fd72824 checks: Make interrupt_provider check dependent on interrupts_extended_is_cell +37fd700685da treesource: Maintain phandle label/path on output +e33ce1d6a8c7 flattree: Use '\n', not ';' to separate asm pseudo-ops +d24cc189dca6 asm: Use assembler macros instead of cpp macros +ff3a30c115ad asm: Use .asciz and .ascii instead of .string +5eb5927d81ee fdtdump: fix -Werror=int-to-pointer-cast +0869f8269161 libfdt: Add ALIGNMENT error string +69595a167f06 checks: Fix bus-range check +72d09e2682a4 Makefile: add -Wsign-compare to warning options +b587787ef388 checks: Fix signedness comparisons warnings +69bed6c2418f dtc: Wrap phandle validity check +910221185560 fdtget: Fix signedness comparisons warnings +d966f08fcd21 tests: Fix signedness comparisons warnings +ecfb438c07fa dtc: Fix signedness comparisons warnings: pointer diff +5bec74a6d135 dtc: Fix signedness comparisons warnings: reservednum +24e7f511fd4a fdtdump: Fix signedness comparisons warnings +b6910bec1161 Bump version to v1.6.1 +21d61d18f968 Fix CID 1461557 +4c2ef8f4d14c checks: Introduce is_multiple_of() +e59ca36fb70e Make handling of cpp line information more tolerant +0c3fd9b6aceb checks: Drop interrupt_cells_is_cell check +6b3081abc4ac checks: Add check_is_cell() for all phandle+arg properties +2dffc192a77f yamltree: Remove marker ordering dependency +61e513439e40 pylibfdt: Rework "avoid unused variable warning" lines +c8bddd106095 tests: add a positive gpio test case +ad4abfadb687 checks: replace strstr and strrchr with strends +09c6a6e88718 dtc.h: add strends for suffix matching +9bb9b8d0b4a0 checks: tigthen up nr-gpios prop exception +b07b62ee3342 libfdt: Add FDT alignment check to fdt_check_header() +a2def5479950 libfdt: Check that the root-node name is empty +4ca61f84dc21 libfdt: Check that there is only one root node +34d708249a91 dtc: Remove -O dtbo support +8e7ff260f755 libfdt: Fix a possible "unchecked return value" warning +88875268c05c checks: Warn on node-name and property name being the same +9d2279e7e6ee checks: Change node-name check to match devicetree spec +f527c867a8c6 util: limit gnu_printf format attribute to gcc >= 4.4.0 + +Reviewed-by: Frank Rowand +Tested-by: Frank Rowand +Signed-off-by: Rob Herring +--- + scripts/dtc/checks.c | 222 ++++++++++++++++++++++-------- + scripts/dtc/dtc-lexer.l | 2 +- + scripts/dtc/dtc.c | 6 +- + scripts/dtc/dtc.h | 40 +++++- + scripts/dtc/flattree.c | 11 +- + scripts/dtc/libfdt/fdt.c | 4 + + scripts/dtc/libfdt/fdt_rw.c | 18 ++- + scripts/dtc/libfdt/fdt_strerror.c | 1 + + scripts/dtc/libfdt/libfdt.h | 7 + + scripts/dtc/livetree.c | 6 +- + scripts/dtc/treesource.c | 48 +++---- + scripts/dtc/util.h | 6 +- + scripts/dtc/version_gen.h | 2 +- + scripts/dtc/yamltree.c | 16 ++- + 14 files changed, 275 insertions(+), 114 deletions(-) + +--- a/scripts/dtc/checks.c ++++ b/scripts/dtc/checks.c +@@ -143,6 +143,14 @@ static void check_nodes_props(struct che + check_nodes_props(c, dti, child); + } + ++static bool is_multiple_of(int multiple, int divisor) ++{ ++ if (divisor == 0) ++ return multiple == 0; ++ else ++ return (multiple % divisor) == 0; ++} ++ + static bool run_check(struct check *c, struct dt_info *dti) + { + struct node *dt = dti->dt; +@@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_du + #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" + #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + #define DIGITS "0123456789" +-#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" ++#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@" ++#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" + #define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" + + static void check_node_name_chars(struct check *c, struct dt_info *dti, + struct node *node) + { +- int n = strspn(node->name, c->data); ++ size_t n = strspn(node->name, c->data); + + if (n < strlen(node->name)) + FAIL(c, dti, node, "Bad character '%c' in node name", + node->name[n]); + } +-ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); ++ERROR(node_name_chars, check_node_name_chars, NODECHARS); + + static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, + struct node *node) +@@ -330,6 +339,20 @@ static void check_node_name_format(struc + } + ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); + ++static void check_node_name_vs_property_name(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ if (!node->parent) ++ return; ++ ++ if (get_property(node->parent, node->name)) { ++ FAIL(c, dti, node, "node name and property name conflict"); ++ } ++} ++WARNING(node_name_vs_property_name, check_node_name_vs_property_name, ++ NULL, &node_name_chars); ++ + static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, + struct node *node) + { +@@ -363,14 +386,14 @@ static void check_property_name_chars(st + struct property *prop; + + for_each_property(node, prop) { +- int n = strspn(prop->name, c->data); ++ size_t n = strspn(prop->name, c->data); + + if (n < strlen(prop->name)) + FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", + prop->name[n]); + } + } +-ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); ++ERROR(property_name_chars, check_property_name_chars, PROPCHARS); + + static void check_property_name_chars_strict(struct check *c, + struct dt_info *dti, +@@ -380,7 +403,7 @@ static void check_property_name_chars_st + + for_each_property(node, prop) { + const char *name = prop->name; +- int n = strspn(name, c->data); ++ size_t n = strspn(name, c->data); + + if (n == strlen(prop->name)) + continue; +@@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct + + phandle = propval_cell(prop); + +- if ((phandle == 0) || (phandle == -1)) { ++ if (!phandle_is_valid(phandle)) { + FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", + phandle, prop->name); + return 0; +@@ -556,7 +579,7 @@ static void check_name_properties(struct + if (!prop) + return; /* No name property, that's fine */ + +- if ((prop->val.len != node->basenamelen+1) ++ if ((prop->val.len != node->basenamelen + 1U) + || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { + FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" + " of base node name)", prop->val.val); +@@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unus + */ + WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); + WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); +-WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); + + WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); + WARNING_IF_NOT_STRING(model_is_string, "model"); +@@ -672,8 +694,7 @@ static void check_names_is_string_list(s + struct property *prop; + + for_each_property(node, prop) { +- const char *s = strrchr(prop->name, '-'); +- if (!s || !streq(s, "-names")) ++ if (!strends(prop->name, "-names")) + continue; + + c->data = prop->name; +@@ -753,7 +774,7 @@ static void check_reg_format(struct chec + size_cells = node_size_cells(node->parent); + entrylen = (addr_cells + size_cells) * sizeof(cell_t); + +- if (!entrylen || (prop->val.len % entrylen) != 0) ++ if (!is_multiple_of(prop->val.len, entrylen)) + FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " + "(#address-cells == %d, #size-cells == %d)", + prop->val.len, addr_cells, size_cells); +@@ -794,7 +815,7 @@ static void check_ranges_format(struct c + "#size-cells (%d) differs from %s (%d)", + ranges, c_size_cells, node->parent->fullpath, + p_size_cells); +- } else if ((prop->val.len % entrylen) != 0) { ++ } else if (!is_multiple_of(prop->val.len, entrylen)) { + FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " + "(parent #address-cells == %d, child #address-cells == %d, " + "#size-cells == %d)", ranges, prop->val.len, +@@ -871,7 +892,7 @@ static void check_pci_device_bus_num(str + } else { + cells = (cell_t *)prop->val.val; + min_bus = fdt32_to_cpu(cells[0]); +- max_bus = fdt32_to_cpu(cells[0]); ++ max_bus = fdt32_to_cpu(cells[1]); + } + if ((bus_num < min_bus) || (bus_num > max_bus)) + FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", +@@ -1367,9 +1388,9 @@ static void check_property_phandle_args( + const struct provider *provider) + { + struct node *root = dti->dt; +- int cell, cellsize = 0; ++ unsigned int cell, cellsize = 0; + +- if (prop->val.len % sizeof(cell_t)) { ++ if (!is_multiple_of(prop->val.len, sizeof(cell_t))) { + FAIL_PROP(c, dti, node, prop, + "property size (%d) is invalid, expected multiple of %zu", + prop->val.len, sizeof(cell_t)); +@@ -1379,14 +1400,14 @@ static void check_property_phandle_args( + for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { + struct node *provider_node; + struct property *cellprop; +- int phandle; ++ cell_t phandle; + + phandle = propval_cell_n(prop, cell); + /* + * Some bindings use a cell value 0 or -1 to skip over optional + * entries when each index position has a specific definition. + */ +- if (phandle == 0 || phandle == -1) { ++ if (!phandle_is_valid(phandle)) { + /* Give up if this is an overlay with external references */ + if (dti->dtsflags & DTSF_PLUGIN) + break; +@@ -1452,7 +1473,8 @@ static void check_provider_cells_propert + } + #define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ + static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ +- WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); ++ WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \ ++ WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references); + + WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); + WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); +@@ -1473,24 +1495,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_s + + static bool prop_is_gpio(struct property *prop) + { +- char *str; +- + /* + * *-gpios and *-gpio can appear in property names, + * so skip over any false matches (only one known ATM) + */ +- if (strstr(prop->name, "nr-gpio")) ++ if (strends(prop->name, ",nr-gpios")) + return false; + +- str = strrchr(prop->name, '-'); +- if (str) +- str++; +- else +- str = prop->name; +- if (!(streq(str, "gpios") || streq(str, "gpio"))) +- return false; +- +- return true; ++ return strends(prop->name, "-gpios") || ++ streq(prop->name, "gpios") || ++ strends(prop->name, "-gpio") || ++ streq(prop->name, "gpio"); + } + + static void check_gpios_property(struct check *c, +@@ -1525,13 +1540,10 @@ static void check_deprecated_gpio_proper + struct property *prop; + + for_each_property(node, prop) { +- char *str; +- + if (!prop_is_gpio(prop)) + continue; + +- str = strstr(prop->name, "gpio"); +- if (!streq(str, "gpio")) ++ if (!strends(prop->name, "gpio")) + continue; + + FAIL_PROP(c, dti, node, prop, +@@ -1561,21 +1573,106 @@ static void check_interrupt_provider(str + struct node *node) + { + struct property *prop; ++ bool irq_provider = node_is_interrupt_provider(node); + +- if (!node_is_interrupt_provider(node)) ++ prop = get_property(node, "#interrupt-cells"); ++ if (irq_provider && !prop) { ++ FAIL(c, dti, node, ++ "Missing '#interrupt-cells' in interrupt provider"); + return; ++ } + +- prop = get_property(node, "#interrupt-cells"); +- if (!prop) ++ if (!irq_provider && prop) { + FAIL(c, dti, node, +- "Missing #interrupt-cells in interrupt provider"); ++ "'#interrupt-cells' found, but node is not an interrupt provider"); ++ return; ++ } ++} ++WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); + +- prop = get_property(node, "#address-cells"); +- if (!prop) ++static void check_interrupt_map(struct check *c, ++ struct dt_info *dti, ++ struct node *node) ++{ ++ struct node *root = dti->dt; ++ struct property *prop, *irq_map_prop; ++ size_t cellsize, cell, map_cells; ++ ++ irq_map_prop = get_property(node, "interrupt-map"); ++ if (!irq_map_prop) ++ return; ++ ++ if (node->addr_cells < 0) { + FAIL(c, dti, node, +- "Missing #address-cells in interrupt provider"); ++ "Missing '#address-cells' in interrupt-map provider"); ++ return; ++ } ++ cellsize = node_addr_cells(node); ++ cellsize += propval_cell(get_property(node, "#interrupt-cells")); ++ ++ prop = get_property(node, "interrupt-map-mask"); ++ if (prop && (prop->val.len != (cellsize * sizeof(cell_t)))) ++ FAIL_PROP(c, dti, node, prop, ++ "property size (%d) is invalid, expected %zu", ++ prop->val.len, cellsize * sizeof(cell_t)); ++ ++ if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) { ++ FAIL_PROP(c, dti, node, irq_map_prop, ++ "property size (%d) is invalid, expected multiple of %zu", ++ irq_map_prop->val.len, sizeof(cell_t)); ++ return; ++ } ++ ++ map_cells = irq_map_prop->val.len / sizeof(cell_t); ++ for (cell = 0; cell < map_cells; ) { ++ struct node *provider_node; ++ struct property *cellprop; ++ int phandle; ++ size_t parent_cellsize; ++ ++ if ((cell + cellsize) >= map_cells) { ++ FAIL_PROP(c, dti, node, irq_map_prop, ++ "property size (%d) too small, expected > %zu", ++ irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t)); ++ break; ++ } ++ cell += cellsize; ++ ++ phandle = propval_cell_n(irq_map_prop, cell); ++ if (!phandle_is_valid(phandle)) { ++ /* Give up if this is an overlay with external references */ ++ if (!(dti->dtsflags & DTSF_PLUGIN)) ++ FAIL_PROP(c, dti, node, irq_map_prop, ++ "Cell %zu is not a phandle(%d)", ++ cell, phandle); ++ break; ++ } ++ ++ provider_node = get_node_by_phandle(root, phandle); ++ if (!provider_node) { ++ FAIL_PROP(c, dti, node, irq_map_prop, ++ "Could not get phandle(%d) node for (cell %zu)", ++ phandle, cell); ++ break; ++ } ++ ++ cellprop = get_property(provider_node, "#interrupt-cells"); ++ if (cellprop) { ++ parent_cellsize = propval_cell(cellprop); ++ } else { ++ FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])", ++ provider_node->fullpath, cell); ++ break; ++ } ++ ++ cellprop = get_property(provider_node, "#address-cells"); ++ if (cellprop) ++ parent_cellsize += propval_cell(cellprop); ++ ++ cell += 1 + parent_cellsize; ++ } + } +-WARNING(interrupt_provider, check_interrupt_provider, NULL); ++WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); + + static void check_interrupts_property(struct check *c, + struct dt_info *dti, +@@ -1584,13 +1681,13 @@ static void check_interrupts_property(st + struct node *root = dti->dt; + struct node *irq_node = NULL, *parent = node; + struct property *irq_prop, *prop = NULL; +- int irq_cells, phandle; ++ cell_t irq_cells, phandle; + + irq_prop = get_property(node, "interrupts"); + if (!irq_prop) + return; + +- if (irq_prop->val.len % sizeof(cell_t)) ++ if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t))) + FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", + irq_prop->val.len, sizeof(cell_t)); + +@@ -1603,7 +1700,7 @@ static void check_interrupts_property(st + prop = get_property(parent, "interrupt-parent"); + if (prop) { + phandle = propval_cell(prop); +- if ((phandle == 0) || (phandle == -1)) { ++ if (!phandle_is_valid(phandle)) { + /* Give up if this is an overlay with + * external references */ + if (dti->dtsflags & DTSF_PLUGIN) +@@ -1639,7 +1736,7 @@ static void check_interrupts_property(st + } + + irq_cells = propval_cell(prop); +- if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { ++ if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) { + FAIL_PROP(c, dti, node, prop, + "size is (%d), expected multiple of %d", + irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); +@@ -1750,7 +1847,7 @@ WARNING(graph_port, check_graph_port, NU + static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, + struct node *endpoint) + { +- int phandle; ++ cell_t phandle; + struct node *node; + struct property *prop; + +@@ -1760,7 +1857,7 @@ static struct node *get_remote_endpoint( + + phandle = propval_cell(prop); + /* Give up if this is an overlay with external references */ +- if (phandle == 0 || phandle == -1) ++ if (!phandle_is_valid(phandle)) + return NULL; + + node = get_node_by_phandle(dti->dt, phandle); +@@ -1796,7 +1893,7 @@ WARNING(graph_endpoint, check_graph_endp + static struct check *check_table[] = { + &duplicate_node_names, &duplicate_property_names, + &node_name_chars, &node_name_format, &property_name_chars, +- &name_is_string, &name_properties, ++ &name_is_string, &name_properties, &node_name_vs_property_name, + + &duplicate_label, + +@@ -1804,7 +1901,7 @@ static struct check *check_table[] = { + &phandle_references, &path_references, + &omit_unused_nodes, + +- &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, ++ &address_cells_is_cell, &size_cells_is_cell, + &device_type_is_string, &model_is_string, &status_is_string, + &label_is_string, + +@@ -1839,26 +1936,43 @@ static struct check *check_table[] = { + &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, + + &clocks_property, ++ &clocks_is_cell, + &cooling_device_property, ++ &cooling_device_is_cell, + &dmas_property, ++ &dmas_is_cell, + &hwlocks_property, ++ &hwlocks_is_cell, + &interrupts_extended_property, ++ &interrupts_extended_is_cell, + &io_channels_property, ++ &io_channels_is_cell, + &iommus_property, ++ &iommus_is_cell, + &mboxes_property, ++ &mboxes_is_cell, + &msi_parent_property, ++ &msi_parent_is_cell, + &mux_controls_property, ++ &mux_controls_is_cell, + &phys_property, ++ &phys_is_cell, + &power_domains_property, ++ &power_domains_is_cell, + &pwms_property, ++ &pwms_is_cell, + &resets_property, ++ &resets_is_cell, + &sound_dai_property, ++ &sound_dai_is_cell, + &thermal_sensors_property, ++ &thermal_sensors_is_cell, + + &deprecated_gpio_property, + &gpios_property, + &interrupts_property, + &interrupt_provider, ++ &interrupt_map, + + &alias_paths, + +@@ -1882,7 +1996,7 @@ static void enable_warning_error(struct + + static void disable_warning_error(struct check *c, bool warn, bool error) + { +- int i; ++ unsigned int i; + + /* Lowering level, also lower it for things this is the prereq + * for */ +@@ -1903,7 +2017,7 @@ static void disable_warning_error(struct + + void parse_checks_option(bool warn, bool error, const char *arg) + { +- int i; ++ unsigned int i; + const char *name = arg; + bool enable = true; + +@@ -1930,7 +2044,7 @@ void parse_checks_option(bool warn, bool + + void process_checks(bool force, struct dt_info *dti) + { +- int i; ++ unsigned int i; + int error = 0; + + for (i = 0; i < ARRAY_SIZE(check_table); i++) { +--- a/scripts/dtc/dtc-lexer.l ++++ b/scripts/dtc/dtc-lexer.l +@@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(c + push_input_file(name); + } + +-<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { ++<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { + char *line, *fnstart, *fnend; + struct data fn; + /* skip text before line # */ +--- a/scripts/dtc/dtc.c ++++ b/scripts/dtc/dtc.c +@@ -12,7 +12,7 @@ + * Command line options + */ + int quiet; /* Level of quietness */ +-int reservenum; /* Number of memory reservation slots */ ++unsigned int reservenum;/* Number of memory reservation slots */ + int minsize; /* Minimum blob size */ + int padsize; /* Additional padding to blob */ + int alignsize; /* Additional padding to blob accroding to the alignsize */ +@@ -197,7 +197,7 @@ int main(int argc, char *argv[]) + depname = optarg; + break; + case 'R': +- reservenum = strtol(optarg, NULL, 0); ++ reservenum = strtoul(optarg, NULL, 0); + break; + case 'S': + minsize = strtol(optarg, NULL, 0); +@@ -359,8 +359,6 @@ int main(int argc, char *argv[]) + #endif + } else if (streq(outform, "dtb")) { + dt_to_blob(outf, dti, outversion); +- } else if (streq(outform, "dtbo")) { +- dt_to_blob(outf, dti, outversion); + } else if (streq(outform, "asm")) { + dt_to_asm(outf, dti, outversion); + } else if (streq(outform, "null")) { +--- a/scripts/dtc/dtc.h ++++ b/scripts/dtc/dtc.h +@@ -35,7 +35,7 @@ + * Command line options + */ + extern int quiet; /* Level of quietness */ +-extern int reservenum; /* Number of memory reservation slots */ ++extern unsigned int reservenum; /* Number of memory reservation slots */ + extern int minsize; /* Minimum blob size */ + extern int padsize; /* Additional padding to blob */ + extern int alignsize; /* Additional padding to blob accroding to the alignsize */ +@@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts w + + typedef uint32_t cell_t; + ++static inline bool phandle_is_valid(cell_t phandle) ++{ ++ return phandle != 0 && phandle != ~0U; ++} ++ + static inline uint16_t dtb_ld16(const void *p) + { + const uint8_t *bp = (const uint8_t *)p; +@@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const vo + #define streq(a, b) (strcmp((a), (b)) == 0) + #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) + #define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0)) ++static inline bool strends(const char *str, const char *suffix) ++{ ++ unsigned int len, suffix_len; ++ ++ len = strlen(str); ++ suffix_len = strlen(suffix); ++ if (len < suffix_len) ++ return false; ++ return streq(str + len - suffix_len, suffix); ++} + + #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +@@ -101,6 +116,12 @@ enum markertype { + TYPE_UINT64, + TYPE_STRING, + }; ++ ++static inline bool is_type_marker(enum markertype type) ++{ ++ return type >= TYPE_UINT8; ++} ++ + extern const char *markername(enum markertype markertype); + + struct marker { +@@ -125,7 +146,22 @@ struct data { + for_each_marker(m) \ + if ((m)->type == (t)) + +-size_t type_marker_length(struct marker *m); ++static inline struct marker *next_type_marker(struct marker *m) ++{ ++ for_each_marker(m) ++ if (is_type_marker(m->type)) ++ break; ++ return m; ++} ++ ++static inline size_t type_marker_length(struct marker *m) ++{ ++ struct marker *next = next_type_marker(m->next); ++ ++ if (next) ++ return next->offset - m->offset; ++ return 0; ++} + + void data_free(struct data d); + +--- a/scripts/dtc/flattree.c ++++ b/scripts/dtc/flattree.c +@@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_ + { + FILE *f = e; + +- fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", ++ fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n" ++ "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n", + (val >> 24) & 0xff, (val >> 16) & 0xff, + (val >> 8) & 0xff, val & 0xff); + } +@@ -134,9 +135,9 @@ static void asm_emit_string(void *e, con + FILE *f = e; + + if (len != 0) +- fprintf(f, "\t.string\t\"%.*s\"\n", len, str); ++ fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str); + else +- fprintf(f, "\t.string\t\"%s\"\n", str); ++ fprintf(f, "\t.asciz\t\"%s\"\n", str); + } + + static void asm_emit_align(void *e, int a) +@@ -295,7 +296,7 @@ static struct data flatten_reserve_list( + { + struct reserve_info *re; + struct data d = empty_data; +- int j; ++ unsigned int j; + + for (re = reservelist; re; re = re->next) { + d = data_append_re(d, re->address, re->size); +@@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f + + while (p < (strbuf.val + strbuf.len)) { + len = strlen(p); +- fprintf(f, "\t.string \"%s\"\n", p); ++ fprintf(f, "\t.asciz \"%s\"\n", p); + p += len+1; + } + } +--- a/scripts/dtc/libfdt/fdt.c ++++ b/scripts/dtc/libfdt/fdt.c +@@ -90,6 +90,10 @@ int fdt_check_header(const void *fdt) + { + size_t hdrsize; + ++ /* The device tree must be at an 8-byte aligned address */ ++ if ((uintptr_t)fdt & 7) ++ return -FDT_ERR_ALIGNMENT; ++ + if (fdt_magic(fdt) != FDT_MAGIC) + return -FDT_ERR_BADMAGIC; + if (!can_assume(LATEST)) { +--- a/scripts/dtc/libfdt/fdt_rw.c ++++ b/scripts/dtc/libfdt/fdt_rw.c +@@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, i + return offset; + + /* Try to place the new node after the parent's properties */ +- fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ ++ tag = fdt_next_tag(fdt, parentoffset, &nextoffset); ++ /* the fdt_subnode_offset_namelen() should ensure this never hits */ ++ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) ++ return -FDT_ERR_INTERNAL; + do { + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); +@@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffs + } + + static void fdt_packblocks_(const char *old, char *new, +- int mem_rsv_size, int struct_size) ++ int mem_rsv_size, ++ int struct_size, ++ int strings_size) + { + int mem_rsv_off, struct_off, strings_off; + +@@ -406,8 +411,7 @@ static void fdt_packblocks_(const char * + fdt_set_off_dt_struct(new, struct_off); + fdt_set_size_dt_struct(new, struct_size); + +- memmove(new + strings_off, old + fdt_off_dt_strings(old), +- fdt_size_dt_strings(old)); ++ memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); + fdt_set_off_dt_strings(new, strings_off); + fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); + } +@@ -467,7 +471,8 @@ int fdt_open_into(const void *fdt, void + return -FDT_ERR_NOSPACE; + } + +- fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); ++ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, ++ fdt_size_dt_strings(fdt)); + memmove(buf, tmp, newsize); + + fdt_set_magic(buf, FDT_MAGIC); +@@ -487,7 +492,8 @@ int fdt_pack(void *fdt) + + mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) + * sizeof(struct fdt_reserve_entry); +- fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); ++ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), ++ fdt_size_dt_strings(fdt)); + fdt_set_totalsize(fdt, fdt_data_size_(fdt)); + + return 0; +--- a/scripts/dtc/libfdt/fdt_strerror.c ++++ b/scripts/dtc/libfdt/fdt_strerror.c +@@ -39,6 +39,7 @@ static struct fdt_errtabent fdt_errtable + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), + FDT_ERRTABENT(FDT_ERR_BADFLAGS), ++ FDT_ERRTABENT(FDT_ERR_ALIGNMENT), + }; + #define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) + +--- a/scripts/dtc/libfdt/libfdt.h ++++ b/scripts/dtc/libfdt/libfdt.h +@@ -131,6 +131,13 @@ uint32_t fdt_next_tag(const void *fdt, i + * to work even with unaligned pointers on platforms (such as ARMv5) that don't + * like unaligned loads and stores. + */ ++static inline uint16_t fdt16_ld(const fdt16_t *p) ++{ ++ const uint8_t *bp = (const uint8_t *)p; ++ ++ return ((uint16_t)bp[0] << 8) | bp[1]; ++} ++ + static inline uint32_t fdt32_ld(const fdt32_t *p) + { + const uint8_t *bp = (const uint8_t *)p; +--- a/scripts/dtc/livetree.c ++++ b/scripts/dtc/livetree.c +@@ -526,7 +526,7 @@ struct node *get_node_by_path(struct nod + p = strchr(path, '/'); + + for_each_child(tree, child) { +- if (p && strprefixeq(path, p - path, child->name)) ++ if (p && strprefixeq(path, (size_t)(p - path), child->name)) + return get_node_by_path(child, p+1); + else if (!p && streq(path, child->name)) + return child; +@@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct + { + struct node *child, *node; + +- if ((phandle == 0) || (phandle == -1)) { ++ if (!phandle_is_valid(phandle)) { + assert(generate_fixups); + return NULL; + } +@@ -594,7 +594,7 @@ cell_t get_node_phandle(struct node *roo + static cell_t phandle = 1; /* FIXME: ick, static local */ + struct data d = empty_data; + +- if ((node->phandle != 0) && (node->phandle != -1)) ++ if (phandle_is_valid(node->phandle)) + return node->phandle; + + while (get_node_by_phandle(root, phandle)) +--- a/scripts/dtc/treesource.c ++++ b/scripts/dtc/treesource.c +@@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, c + } + } + +-static bool has_data_type_information(struct marker *m) +-{ +- return m->type >= TYPE_UINT8; +-} +- +-static struct marker *next_type_marker(struct marker *m) +-{ +- while (m && !has_data_type_information(m)) +- m = m->next; +- return m; +-} +- +-size_t type_marker_length(struct marker *m) +-{ +- struct marker *next = next_type_marker(m->next); +- +- if (next) +- return next->offset - m->offset; +- return 0; +-} +- + static const char *delim_start[] = { + [TYPE_UINT8] = "[", + [TYPE_UINT16] = "/bits/ 16 <", +@@ -229,26 +208,39 @@ static void write_propval(FILE *f, struc + size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; + size_t data_len = type_marker_length(m) ? : len - m->offset; + const char *p = &prop->val.val[m->offset]; ++ struct marker *m_phandle; + +- if (has_data_type_information(m)) { ++ if (is_type_marker(m->type)) { + emit_type = m->type; + fprintf(f, " %s", delim_start[emit_type]); + } else if (m->type == LABEL) + fprintf(f, " %s:", m->ref); +- else if (m->offset) +- fputc(' ', f); + +- if (emit_type == TYPE_NONE) { +- assert(chunk_len == 0); ++ if (emit_type == TYPE_NONE || chunk_len == 0) + continue; +- } + + switch(emit_type) { + case TYPE_UINT16: + write_propval_int(f, p, chunk_len, 2); + break; + case TYPE_UINT32: +- write_propval_int(f, p, chunk_len, 4); ++ m_phandle = prop->val.markers; ++ for_each_marker_of_type(m_phandle, REF_PHANDLE) ++ if (m->offset == m_phandle->offset) ++ break; ++ ++ if (m_phandle) { ++ if (m_phandle->ref[0] == '/') ++ fprintf(f, "&{%s}", m_phandle->ref); ++ else ++ fprintf(f, "&%s", m_phandle->ref); ++ if (chunk_len > 4) { ++ fputc(' ', f); ++ write_propval_int(f, p + 4, chunk_len - 4, 4); ++ } ++ } else { ++ write_propval_int(f, p, chunk_len, 4); ++ } + break; + case TYPE_UINT64: + write_propval_int(f, p, chunk_len, 8); +--- a/scripts/dtc/util.h ++++ b/scripts/dtc/util.h +@@ -13,10 +13,10 @@ + */ + + #ifdef __GNUC__ +-#ifdef __clang__ +-#define PRINTF(i, j) __attribute__((format (printf, i, j))) +-#else ++#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) + #define PRINTF(i, j) __attribute__((format (gnu_printf, i, j))) ++#else ++#define PRINTF(i, j) __attribute__((format (printf, i, j))) + #endif + #define NORETURN __attribute__((noreturn)) + #else +--- a/scripts/dtc/version_gen.h ++++ b/scripts/dtc/version_gen.h +@@ -1 +1 @@ +-#define DTC_VERSION "DTC 1.6.0-g183df9e9" ++#define DTC_VERSION "DTC 1.6.1-g0a3a9d34" +--- a/scripts/dtc/yamltree.c ++++ b/scripts/dtc/yamltree.c +@@ -29,11 +29,12 @@ char *yaml_error_name[] = { + (emitter)->problem, __func__, __LINE__); \ + }) + +-static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, unsigned int len, int width) ++static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ++ char *data, unsigned int seq_offset, unsigned int len, int width) + { + yaml_event_t event; + void *tag; +- unsigned int off, start_offset = markers->offset; ++ unsigned int off; + + switch(width) { + case 1: tag = "!u8"; break; +@@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitte + m = markers; + is_phandle = false; + for_each_marker_of_type(m, REF_PHANDLE) { +- if (m->offset == (start_offset + off)) { ++ if (m->offset == (seq_offset + off)) { + is_phandle = true; + break; + } +@@ -114,6 +115,7 @@ static void yaml_propval(yaml_emitter_t + yaml_event_t event; + unsigned int len = prop->val.len; + struct marker *m = prop->val.markers; ++ struct marker *markers = prop->val.markers; + + /* Emit the property name */ + yaml_scalar_event_initialize(&event, NULL, +@@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t + + switch(m->type) { + case TYPE_UINT16: +- yaml_propval_int(emitter, m, data, chunk_len, 2); ++ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2); + break; + case TYPE_UINT32: +- yaml_propval_int(emitter, m, data, chunk_len, 4); ++ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4); + break; + case TYPE_UINT64: +- yaml_propval_int(emitter, m, data, chunk_len, 8); ++ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8); + break; + case TYPE_STRING: + yaml_propval_string(emitter, data, chunk_len); + break; + default: +- yaml_propval_int(emitter, m, data, chunk_len, 1); ++ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1); + break; + } + } diff --git a/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch b/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch new file mode 100644 index 00000000000..18a8752a18f --- /dev/null +++ b/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch @@ -0,0 +1,48 @@ +From: Manivannan Sadhasivam +To: linus.walleij@linaro.org +Cc: bjorn.andersson@linaro.org, dianders@chromium.org, + linux-arm-msm@vger.kernel.org, linux-gpio@vger.kernel.org, + linux-kernel@vger.kernel.org, + Manivannan Sadhasivam +Subject: [PATCH] pinctrl: qcom: Return -EINVAL for setting affinity if no IRQ + parent +Date: Thu, 13 Jan 2022 21:56:17 +0530 +Message-Id: <20220113162617.131697-1-manivannan.sadhasivam@linaro.org> + +The MSM GPIO IRQ controller relies on the parent IRQ controller to set the +CPU affinity for the IRQ. And this is only valid if there is any wakeup +parent available and defined in DT. + +For the case of no parent IRQ controller defined in DT, +msm_gpio_irq_set_affinity() and msm_gpio_irq_set_vcpu_affinity() should +return -EINVAL instead of 0 as the affinity can't be set. + +Otherwise, below warning will be printed by genirq: + +genirq: irq_chip msmgpio did not update eff. affinity mask of irq 70 + +Signed-off-by: Manivannan Sadhasivam +--- + drivers/pinctrl/qcom/pinctrl-msm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/pinctrl/qcom/pinctrl-msm.c ++++ b/drivers/pinctrl/qcom/pinctrl-msm.c +@@ -1157,7 +1157,7 @@ static int msm_gpio_irq_set_affinity(str + if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs)) + return irq_chip_set_affinity_parent(d, dest, force); + +- return 0; ++ return -EINVAL; + } + + static int msm_gpio_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info) +@@ -1168,7 +1168,7 @@ static int msm_gpio_irq_set_vcpu_affinit + if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs)) + return irq_chip_set_vcpu_affinity_parent(d, vcpu_info); + +- return 0; ++ return -EINVAL; + } + + static void msm_gpio_irq_handler(struct irq_desc *desc) diff --git a/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch b/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch new file mode 100644 index 00000000000..ee0bf9309ff --- /dev/null +++ b/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch @@ -0,0 +1,166 @@ +From b5af64fceb04dc298c5e69c517b4d83893ff060b Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Thu, 30 Sep 2021 11:21:10 -0700 +Subject: [PATCH 1/1] soc: qcom: smem: Support reserved-memory description + +Practically all modern Qualcomm platforms has a single reserved-memory +region for SMEM. So rather than having to describe SMEM in the form of a +node with a reference to a reserved-memory node, allow the SMEM device +to be instantiated directly from the reserved-memory node. + +The current means of falling back to dereferencing the "memory-region" +is kept as a fallback, if it's determined that the SMEM node is a +reserved-memory node. + +The "qcom,smem" compatible is added to the reserved_mem_matches list, to +allow the reserved-memory device to be probed. + +In order to retain the readability of the code, the resolution of +resources is split from the actual ioremapping. + +Signed-off-by: Bjorn Andersson +Acked-by: Rob Herring +Reviewed-by: Vladimir Zapolskiy +Link: https://lore.kernel.org/r/20210930182111.57353-4-bjorn.andersson@linaro.org +--- + drivers/of/platform.c | 1 + + drivers/soc/qcom/smem.c | 57 ++++++++++++++++++++++++++++------------- + 2 files changed, 40 insertions(+), 18 deletions(-) + +--- a/drivers/of/platform.c ++++ b/drivers/of/platform.c +@@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_po + static const struct of_device_id reserved_mem_matches[] = { + { .compatible = "qcom,rmtfs-mem" }, + { .compatible = "qcom,cmd-db" }, ++ { .compatible = "qcom,smem" }, + { .compatible = "ramoops" }, + { .compatible = "nvmem-rmem" }, + {} +--- a/drivers/soc/qcom/smem.c ++++ b/drivers/soc/qcom/smem.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x + * @size: size of the memory region + */ + struct smem_region { +- u32 aux_base; ++ phys_addr_t aux_base; + void __iomem *virt_base; + size_t size; + }; +@@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct + for (i = 0; i < smem->num_regions; i++) { + region = &smem->regions[i]; + +- if (region->aux_base == aux_base || !aux_base) { ++ if ((u32)region->aux_base == aux_base || !aux_base) { + if (size != NULL) + *size = le32_to_cpu(entry->size); + return region->virt_base + le32_to_cpu(entry->offset); +@@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void + if (p < region->virt_base + region->size) { + u64 offset = p - region->virt_base; + +- return (phys_addr_t)region->aux_base + offset; ++ return region->aux_base + offset; + } + } + +@@ -863,12 +864,12 @@ qcom_smem_enumerate_partitions(struct qc + return 0; + } + +-static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, +- const char *name, int i) ++static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name, ++ struct smem_region *region) + { ++ struct device *dev = smem->dev; + struct device_node *np; + struct resource r; +- resource_size_t size; + int ret; + + np = of_parse_phandle(dev->of_node, name, 0); +@@ -881,13 +882,9 @@ static int qcom_smem_map_memory(struct q + of_node_put(np); + if (ret) + return ret; +- size = resource_size(&r); + +- smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); +- if (!smem->regions[i].virt_base) +- return -ENOMEM; +- smem->regions[i].aux_base = (u32)r.start; +- smem->regions[i].size = size; ++ region->aux_base = r.start; ++ region->size = resource_size(&r); + + return 0; + } +@@ -895,12 +892,14 @@ static int qcom_smem_map_memory(struct q + static int qcom_smem_probe(struct platform_device *pdev) + { + struct smem_header *header; ++ struct reserved_mem *rmem; + struct qcom_smem *smem; + size_t array_size; + int num_regions; + int hwlock_id; + u32 version; + int ret; ++ int i; + + num_regions = 1; + if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) +@@ -914,13 +913,35 @@ static int qcom_smem_probe(struct platfo + smem->dev = &pdev->dev; + smem->num_regions = num_regions; + +- ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); +- if (ret) +- return ret; +- +- if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev, +- "qcom,rpm-msg-ram", 1))) +- return ret; ++ rmem = of_reserved_mem_lookup(pdev->dev.of_node); ++ if (rmem) { ++ smem->regions[0].aux_base = rmem->base; ++ smem->regions[0].size = rmem->size; ++ } else { ++ /* ++ * Fall back to the memory-region reference, if we're not a ++ * reserved-memory node. ++ */ ++ ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]); ++ if (ret) ++ return ret; ++ } ++ ++ if (num_regions > 1) { ++ ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]); ++ if (ret) ++ return ret; ++ } ++ ++ for (i = 0; i < num_regions; i++) { ++ smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev, ++ smem->regions[i].aux_base, ++ smem->regions[i].size); ++ if (!smem->regions[i].virt_base) { ++ dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base); ++ return -ENOMEM; ++ } ++ } + + header = smem->regions[0].virt_base; + if (le32_to_cpu(header->initialized) != 1 || diff --git a/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch b/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch new file mode 100644 index 00000000000..84ae5a7fc73 --- /dev/null +++ b/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch @@ -0,0 +1,33 @@ +From ee1a0696934a8b77a6a2098f92832c46d34ec5da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 27 Oct 2021 14:31:35 +0200 +Subject: [PATCH] watchdog: bcm63xx_wdt: fix fallthrough warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes: +drivers/watchdog/bcm63xx_wdt.c: In function 'bcm63xx_wdt_ioctl': +drivers/watchdog/bcm63xx_wdt.c:208:17: warning: this statement may fall through [-Wimplicit-fallthrough=] + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20211027123135.27458-1-zajec5@gmail.com +Signed-off-by: Guenter Roeck +Signed-off-by: Wim Van Sebroeck +--- + drivers/watchdog/bcm63xx_wdt.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/watchdog/bcm63xx_wdt.c ++++ b/drivers/watchdog/bcm63xx_wdt.c +@@ -207,6 +207,8 @@ static long bcm63xx_wdt_ioctl(struct fil + + bcm63xx_wdt_pet(); + ++ fallthrough; ++ + case WDIOC_GETTIMEOUT: + return put_user(wdt_time, p); + diff --git a/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch b/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch new file mode 100644 index 00000000000..c66a3f11b4b --- /dev/null +++ b/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch @@ -0,0 +1,162 @@ +From 626bfa03729959ea9917181fb3d8ffaa1594d02a Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Wed, 13 Oct 2021 22:40:18 -0700 +Subject: [PATCH 1/1] MIPS: kernel: proc: add CPU option reporting + +Many MIPS CPUs have optional CPU features which are not activated for +all CPU cores. Print the CPU options, which are implemented in the core, +in /proc/cpuinfo. This makes it possible to see which features are +supported and which are not supported. This should cover all standard +MIPS extensions. Before, it only printed information about the main MIPS +ASEs. + +Signed-off-by: Hauke Mehrtens + +Changes from original patch[0]: +- Remove cpu_has_6k_cache and cpu_has_8k_cache due to commit 6ce91ba8589a + ("MIPS: Remove cpu_has_6k_cache and cpu_has_8k_cache in cpu_cache_init()") +- Add new options: mac2008_only, ftlbparex, gsexcex, mmid, mm_sysad, + mm_full +- Use seq_puts instead of seq_printf as suggested by checkpatch +- Minor commit message reword + +[0]: https://lore.kernel.org/linux-mips/20181223225224.23042-1-hauke@hauke-m.de/ + +Signed-off-by: Ilya Lipnitskiy +Acked-by: Hauke Mehrtens +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/kernel/proc.c | 122 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 122 insertions(+) + +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -138,6 +138,128 @@ static int show_cpuinfo(struct seq_file + seq_printf(m, "micromips kernel\t: %s\n", + (read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no"); + } ++ ++ seq_puts(m, "Options implemented\t:"); ++ if (cpu_has_tlb) ++ seq_puts(m, " tlb"); ++ if (cpu_has_ftlb) ++ seq_puts(m, " ftlb"); ++ if (cpu_has_tlbinv) ++ seq_puts(m, " tlbinv"); ++ if (cpu_has_segments) ++ seq_puts(m, " segments"); ++ if (cpu_has_rixiex) ++ seq_puts(m, " rixiex"); ++ if (cpu_has_ldpte) ++ seq_puts(m, " ldpte"); ++ if (cpu_has_maar) ++ seq_puts(m, " maar"); ++ if (cpu_has_rw_llb) ++ seq_puts(m, " rw_llb"); ++ if (cpu_has_4kex) ++ seq_puts(m, " 4kex"); ++ if (cpu_has_3k_cache) ++ seq_puts(m, " 3k_cache"); ++ if (cpu_has_4k_cache) ++ seq_puts(m, " 4k_cache"); ++ if (cpu_has_tx39_cache) ++ seq_puts(m, " tx39_cache"); ++ if (cpu_has_octeon_cache) ++ seq_puts(m, " octeon_cache"); ++ if (cpu_has_fpu) ++ seq_puts(m, " fpu"); ++ if (cpu_has_32fpr) ++ seq_puts(m, " 32fpr"); ++ if (cpu_has_cache_cdex_p) ++ seq_puts(m, " cache_cdex_p"); ++ if (cpu_has_cache_cdex_s) ++ seq_puts(m, " cache_cdex_s"); ++ if (cpu_has_prefetch) ++ seq_puts(m, " prefetch"); ++ if (cpu_has_mcheck) ++ seq_puts(m, " mcheck"); ++ if (cpu_has_ejtag) ++ seq_puts(m, " ejtag"); ++ if (cpu_has_llsc) ++ seq_puts(m, " llsc"); ++ if (cpu_has_guestctl0ext) ++ seq_puts(m, " guestctl0ext"); ++ if (cpu_has_guestctl1) ++ seq_puts(m, " guestctl1"); ++ if (cpu_has_guestctl2) ++ seq_puts(m, " guestctl2"); ++ if (cpu_has_guestid) ++ seq_puts(m, " guestid"); ++ if (cpu_has_drg) ++ seq_puts(m, " drg"); ++ if (cpu_has_rixi) ++ seq_puts(m, " rixi"); ++ if (cpu_has_lpa) ++ seq_puts(m, " lpa"); ++ if (cpu_has_mvh) ++ seq_puts(m, " mvh"); ++ if (cpu_has_vtag_icache) ++ seq_puts(m, " vtag_icache"); ++ if (cpu_has_dc_aliases) ++ seq_puts(m, " dc_aliases"); ++ if (cpu_has_ic_fills_f_dc) ++ seq_puts(m, " ic_fills_f_dc"); ++ if (cpu_has_pindexed_dcache) ++ seq_puts(m, " pindexed_dcache"); ++ if (cpu_has_userlocal) ++ seq_puts(m, " userlocal"); ++ if (cpu_has_nofpuex) ++ seq_puts(m, " nofpuex"); ++ if (cpu_has_vint) ++ seq_puts(m, " vint"); ++ if (cpu_has_veic) ++ seq_puts(m, " veic"); ++ if (cpu_has_inclusive_pcaches) ++ seq_puts(m, " inclusive_pcaches"); ++ if (cpu_has_perf_cntr_intr_bit) ++ seq_puts(m, " perf_cntr_intr_bit"); ++ if (cpu_has_ufr) ++ seq_puts(m, " ufr"); ++ if (cpu_has_fre) ++ seq_puts(m, " fre"); ++ if (cpu_has_cdmm) ++ seq_puts(m, " cdmm"); ++ if (cpu_has_small_pages) ++ seq_puts(m, " small_pages"); ++ if (cpu_has_nan_legacy) ++ seq_puts(m, " nan_legacy"); ++ if (cpu_has_nan_2008) ++ seq_puts(m, " nan_2008"); ++ if (cpu_has_ebase_wg) ++ seq_puts(m, " ebase_wg"); ++ if (cpu_has_badinstr) ++ seq_puts(m, " badinstr"); ++ if (cpu_has_badinstrp) ++ seq_puts(m, " badinstrp"); ++ if (cpu_has_contextconfig) ++ seq_puts(m, " contextconfig"); ++ if (cpu_has_perf) ++ seq_puts(m, " perf"); ++ if (cpu_has_mac2008_only) ++ seq_puts(m, " mac2008_only"); ++ if (cpu_has_ftlbparex) ++ seq_puts(m, " ftlbparex"); ++ if (cpu_has_gsexcex) ++ seq_puts(m, " gsexcex"); ++ if (cpu_has_shared_ftlb_ram) ++ seq_puts(m, " shared_ftlb_ram"); ++ if (cpu_has_shared_ftlb_entries) ++ seq_puts(m, " shared_ftlb_entries"); ++ if (cpu_has_mipsmt_pertccounters) ++ seq_puts(m, " mipsmt_pertccounters"); ++ if (cpu_has_mmid) ++ seq_puts(m, " mmid"); ++ if (cpu_has_mm_sysad) ++ seq_puts(m, " mm_sysad"); ++ if (cpu_has_mm_full) ++ seq_puts(m, " mm_full"); ++ seq_puts(m, "\n"); ++ + seq_printf(m, "shadow register sets\t: %d\n", + cpu_data[n].srsets); + seq_printf(m, "kscratch registers\t: %d\n", diff --git a/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch b/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch new file mode 100644 index 00000000000..6caf7d06d4e --- /dev/null +++ b/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch @@ -0,0 +1,62 @@ +From 1cab5bd69eb1f995ced2d7576cb15f8a8941fd85 Mon Sep 17 00:00:00 2001 +From: Tiezhu Yang +Date: Thu, 25 Nov 2021 19:39:32 +0800 +Subject: [PATCH 1/1] MIPS: Fix using smp_processor_id() in preemptible in + show_cpuinfo() + +There exists the following issue under DEBUG_PREEMPT: + + BUG: using smp_processor_id() in preemptible [00000000] code: systemd/1 + caller is show_cpuinfo+0x460/0xea0 + ... + Call Trace: + [] show_stack+0x94/0x128 + [] dump_stack_lvl+0x94/0xd8 + [] check_preemption_disabled+0x104/0x110 + [] show_cpuinfo+0x460/0xea0 + [] seq_read_iter+0xfc/0x4f8 + [] new_sync_read+0x110/0x1b8 + [] vfs_read+0x1b4/0x1d0 + [] ksys_read+0xd0/0x110 + [] syscall_common+0x34/0x58 + +We can see the following call trace: + show_cpuinfo() + cpu_has_fpu + current_cpu_data + smp_processor_id() + + $ addr2line -f -e vmlinux 0xffffffff802209c8 + show_cpuinfo + arch/mips/kernel/proc.c:188 + + $ head -188 arch/mips/kernel/proc.c | tail -1 + if (cpu_has_fpu) + + arch/mips/include/asm/cpu-features.h + # define cpu_has_fpu (current_cpu_data.options & MIPS_CPU_FPU) + + arch/mips/include/asm/cpu-info.h + #define current_cpu_data cpu_data[smp_processor_id()] + +Based on the above analysis, fix the issue by using raw_cpu_has_fpu +which calls raw_smp_processor_id() in show_cpuinfo(). + +Fixes: 626bfa037299 ("MIPS: kernel: proc: add CPU option reporting") +Signed-off-by: Tiezhu Yang +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/kernel/proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/kernel/proc.c ++++ b/arch/mips/kernel/proc.c +@@ -166,7 +166,7 @@ static int show_cpuinfo(struct seq_file + seq_puts(m, " tx39_cache"); + if (cpu_has_octeon_cache) + seq_puts(m, " octeon_cache"); +- if (cpu_has_fpu) ++ if (raw_cpu_has_fpu) + seq_puts(m, " fpu"); + if (cpu_has_32fpr) + seq_puts(m, " 32fpr"); diff --git a/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch b/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch new file mode 100644 index 00000000000..541d247542b --- /dev/null +++ b/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch @@ -0,0 +1,186 @@ +From f4c5c7f9d2e5ab005d57826b740b694b042a737c Mon Sep 17 00:00:00 2001 +From: Felix Matouschek +Date: Mon, 18 Apr 2022 15:28:03 +0200 +Subject: [PATCH 1/1] mtd: spinand: Add support for XTX XT26G0xA + +Add support for XTX Technology XT26G01AXXXXX, XTX26G02AXXXXX and +XTX26G04AXXXXX SPI NAND. + +These are 3V, 1G/2G/4Gbit serial SLC NAND flash devices with on-die ECC +(8bit strength per 512bytes). + +Tested on Teltonika RUTX10 flashed with OpenWrt. + +Links: + - http://www.xtxtech.com/download/?AId=225 + - https://datasheet.lcsc.com/szlcsc/2005251034_XTX-XT26G01AWSEGA_C558841.pdf +Signed-off-by: Felix Matouschek +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220418132803.664103-1-felix@matouschek.org +--- + drivers/mtd/nand/spi/Makefile | 2 +- + drivers/mtd/nand/spi/core.c | 1 + + drivers/mtd/nand/spi/xtx.c | 129 ++++++++++++++++++++++++++++++++++ + include/linux/mtd/spinand.h | 1 + + 4 files changed, 132 insertions(+), 1 deletion(-) + create mode 100644 drivers/mtd/nand/spi/xtx.c + +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o ++spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -902,6 +902,7 @@ static const struct spinand_manufacturer + ¶gon_spinand_manufacturer, + &toshiba_spinand_manufacturer, + &winbond_spinand_manufacturer, ++ &xtx_spinand_manufacturer, + }; + + static int spinand_manufacturer_match(struct spinand_device *spinand, +--- /dev/null ++++ b/drivers/mtd/nand/spi/xtx.c +@@ -0,0 +1,129 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Author: ++ * Felix Matouschek ++ */ ++ ++#include ++#include ++#include ++ ++#define SPINAND_MFR_XTX 0x0B ++ ++#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2) ++#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2) ++#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4) ++#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4) ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), ++ SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ ++static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section) ++ return -ERANGE; ++ ++ region->offset = 48; ++ region->length = 16; ++ ++ return 0; ++} ++ ++static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section) ++ return -ERANGE; ++ ++ region->offset = 1; ++ region->length = 47; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = { ++ .ecc = xt26g0xa_ooblayout_ecc, ++ .free = xt26g0xa_ooblayout_free, ++}; ++ ++static int xt26g0xa_ecc_get_status(struct spinand_device *spinand, ++ u8 status) ++{ ++ status = status & XT26G0XA_STATUS_ECC_MASK; ++ ++ switch (status) { ++ case XT26G0XA_STATUS_ECC_NO_DETECTED: ++ return 0; ++ case XT26G0XA_STATUS_ECC_8_CORRECTED: ++ return 8; ++ case XT26G0XA_STATUS_ECC_UNCOR_ERROR: ++ return -EBADMSG; ++ default: ++ break; ++ } ++ ++ /* At this point values greater than (2 << 4) are invalid */ ++ if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR) ++ return -EINVAL; ++ ++ /* (1 << 2) through (7 << 2) are 1-7 corrected errors */ ++ return status >> 2; ++} ++ ++static const struct spinand_info xtx_spinand_table[] = { ++ SPINAND_INFO("XT26G01A", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&xt26g0xa_ooblayout, ++ xt26g0xa_ecc_get_status)), ++ SPINAND_INFO("XT26G02A", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2), ++ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&xt26g0xa_ooblayout, ++ xt26g0xa_ecc_get_status)), ++ SPINAND_INFO("XT26G04A", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3), ++ NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&xt26g0xa_ooblayout, ++ xt26g0xa_ecc_get_status)), ++}; ++ ++static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer xtx_spinand_manufacturer = { ++ .id = SPINAND_MFR_XTX, ++ .name = "XTX", ++ .chips = xtx_spinand_table, ++ .nchips = ARRAY_SIZE(xtx_spinand_table), ++ .ops = &xtx_spinand_manuf_ops, ++}; +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -266,6 +266,7 @@ extern const struct spinand_manufacturer + extern const struct spinand_manufacturer paragon_spinand_manufacturer; + extern const struct spinand_manufacturer toshiba_spinand_manufacturer; + extern const struct spinand_manufacturer winbond_spinand_manufacturer; ++extern const struct spinand_manufacturer xtx_spinand_manufacturer; + + /** + * struct spinand_op_variants - SPI NAND operation variants diff --git a/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch b/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch new file mode 100644 index 00000000000..d6c4b4fd1ee --- /dev/null +++ b/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch @@ -0,0 +1,219 @@ +From 4bf18d5a2dd02db8c5b16a2cfae513510506df5b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 3 Feb 2022 22:44:40 +0100 +Subject: [PATCH 1/2] phy: marvell: phy-mvebu-a3700-comphy: Remove port from + driver configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Port number is encoded into argument for SMC call. It is zero for SATA, +PCIe and also both USB 3.0 PHYs. It is non-zero only for Ethernet PHY +(incorrectly called SGMII) on lane 0. Ethernet PHY on lane 1 also uses zero +port number. + +So construct "port" bits for SMC call argument can be constructed directly +from PHY type and lane number. + +Change driver code to always pass zero port number for non-ethernet PHYs +and for ethernet PHYs determinate port number from lane number. This +simplifies the driver. + +As port number from DT PHY configuration is not used anymore, remove whole +driver code which parses it. This also simplifies the driver. + +Signed-off-by: Pali Rohár +Signed-off-by: Marek Behún +Reviewed-by: Miquel Raynal +Link: https://lore.kernel.org/r/20220203214444.1508-2-kabel@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 62 +++++++++----------- + 1 file changed, 29 insertions(+), 33 deletions(-) + +--- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c ++++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +@@ -20,7 +20,6 @@ + #include + + #define MVEBU_A3700_COMPHY_LANES 3 +-#define MVEBU_A3700_COMPHY_PORTS 2 + + /* COMPHY Fast SMC function identifiers */ + #define COMPHY_SIP_POWER_ON 0x82000001 +@@ -45,51 +44,47 @@ + #define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ + ((idx) << 8) | \ + ((speed) << 2)) +-#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \ ++#define COMPHY_FW_PCIE(mode, speed, width) (COMPHY_FW_NET(mode, 0, speed) | \ + ((width) << 18)) + + struct mvebu_a3700_comphy_conf { + unsigned int lane; + enum phy_mode mode; + int submode; +- unsigned int port; + u32 fw_mode; + }; + +-#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \ ++#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _fw) \ + { \ + .lane = _lane, \ + .mode = _mode, \ + .submode = _smode, \ +- .port = _port, \ + .fw_mode = _fw, \ + } + +-#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \ +- MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw) ++#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _fw) \ ++ MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _fw) + +-#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \ +- MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw) ++#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _fw) \ ++ MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _fw) + + static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { + /* lane 0 */ +- MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0, ++ MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, + COMPHY_FW_MODE_USB3H), +- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1, ++ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, + COMPHY_FW_MODE_SGMII), +- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1, ++ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, + COMPHY_FW_MODE_2500BASEX), + /* lane 1 */ +- MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0, +- COMPHY_FW_MODE_PCIE), +- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0, ++ MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), ++ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, + COMPHY_FW_MODE_SGMII), +- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0, ++ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, + COMPHY_FW_MODE_2500BASEX), + /* lane 2 */ +- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0, +- COMPHY_FW_MODE_SATA), +- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0, ++ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), ++ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, + COMPHY_FW_MODE_USB3H), + }; + +@@ -98,7 +93,6 @@ struct mvebu_a3700_comphy_lane { + unsigned int id; + enum phy_mode mode; + int submode; +- int port; + }; + + static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, +@@ -120,7 +114,7 @@ static int mvebu_a3700_comphy_smc(unsign + } + } + +-static int mvebu_a3700_comphy_get_fw_mode(int lane, int port, ++static int mvebu_a3700_comphy_get_fw_mode(int lane, + enum phy_mode mode, + int submode) + { +@@ -132,7 +126,6 @@ static int mvebu_a3700_comphy_get_fw_mod + + for (i = 0; i < n; i++) { + if (mvebu_a3700_comphy_modes[i].lane == lane && +- mvebu_a3700_comphy_modes[i].port == port && + mvebu_a3700_comphy_modes[i].mode == mode && + mvebu_a3700_comphy_modes[i].submode == submode) + break; +@@ -153,7 +146,7 @@ static int mvebu_a3700_comphy_set_mode(s + if (submode == PHY_INTERFACE_MODE_1000BASEX) + submode = PHY_INTERFACE_MODE_SGMII; + +- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode, ++ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, mode, + submode); + if (fw_mode < 0) { + dev_err(lane->dev, "invalid COMPHY mode\n"); +@@ -172,9 +165,10 @@ static int mvebu_a3700_comphy_power_on(s + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + u32 fw_param; + int fw_mode; ++ int fw_port; + int ret; + +- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, ++ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, + lane->mode, lane->submode); + if (fw_mode < 0) { + dev_err(lane->dev, "invalid COMPHY mode\n"); +@@ -191,17 +185,18 @@ static int mvebu_a3700_comphy_power_on(s + fw_param = COMPHY_FW_MODE(fw_mode); + break; + case PHY_MODE_ETHERNET: ++ fw_port = (lane->id == 0) ? 1 : 0; + switch (lane->submode) { + case PHY_INTERFACE_MODE_SGMII: + dev_dbg(lane->dev, "set lane %d to SGMII mode\n", + lane->id); +- fw_param = COMPHY_FW_NET(fw_mode, lane->port, ++ fw_param = COMPHY_FW_NET(fw_mode, fw_port, + COMPHY_FW_SPEED_1_25G); + break; + case PHY_INTERFACE_MODE_2500BASEX: + dev_dbg(lane->dev, "set lane %d to 2500BASEX mode\n", + lane->id); +- fw_param = COMPHY_FW_NET(fw_mode, lane->port, ++ fw_param = COMPHY_FW_NET(fw_mode, fw_port, + COMPHY_FW_SPEED_3_125G); + break; + default: +@@ -212,8 +207,7 @@ static int mvebu_a3700_comphy_power_on(s + break; + case PHY_MODE_PCIE: + dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); +- fw_param = COMPHY_FW_PCIE(fw_mode, lane->port, +- COMPHY_FW_SPEED_5G, ++ fw_param = COMPHY_FW_PCIE(fw_mode, COMPHY_FW_SPEED_5G, + phy->attrs.bus_width); + break; + default: +@@ -247,17 +241,20 @@ static struct phy *mvebu_a3700_comphy_xl + struct of_phandle_args *args) + { + struct mvebu_a3700_comphy_lane *lane; ++ unsigned int port; + struct phy *phy; + +- if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS)) +- return ERR_PTR(-EINVAL); +- + phy = of_phy_simple_xlate(dev, args); + if (IS_ERR(phy)) + return phy; + + lane = phy_get_drvdata(phy); +- lane->port = args->args[0]; ++ ++ port = args->args[0]; ++ if (port != 0 && (port != 1 || lane->id != 0)) { ++ dev_err(lane->dev, "invalid port number %u\n", port); ++ return ERR_PTR(-EINVAL); ++ } + + return phy; + } +@@ -302,7 +299,6 @@ static int mvebu_a3700_comphy_probe(stru + lane->mode = PHY_MODE_INVALID; + lane->submode = PHY_INTERFACE_MODE_NA; + lane->id = lane_id; +- lane->port = -1; + phy_set_drvdata(phy, lane); + } + diff --git a/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch b/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch new file mode 100644 index 00000000000..4593d14bfe6 --- /dev/null +++ b/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch @@ -0,0 +1,1552 @@ +From 934337080c6c59b75db76b180b509f218640ad48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 3 Feb 2022 22:44:41 +0100 +Subject: [PATCH 2/2] phy: marvell: phy-mvebu-a3700-comphy: Add native kernel + implementation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove old RPC implementation and add a new native kernel implementation. + +The old implementation uses ARM SMC API to issue RPC calls to ARM Trusted +Firmware which provides real implementation of PHY configuration. + +But older versions of ARM Trusted Firmware do not provide this PHY +configuration functionality, simply returning: operation not supported; or +worse, some versions provide the configuration functionality incorrectly. + +For example the firmware shipped in ESPRESSObin board has this older +version of ARM Trusted Firmware and therefore SATA, USB 3.0 and PCIe +functionality do not work with newer versions of Linux kernel. + +Due to the above reasons, the following commits were introduced into Linux, +to workaround these issues by ignoring -EOPNOTSUPP error code from +phy-mvebu-a3700-comphy driver function phy_power_on(): + +commit 45aefe3d2251 ("ata: ahci: mvebu: Make SATA PHY optional for Armada +3720") +commit 3241929b67d2 ("usb: host: xhci: mvebu: make USB 3.0 PHY optional for +Armada 3720") +commit b0c6ae0f8948 ("PCI: aardvark: Fix initialization with old Marvell's +Arm Trusted Firmware") + +Replace this RPC implementation with proper native kernel implementation, +which is independent on the firmware. Never return -EOPNOTSUPP for proper +arguments. + +This should solve multiple issues with real-world boards, where it is not +possible or really inconvenient to change the firmware. Let's eliminate +these issues. + +This implementation is ported directly from Armada 3720 comphy driver found +in newest version of ARM Trusted Firmware source code, but with various +fixes of register names, some added comments, some refactoring due to the +original code not conforming to kernel standards. Also PCIe mode poweroff +support was added here, and PHY reset support. These changes are also going +to be sent to ARM Trusted Firmware. + +[ Pali did the porting from ATF. + I (Marek) then fixed some register names, some various other things, + added some comments and refactored the code to kernel standards. Also + fixed PHY poweroff and added PHY reset. ] + +Signed-off-by: Pali Rohár +Acked-by: Miquel Raynal +Signed-off-by: Marek Behún +Link: https://lore.kernel.org/r/20220203214444.1508-3-kabel@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 1332 ++++++++++++++++-- + 1 file changed, 1215 insertions(+), 117 deletions(-) + +--- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c ++++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +@@ -5,12 +5,16 @@ + * Authors: + * Evan Wang + * Miquèl Raynal ++ * Pali Rohár ++ * Marek Behún + * + * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart. +- * SMC call initial support done by Grzegorz Jaszczyk. ++ * Comphy code from ARM Trusted Firmware ported by Pali Rohár ++ * and Marek Behún . + */ + +-#include ++#include ++#include + #include + #include + #include +@@ -18,103 +22,1118 @@ + #include + #include + #include ++#include + +-#define MVEBU_A3700_COMPHY_LANES 3 ++#define PLL_SET_DELAY_US 600 ++#define COMPHY_PLL_SLEEP 1000 ++#define COMPHY_PLL_TIMEOUT 150000 ++ ++/* Comphy lane2 indirect access register offset */ ++#define COMPHY_LANE2_INDIR_ADDR 0x0 ++#define COMPHY_LANE2_INDIR_DATA 0x4 ++ ++/* SATA and USB3 PHY offset compared to SATA PHY */ ++#define COMPHY_LANE2_REGS_BASE 0x200 ++ ++/* ++ * When accessing common PHY lane registers directly, we need to shift by 1, ++ * since the registers are 16-bit. ++ */ ++#define COMPHY_LANE_REG_DIRECT(reg) (((reg) & 0x7FF) << 1) ++ ++/* COMPHY registers */ ++#define COMPHY_POWER_PLL_CTRL 0x01 ++#define PU_IVREF_BIT BIT(15) ++#define PU_PLL_BIT BIT(14) ++#define PU_RX_BIT BIT(13) ++#define PU_TX_BIT BIT(12) ++#define PU_TX_INTP_BIT BIT(11) ++#define PU_DFE_BIT BIT(10) ++#define RESET_DTL_RX_BIT BIT(9) ++#define PLL_LOCK_BIT BIT(8) ++#define REF_FREF_SEL_MASK GENMASK(4, 0) ++#define REF_FREF_SEL_SERDES_25MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x1) ++#define REF_FREF_SEL_SERDES_40MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x3) ++#define REF_FREF_SEL_SERDES_50MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x4) ++#define REF_FREF_SEL_PCIE_USB3_25MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x2) ++#define REF_FREF_SEL_PCIE_USB3_40MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x3) ++#define COMPHY_MODE_MASK GENMASK(7, 5) ++#define COMPHY_MODE_SATA FIELD_PREP(COMPHY_MODE_MASK, 0x0) ++#define COMPHY_MODE_PCIE FIELD_PREP(COMPHY_MODE_MASK, 0x3) ++#define COMPHY_MODE_SERDES FIELD_PREP(COMPHY_MODE_MASK, 0x4) ++#define COMPHY_MODE_USB3 FIELD_PREP(COMPHY_MODE_MASK, 0x5) ++ ++#define COMPHY_KVCO_CAL_CTRL 0x02 ++#define USE_MAX_PLL_RATE_BIT BIT(12) ++#define SPEED_PLL_MASK GENMASK(7, 2) ++#define SPEED_PLL_VALUE_16 FIELD_PREP(SPEED_PLL_MASK, 0x10) ++ ++#define COMPHY_DIG_LOOPBACK_EN 0x23 ++#define SEL_DATA_WIDTH_MASK GENMASK(11, 10) ++#define DATA_WIDTH_10BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x0) ++#define DATA_WIDTH_20BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x1) ++#define DATA_WIDTH_40BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x2) ++#define PLL_READY_TX_BIT BIT(4) ++ ++#define COMPHY_SYNC_PATTERN 0x24 ++#define TXD_INVERT_BIT BIT(10) ++#define RXD_INVERT_BIT BIT(11) ++ ++#define COMPHY_SYNC_MASK_GEN 0x25 ++#define PHY_GEN_MAX_MASK GENMASK(11, 10) ++#define PHY_GEN_MAX_USB3_5G FIELD_PREP(PHY_GEN_MAX_MASK, 0x1) ++ ++#define COMPHY_ISOLATION_CTRL 0x26 ++#define PHY_ISOLATE_MODE BIT(15) ++ ++#define COMPHY_GEN2_SET2 0x3e ++#define GS2_TX_SSC_AMP_MASK GENMASK(15, 9) ++#define GS2_TX_SSC_AMP_4128 FIELD_PREP(GS2_TX_SSC_AMP_MASK, 0x20) ++#define GS2_VREG_RXTX_MAS_ISET_MASK GENMASK(8, 7) ++#define GS2_VREG_RXTX_MAS_ISET_60U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ ++ 0x0) ++#define GS2_VREG_RXTX_MAS_ISET_80U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ ++ 0x1) ++#define GS2_VREG_RXTX_MAS_ISET_100U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ ++ 0x2) ++#define GS2_VREG_RXTX_MAS_ISET_120U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ ++ 0x3) ++#define GS2_RSVD_6_0_MASK GENMASK(6, 0) ++ ++#define COMPHY_GEN3_SET2 0x3f ++ ++#define COMPHY_IDLE_SYNC_EN 0x48 ++#define IDLE_SYNC_EN BIT(12) ++ ++#define COMPHY_MISC_CTRL0 0x4F ++#define CLK100M_125M_EN BIT(4) ++#define TXDCLK_2X_SEL BIT(6) ++#define CLK500M_EN BIT(7) ++#define PHY_REF_CLK_SEL BIT(10) ++ ++#define COMPHY_SFT_RESET 0x52 ++#define SFT_RST BIT(9) ++#define SFT_RST_NO_REG BIT(10) ++ ++#define COMPHY_MISC_CTRL1 0x73 ++#define SEL_BITS_PCIE_FORCE BIT(15) ++ ++#define COMPHY_GEN2_SET3 0x112 ++#define GS3_FFE_CAP_SEL_MASK GENMASK(3, 0) ++#define GS3_FFE_CAP_SEL_VALUE FIELD_PREP(GS3_FFE_CAP_SEL_MASK, 0xF) ++ ++/* PIPE registers */ ++#define COMPHY_PIPE_LANE_CFG0 0x180 ++#define PRD_TXDEEMPH0_MASK BIT(0) ++#define PRD_TXMARGIN_MASK GENMASK(3, 1) ++#define PRD_TXSWING_MASK BIT(4) ++#define CFG_TX_ALIGN_POS_MASK GENMASK(8, 5) ++ ++#define COMPHY_PIPE_LANE_CFG1 0x181 ++#define PRD_TXDEEMPH1_MASK BIT(15) ++#define USE_MAX_PLL_RATE_EN BIT(9) ++#define TX_DET_RX_MODE BIT(6) ++#define GEN2_TX_DATA_DLY_MASK GENMASK(4, 3) ++#define GEN2_TX_DATA_DLY_DEFT FIELD_PREP(GEN2_TX_DATA_DLY_MASK, 2) ++#define TX_ELEC_IDLE_MODE_EN BIT(0) ++ ++#define COMPHY_PIPE_LANE_STAT1 0x183 ++#define TXDCLK_PCLK_EN BIT(0) ++ ++#define COMPHY_PIPE_LANE_CFG4 0x188 ++#define SPREAD_SPECTRUM_CLK_EN BIT(7) ++ ++#define COMPHY_PIPE_RST_CLK_CTRL 0x1C1 ++#define PIPE_SOFT_RESET BIT(0) ++#define PIPE_REG_RESET BIT(1) ++#define MODE_CORE_CLK_FREQ_SEL BIT(9) ++#define MODE_PIPE_WIDTH_32 BIT(3) ++#define MODE_REFDIV_MASK GENMASK(5, 4) ++#define MODE_REFDIV_BY_4 FIELD_PREP(MODE_REFDIV_MASK, 0x2) ++ ++#define COMPHY_PIPE_TEST_MODE_CTRL 0x1C2 ++#define MODE_MARGIN_OVERRIDE BIT(2) ++ ++#define COMPHY_PIPE_CLK_SRC_LO 0x1C3 ++#define MODE_CLK_SRC BIT(0) ++#define BUNDLE_PERIOD_SEL BIT(1) ++#define BUNDLE_PERIOD_SCALE_MASK GENMASK(3, 2) ++#define BUNDLE_SAMPLE_CTRL BIT(4) ++#define PLL_READY_DLY_MASK GENMASK(7, 5) ++#define CFG_SEL_20B BIT(15) ++ ++#define COMPHY_PIPE_PWR_MGM_TIM1 0x1D0 ++#define CFG_PM_OSCCLK_WAIT_MASK GENMASK(15, 12) ++#define CFG_PM_RXDEN_WAIT_MASK GENMASK(11, 8) ++#define CFG_PM_RXDEN_WAIT_1_UNIT FIELD_PREP(CFG_PM_RXDEN_WAIT_MASK, 0x1) ++#define CFG_PM_RXDLOZ_WAIT_MASK GENMASK(7, 0) ++#define CFG_PM_RXDLOZ_WAIT_7_UNIT FIELD_PREP(CFG_PM_RXDLOZ_WAIT_MASK, 0x7) ++#define CFG_PM_RXDLOZ_WAIT_12_UNIT FIELD_PREP(CFG_PM_RXDLOZ_WAIT_MASK, 0xC) ++ ++/* ++ * This register is not from PHY lane register space. It only exists in the ++ * indirect register space, before the actual PHY lane 2 registers. So the ++ * offset is absolute, not relative to COMPHY_LANE2_REGS_BASE. ++ * It is used only for SATA PHY initialization. ++ */ ++#define COMPHY_RESERVED_REG 0x0E ++#define PHYCTRL_FRM_PIN_BIT BIT(13) + +-/* COMPHY Fast SMC function identifiers */ +-#define COMPHY_SIP_POWER_ON 0x82000001 +-#define COMPHY_SIP_POWER_OFF 0x82000002 +-#define COMPHY_SIP_PLL_LOCK 0x82000003 +- +-#define COMPHY_FW_MODE_SATA 0x1 +-#define COMPHY_FW_MODE_SGMII 0x2 +-#define COMPHY_FW_MODE_2500BASEX 0x3 +-#define COMPHY_FW_MODE_USB3H 0x4 +-#define COMPHY_FW_MODE_USB3D 0x5 +-#define COMPHY_FW_MODE_PCIE 0x6 +-#define COMPHY_FW_MODE_USB3 0xa +- +-#define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */ +-#define COMPHY_FW_SPEED_2_5G 1 +-#define COMPHY_FW_SPEED_3_125G 2 /* 2500BASE-X */ +-#define COMPHY_FW_SPEED_5G 3 +-#define COMPHY_FW_SPEED_MAX 0x3F +- +-#define COMPHY_FW_MODE(mode) ((mode) << 12) +-#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ +- ((idx) << 8) | \ +- ((speed) << 2)) +-#define COMPHY_FW_PCIE(mode, speed, width) (COMPHY_FW_NET(mode, 0, speed) | \ +- ((width) << 18)) ++/* South Bridge PHY Configuration Registers */ ++#define COMPHY_PHY_REG(lane, reg) (((1 - (lane)) * 0x28) + ((reg) & 0x3f)) ++ ++/* ++ * lane0: USB3/GbE1 PHY Configuration 1 ++ * lane1: PCIe/GbE0 PHY Configuration 1 ++ * (used only by SGMII code) ++ */ ++#define COMPHY_PHY_CFG1 0x0 ++#define PIN_PU_IVREF_BIT BIT(1) ++#define PIN_RESET_CORE_BIT BIT(11) ++#define PIN_RESET_COMPHY_BIT BIT(12) ++#define PIN_PU_PLL_BIT BIT(16) ++#define PIN_PU_RX_BIT BIT(17) ++#define PIN_PU_TX_BIT BIT(18) ++#define PIN_TX_IDLE_BIT BIT(19) ++#define GEN_RX_SEL_MASK GENMASK(25, 22) ++#define GEN_RX_SEL_VALUE(val) FIELD_PREP(GEN_RX_SEL_MASK, (val)) ++#define GEN_TX_SEL_MASK GENMASK(29, 26) ++#define GEN_TX_SEL_VALUE(val) FIELD_PREP(GEN_TX_SEL_MASK, (val)) ++#define SERDES_SPEED_1_25_G 0x6 ++#define SERDES_SPEED_3_125_G 0x8 ++#define PHY_RX_INIT_BIT BIT(30) ++ ++/* ++ * lane0: USB3/GbE1 PHY Status 1 ++ * lane1: PCIe/GbE0 PHY Status 1 ++ * (used only by SGMII code) ++ */ ++#define COMPHY_PHY_STAT1 0x18 ++#define PHY_RX_INIT_DONE_BIT BIT(0) ++#define PHY_PLL_READY_RX_BIT BIT(2) ++#define PHY_PLL_READY_TX_BIT BIT(3) ++ ++/* PHY Selector */ ++#define COMPHY_SELECTOR_PHY_REG 0xFC ++/* bit0: 0: Lane1 is GbE0; 1: Lane1 is PCIe */ ++#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0) ++/* bit4: 0: Lane0 is GbE1; 1: Lane0 is USB3 */ ++#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4) ++/* bit8: 0: Lane0 is USB3 instead of GbE1, Lane2 is SATA; 1: Lane2 is USB3 */ ++#define COMPHY_SELECTOR_USB3_PHY_SEL_BIT BIT(8) + + struct mvebu_a3700_comphy_conf { + unsigned int lane; + enum phy_mode mode; + int submode; +- u32 fw_mode; + }; + +-#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _fw) \ ++#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode) \ + { \ + .lane = _lane, \ + .mode = _mode, \ + .submode = _smode, \ +- .fw_mode = _fw, \ + } + +-#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _fw) \ +- MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _fw) ++#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode) \ ++ MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA) + +-#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _fw) \ +- MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _fw) ++#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode) \ ++ MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode) + + static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { + /* lane 0 */ +- MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, +- COMPHY_FW_MODE_USB3H), +- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, +- COMPHY_FW_MODE_SGMII), +- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, +- COMPHY_FW_MODE_2500BASEX), ++ MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS), ++ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII), ++ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_1000BASEX), ++ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX), + /* lane 1 */ +- MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), +- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, +- COMPHY_FW_MODE_SGMII), +- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, +- COMPHY_FW_MODE_2500BASEX), ++ MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE), ++ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII), ++ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_1000BASEX), ++ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX), + /* lane 2 */ +- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), +- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, +- COMPHY_FW_MODE_USB3H), ++ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA), ++ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS), ++}; ++ ++struct mvebu_a3700_comphy_priv { ++ void __iomem *comphy_regs; ++ void __iomem *lane0_phy_regs; /* USB3 and GbE1 */ ++ void __iomem *lane1_phy_regs; /* PCIe and GbE0 */ ++ void __iomem *lane2_phy_indirect; /* SATA and USB3 */ ++ spinlock_t lock; /* for PHY selector access */ ++ bool xtal_is_40m; + }; + + struct mvebu_a3700_comphy_lane { ++ struct mvebu_a3700_comphy_priv *priv; + struct device *dev; + unsigned int id; + enum phy_mode mode; + int submode; ++ bool invert_tx; ++ bool invert_rx; ++ bool needs_reset; ++}; ++ ++struct gbe_phy_init_data_fix { ++ u16 addr; ++ u16 value; ++}; ++ ++/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */ ++static struct gbe_phy_init_data_fix gbe_phy_init_fix[] = { ++ { 0x005, 0x07CC }, { 0x015, 0x0000 }, { 0x01B, 0x0000 }, ++ { 0x01D, 0x0000 }, { 0x01E, 0x0000 }, { 0x01F, 0x0000 }, ++ { 0x020, 0x0000 }, { 0x021, 0x0030 }, { 0x026, 0x0888 }, ++ { 0x04D, 0x0152 }, { 0x04F, 0xA020 }, { 0x050, 0x07CC }, ++ { 0x053, 0xE9CA }, { 0x055, 0xBD97 }, { 0x071, 0x3015 }, ++ { 0x076, 0x03AA }, { 0x07C, 0x0FDF }, { 0x0C2, 0x3030 }, ++ { 0x0C3, 0x8000 }, { 0x0E2, 0x5550 }, { 0x0E3, 0x12A4 }, ++ { 0x0E4, 0x7D00 }, { 0x0E6, 0x0C83 }, { 0x101, 0xFCC0 }, ++ { 0x104, 0x0C10 } + }; + +-static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, +- unsigned long mode) ++/* 40M1G25 mode init data */ ++static u16 gbe_phy_init[512] = { ++ /* 0 1 2 3 4 5 6 7 */ ++ /*-----------------------------------------------------------*/ ++ /* 8 9 A B C D E F */ ++ 0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */ ++ 0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */ ++ 0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */ ++ 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */ ++ 0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */ ++ 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */ ++ 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ ++ 0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */ ++ 0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */ ++ 0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */ ++ 0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */ ++ 0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */ ++ 0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */ ++ 0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */ ++ 0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */ ++ 0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */ ++ 0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */ ++ 0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */ ++ 0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */ ++ 0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */ ++ 0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */ ++ 0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */ ++ 0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */ ++ 0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */ ++ 0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */ ++ 0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */ ++ 0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */ ++ 0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */ ++ 0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */ ++ 0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */ ++ 0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */ ++ 0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */ ++ 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */ ++ 0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */ ++ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */ ++}; ++ ++static inline void comphy_reg_set(void __iomem *addr, u32 data, u32 mask) + { +- struct arm_smccc_res res; +- s32 ret; ++ u32 val; ++ ++ val = readl(addr); ++ val = (val & ~mask) | (data & mask); ++ writel(val, addr); ++} + +- arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res); +- ret = res.a0; ++static inline void comphy_reg_set16(void __iomem *addr, u16 data, u16 mask) ++{ ++ u16 val; + +- switch (ret) { +- case SMCCC_RET_SUCCESS: +- return 0; +- case SMCCC_RET_NOT_SUPPORTED: +- return -EOPNOTSUPP; ++ val = readw(addr); ++ val = (val & ~mask) | (data & mask); ++ writew(val, addr); ++} ++ ++/* Used for accessing lane 2 registers (SATA/USB3 PHY) */ ++static void comphy_set_indirect(struct mvebu_a3700_comphy_priv *priv, ++ u32 offset, u16 data, u16 mask) ++{ ++ writel(offset, ++ priv->lane2_phy_indirect + COMPHY_LANE2_INDIR_ADDR); ++ comphy_reg_set(priv->lane2_phy_indirect + COMPHY_LANE2_INDIR_DATA, ++ data, mask); ++} ++ ++static void comphy_lane_reg_set(struct mvebu_a3700_comphy_lane *lane, ++ u16 reg, u16 data, u16 mask) ++{ ++ if (lane->id == 2) { ++ /* lane 2 PHY registers are accessed indirectly */ ++ comphy_set_indirect(lane->priv, ++ reg + COMPHY_LANE2_REGS_BASE, ++ data, mask); ++ } else { ++ void __iomem *base = lane->id == 1 ? ++ lane->priv->lane1_phy_regs : ++ lane->priv->lane0_phy_regs; ++ ++ comphy_reg_set16(base + COMPHY_LANE_REG_DIRECT(reg), ++ data, mask); ++ } ++} ++ ++static int comphy_lane_reg_poll(struct mvebu_a3700_comphy_lane *lane, ++ u16 reg, u16 bits, ++ ulong sleep_us, ulong timeout_us) ++{ ++ int ret; ++ ++ if (lane->id == 2) { ++ u32 data; ++ ++ /* lane 2 PHY registers are accessed indirectly */ ++ writel(reg + COMPHY_LANE2_REGS_BASE, ++ lane->priv->lane2_phy_indirect + ++ COMPHY_LANE2_INDIR_ADDR); ++ ++ ret = readl_poll_timeout(lane->priv->lane2_phy_indirect + ++ COMPHY_LANE2_INDIR_DATA, ++ data, (data & bits) == bits, ++ sleep_us, timeout_us); ++ } else { ++ void __iomem *base = lane->id == 1 ? ++ lane->priv->lane1_phy_regs : ++ lane->priv->lane0_phy_regs; ++ u16 data; ++ ++ ret = readw_poll_timeout(base + COMPHY_LANE_REG_DIRECT(reg), ++ data, (data & bits) == bits, ++ sleep_us, timeout_us); ++ } ++ ++ return ret; ++} ++ ++static void comphy_periph_reg_set(struct mvebu_a3700_comphy_lane *lane, ++ u8 reg, u32 data, u32 mask) ++{ ++ comphy_reg_set(lane->priv->comphy_regs + COMPHY_PHY_REG(lane->id, reg), ++ data, mask); ++} ++ ++static int comphy_periph_reg_poll(struct mvebu_a3700_comphy_lane *lane, ++ u8 reg, u32 bits, ++ ulong sleep_us, ulong timeout_us) ++{ ++ u32 data; ++ ++ return readl_poll_timeout(lane->priv->comphy_regs + ++ COMPHY_PHY_REG(lane->id, reg), ++ data, (data & bits) == bits, ++ sleep_us, timeout_us); ++} ++ ++/* PHY selector configures with corresponding modes */ ++static int ++mvebu_a3700_comphy_set_phy_selector(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 old, new, clr = 0, set = 0; ++ unsigned long flags; ++ ++ switch (lane->mode) { ++ case PHY_MODE_SATA: ++ /* SATA must be in Lane2 */ ++ if (lane->id == 2) ++ clr = COMPHY_SELECTOR_USB3_PHY_SEL_BIT; ++ else ++ goto error; ++ break; ++ ++ case PHY_MODE_ETHERNET: ++ if (lane->id == 0) ++ clr = COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; ++ else if (lane->id == 1) ++ clr = COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; ++ else ++ goto error; ++ break; ++ ++ case PHY_MODE_USB_HOST_SS: ++ if (lane->id == 2) ++ set = COMPHY_SELECTOR_USB3_PHY_SEL_BIT; ++ else if (lane->id == 0) ++ set = COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; ++ else ++ goto error; ++ break; ++ ++ case PHY_MODE_PCIE: ++ /* PCIE must be in Lane1 */ ++ if (lane->id == 1) ++ set = COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; ++ else ++ goto error; ++ break; ++ ++ default: ++ goto error; ++ } ++ ++ spin_lock_irqsave(&lane->priv->lock, flags); ++ ++ old = readl(lane->priv->comphy_regs + COMPHY_SELECTOR_PHY_REG); ++ new = (old & ~clr) | set; ++ writel(new, lane->priv->comphy_regs + COMPHY_SELECTOR_PHY_REG); ++ ++ spin_unlock_irqrestore(&lane->priv->lock, flags); ++ ++ dev_dbg(lane->dev, ++ "COMPHY[%d] mode[%d] changed PHY selector 0x%08x -> 0x%08x\n", ++ lane->id, lane->mode, old, new); ++ ++ return 0; ++error: ++ dev_err(lane->dev, "COMPHY[%d] mode[%d] is invalid\n", lane->id, ++ lane->mode); ++ return -EINVAL; ++} ++ ++static int ++mvebu_a3700_comphy_sata_power_on(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 mask, data, ref_clk; ++ int ret; ++ ++ /* Configure phy selector for SATA */ ++ ret = mvebu_a3700_comphy_set_phy_selector(lane); ++ if (ret) ++ return ret; ++ ++ /* Clear phy isolation mode to make it work in normal mode */ ++ comphy_lane_reg_set(lane, COMPHY_ISOLATION_CTRL, ++ 0x0, PHY_ISOLATE_MODE); ++ ++ /* 0. Check the Polarity invert bits */ ++ data = 0x0; ++ if (lane->invert_tx) ++ data |= TXD_INVERT_BIT; ++ if (lane->invert_rx) ++ data |= RXD_INVERT_BIT; ++ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; ++ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); ++ ++ /* 1. Select 40-bit data width */ ++ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, ++ DATA_WIDTH_40BIT, SEL_DATA_WIDTH_MASK); ++ ++ /* 2. Select reference clock(25M) and PHY mode (SATA) */ ++ if (lane->priv->xtal_is_40m) ++ ref_clk = REF_FREF_SEL_SERDES_40MHZ; ++ else ++ ref_clk = REF_FREF_SEL_SERDES_25MHZ; ++ ++ data = ref_clk | COMPHY_MODE_SATA; ++ mask = REF_FREF_SEL_MASK | COMPHY_MODE_MASK; ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); ++ ++ /* 3. Use maximum PLL rate (no power save) */ ++ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, ++ USE_MAX_PLL_RATE_BIT, USE_MAX_PLL_RATE_BIT); ++ ++ /* 4. Reset reserved bit */ ++ comphy_set_indirect(lane->priv, COMPHY_RESERVED_REG, ++ 0x0, PHYCTRL_FRM_PIN_BIT); ++ ++ /* 5. Set vendor-specific configuration (It is done in sata driver) */ ++ /* XXX: in U-Boot below sequence was executed in this place, in Linux ++ * not. Now it is done only in U-Boot before this comphy ++ * initialization - tests shows that it works ok, but in case of any ++ * future problem it is left for reference. ++ * reg_set(MVEBU_REGS_BASE + 0xe00a0, 0, 0xffffffff); ++ * reg_set(MVEBU_REGS_BASE + 0xe00a4, BIT(6), BIT(6)); ++ */ ++ ++ /* Wait for > 55 us to allow PLL be enabled */ ++ udelay(PLL_SET_DELAY_US); ++ ++ /* Polling status */ ++ ret = comphy_lane_reg_poll(lane, COMPHY_DIG_LOOPBACK_EN, ++ PLL_READY_TX_BIT, COMPHY_PLL_SLEEP, ++ COMPHY_PLL_TIMEOUT); ++ if (ret) ++ dev_err(lane->dev, "Failed to lock SATA PLL\n"); ++ ++ return ret; ++} ++ ++static void comphy_gbe_phy_init(struct mvebu_a3700_comphy_lane *lane, ++ bool is_1gbps) ++{ ++ int addr, fix_idx; ++ u16 val; ++ ++ fix_idx = 0; ++ for (addr = 0; addr < 512; addr++) { ++ /* ++ * All PHY register values are defined in full for 3.125Gbps ++ * SERDES speed. The values required for 1.25 Gbps are almost ++ * the same and only few registers should be "fixed" in ++ * comparison to 3.125 Gbps values. These register values are ++ * stored in "gbe_phy_init_fix" array. ++ */ ++ if (!is_1gbps && gbe_phy_init_fix[fix_idx].addr == addr) { ++ /* Use new value */ ++ val = gbe_phy_init_fix[fix_idx].value; ++ if (fix_idx < ARRAY_SIZE(gbe_phy_init_fix)) ++ fix_idx++; ++ } else { ++ val = gbe_phy_init[addr]; ++ } ++ ++ comphy_lane_reg_set(lane, addr, val, 0xFFFF); ++ } ++} ++ ++static int ++mvebu_a3700_comphy_ethernet_power_on(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 mask, data, speed_sel; ++ int ret; ++ ++ /* Set selector */ ++ ret = mvebu_a3700_comphy_set_phy_selector(lane); ++ if (ret) ++ return ret; ++ ++ /* ++ * 1. Reset PHY by setting PHY input port PIN_RESET=1. ++ * 2. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep ++ * PHY TXP/TXN output to idle state during PHY initialization ++ * 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0. ++ */ ++ data = PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT; ++ mask = data | PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT | ++ PIN_PU_TX_BIT | PHY_RX_INIT_BIT; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++ ++ /* 4. Release reset to the PHY by setting PIN_RESET=0. */ ++ data = 0x0; ++ mask = PIN_RESET_COMPHY_BIT; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++ ++ /* ++ * 5. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide COMPHY ++ * bit rate ++ */ ++ switch (lane->submode) { ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_1000BASEX: ++ /* SGMII 1G, SerDes speed 1.25G */ ++ speed_sel = SERDES_SPEED_1_25_G; ++ break; ++ case PHY_INTERFACE_MODE_2500BASEX: ++ /* 2500Base-X, SerDes speed 3.125G */ ++ speed_sel = SERDES_SPEED_3_125_G; ++ break; + default: ++ /* Other rates are not supported */ ++ dev_err(lane->dev, ++ "unsupported phy speed %d on comphy lane%d\n", ++ lane->submode, lane->id); + return -EINVAL; + } ++ data = GEN_RX_SEL_VALUE(speed_sel) | GEN_TX_SEL_VALUE(speed_sel); ++ mask = GEN_RX_SEL_MASK | GEN_TX_SEL_MASK; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++ ++ /* ++ * 6. Wait 10mS for bandgap and reference clocks to stabilize; then ++ * start SW programming. ++ */ ++ mdelay(10); ++ ++ /* 7. Program COMPHY register PHY_MODE */ ++ data = COMPHY_MODE_SERDES; ++ mask = COMPHY_MODE_MASK; ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); ++ ++ /* ++ * 8. Set COMPHY register REFCLK_SEL to select the correct REFCLK ++ * source ++ */ ++ data = 0x0; ++ mask = PHY_REF_CLK_SEL; ++ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, data, mask); ++ ++ /* ++ * 9. Set correct reference clock frequency in COMPHY register ++ * REF_FREF_SEL. ++ */ ++ if (lane->priv->xtal_is_40m) ++ data = REF_FREF_SEL_SERDES_50MHZ; ++ else ++ data = REF_FREF_SEL_SERDES_25MHZ; ++ ++ mask = REF_FREF_SEL_MASK; ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); ++ ++ /* ++ * 10. Program COMPHY register PHY_GEN_MAX[1:0] ++ * This step is mentioned in the flow received from verification team. ++ * However the PHY_GEN_MAX value is only meaningful for other interfaces ++ * (not SERDES). For instance, it selects SATA speed 1.5/3/6 Gbps or ++ * PCIe speed 2.5/5 Gbps ++ */ ++ ++ /* ++ * 11. Program COMPHY register SEL_BITS to set correct parallel data ++ * bus width ++ */ ++ data = DATA_WIDTH_10BIT; ++ mask = SEL_DATA_WIDTH_MASK; ++ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, data, mask); ++ ++ /* ++ * 12. As long as DFE function needs to be enabled in any mode, ++ * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F ++ * for real chip during COMPHY power on. ++ * The value of the DFE_UPDATE_EN already is 0x3F, because it is the ++ * default value after reset of the PHY. ++ */ ++ ++ /* ++ * 13. Program COMPHY GEN registers. ++ * These registers should be programmed based on the lab testing result ++ * to achieve optimal performance. Please contact the CEA group to get ++ * the related GEN table during real chip bring-up. We only required to ++ * run though the entire registers programming flow defined by ++ * "comphy_gbe_phy_init" when the REF clock is 40 MHz. For REF clock ++ * 25 MHz the default values stored in PHY registers are OK. ++ */ ++ dev_dbg(lane->dev, "Running C-DPI phy init %s mode\n", ++ lane->submode == PHY_INTERFACE_MODE_2500BASEX ? "2G5" : "1G"); ++ if (lane->priv->xtal_is_40m) ++ comphy_gbe_phy_init(lane, ++ lane->submode != PHY_INTERFACE_MODE_2500BASEX); ++ ++ /* ++ * 14. Check the PHY Polarity invert bit ++ */ ++ data = 0x0; ++ if (lane->invert_tx) ++ data |= TXD_INVERT_BIT; ++ if (lane->invert_rx) ++ data |= RXD_INVERT_BIT; ++ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; ++ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); ++ ++ /* ++ * 15. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to ++ * start PHY power up sequence. All the PHY register programming should ++ * be done before PIN_PU_PLL=1. There should be no register programming ++ * for normal PHY operation from this point. ++ */ ++ data = PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; ++ mask = data; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++ ++ /* ++ * 16. Wait for PHY power up sequence to finish by checking output ports ++ * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1. ++ */ ++ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, ++ PHY_PLL_READY_TX_BIT | ++ PHY_PLL_READY_RX_BIT, ++ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); ++ if (ret) { ++ dev_err(lane->dev, "Failed to lock PLL for SERDES PHY %d\n", ++ lane->id); ++ return ret; ++ } ++ ++ /* ++ * 17. Set COMPHY input port PIN_TX_IDLE=0 ++ */ ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, 0x0, PIN_TX_IDLE_BIT); ++ ++ /* ++ * 18. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. To ++ * start RX initialization. PIN_RX_INIT_DONE will be cleared to 0 by the ++ * PHY After RX initialization is done, PIN_RX_INIT_DONE will be set to ++ * 1 by COMPHY Set PIN_RX_INIT=0 after PIN_RX_INIT_DONE= 1. Please ++ * refer to RX initialization part for details. ++ */ ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, ++ PHY_RX_INIT_BIT, PHY_RX_INIT_BIT); ++ ++ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, ++ PHY_PLL_READY_TX_BIT | ++ PHY_PLL_READY_RX_BIT, ++ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); ++ if (ret) { ++ dev_err(lane->dev, "Failed to lock PLL for SERDES PHY %d\n", ++ lane->id); ++ return ret; ++ } ++ ++ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, ++ PHY_RX_INIT_DONE_BIT, ++ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); ++ if (ret) ++ dev_err(lane->dev, "Failed to init RX of SERDES PHY %d\n", ++ lane->id); ++ ++ return ret; + } + +-static int mvebu_a3700_comphy_get_fw_mode(int lane, ++static int ++mvebu_a3700_comphy_usb3_power_on(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 mask, data, cfg, ref_clk; ++ int ret; ++ ++ /* Set phy seclector */ ++ ret = mvebu_a3700_comphy_set_phy_selector(lane); ++ if (ret) ++ return ret; ++ ++ /* ++ * 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The ++ * register belong to UTMI module, so it is set in UTMI phy driver. ++ */ ++ ++ /* ++ * 1. Set PRD_TXDEEMPH (3.5db de-emph) ++ */ ++ data = PRD_TXDEEMPH0_MASK; ++ mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK | ++ CFG_TX_ALIGN_POS_MASK; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG0, data, mask); ++ ++ /* ++ * 2. Set BIT0: enable transmitter in high impedance mode ++ * Set BIT[3:4]: delay 2 clock cycles for HiZ off latency ++ * Set BIT6: Tx detect Rx at HiZ mode ++ * Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db ++ * together with bit 0 of COMPHY_PIPE_LANE_CFG0 register ++ */ ++ data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN; ++ mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK | ++ TX_ELEC_IDLE_MODE_EN; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG1, data, mask); ++ ++ /* ++ * 3. Set Spread Spectrum Clock Enabled ++ */ ++ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG4, ++ SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN); ++ ++ /* ++ * 4. Set Override Margining Controls From the MAC: ++ * Use margining signals from lane configuration ++ */ ++ comphy_lane_reg_set(lane, COMPHY_PIPE_TEST_MODE_CTRL, ++ MODE_MARGIN_OVERRIDE, 0xFFFF); ++ ++ /* ++ * 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles ++ * set Mode Clock Source = PCLK is generated from REFCLK ++ */ ++ data = 0x0; ++ mask = MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE_MASK | ++ BUNDLE_SAMPLE_CTRL | PLL_READY_DLY_MASK; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_CLK_SRC_LO, data, mask); ++ ++ /* ++ * 6. Set G2 Spread Spectrum Clock Amplitude at 4K ++ */ ++ comphy_lane_reg_set(lane, COMPHY_GEN2_SET2, ++ GS2_TX_SSC_AMP_4128, GS2_TX_SSC_AMP_MASK); ++ ++ /* ++ * 7. Unset G3 Spread Spectrum Clock Amplitude ++ * set G3 TX and RX Register Master Current Select ++ */ ++ data = GS2_VREG_RXTX_MAS_ISET_60U; ++ mask = GS2_TX_SSC_AMP_MASK | GS2_VREG_RXTX_MAS_ISET_MASK | ++ GS2_RSVD_6_0_MASK; ++ comphy_lane_reg_set(lane, COMPHY_GEN3_SET2, data, mask); ++ ++ /* ++ * 8. Check crystal jumper setting and program the Power and PLL Control ++ * accordingly Change RX wait ++ */ ++ if (lane->priv->xtal_is_40m) { ++ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ; ++ cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT; ++ } else { ++ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ; ++ cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT; ++ } ++ ++ data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | ++ PU_TX_INTP_BIT | PU_DFE_BIT | COMPHY_MODE_USB3 | ref_clk; ++ mask = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | ++ PU_TX_INTP_BIT | PU_DFE_BIT | PLL_LOCK_BIT | COMPHY_MODE_MASK | ++ REF_FREF_SEL_MASK; ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); ++ ++ data = CFG_PM_RXDEN_WAIT_1_UNIT | cfg; ++ mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | ++ CFG_PM_RXDLOZ_WAIT_MASK; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_PWR_MGM_TIM1, data, mask); ++ ++ /* ++ * 9. Enable idle sync ++ */ ++ comphy_lane_reg_set(lane, COMPHY_IDLE_SYNC_EN, ++ IDLE_SYNC_EN, IDLE_SYNC_EN); ++ ++ /* ++ * 10. Enable the output of 500M clock ++ */ ++ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, CLK500M_EN, CLK500M_EN); ++ ++ /* ++ * 11. Set 20-bit data width ++ */ ++ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, ++ DATA_WIDTH_20BIT, 0xFFFF); ++ ++ /* ++ * 12. Override Speed_PLL value and use MAC PLL ++ */ ++ data = SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT; ++ mask = 0xFFFF; ++ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, data, mask); ++ ++ /* ++ * 13. Check the Polarity invert bit ++ */ ++ data = 0x0; ++ if (lane->invert_tx) ++ data |= TXD_INVERT_BIT; ++ if (lane->invert_rx) ++ data |= RXD_INVERT_BIT; ++ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; ++ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); ++ ++ /* ++ * 14. Set max speed generation to USB3.0 5Gbps ++ */ ++ comphy_lane_reg_set(lane, COMPHY_SYNC_MASK_GEN, ++ PHY_GEN_MAX_USB3_5G, PHY_GEN_MAX_MASK); ++ ++ /* ++ * 15. Set capacitor value for FFE gain peaking to 0xF ++ */ ++ comphy_lane_reg_set(lane, COMPHY_GEN2_SET3, ++ GS3_FFE_CAP_SEL_VALUE, GS3_FFE_CAP_SEL_MASK); ++ ++ /* ++ * 16. Release SW reset ++ */ ++ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4; ++ mask = 0xFFFF; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); ++ ++ /* Wait for > 55 us to allow PCLK be enabled */ ++ udelay(PLL_SET_DELAY_US); ++ ++ ret = comphy_lane_reg_poll(lane, COMPHY_PIPE_LANE_STAT1, TXDCLK_PCLK_EN, ++ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); ++ if (ret) ++ dev_err(lane->dev, "Failed to lock USB3 PLL\n"); ++ ++ return ret; ++} ++ ++static int ++mvebu_a3700_comphy_pcie_power_on(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 mask, data, ref_clk; ++ int ret; ++ ++ /* Configure phy selector for PCIe */ ++ ret = mvebu_a3700_comphy_set_phy_selector(lane); ++ if (ret) ++ return ret; ++ ++ /* 1. Enable max PLL. */ ++ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG1, ++ USE_MAX_PLL_RATE_EN, USE_MAX_PLL_RATE_EN); ++ ++ /* 2. Select 20 bit SERDES interface. */ ++ comphy_lane_reg_set(lane, COMPHY_PIPE_CLK_SRC_LO, ++ CFG_SEL_20B, CFG_SEL_20B); ++ ++ /* 3. Force to use reg setting for PCIe mode */ ++ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL1, ++ SEL_BITS_PCIE_FORCE, SEL_BITS_PCIE_FORCE); ++ ++ /* 4. Change RX wait */ ++ data = CFG_PM_RXDEN_WAIT_1_UNIT | CFG_PM_RXDLOZ_WAIT_12_UNIT; ++ mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | ++ CFG_PM_RXDLOZ_WAIT_MASK; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_PWR_MGM_TIM1, data, mask); ++ ++ /* 5. Enable idle sync */ ++ comphy_lane_reg_set(lane, COMPHY_IDLE_SYNC_EN, ++ IDLE_SYNC_EN, IDLE_SYNC_EN); ++ ++ /* 6. Enable the output of 100M/125M/500M clock */ ++ data = CLK500M_EN | TXDCLK_2X_SEL | CLK100M_125M_EN; ++ mask = data; ++ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, data, mask); ++ ++ /* ++ * 7. Enable TX, PCIE global register, 0xd0074814, it is done in ++ * PCI-E driver ++ */ ++ ++ /* ++ * 8. Check crystal jumper setting and program the Power and PLL ++ * Control accordingly ++ */ ++ ++ if (lane->priv->xtal_is_40m) ++ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ; ++ else ++ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ; ++ ++ data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | ++ PU_TX_INTP_BIT | PU_DFE_BIT | COMPHY_MODE_PCIE | ref_clk; ++ mask = 0xFFFF; ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); ++ ++ /* 9. Override Speed_PLL value and use MAC PLL */ ++ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, ++ SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT, ++ 0xFFFF); ++ ++ /* 10. Check the Polarity invert bit */ ++ data = 0x0; ++ if (lane->invert_tx) ++ data |= TXD_INVERT_BIT; ++ if (lane->invert_rx) ++ data |= RXD_INVERT_BIT; ++ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; ++ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); ++ ++ /* 11. Release SW reset */ ++ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32; ++ mask = data | PIPE_SOFT_RESET | MODE_REFDIV_MASK; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); ++ ++ /* Wait for > 55 us to allow PCLK be enabled */ ++ udelay(PLL_SET_DELAY_US); ++ ++ ret = comphy_lane_reg_poll(lane, COMPHY_PIPE_LANE_STAT1, TXDCLK_PCLK_EN, ++ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); ++ if (ret) ++ dev_err(lane->dev, "Failed to lock PCIE PLL\n"); ++ ++ return ret; ++} ++ ++static void ++mvebu_a3700_comphy_sata_power_off(struct mvebu_a3700_comphy_lane *lane) ++{ ++ /* Set phy isolation mode */ ++ comphy_lane_reg_set(lane, COMPHY_ISOLATION_CTRL, ++ PHY_ISOLATE_MODE, PHY_ISOLATE_MODE); ++ ++ /* Power off PLL, Tx, Rx */ ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, ++ 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); ++} ++ ++static void ++mvebu_a3700_comphy_ethernet_power_off(struct mvebu_a3700_comphy_lane *lane) ++{ ++ u32 mask, data; ++ ++ data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | PIN_PU_IVREF_BIT | ++ PHY_RX_INIT_BIT; ++ mask = data; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++} ++ ++static void ++mvebu_a3700_comphy_pcie_power_off(struct mvebu_a3700_comphy_lane *lane) ++{ ++ /* Power off PLL, Tx, Rx */ ++ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, ++ 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); ++} ++ ++static int mvebu_a3700_comphy_reset(struct phy *phy) ++{ ++ struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); ++ u16 mask, data; ++ ++ dev_dbg(lane->dev, "resetting lane %d\n", lane->id); ++ ++ /* COMPHY reset for internal logic */ ++ comphy_lane_reg_set(lane, COMPHY_SFT_RESET, ++ SFT_RST_NO_REG, SFT_RST_NO_REG); ++ ++ /* COMPHY register reset (cleared automatically) */ ++ comphy_lane_reg_set(lane, COMPHY_SFT_RESET, SFT_RST, SFT_RST); ++ ++ /* PIPE soft and register reset */ ++ data = PIPE_SOFT_RESET | PIPE_REG_RESET; ++ mask = data; ++ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); ++ ++ /* Release PIPE register reset */ ++ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, ++ 0x0, PIPE_REG_RESET); ++ ++ /* Reset SB configuration register (only for lanes 0 and 1) */ ++ if (lane->id == 0 || lane->id == 1) { ++ u32 mask, data; ++ ++ data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | ++ PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; ++ mask = data | PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT; ++ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); ++ } ++ ++ return 0; ++} ++ ++static bool mvebu_a3700_comphy_check_mode(int lane, + enum phy_mode mode, + int submode) + { +@@ -122,7 +1141,7 @@ static int mvebu_a3700_comphy_get_fw_mod + + /* Unused PHY mux value is 0x0 */ + if (mode == PHY_MODE_INVALID) +- return -EINVAL; ++ return false; + + for (i = 0; i < n; i++) { + if (mvebu_a3700_comphy_modes[i].lane == lane && +@@ -132,27 +1151,30 @@ static int mvebu_a3700_comphy_get_fw_mod + } + + if (i == n) +- return -EINVAL; ++ return false; + +- return mvebu_a3700_comphy_modes[i].fw_mode; ++ return true; + } + + static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode, + int submode) + { + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); +- int fw_mode; + +- if (submode == PHY_INTERFACE_MODE_1000BASEX) +- submode = PHY_INTERFACE_MODE_SGMII; +- +- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, mode, +- submode); +- if (fw_mode < 0) { ++ if (!mvebu_a3700_comphy_check_mode(lane->id, mode, submode)) { + dev_err(lane->dev, "invalid COMPHY mode\n"); +- return fw_mode; ++ return -EINVAL; + } + ++ /* Mode cannot be changed while the PHY is powered on */ ++ if (phy->power_count && ++ (lane->mode != mode || lane->submode != submode)) ++ return -EBUSY; ++ ++ /* If changing mode, ensure reset is called */ ++ if (lane->mode != PHY_MODE_INVALID && lane->mode != mode) ++ lane->needs_reset = true; ++ + /* Just remember the mode, ->power_on() will do the real setup */ + lane->mode = mode; + lane->submode = submode; +@@ -163,76 +1185,77 @@ static int mvebu_a3700_comphy_set_mode(s + static int mvebu_a3700_comphy_power_on(struct phy *phy) + { + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); +- u32 fw_param; +- int fw_mode; +- int fw_port; + int ret; + +- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, +- lane->mode, lane->submode); +- if (fw_mode < 0) { ++ if (!mvebu_a3700_comphy_check_mode(lane->id, lane->mode, ++ lane->submode)) { + dev_err(lane->dev, "invalid COMPHY mode\n"); +- return fw_mode; ++ return -EINVAL; ++ } ++ ++ if (lane->needs_reset) { ++ ret = mvebu_a3700_comphy_reset(phy); ++ if (ret) ++ return ret; ++ ++ lane->needs_reset = false; + } + + switch (lane->mode) { + case PHY_MODE_USB_HOST_SS: + dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); +- fw_param = COMPHY_FW_MODE(fw_mode); +- break; ++ return mvebu_a3700_comphy_usb3_power_on(lane); + case PHY_MODE_SATA: + dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id); +- fw_param = COMPHY_FW_MODE(fw_mode); +- break; ++ return mvebu_a3700_comphy_sata_power_on(lane); + case PHY_MODE_ETHERNET: +- fw_port = (lane->id == 0) ? 1 : 0; +- switch (lane->submode) { +- case PHY_INTERFACE_MODE_SGMII: +- dev_dbg(lane->dev, "set lane %d to SGMII mode\n", +- lane->id); +- fw_param = COMPHY_FW_NET(fw_mode, fw_port, +- COMPHY_FW_SPEED_1_25G); +- break; +- case PHY_INTERFACE_MODE_2500BASEX: +- dev_dbg(lane->dev, "set lane %d to 2500BASEX mode\n", +- lane->id); +- fw_param = COMPHY_FW_NET(fw_mode, fw_port, +- COMPHY_FW_SPEED_3_125G); +- break; +- default: +- dev_err(lane->dev, "unsupported PHY submode (%d)\n", +- lane->submode); +- return -ENOTSUPP; +- } +- break; ++ dev_dbg(lane->dev, "set lane %d to Ethernet mode\n", lane->id); ++ return mvebu_a3700_comphy_ethernet_power_on(lane); + case PHY_MODE_PCIE: + dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); +- fw_param = COMPHY_FW_PCIE(fw_mode, COMPHY_FW_SPEED_5G, +- phy->attrs.bus_width); +- break; ++ return mvebu_a3700_comphy_pcie_power_on(lane); + default: + dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode); +- return -ENOTSUPP; ++ return -EOPNOTSUPP; + } +- +- ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param); +- if (ret == -EOPNOTSUPP) +- dev_err(lane->dev, +- "unsupported SMC call, try updating your firmware\n"); +- +- return ret; + } + + static int mvebu_a3700_comphy_power_off(struct phy *phy) + { + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + +- return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0); ++ switch (lane->mode) { ++ case PHY_MODE_USB_HOST_SS: ++ /* ++ * The USB3 MAC sets the USB3 PHY to low state, so we do not ++ * need to power off USB3 PHY again. ++ */ ++ break; ++ ++ case PHY_MODE_SATA: ++ mvebu_a3700_comphy_sata_power_off(lane); ++ break; ++ ++ case PHY_MODE_ETHERNET: ++ mvebu_a3700_comphy_ethernet_power_off(lane); ++ break; ++ ++ case PHY_MODE_PCIE: ++ mvebu_a3700_comphy_pcie_power_off(lane); ++ break; ++ ++ default: ++ dev_err(lane->dev, "invalid COMPHY mode\n"); ++ return -EINVAL; ++ } ++ ++ return 0; + } + + static const struct phy_ops mvebu_a3700_comphy_ops = { + .power_on = mvebu_a3700_comphy_power_on, + .power_off = mvebu_a3700_comphy_power_off, ++ .reset = mvebu_a3700_comphy_reset, + .set_mode = mvebu_a3700_comphy_set_mode, + .owner = THIS_MODULE, + }; +@@ -256,13 +1279,75 @@ static struct phy *mvebu_a3700_comphy_xl + return ERR_PTR(-EINVAL); + } + ++ lane->invert_tx = args->args[1] & BIT(0); ++ lane->invert_rx = args->args[1] & BIT(1); ++ + return phy; + } + + static int mvebu_a3700_comphy_probe(struct platform_device *pdev) + { ++ struct mvebu_a3700_comphy_priv *priv; + struct phy_provider *provider; + struct device_node *child; ++ struct resource *res; ++ struct clk *clk; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ spin_lock_init(&priv->lock); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "comphy"); ++ priv->comphy_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->comphy_regs)) ++ return PTR_ERR(priv->comphy_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "lane1_pcie_gbe"); ++ priv->lane1_phy_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->lane1_phy_regs)) ++ return PTR_ERR(priv->lane1_phy_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "lane0_usb3_gbe"); ++ priv->lane0_phy_regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->lane0_phy_regs)) ++ return PTR_ERR(priv->lane0_phy_regs); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "lane2_sata_usb3"); ++ priv->lane2_phy_indirect = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->lane2_phy_indirect)) ++ return PTR_ERR(priv->lane2_phy_indirect); ++ ++ /* ++ * Driver needs to know if reference xtal clock is 40MHz or 25MHz. ++ * Old DT bindings do not have xtal clk present. So do not fail here ++ * and expects that default 25MHz reference clock is used. ++ */ ++ clk = clk_get(&pdev->dev, "xtal"); ++ if (IS_ERR(clk)) { ++ if (PTR_ERR(clk) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ dev_warn(&pdev->dev, "missing 'xtal' clk (%ld)\n", ++ PTR_ERR(clk)); ++ } else { ++ ret = clk_prepare_enable(clk); ++ if (ret) { ++ dev_warn(&pdev->dev, "enabling xtal clk failed (%d)\n", ++ ret); ++ } else { ++ if (clk_get_rate(clk) == 40000000) ++ priv->xtal_is_40m = true; ++ clk_disable_unprepare(clk); ++ } ++ clk_put(clk); ++ } ++ ++ dev_set_drvdata(&pdev->dev, priv); + + for_each_available_child_of_node(pdev->dev.of_node, child) { + struct mvebu_a3700_comphy_lane *lane; +@@ -277,7 +1362,7 @@ static int mvebu_a3700_comphy_probe(stru + continue; + } + +- if (lane_id >= MVEBU_A3700_COMPHY_LANES) { ++ if (lane_id >= 3) { + dev_err(&pdev->dev, "invalid 'reg' property\n"); + continue; + } +@@ -295,15 +1380,26 @@ static int mvebu_a3700_comphy_probe(stru + return PTR_ERR(phy); + } + ++ lane->priv = priv; + lane->dev = &pdev->dev; + lane->mode = PHY_MODE_INVALID; + lane->submode = PHY_INTERFACE_MODE_NA; + lane->id = lane_id; ++ lane->invert_tx = false; ++ lane->invert_rx = false; + phy_set_drvdata(phy, lane); ++ ++ /* ++ * To avoid relying on the bootloader/firmware configuration, ++ * power off all comphys. ++ */ ++ mvebu_a3700_comphy_reset(phy); ++ lane->needs_reset = false; + } + + provider = devm_of_phy_provider_register(&pdev->dev, + mvebu_a3700_comphy_xlate); ++ + return PTR_ERR_OR_ZERO(provider); + } + +@@ -323,5 +1419,7 @@ static struct platform_driver mvebu_a370 + module_platform_driver(mvebu_a3700_comphy_driver); + + MODULE_AUTHOR("Miquèl Raynal "); ++MODULE_AUTHOR("Pali Rohár "); ++MODULE_AUTHOR("Marek Behún "); + MODULE_DESCRIPTION("Common PHY driver for A3700"); + MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch b/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch new file mode 100644 index 00000000000..03b6a5754d9 --- /dev/null +++ b/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch @@ -0,0 +1,32 @@ +From 73a78b6130d9e13daca22b86ad52f063b9403e03 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Wed, 8 Dec 2021 03:40:35 +0100 +Subject: [PATCH 1/1] arm64: dts: marvell: armada-37xx: Add xtal clock to + comphy node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Kernel driver phy-mvebu-a3700-comphy.c needs to know the rate of the +reference xtal clock. So add missing xtal clock source into comphy device +tree node. If the property is not present, the driver defaults to 25 MHz +xtal rate (which, as far as we know, is used by all the existing boards). + +Signed-off-by: Pali Rohár +Signed-off-by: Marek Behún +Signed-off-by: Gregory CLEMENT +--- + arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi ++++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi +@@ -265,6 +265,8 @@ + "lane2_sata_usb3"; + #address-cells = <1>; + #size-cells = <0>; ++ clocks = <&xtalclk>; ++ clock-names = "xtal"; + + comphy0: phy@0 { + reg = <0>; diff --git a/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch b/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch new file mode 100644 index 00000000000..b254e7c0b3f --- /dev/null +++ b/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch @@ -0,0 +1,64 @@ +From ee995101fde67f85a3cd4c74f4f92fc4592e726b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 3 Feb 2022 22:44:42 +0100 +Subject: [PATCH 1/3] Revert "ata: ahci: mvebu: Make SATA PHY optional for + Armada 3720" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 45aefe3d2251e4e229d7662052739f96ad1d08d9. + +Armada 3720 PHY driver (phy-mvebu-a3700-comphy.c) does not return +-EOPNOTSUPP from phy_power_on() callback anymore. + +So remove AHCI_HFLAG_IGN_NOTSUPP_POWER_ON flag from Armada 3720 plat data. + +AHCI_HFLAG_IGN_NOTSUPP_POWER_ON is not used by any other ahci driver, so +remove this flag completely. + +Signed-off-by: Pali Rohár +Signed-off-by: Marek Behún +Acked-by: Miquel Raynal +Acked-by: Damien Le Moal +Link: https://lore.kernel.org/r/20220203214444.1508-4-kabel@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/ata/ahci.h | 2 -- + drivers/ata/ahci_mvebu.c | 2 +- + drivers/ata/libahci_platform.c | 2 +- + 3 files changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/ata/ahci.h ++++ b/drivers/ata/ahci.h +@@ -240,8 +240,6 @@ enum { + as default lpm_policy */ + AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during + suspend/resume */ +- AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = (1 << 27), /* ignore -EOPNOTSUPP +- from phy_power_on() */ + AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */ + + /* ap->flags bits */ +--- a/drivers/ata/ahci_mvebu.c ++++ b/drivers/ata/ahci_mvebu.c +@@ -227,7 +227,7 @@ static const struct ahci_mvebu_plat_data + + static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = { + .plat_config = ahci_mvebu_armada_3700_config, +- .flags = AHCI_HFLAG_SUSPEND_PHYS | AHCI_HFLAG_IGN_NOTSUPP_POWER_ON, ++ .flags = AHCI_HFLAG_SUSPEND_PHYS, + }; + + static const struct of_device_id ahci_mvebu_of_match[] = { +--- a/drivers/ata/libahci_platform.c ++++ b/drivers/ata/libahci_platform.c +@@ -59,7 +59,7 @@ int ahci_platform_enable_phys(struct ahc + } + + rc = phy_power_on(hpriv->phys[i]); +- if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) { ++ if (rc) { + phy_exit(hpriv->phys[i]); + goto disable_phys; + } diff --git a/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch b/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch new file mode 100644 index 00000000000..1e8afb7bbf5 --- /dev/null +++ b/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch @@ -0,0 +1,166 @@ +From 8e10548f7f4814e530857d2049d6af6bc78add53 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 3 Feb 2022 22:44:43 +0100 +Subject: [PATCH 2/3] Revert "usb: host: xhci: mvebu: make USB 3.0 PHY optional + for Armada 3720" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit 3241929b67d28c83945d3191c6816a3271fd6b85. + +Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return +-EOPNOTSUPP from phy_power_on() callback anymore. + +So remove XHCI_SKIP_PHY_INIT flag from xhci_mvebu_a3700_plat_setup() and +then also whole xhci_mvebu_a3700_plat_setup() function which is there just +to handle -EOPNOTSUPP for XHCI_SKIP_PHY_INIT. + +xhci plat_setup callback is not used by any other xhci plat driver, so +remove this callback completely. + +Signed-off-by: Pali Rohár +Signed-off-by: Marek Behún +Acked-by: Miquel Raynal +Acked-by: Greg Kroah-Hartman +Link: https://lore.kernel.org/r/20220203214444.1508-5-kabel@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/usb/host/xhci-mvebu.c | 42 ----------------------------------- + drivers/usb/host/xhci-mvebu.h | 6 ----- + drivers/usb/host/xhci-plat.c | 20 +---------------- + drivers/usb/host/xhci-plat.h | 1 - + 4 files changed, 1 insertion(+), 68 deletions(-) + +--- a/drivers/usb/host/xhci-mvebu.c ++++ b/drivers/usb/host/xhci-mvebu.c +@@ -8,7 +8,6 @@ + #include + #include + #include +-#include + + #include + #include +@@ -74,47 +73,6 @@ int xhci_mvebu_mbus_init_quirk(struct us + + return 0; + } +- +-int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd) +-{ +- struct xhci_hcd *xhci = hcd_to_xhci(hcd); +- struct device *dev = hcd->self.controller; +- struct phy *phy; +- int ret; +- +- /* Old bindings miss the PHY handle */ +- phy = of_phy_get(dev->of_node, "usb3-phy"); +- if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER) +- return -EPROBE_DEFER; +- else if (IS_ERR(phy)) +- goto phy_out; +- +- ret = phy_init(phy); +- if (ret) +- goto phy_put; +- +- ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS); +- if (ret) +- goto phy_exit; +- +- ret = phy_power_on(phy); +- if (ret == -EOPNOTSUPP) { +- /* Skip initializatin of XHCI PHY when it is unsupported by firmware */ +- dev_warn(dev, "PHY unsupported by firmware\n"); +- xhci->quirks |= XHCI_SKIP_PHY_INIT; +- } +- if (ret) +- goto phy_exit; +- +- phy_power_off(phy); +-phy_exit: +- phy_exit(phy); +-phy_put: +- of_phy_put(phy); +-phy_out: +- +- return 0; +-} + + int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) + { +--- a/drivers/usb/host/xhci-mvebu.h ++++ b/drivers/usb/host/xhci-mvebu.h +@@ -12,18 +12,12 @@ struct usb_hcd; + + #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) + int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); +-int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd); + int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); + #else + static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) + { + return 0; + } +- +-static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd) +-{ +- return 0; +-} + + static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) + { +--- a/drivers/usb/host/xhci-plat.c ++++ b/drivers/usb/host/xhci-plat.c +@@ -44,16 +44,6 @@ static void xhci_priv_plat_start(struct + priv->plat_start(hcd); + } + +-static int xhci_priv_plat_setup(struct usb_hcd *hcd) +-{ +- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); +- +- if (!priv->plat_setup) +- return 0; +- +- return priv->plat_setup(hcd); +-} +- + static int xhci_priv_init_quirk(struct usb_hcd *hcd) + { + struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); +@@ -121,7 +111,6 @@ static const struct xhci_plat_priv xhci_ + }; + + static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { +- .plat_setup = xhci_mvebu_a3700_plat_setup, + .init_quirk = xhci_mvebu_a3700_init_quirk, + }; + +@@ -341,14 +330,7 @@ static int xhci_plat_probe(struct platfo + + hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); + xhci->shared_hcd->tpl_support = hcd->tpl_support; +- +- if (priv) { +- ret = xhci_priv_plat_setup(hcd); +- if (ret) +- goto disable_usb_phy; +- } +- +- if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))) ++ if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) + hcd->skip_phy_initialization = 1; + + if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK)) +--- a/drivers/usb/host/xhci-plat.h ++++ b/drivers/usb/host/xhci-plat.h +@@ -13,7 +13,6 @@ + struct xhci_plat_priv { + const char *firmware_name; + unsigned long long quirks; +- int (*plat_setup)(struct usb_hcd *); + void (*plat_start)(struct usb_hcd *); + int (*init_quirk)(struct usb_hcd *); + int (*suspend_quirk)(struct usb_hcd *); diff --git a/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch b/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch new file mode 100644 index 00000000000..fcfb02d35a1 --- /dev/null +++ b/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch @@ -0,0 +1,39 @@ +From 9a4556dad7bd0a6b8339cb72e169f5c76f2af6f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 3 Feb 2022 22:44:44 +0100 +Subject: [PATCH 3/3] Revert "PCI: aardvark: Fix initialization with old + Marvell's Arm Trusted Firmware" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit b0c6ae0f8948a2be6bf4e8b4bbab9ca1343289b6. + +Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return +-EOPNOTSUPP from phy_power_on() callback anymore. + +So remove dead code which handles -EOPNOTSUPP return value. + +Signed-off-by: Pali Rohár +Signed-off-by: Marek Behún +Acked-by: Miquel Raynal +Acked-by: Lorenzo Pieralisi +Link: https://lore.kernel.org/r/20220203214444.1508-6-kabel@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/pci/controller/pci-aardvark.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/pci/controller/pci-aardvark.c ++++ b/drivers/pci/controller/pci-aardvark.c +@@ -1642,9 +1642,7 @@ static int advk_pcie_enable_phy(struct a + } + + ret = phy_power_on(pcie->phy); +- if (ret == -EOPNOTSUPP) { +- dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n"); +- } else if (ret) { ++ if (ret) { + phy_exit(pcie->phy); + return ret; + } diff --git a/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch b/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch new file mode 100644 index 00000000000..a2c897b7a9a --- /dev/null +++ b/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch @@ -0,0 +1,194 @@ +From 0a6fc70d76bddf98278af2ac000379c82aec8f11 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Mon, 29 Aug 2022 10:30:46 +0200 +Subject: [PATCH] phy: marvell: phy-mvebu-a3700-comphy: Remove broken reset + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reset support for SATA PHY is somehow broken and after calling it, kernel +is not able to detect and initialize SATA disk Samsung SSD 850 EMT0 [1]. + +Reset support was introduced in commit 934337080c6c ("phy: marvell: +phy-mvebu-a3700-comphy: Add native kernel implementation") as part of +complete rewrite of this driver. v1 patch series of that commit [2] did +not contain reset support and was tested that is working fine with +Ethernet, SATA and USB PHYs without issues too. + +So for now remove broken reset support and change implementation of +power_off callback to power off all functions on specified lane (and not +only selected function) because during startup kernel does not know which +function was selected and configured by bootloader. Same logic was used +also in v1 patch series of that commit. + +This change fixes issues with initialization of SATA disk Samsung SSD 850 +and disk is working again, like before mentioned commit. + +Once problem with PHY reset callback is solved its functionality could be +re-introduced. But for now it is unknown why it does not work. + +[1] - https://lore.kernel.org/r/20220531124159.3e4lgn2v462irbtz@shindev/ +[2] - https://lore.kernel.org/r/20211028184242.22105-1-kabel@kernel.org/ + +Reported-by: Shinichiro Kawasaki +Fixes: 934337080c6c ("phy: marvell: phy-mvebu-a3700-comphy: Add native kernel implementation") +Cc: stable@vger.kernel.org # v5.18+ +Signed-off-by: Pali Rohár +Tested-by: Shinichiro Kawasaki +Link: https://lore.kernel.org/r/20220829083046.15082-1-pali@kernel.org +Signed-off-by: Vinod Koul +--- + drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 87 ++++---------------- + 1 file changed, 17 insertions(+), 70 deletions(-) + +--- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c ++++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +@@ -274,7 +274,6 @@ struct mvebu_a3700_comphy_lane { + int submode; + bool invert_tx; + bool invert_rx; +- bool needs_reset; + }; + + struct gbe_phy_init_data_fix { +@@ -1097,40 +1096,12 @@ mvebu_a3700_comphy_pcie_power_off(struct + 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); + } + +-static int mvebu_a3700_comphy_reset(struct phy *phy) ++static void mvebu_a3700_comphy_usb3_power_off(struct mvebu_a3700_comphy_lane *lane) + { +- struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); +- u16 mask, data; +- +- dev_dbg(lane->dev, "resetting lane %d\n", lane->id); +- +- /* COMPHY reset for internal logic */ +- comphy_lane_reg_set(lane, COMPHY_SFT_RESET, +- SFT_RST_NO_REG, SFT_RST_NO_REG); +- +- /* COMPHY register reset (cleared automatically) */ +- comphy_lane_reg_set(lane, COMPHY_SFT_RESET, SFT_RST, SFT_RST); +- +- /* PIPE soft and register reset */ +- data = PIPE_SOFT_RESET | PIPE_REG_RESET; +- mask = data; +- comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); +- +- /* Release PIPE register reset */ +- comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, +- 0x0, PIPE_REG_RESET); +- +- /* Reset SB configuration register (only for lanes 0 and 1) */ +- if (lane->id == 0 || lane->id == 1) { +- u32 mask, data; +- +- data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | +- PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; +- mask = data | PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT; +- comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); +- } +- +- return 0; ++ /* ++ * The USB3 MAC sets the USB3 PHY to low state, so we do not ++ * need to power off USB3 PHY again. ++ */ + } + + static bool mvebu_a3700_comphy_check_mode(int lane, +@@ -1171,10 +1142,6 @@ static int mvebu_a3700_comphy_set_mode(s + (lane->mode != mode || lane->submode != submode)) + return -EBUSY; + +- /* If changing mode, ensure reset is called */ +- if (lane->mode != PHY_MODE_INVALID && lane->mode != mode) +- lane->needs_reset = true; +- + /* Just remember the mode, ->power_on() will do the real setup */ + lane->mode = mode; + lane->submode = submode; +@@ -1185,7 +1152,6 @@ static int mvebu_a3700_comphy_set_mode(s + static int mvebu_a3700_comphy_power_on(struct phy *phy) + { + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); +- int ret; + + if (!mvebu_a3700_comphy_check_mode(lane->id, lane->mode, + lane->submode)) { +@@ -1193,14 +1159,6 @@ static int mvebu_a3700_comphy_power_on(s + return -EINVAL; + } + +- if (lane->needs_reset) { +- ret = mvebu_a3700_comphy_reset(phy); +- if (ret) +- return ret; +- +- lane->needs_reset = false; +- } +- + switch (lane->mode) { + case PHY_MODE_USB_HOST_SS: + dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); +@@ -1224,38 +1182,28 @@ static int mvebu_a3700_comphy_power_off( + { + struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); + +- switch (lane->mode) { +- case PHY_MODE_USB_HOST_SS: +- /* +- * The USB3 MAC sets the USB3 PHY to low state, so we do not +- * need to power off USB3 PHY again. +- */ +- break; +- +- case PHY_MODE_SATA: +- mvebu_a3700_comphy_sata_power_off(lane); +- break; +- +- case PHY_MODE_ETHERNET: ++ switch (lane->id) { ++ case 0: ++ mvebu_a3700_comphy_usb3_power_off(lane); + mvebu_a3700_comphy_ethernet_power_off(lane); +- break; +- +- case PHY_MODE_PCIE: ++ return 0; ++ case 1: + mvebu_a3700_comphy_pcie_power_off(lane); +- break; +- ++ mvebu_a3700_comphy_ethernet_power_off(lane); ++ return 0; ++ case 2: ++ mvebu_a3700_comphy_usb3_power_off(lane); ++ mvebu_a3700_comphy_sata_power_off(lane); ++ return 0; + default: + dev_err(lane->dev, "invalid COMPHY mode\n"); + return -EINVAL; + } +- +- return 0; + } + + static const struct phy_ops mvebu_a3700_comphy_ops = { + .power_on = mvebu_a3700_comphy_power_on, + .power_off = mvebu_a3700_comphy_power_off, +- .reset = mvebu_a3700_comphy_reset, + .set_mode = mvebu_a3700_comphy_set_mode, + .owner = THIS_MODULE, + }; +@@ -1393,8 +1341,7 @@ static int mvebu_a3700_comphy_probe(stru + * To avoid relying on the bootloader/firmware configuration, + * power off all comphys. + */ +- mvebu_a3700_comphy_reset(phy); +- lane->needs_reset = false; ++ mvebu_a3700_comphy_power_off(phy); + } + + provider = devm_of_phy_provider_register(&pdev->dev, diff --git a/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch b/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch new file mode 100644 index 00000000000..99cd89ea002 --- /dev/null +++ b/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch @@ -0,0 +1,90 @@ +From 86fc59ef818beb0e1945d17f8e734898baba7e4e Mon Sep 17 00:00:00 2001 +From: Colin Foster +Date: Sun, 13 Mar 2022 15:45:23 -0700 +Subject: [PATCH 1/2] regmap: add configurable downshift for addresses + +Add an additional reg_downshift to be applied to register addresses before +any register accesses. An example of a device that uses this is a VSC7514 +chip, which require each register address to be downshifted by two if the +access is performed over a SPI bus. + +Signed-off-by: Colin Foster +Link: https://lore.kernel.org/r/20220313224524.399947-2-colin.foster@in-advantage.com +Signed-off-by: Mark Brown +--- + drivers/base/regmap/internal.h | 1 + + drivers/base/regmap/regmap.c | 5 +++++ + include/linux/regmap.h | 3 +++ + 3 files changed, 9 insertions(+) + +--- a/drivers/base/regmap/internal.h ++++ b/drivers/base/regmap/internal.h +@@ -31,6 +31,7 @@ struct regmap_format { + size_t buf_size; + size_t reg_bytes; + size_t pad_bytes; ++ size_t reg_downshift; + size_t val_bytes; + void (*format_write)(struct regmap *map, + unsigned int reg, unsigned int val); +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -823,6 +823,7 @@ struct regmap *__regmap_init(struct devi + + map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); + map->format.pad_bytes = config->pad_bits / 8; ++ map->format.reg_downshift = config->reg_downshift; + map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); + map->format.buf_size = DIV_ROUND_UP(config->reg_bits + + config->val_bits + config->pad_bits, 8); +@@ -1735,6 +1736,7 @@ static int _regmap_raw_write_impl(struct + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, + map->write_flag_mask); +@@ -1905,6 +1907,7 @@ static int _regmap_bus_formatted_write(v + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_write(map, reg, val); + + trace_regmap_hw_write_start(map, reg, 1); +@@ -2346,6 +2349,7 @@ static int _regmap_raw_multi_reg_write(s + unsigned int reg = regs[i].reg; + unsigned int val = regs[i].def; + trace_regmap_hw_write_start(map, reg, 1); ++ reg >>= map->format.reg_downshift; + map->format.format_reg(u8, reg, map->reg_shift); + u8 += reg_bytes + pad_bytes; + map->format.format_val(u8, val, 0); +@@ -2673,6 +2677,7 @@ static int _regmap_raw_read(struct regma + return ret; + } + ++ reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, + map->read_flag_mask); +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -237,6 +237,8 @@ typedef void (*regmap_unlock)(void *); + * @reg_stride: The register address stride. Valid register addresses are a + * multiple of this value. If set to 0, a value of 1 will be + * used. ++ * @reg_downshift: The number of bits to downshift the register before ++ * performing any operations. + * @pad_bits: Number of bits of padding between register and value. + * @val_bits: Number of bits in a register value, mandatory. + * +@@ -360,6 +362,7 @@ struct regmap_config { + + int reg_bits; + int reg_stride; ++ int reg_downshift; + int pad_bits; + int val_bits; + diff --git a/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch b/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch new file mode 100644 index 00000000000..0f32288fcab --- /dev/null +++ b/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch @@ -0,0 +1,95 @@ +From 0074f3f2b1e43d3cedd97e47fb6980db6d2ba79e Mon Sep 17 00:00:00 2001 +From: Colin Foster +Date: Sun, 13 Mar 2022 15:45:24 -0700 +Subject: [PATCH 2/2] regmap: allow a defined reg_base to be added to every + address + +There's an inconsistency that arises when a register set can be accessed +internally via MMIO, or externally via SPI. The VSC7514 chip allows both +modes of operation. When internally accessed, the system utilizes __iomem, +devm_ioremap_resource, and devm_regmap_init_mmio. + +For SPI it isn't possible to utilize memory-mapped IO. To properly operate, +the resource base must be added to the register before every operation. + +Signed-off-by: Colin Foster +Link: https://lore.kernel.org/r/20220313224524.399947-3-colin.foster@in-advantage.com +Signed-off-by: Mark Brown +--- + drivers/base/regmap/internal.h | 1 + + drivers/base/regmap/regmap.c | 6 ++++++ + include/linux/regmap.h | 3 +++ + 3 files changed, 10 insertions(+) + +--- a/drivers/base/regmap/internal.h ++++ b/drivers/base/regmap/internal.h +@@ -63,6 +63,7 @@ struct regmap { + regmap_unlock unlock; + void *lock_arg; /* This is passed to lock/unlock functions */ + gfp_t alloc_flags; ++ unsigned int reg_base; + + struct device *dev; /* Device we do I/O on */ + void *work_buf; /* Scratch buffer used to format I/O */ +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -821,6 +821,8 @@ struct regmap *__regmap_init(struct devi + else + map->alloc_flags = GFP_KERNEL; + ++ map->reg_base = config->reg_base; ++ + map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); + map->format.pad_bytes = config->pad_bits / 8; + map->format.reg_downshift = config->reg_downshift; +@@ -1736,6 +1738,7 @@ static int _regmap_raw_write_impl(struct + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, +@@ -1907,6 +1910,7 @@ static int _regmap_bus_formatted_write(v + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_write(map, reg, val); + +@@ -2349,6 +2353,7 @@ static int _regmap_raw_multi_reg_write(s + unsigned int reg = regs[i].reg; + unsigned int val = regs[i].def; + trace_regmap_hw_write_start(map, reg, 1); ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(u8, reg, map->reg_shift); + u8 += reg_bytes + pad_bytes; +@@ -2677,6 +2682,7 @@ static int _regmap_raw_read(struct regma + return ret; + } + ++ reg += map->reg_base; + reg >>= map->format.reg_downshift; + map->format.format_reg(map->work_buf, reg, map->reg_shift); + regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -239,6 +239,8 @@ typedef void (*regmap_unlock)(void *); + * used. + * @reg_downshift: The number of bits to downshift the register before + * performing any operations. ++ * @reg_base: Value to be added to every register address before performing any ++ * operation. + * @pad_bits: Number of bits of padding between register and value. + * @val_bits: Number of bits in a register value, mandatory. + * +@@ -363,6 +365,7 @@ struct regmap_config { + int reg_bits; + int reg_stride; + int reg_downshift; ++ unsigned int reg_base; + int pad_bits; + int val_bits; + diff --git a/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch b/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch new file mode 100644 index 00000000000..804f68d23c5 --- /dev/null +++ b/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch @@ -0,0 +1,57 @@ +From 697c3892d825fb78f42ec8e53bed065dd728db3e Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 30 Jan 2023 02:04:57 +0000 +Subject: [PATCH] regmap: apply reg_base and reg_downshift for single register + ops + +reg_base and reg_downshift currently don't have any effect if used with +a regmap_bus or regmap_config which only offers single register +operations (ie. reg_read, reg_write and optionally reg_update_bits). + +Fix that and take them into account also for regmap_bus with only +reg_read and read_write operations by applying reg_base and +reg_downshift in _regmap_bus_reg_write, _regmap_bus_reg_read. + +Also apply reg_base and reg_downshift in _regmap_update_bits, but only +in case the operation is carried out with a reg_update_bits call +defined in either regmap_bus or regmap_config. + +Fixes: 0074f3f2b1e43d ("regmap: allow a defined reg_base to be added to every address") +Fixes: 86fc59ef818beb ("regmap: add configurable downshift for addresses") +Signed-off-by: Daniel Golle +Tested-by: Colin Foster +Link: https://lore.kernel.org/r/Y9clyVS3tQEHlUhA@makrotopia.org +Signed-off-by: Mark Brown +--- + drivers/base/regmap/regmap.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -1929,6 +1929,8 @@ static int _regmap_bus_reg_write(void *c + { + struct regmap *map = context; + ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + return map->bus->reg_write(map->bus_context, reg, val); + } + +@@ -2703,6 +2705,8 @@ static int _regmap_bus_reg_read(void *co + { + struct regmap *map = context; + ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + return map->bus->reg_read(map->bus_context, reg, val); + } + +@@ -3078,6 +3082,8 @@ static int _regmap_update_bits(struct re + *change = false; + + if (regmap_volatile(map, reg) && map->reg_update_bits) { ++ reg += map->reg_base; ++ reg >>= map->format.reg_downshift; + ret = map->reg_update_bits(map->bus_context, reg, mask, val); + if (ret == 0 && change) + *change = true; diff --git a/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch b/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch new file mode 100644 index 00000000000..1f3aae13b4d --- /dev/null +++ b/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch @@ -0,0 +1,72 @@ +From bcdf0315a61a29eb753a607d3a85a4032de72d94 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 10 May 2022 15:12:59 +0200 +Subject: [PATCH] mtd: call of_platform_populate() for MTD partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Until this change MTD subsystem supported handling partitions only with +MTD partitions parsers. That's a specific / limited API designed around +partitions. + +Some MTD partitions may however require different handling. They may +contain specific data that needs to be parsed and somehow extracted. For +that purpose MTD subsystem should allow binding of standard platform +drivers. + +An example can be U-Boot (sub)partition with environment variables. +There exist a "u-boot,env" DT binding for MTD (sub)partition that +requires an NVMEM driver. + +Ref: 5db1c2dbc04c ("dt-bindings: nvmem: add U-Boot environment variables binding") +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220510131259.555-1-zajec5@gmail.com +--- + drivers/mtd/mtdpart.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + + #include "mtdcore.h" + +@@ -577,10 +578,16 @@ static int mtd_part_of_parse(struct mtd_ + struct mtd_part_parser *parser; + struct device_node *np; + struct property *prop; ++ struct device *dev; + const char *compat; + const char *fixed = "fixed-partitions"; + int ret, err = 0; + ++ dev = &master->dev; ++ /* Use parent device (controller) if the top level MTD is not registered */ ++ if (!IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) && !mtd_is_partition(master)) ++ dev = master->dev.parent; ++ + np = mtd_get_of_node(master); + if (mtd_is_partition(master)) + of_node_get(np); +@@ -593,6 +600,7 @@ static int mtd_part_of_parse(struct mtd_ + continue; + ret = mtd_part_do_parse(parser, master, pparts, NULL); + if (ret > 0) { ++ of_platform_populate(np, NULL, NULL, dev); + of_node_put(np); + return ret; + } +@@ -600,6 +608,7 @@ static int mtd_part_of_parse(struct mtd_ + if (ret < 0 && !err) + err = ret; + } ++ of_platform_populate(np, NULL, NULL, dev); + of_node_put(np); + + /* diff --git a/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch b/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch new file mode 100644 index 00000000000..113a96ad42e --- /dev/null +++ b/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch @@ -0,0 +1,302 @@ +From 9b78ef0c7997052e9eaa0f7a4513d546fa17358c Mon Sep 17 00:00:00 2001 +From: Mikhail Zhilkin +Date: Sun, 29 May 2022 11:07:14 +0000 +Subject: [PATCH] mtd: parsers: add support for Sercomm partitions + +This adds an MTD partition parser for the Sercomm partition table that +is used in some Beeline, Netgear and Sercomm routers. + +The Sercomm partition map table contains real partition offsets, which +may differ from device to device depending on the number and location of +bad blocks on NAND. + +Original patch (proposed by NOGUCHI Hiroshi): +Link: https://github.com/openwrt/openwrt/pull/1318#issuecomment-420607394 + +Signed-off-by: NOGUCHI Hiroshi +Signed-off-by: Mikhail Zhilkin +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220529110714.189732-1-csharper2005@gmail.com +--- + drivers/mtd/parsers/Kconfig | 9 ++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/scpart.c | 248 +++++++++++++++++++++++++++++++++++ + 3 files changed, 258 insertions(+) + create mode 100644 drivers/mtd/parsers/scpart.c + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -186,3 +186,12 @@ config MTD_QCOMSMEM_PARTS + help + This provides support for parsing partitions from Shared Memory (SMEM) + for NAND and SPI flash on Qualcomm platforms. ++ ++config MTD_SERCOMM_PARTS ++ tristate "Sercomm partition table parser" ++ depends on MTD && RALINK ++ help ++ This provides partitions table parser for devices with Sercomm ++ partition map. This partition table contains real partition ++ offsets, which may differ from device to device depending on the ++ number and location of bad blocks on NAND. +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS) + obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o ++obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o +--- /dev/null ++++ b/drivers/mtd/parsers/scpart.c +@@ -0,0 +1,248 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * drivers/mtd/scpart.c: Sercomm Partition Parser ++ * ++ * Copyright (C) 2018 NOGUCHI Hiroshi ++ * Copyright (C) 2022 Mikhail Zhilkin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define MOD_NAME "scpart" ++ ++#ifdef pr_fmt ++#undef pr_fmt ++#endif ++ ++#define pr_fmt(fmt) MOD_NAME ": " fmt ++ ++#define ID_ALREADY_FOUND 0xffffffffUL ++ ++#define MAP_OFFS_IN_BLK 0x800 ++#define MAP_MIRROR_NUM 2 ++ ++static const char sc_part_magic[] = { ++ 'S', 'C', 'F', 'L', 'M', 'A', 'P', 'O', 'K', '\0', ++}; ++#define PART_MAGIC_LEN sizeof(sc_part_magic) ++ ++/* assumes that all fields are set by CPU native endian */ ++struct sc_part_desc { ++ uint32_t part_id; ++ uint32_t part_offs; ++ uint32_t part_bytes; ++}; ++ ++static uint32_t scpart_desc_is_valid(struct sc_part_desc *pdesc) ++{ ++ return ((pdesc->part_id != 0xffffffffUL) && ++ (pdesc->part_offs != 0xffffffffUL) && ++ (pdesc->part_bytes != 0xffffffffUL)); ++} ++ ++static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs, ++ struct sc_part_desc **ppdesc) ++{ ++ int cnt = 0; ++ int res = 0; ++ int res2; ++ loff_t offs; ++ size_t retlen; ++ struct sc_part_desc *pdesc = NULL; ++ struct sc_part_desc *tmpdesc; ++ uint8_t *buf; ++ ++ buf = kzalloc(master->erasesize, GFP_KERNEL); ++ if (!buf) { ++ res = -ENOMEM; ++ goto out; ++ } ++ ++ res2 = mtd_read(master, partmap_offs, master->erasesize, &retlen, buf); ++ if (res2 || retlen != master->erasesize) { ++ res = -EIO; ++ goto free; ++ } ++ ++ for (offs = MAP_OFFS_IN_BLK; ++ offs < master->erasesize - sizeof(*tmpdesc); ++ offs += sizeof(*tmpdesc)) { ++ tmpdesc = (struct sc_part_desc *)&buf[offs]; ++ if (!scpart_desc_is_valid(tmpdesc)) ++ break; ++ cnt++; ++ } ++ ++ if (cnt > 0) { ++ int bytes = cnt * sizeof(*pdesc); ++ ++ pdesc = kcalloc(cnt, sizeof(*pdesc), GFP_KERNEL); ++ if (!pdesc) { ++ res = -ENOMEM; ++ goto free; ++ } ++ memcpy(pdesc, &(buf[MAP_OFFS_IN_BLK]), bytes); ++ ++ *ppdesc = pdesc; ++ res = cnt; ++ } ++ ++free: ++ kfree(buf); ++ ++out: ++ return res; ++} ++ ++static int scpart_find_partmap(struct mtd_info *master, ++ struct sc_part_desc **ppdesc) ++{ ++ int magic_found = 0; ++ int res = 0; ++ int res2; ++ loff_t offs = 0; ++ size_t retlen; ++ uint8_t rdbuf[PART_MAGIC_LEN]; ++ ++ while ((magic_found < MAP_MIRROR_NUM) && ++ (offs < master->size) && ++ !mtd_block_isbad(master, offs)) { ++ res2 = mtd_read(master, offs, PART_MAGIC_LEN, &retlen, rdbuf); ++ if (res2 || retlen != PART_MAGIC_LEN) { ++ res = -EIO; ++ goto out; ++ } ++ if (!memcmp(rdbuf, sc_part_magic, PART_MAGIC_LEN)) { ++ pr_debug("Signature found at 0x%llx\n", offs); ++ magic_found++; ++ res = scpart_scan_partmap(master, offs, ppdesc); ++ if (res > 0) ++ goto out; ++ } ++ offs += master->erasesize; ++ } ++ ++out: ++ if (res > 0) ++ pr_info("Valid 'SC PART MAP' (%d partitions) found at 0x%llx\n", res, offs); ++ else ++ pr_info("No valid 'SC PART MAP' was found\n"); ++ ++ return res; ++} ++ ++static int scpart_parse(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ const char *partname; ++ int n; ++ int nr_scparts; ++ int nr_parts = 0; ++ int res = 0; ++ struct sc_part_desc *scpart_map = NULL; ++ struct mtd_partition *parts = NULL; ++ struct device_node *mtd_node; ++ struct device_node *ofpart_node; ++ struct device_node *pp; ++ ++ mtd_node = mtd_get_of_node(master); ++ if (!mtd_node) { ++ res = -ENOENT; ++ goto out; ++ } ++ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ if (!ofpart_node) { ++ pr_info("%s: 'partitions' subnode not found on %pOF.\n", ++ master->name, mtd_node); ++ res = -ENOENT; ++ goto out; ++ } ++ ++ nr_scparts = scpart_find_partmap(master, &scpart_map); ++ if (nr_scparts <= 0) { ++ pr_info("No any partitions was found in 'SC PART MAP'.\n"); ++ res = -ENOENT; ++ goto free; ++ } ++ ++ parts = kcalloc(of_get_child_count(ofpart_node), sizeof(*parts), ++ GFP_KERNEL); ++ if (!parts) { ++ res = -ENOMEM; ++ goto free; ++ } ++ ++ for_each_child_of_node(ofpart_node, pp) { ++ u32 scpart_id; ++ ++ if (of_property_read_u32(pp, "sercomm,scpart-id", &scpart_id)) ++ continue; ++ ++ for (n = 0 ; n < nr_scparts ; n++) ++ if ((scpart_map[n].part_id != ID_ALREADY_FOUND) && ++ (scpart_id == scpart_map[n].part_id)) ++ break; ++ if (n >= nr_scparts) ++ /* not match */ ++ continue; ++ ++ /* add the partition found in OF into MTD partition array */ ++ parts[nr_parts].offset = scpart_map[n].part_offs; ++ parts[nr_parts].size = scpart_map[n].part_bytes; ++ parts[nr_parts].of_node = pp; ++ ++ if (!of_property_read_string(pp, "label", &partname)) ++ parts[nr_parts].name = partname; ++ if (of_property_read_bool(pp, "read-only")) ++ parts[nr_parts].mask_flags |= MTD_WRITEABLE; ++ if (of_property_read_bool(pp, "lock")) ++ parts[nr_parts].mask_flags |= MTD_POWERUP_LOCK; ++ ++ /* mark as 'done' */ ++ scpart_map[n].part_id = ID_ALREADY_FOUND; ++ ++ nr_parts++; ++ } ++ ++ if (nr_parts > 0) { ++ *pparts = parts; ++ res = nr_parts; ++ } else ++ pr_info("No partition in OF matches partition ID with 'SC PART MAP'.\n"); ++ ++ of_node_put(pp); ++ ++free: ++ kfree(scpart_map); ++ if (res <= 0) ++ kfree(parts); ++ ++out: ++ return res; ++} ++ ++static const struct of_device_id scpart_parser_of_match_table[] = { ++ { .compatible = "sercomm,sc-partitions" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, scpart_parser_of_match_table); ++ ++static struct mtd_part_parser scpart_parser = { ++ .parse_fn = scpart_parse, ++ .name = "scpart", ++ .of_match_table = scpart_parser_of_match_table, ++}; ++module_mtd_part_parser(scpart_parser); ++ ++/* mtd parsers will request the module by parser name */ ++MODULE_ALIAS("scpart"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("NOGUCHI Hiroshi "); ++MODULE_AUTHOR("Mikhail Zhilkin "); ++MODULE_DESCRIPTION("Sercomm partition parser"); diff --git a/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch b/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch new file mode 100644 index 00000000000..ee385416d1d --- /dev/null +++ b/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch @@ -0,0 +1,106 @@ +From ad9b10d1eaada169bd764abcab58f08538877e26 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 22 Jun 2022 03:06:28 +0200 +Subject: mtd: core: introduce of support for dynamic partitions + +We have many parser that register mtd partitions at runtime. One example +is the cmdlinepart or the smem-part parser where the compatible is defined +in the dts and the partitions gets detected and registered by the +parser. This is problematic for the NVMEM subsystem that requires an OF +node to detect NVMEM cells. + +To fix this problem, introduce an additional logic that will try to +assign an OF node to the MTD if declared. + +On MTD addition, it will be checked if the MTD has an OF node and if +not declared will check if a partition with the same label / node name is +declared in DTS. If an exact match is found, the partition dynamically +allocated by the parser will have a connected OF node. + +The NVMEM subsystem will detect the OF node and register any NVMEM cells +declared statically in the DTS. + +Signed-off-by: Christian Marangi +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220622010628.30414-4-ansuelsmth@gmail.com +--- + drivers/mtd/mtdcore.c | 61 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 61 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -564,6 +564,66 @@ static int mtd_nvmem_add(struct mtd_info + return 0; + } + ++static void mtd_check_of_node(struct mtd_info *mtd) ++{ ++ struct device_node *partitions, *parent_dn, *mtd_dn = NULL; ++ const char *pname, *prefix = "partition-"; ++ int plen, mtd_name_len, offset, prefix_len; ++ struct mtd_info *parent; ++ bool found = false; ++ ++ /* Check if MTD already has a device node */ ++ if (dev_of_node(&mtd->dev)) ++ return; ++ ++ /* Check if a partitions node exist */ ++ parent = mtd->parent; ++ parent_dn = dev_of_node(&parent->dev); ++ if (!parent_dn) ++ return; ++ ++ partitions = of_get_child_by_name(parent_dn, "partitions"); ++ if (!partitions) ++ goto exit_parent; ++ ++ prefix_len = strlen(prefix); ++ mtd_name_len = strlen(mtd->name); ++ ++ /* Search if a partition is defined with the same name */ ++ for_each_child_of_node(partitions, mtd_dn) { ++ offset = 0; ++ ++ /* Skip partition with no/wrong prefix */ ++ if (!of_node_name_prefix(mtd_dn, "partition-")) ++ continue; ++ ++ /* Label have priority. Check that first */ ++ if (of_property_read_string(mtd_dn, "label", &pname)) { ++ of_property_read_string(mtd_dn, "name", &pname); ++ offset = prefix_len; ++ } ++ ++ plen = strlen(pname) - offset; ++ if (plen == mtd_name_len && ++ !strncmp(mtd->name, pname + offset, plen)) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) ++ goto exit_partitions; ++ ++ /* Set of_node only for nvmem */ ++ if (of_device_is_compatible(mtd_dn, "nvmem-cells")) ++ mtd_set_of_node(mtd, mtd_dn); ++ ++exit_partitions: ++ of_node_put(partitions); ++exit_parent: ++ of_node_put(parent_dn); ++} ++ + /** + * add_mtd_device - register an MTD device + * @mtd: pointer to new MTD device info structure +@@ -669,6 +729,7 @@ int add_mtd_device(struct mtd_info *mtd) + mtd->dev.devt = MTD_DEVT(i); + dev_set_name(&mtd->dev, "mtd%d", i); + dev_set_drvdata(&mtd->dev, mtd); ++ mtd_check_of_node(mtd); + of_node_get(mtd_get_of_node(mtd)); + error = device_register(&mtd->dev); + if (error) { diff --git a/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch b/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch new file mode 100644 index 00000000000..3039eabea50 --- /dev/null +++ b/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch @@ -0,0 +1,72 @@ +From b0321721be50b80c03a51866a94fde4f94690e18 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Wed, 15 Jun 2022 21:42:59 +0200 +Subject: [PATCH] mtd: allow getting MTD device associated with a specific DT + node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +MTD subsystem API allows interacting with MTD devices (e.g. reading, +writing, handling bad blocks). So far a random driver could get MTD +device only by its name (get_mtd_device_nm()). This change allows +getting them also by a DT node. + +This API is required for drivers handling DT defined MTD partitions in a +specific way (e.g. U-Boot (sub)partition with environment variables). + +Signed-off-by: Rafał Miłecki +Acked-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +--- + drivers/mtd/mtdcore.c | 28 ++++++++++++++++++++++++++++ + include/linux/mtd/mtd.h | 1 + + 2 files changed, 29 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -1236,6 +1236,34 @@ int __get_mtd_device(struct mtd_info *mt + EXPORT_SYMBOL_GPL(__get_mtd_device); + + /** ++ * of_get_mtd_device_by_node - obtain an MTD device associated with a given node ++ * ++ * @np: device tree node ++ */ ++struct mtd_info *of_get_mtd_device_by_node(struct device_node *np) ++{ ++ struct mtd_info *mtd = NULL; ++ struct mtd_info *tmp; ++ int err; ++ ++ mutex_lock(&mtd_table_mutex); ++ ++ err = -EPROBE_DEFER; ++ mtd_for_each_device(tmp) { ++ if (mtd_get_of_node(tmp) == np) { ++ mtd = tmp; ++ err = __get_mtd_device(mtd); ++ break; ++ } ++ } ++ ++ mutex_unlock(&mtd_table_mutex); ++ ++ return err ? ERR_PTR(err) : mtd; ++} ++EXPORT_SYMBOL_GPL(of_get_mtd_device_by_node); ++ ++/** + * get_mtd_device_nm - obtain a validated handle for an MTD device by + * device name + * @name: MTD device name to open +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -682,6 +682,7 @@ extern int mtd_device_unregister(struct + extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); + extern int __get_mtd_device(struct mtd_info *mtd); + extern void __put_mtd_device(struct mtd_info *mtd); ++extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np); + extern struct mtd_info *get_mtd_device_nm(const char *name); + extern void put_mtd_device(struct mtd_info *mtd); + diff --git a/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch b/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch new file mode 100644 index 00000000000..e45e2ab48e3 --- /dev/null +++ b/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch @@ -0,0 +1,30 @@ +From 7ec4cdb321738d44ae5d405e7b6ac73dfbf99caa Mon Sep 17 00:00:00 2001 +From: Tetsuo Handa +Date: Mon, 25 Jul 2022 22:49:25 +0900 +Subject: [PATCH] mtd: core: check partition before dereference + +syzbot is reporting NULL pointer dereference at mtd_check_of_node() [1], +for mtdram test device (CONFIG_MTD_MTDRAM) is not partition. + +Link: https://syzkaller.appspot.com/bug?extid=fe013f55a2814a9e8cfd [1] +Reported-by: syzbot +Reported-by: kernel test robot +Fixes: ad9b10d1eaada169 ("mtd: core: introduce of support for dynamic partitions") +Signed-off-by: Tetsuo Handa +CC: stable@vger.kernel.org +Signed-off-by: Richard Weinberger +--- + drivers/mtd/mtdcore.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -577,6 +577,8 @@ static void mtd_check_of_node(struct mtd + return; + + /* Check if a partitions node exist */ ++ if (!mtd_is_partition(mtd)) ++ return; + parent = mtd->parent; + parent_dn = dev_of_node(&parent->dev); + if (!parent_dn) diff --git a/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch b/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch new file mode 100644 index 00000000000..9399a00aa16 --- /dev/null +++ b/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch @@ -0,0 +1,101 @@ +From 12b58961de0bd88b3c7dfa5d21f6d67f4678b780 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 18 Oct 2022 07:18:22 +0200 +Subject: [PATCH] mtd: core: add missing of_node_get() in dynamic partitions + code +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes unbalanced of_node_put(): +[ 1.078910] 6 cmdlinepart partitions found on MTD device gpmi-nand +[ 1.085116] Creating 6 MTD partitions on "gpmi-nand": +[ 1.090181] 0x000000000000-0x000008000000 : "nandboot" +[ 1.096952] 0x000008000000-0x000009000000 : "nandfit" +[ 1.103547] 0x000009000000-0x00000b000000 : "nandkernel" +[ 1.110317] 0x00000b000000-0x00000c000000 : "nanddtb" +[ 1.115525] ------------[ cut here ]------------ +[ 1.120141] refcount_t: addition on 0; use-after-free. +[ 1.125328] WARNING: CPU: 0 PID: 1 at lib/refcount.c:25 refcount_warn_saturate+0xdc/0x148 +[ 1.133528] Modules linked in: +[ 1.136589] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.0.0-rc7-next-20220930-04543-g8cf3f7 +[ 1.146342] Hardware name: Freescale i.MX8DXL DDR3L EVK (DT) +[ 1.151999] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 1.158965] pc : refcount_warn_saturate+0xdc/0x148 +[ 1.163760] lr : refcount_warn_saturate+0xdc/0x148 +[ 1.168556] sp : ffff800009ddb080 +[ 1.171866] x29: ffff800009ddb080 x28: ffff800009ddb35a x27: 0000000000000002 +[ 1.179015] x26: ffff8000098b06ad x25: ffffffffffffffff x24: ffff0a00ffffff05 +[ 1.186165] x23: ffff00001fdf6470 x22: ffff800009ddb367 x21: 0000000000000000 +[ 1.193314] x20: ffff00001fdfebe8 x19: ffff00001fdfec50 x18: ffffffffffffffff +[ 1.200464] x17: 0000000000000000 x16: 0000000000000118 x15: 0000000000000004 +[ 1.207614] x14: 0000000000000fff x13: ffff800009bca248 x12: 0000000000000003 +[ 1.214764] x11: 00000000ffffefff x10: c0000000ffffefff x9 : 4762cb2ccb52de00 +[ 1.221914] x8 : 4762cb2ccb52de00 x7 : 205d313431303231 x6 : 312e31202020205b +[ 1.229063] x5 : ffff800009d55c1f x4 : 0000000000000001 x3 : 0000000000000000 +[ 1.236213] x2 : 0000000000000000 x1 : ffff800009954be6 x0 : 000000000000002a +[ 1.243365] Call trace: +[ 1.245806] refcount_warn_saturate+0xdc/0x148 +[ 1.250253] kobject_get+0x98/0x9c +[ 1.253658] of_node_get+0x20/0x34 +[ 1.257072] of_fwnode_get+0x3c/0x54 +[ 1.260652] fwnode_get_nth_parent+0xd8/0xf4 +[ 1.264926] fwnode_full_name_string+0x3c/0xb4 +[ 1.269373] device_node_string+0x498/0x5b4 +[ 1.273561] pointer+0x41c/0x5d0 +[ 1.276793] vsnprintf+0x4d8/0x694 +[ 1.280198] vprintk_store+0x164/0x528 +[ 1.283951] vprintk_emit+0x98/0x164 +[ 1.287530] vprintk_default+0x44/0x6c +[ 1.291284] vprintk+0xf0/0x134 +[ 1.294428] _printk+0x54/0x7c +[ 1.297486] of_node_release+0xe8/0x128 +[ 1.301326] kobject_put+0x98/0xfc +[ 1.304732] of_node_put+0x1c/0x28 +[ 1.308137] add_mtd_device+0x484/0x6d4 +[ 1.311977] add_mtd_partitions+0xf0/0x1d0 +[ 1.316078] parse_mtd_partitions+0x45c/0x518 +[ 1.320439] mtd_device_parse_register+0xb0/0x274 +[ 1.325147] gpmi_nand_probe+0x51c/0x650 +[ 1.329074] platform_probe+0xa8/0xd0 +[ 1.332740] really_probe+0x130/0x334 +[ 1.336406] __driver_probe_device+0xb4/0xe0 +[ 1.340681] driver_probe_device+0x3c/0x1f8 +[ 1.344869] __driver_attach+0xdc/0x1a4 +[ 1.348708] bus_for_each_dev+0x80/0xcc +[ 1.352548] driver_attach+0x24/0x30 +[ 1.356127] bus_add_driver+0x108/0x1f4 +[ 1.359967] driver_register+0x78/0x114 +[ 1.363807] __platform_driver_register+0x24/0x30 +[ 1.368515] gpmi_nand_driver_init+0x1c/0x28 +[ 1.372798] do_one_initcall+0xbc/0x238 +[ 1.376638] do_initcall_level+0x94/0xb4 +[ 1.380565] do_initcalls+0x54/0x94 +[ 1.384058] do_basic_setup+0x1c/0x28 +[ 1.387724] kernel_init_freeable+0x110/0x188 +[ 1.392084] kernel_init+0x20/0x1a0 +[ 1.395578] ret_from_fork+0x10/0x20 +[ 1.399157] ---[ end trace 0000000000000000 ]--- +[ 1.403782] ------------[ cut here ]------------ + +Reported-by: Han Xu +Fixes: ad9b10d1eaada169 ("mtd: core: introduce of support for dynamic partitions") +Signed-off-by: Rafał Miłecki +Tested-by: Han Xu +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221018051822.28685-1-zajec5@gmail.com +--- + drivers/mtd/mtdcore.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -580,7 +580,7 @@ static void mtd_check_of_node(struct mtd + if (!mtd_is_partition(mtd)) + return; + parent = mtd->parent; +- parent_dn = dev_of_node(&parent->dev); ++ parent_dn = of_node_get(dev_of_node(&parent->dev)); + if (!parent_dn) + return; + diff --git a/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch b/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch new file mode 100644 index 00000000000..7e9645ea98d --- /dev/null +++ b/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch @@ -0,0 +1,65 @@ +From 63db0cb35e1cb3b3c134906d1062f65513fdda2d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 4 Oct 2022 10:37:09 +0200 +Subject: [PATCH] mtd: core: simplify (a bit) code find partition-matching + dynamic OF node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Don't hardcode "partition-" string twice +2. Use simpler logic & use ->name to avoid of_property_read_string() +3. Use mtd_get_of_node() helper + +Cc: Christian Marangi +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-1-zajec5@gmail.com +--- + drivers/mtd/mtdcore.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -569,18 +569,16 @@ static void mtd_check_of_node(struct mtd + struct device_node *partitions, *parent_dn, *mtd_dn = NULL; + const char *pname, *prefix = "partition-"; + int plen, mtd_name_len, offset, prefix_len; +- struct mtd_info *parent; + bool found = false; + + /* Check if MTD already has a device node */ +- if (dev_of_node(&mtd->dev)) ++ if (mtd_get_of_node(mtd)) + return; + + /* Check if a partitions node exist */ + if (!mtd_is_partition(mtd)) + return; +- parent = mtd->parent; +- parent_dn = of_node_get(dev_of_node(&parent->dev)); ++ parent_dn = of_node_get(mtd_get_of_node(mtd->parent)); + if (!parent_dn) + return; + +@@ -593,15 +591,15 @@ static void mtd_check_of_node(struct mtd + + /* Search if a partition is defined with the same name */ + for_each_child_of_node(partitions, mtd_dn) { +- offset = 0; +- + /* Skip partition with no/wrong prefix */ +- if (!of_node_name_prefix(mtd_dn, "partition-")) ++ if (!of_node_name_prefix(mtd_dn, prefix)) + continue; + + /* Label have priority. Check that first */ +- if (of_property_read_string(mtd_dn, "label", &pname)) { +- of_property_read_string(mtd_dn, "name", &pname); ++ if (!of_property_read_string(mtd_dn, "label", &pname)) { ++ offset = 0; ++ } else { ++ pname = mtd_dn->name; + offset = prefix_len; + } + diff --git a/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch b/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch new file mode 100644 index 00000000000..48a7c13cd01 --- /dev/null +++ b/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch @@ -0,0 +1,84 @@ +From ddb8cefb7af288950447ca6eeeafb09977dab56f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 4 Oct 2022 10:37:10 +0200 +Subject: [PATCH] mtd: core: try to find OF node for every MTD partition +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +So far this feature was limited to the top-level "nvmem-cells" node. +There are multiple parsers creating partitions and subpartitions +dynamically. Extend that code to handle them too. + +This allows finding partition-* node for every MTD (sub)partition. + +Random example: + +partitions { + compatible = "brcm,bcm947xx-cfe-partitions"; + + partition-firmware { + compatible = "brcm,trx"; + + partition-loader { + }; + }; +}; + +Cc: Christian Marangi +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-2-zajec5@gmail.com +--- + drivers/mtd/mtdcore.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -569,20 +569,22 @@ static void mtd_check_of_node(struct mtd + struct device_node *partitions, *parent_dn, *mtd_dn = NULL; + const char *pname, *prefix = "partition-"; + int plen, mtd_name_len, offset, prefix_len; +- bool found = false; + + /* Check if MTD already has a device node */ + if (mtd_get_of_node(mtd)) + return; + +- /* Check if a partitions node exist */ + if (!mtd_is_partition(mtd)) + return; ++ + parent_dn = of_node_get(mtd_get_of_node(mtd->parent)); + if (!parent_dn) + return; + +- partitions = of_get_child_by_name(parent_dn, "partitions"); ++ if (mtd_is_partition(mtd->parent)) ++ partitions = of_node_get(parent_dn); ++ else ++ partitions = of_get_child_by_name(parent_dn, "partitions"); + if (!partitions) + goto exit_parent; + +@@ -606,19 +608,11 @@ static void mtd_check_of_node(struct mtd + plen = strlen(pname) - offset; + if (plen == mtd_name_len && + !strncmp(mtd->name, pname + offset, plen)) { +- found = true; ++ mtd_set_of_node(mtd, mtd_dn); + break; + } + } + +- if (!found) +- goto exit_partitions; +- +- /* Set of_node only for nvmem */ +- if (of_device_is_compatible(mtd_dn, "nvmem-cells")) +- mtd_set_of_node(mtd, mtd_dn); +- +-exit_partitions: + of_node_put(partitions); + exit_parent: + of_node_put(parent_dn); diff --git a/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch b/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch new file mode 100644 index 00000000000..0efad99157a --- /dev/null +++ b/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch @@ -0,0 +1,32 @@ +From 26bccc9671ba5e01f7153addbe94e7dc3f677375 Mon Sep 17 00:00:00 2001 +From: Bryan O'Donoghue +Date: Mon, 3 Jan 2022 03:03:16 +0000 +Subject: [PATCH 13/14] mtd: parsers: qcom: Don't print error message on + -EPROBE_DEFER + +Its possible for the main smem driver to not be loaded by the time we come +along to parse the smem partition description but, this is a perfectly +normal thing. + +No need to print out an error message in this case. + +Signed-off-by: Bryan O'Donoghue +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220103030316.58301-3-bryan.odonoghue@linaro.org +--- + drivers/mtd/parsers/qcomsmempart.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/qcomsmempart.c ++++ b/drivers/mtd/parsers/qcomsmempart.c +@@ -75,7 +75,8 @@ static int parse_qcomsmem_part(struct mt + pr_debug("Parsing partition table info from SMEM\n"); + ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); + if (IS_ERR(ptable)) { +- pr_err("Error reading partition table header\n"); ++ if (PTR_ERR(ptable) != -EPROBE_DEFER) ++ pr_err("Error reading partition table header\n"); + return PTR_ERR(ptable); + } + diff --git a/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch b/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch new file mode 100644 index 00000000000..505e347e40e --- /dev/null +++ b/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch @@ -0,0 +1,47 @@ +From 26422ac78e9d8767bd4aabfbae616b15edbf6a1b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sat, 22 Oct 2022 23:13:18 +0200 +Subject: [PATCH] mtd: core: set ROOT_DEV for partitions marked as rootfs in DT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds support for "linux,rootfs" binding that is used to mark flash +partition containing rootfs. It's useful for devices using device tree +that don't have bootloader passing root info in cmdline. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221022211318.32009-2-zajec5@gmail.com +--- + drivers/mtd/mtdcore.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -748,6 +749,17 @@ int add_mtd_device(struct mtd_info *mtd) + not->add(mtd); + + mutex_unlock(&mtd_table_mutex); ++ ++ if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { ++ if (IS_BUILTIN(CONFIG_MTD)) { ++ pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); ++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); ++ } else { ++ pr_warn("mtd: can't set mtd%d (%s) as root device - mtd must be builtin\n", ++ mtd->index, mtd->name); ++ } ++ } ++ + /* We _know_ we aren't being removed, because + our caller is still holding us here. So none + of this try_ nonsense, and no bitching about it diff --git a/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch b/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch new file mode 100644 index 00000000000..5c49841760f --- /dev/null +++ b/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch @@ -0,0 +1,33 @@ +From 2365f91c861cbfeef7141c69842848c7b2d3c2db Mon Sep 17 00:00:00 2001 +From: INAGAKI Hiroshi +Date: Sun, 13 Feb 2022 15:40:44 +0900 +Subject: [PATCH] mtd: parsers: trx: allow to use on MediaTek MIPS SoCs + +Buffalo sells some router devices which have trx-formatted firmware, +based on MediaTek MIPS SoCs. To use parser_trx on those devices, add +"RALINK" to dependency and allow to compile for MediaTek MIPS SoCs. + +examples: + +- WCR-1166DS (MT7628) +- WSR-1166DHP (MT7621) +- WSR-2533DHP (MT7621) + +Signed-off-by: INAGAKI Hiroshi +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220213064045.1781-1-musashino.open@gmail.com +--- + drivers/mtd/parsers/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -115,7 +115,7 @@ config MTD_AFS_PARTS + + config MTD_PARSER_TRX + tristate "Parser for TRX format partitions" +- depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || COMPILE_TEST) ++ depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) + help + TRX is a firmware format used by Broadcom on their devices. It + may contain up to 3/4 partitions (depending on the version). diff --git a/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch new file mode 100644 index 00000000000..181c912fbfc --- /dev/null +++ b/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch @@ -0,0 +1,58 @@ +From 573eec222bc82fb5e724586267fbbb1aed9ffd03 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Sun, 20 Mar 2022 17:59:58 +0800 +Subject: [PATCH 2/5] mtd: spinand: gigadevice: add support for GD5FxGQ4xExxG + +Add support for: + GD5F1GQ4RExxG + GD5F2GQ4{U,R}ExxG + +These chips differ from GD5F1GQ4UExxG only in chip ID, voltage +and capacity. + +Signed-off-by: Chuanhong Guo +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-3-gch981213@gmail.com +--- + drivers/mtd/nand/spi/gigadevice.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -333,6 +333,36 @@ static const struct spinand_info gigadev + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F1GQ4RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1), ++ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GQ4UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GQ4RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GQ4UFxxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), diff --git a/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch new file mode 100644 index 00000000000..3a1cc9efcfb --- /dev/null +++ b/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch @@ -0,0 +1,33 @@ +From 620a988813403318023296b61228ee8f3fcdb8e0 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Sun, 20 Mar 2022 17:59:59 +0800 +Subject: [PATCH 3/5] mtd: spinand: gigadevice: add support for GD5F1GQ5RExxG + +This chip is the 1.8v version of GD5F1GQ5UExxG. + +Signed-off-by: Chuanhong Guo +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-4-gch981213@gmail.com +--- + drivers/mtd/nand/spi/gigadevice.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -383,6 +383,16 @@ static const struct spinand_info gigadev + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F1GQ5RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41), ++ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq5xexxg_ecc_get_status)), + }; + + static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch b/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch new file mode 100644 index 00000000000..cee9d9db3eb --- /dev/null +++ b/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch @@ -0,0 +1,84 @@ +From 194ec04b3a9e7fa97d1fbef296410631bc3cf1c8 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Sun, 20 Mar 2022 18:00:00 +0800 +Subject: [PATCH 4/5] mtd: spinand: gigadevice: add support for GD5F{2, + 4}GQ5xExxG + +Add support for: + GD5F2GQ5{U,R}ExxG + GD5F4GQ6{U,R}ExxG + +These chips uses 4 dummy bytes for quad io and 2 dummy bytes for dual io. +Besides that and memory layout, they are identical to their 1G variant. + +Signed-off-by: Chuanhong Guo +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-5-gch981213@gmail.com +--- + drivers/mtd/nand/spi/gigadevice.c | 48 +++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -47,6 +47,14 @@ static SPINAND_OP_VARIANTS(read_cache_va + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + ++static SPINAND_OP_VARIANTS(read_cache_variants_2gq5, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ + static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), + SPINAND_PROG_LOAD(true, 0, NULL, 0)); +@@ -391,6 +399,46 @@ static const struct spinand_info gigadev + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GQ5UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GQ5RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F4GQ6UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F4GQ6RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), ++ NAND_ECCREQ(4, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), + }; diff --git a/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch new file mode 100644 index 00000000000..d63113e1a66 --- /dev/null +++ b/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch @@ -0,0 +1,91 @@ +From 54647cd003c08b714474a5b599a147ec6a160486 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Sun, 20 Mar 2022 18:00:01 +0800 +Subject: [PATCH 5/5] mtd: spinand: gigadevice: add support for GD5FxGM7xExxG + +Add support for: + GD5F{1,2}GM7{U,R}ExxG + GD5F4GM8{U,R}ExxG + +These are new 27nm counterparts for the GD5FxGQ4 chips from GigaDevice +with 8b/512b on-die ECC capability. +These chips (and currently supported GD5FxGQ5 chips) have QIO DTR +instruction for reading page cache. It isn't added in this patch because +I don't have a DTR spi controller for testing. + +Signed-off-by: Chuanhong Guo +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-6-gch981213@gmail.com +--- + drivers/mtd/nand/spi/gigadevice.c | 60 +++++++++++++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +--- a/drivers/mtd/nand/spi/gigadevice.c ++++ b/drivers/mtd/nand/spi/gigadevice.c +@@ -441,6 +441,66 @@ static const struct spinand_info gigadev + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq5xexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F1GM7UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91), ++ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F1GM7RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81), ++ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GM7UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F2GM7RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F4GM8UExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95), ++ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), ++ SPINAND_INFO("GD5F4GM8RExxG", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85), ++ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, ++ gd5fxgq4uexxg_ecc_get_status)), + }; + + static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch b/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch new file mode 100644 index 00000000000..9f543365a57 --- /dev/null +++ b/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch @@ -0,0 +1,229 @@ +From aec4d5f5ffd0f0092bd9dc21ea90e0bc237d4b74 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sat, 15 Oct 2022 11:29:50 +0200 +Subject: [PATCH] mtd: parsers: add TP-Link SafeLoader partitions table parser +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This parser deals with most TP-Link home routers. It reads info about +partitions and registers them in the MTD subsystem. + +Example from TP-Link Archer C5 V2: + +spi-nor spi0.0: s25fl128s1 (16384 Kbytes) +15 tplink-safeloader partitions found on MTD device spi0.0 +Creating 15 MTD partitions on "spi0.0": +0x000000000000-0x000000040000 : "fs-uboot" +0x000000040000-0x000000440000 : "os-image" +0x000000440000-0x000000e40000 : "rootfs" +0x000000e40000-0x000000e40200 : "default-mac" +0x000000e40200-0x000000e40400 : "pin" +0x000000e40400-0x000000e40600 : "product-info" +0x000000e50000-0x000000e60000 : "partition-table" +0x000000e60000-0x000000e60200 : "soft-version" +0x000000e61000-0x000000e70000 : "support-list" +0x000000e70000-0x000000e80000 : "profile" +0x000000e80000-0x000000e90000 : "default-config" +0x000000e90000-0x000000ee0000 : "user-config" +0x000000ee0000-0x000000fe0000 : "log" +0x000000fe0000-0x000000ff0000 : "radio_bk" +0x000000ff0000-0x000001000000 : "radio" + +Signed-off-by: Rafał Miłecki +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221015092950.27467-2-zajec5@gmail.com +--- + drivers/mtd/parsers/Kconfig | 15 +++ + drivers/mtd/parsers/Makefile | 1 + + drivers/mtd/parsers/tplink_safeloader.c | 150 ++++++++++++++++++++++++ + 3 files changed, 166 insertions(+) + create mode 100644 drivers/mtd/parsers/tplink_safeloader.c + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -113,6 +113,21 @@ config MTD_AFS_PARTS + for your particular device. It won't happen automatically. The + 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. + ++config MTD_PARSER_TPLINK_SAFELOADER ++ tristate "TP-Link Safeloader partitions parser" ++ depends on MTD && (ARCH_BCM_5301X || ATH79 || SOC_MT7620 || SOC_MT7621 || COMPILE_TEST) ++ help ++ TP-Link home routers use flash partitions to store various data. Info ++ about flash space layout is stored in a partitions table using a ++ custom ASCII-based format. ++ ++ That format was first found in devices with SafeLoader bootloader and ++ was named after it. Later it was adapted to CFE and U-Boot ++ bootloaders. ++ ++ This driver reads partitions table, parses it and creates MTD ++ partitions. ++ + config MTD_PARSER_TRX + tristate "Parser for TRX format partitions" + depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -9,6 +9,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += + ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o + obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o + obj-$(CONFIG_MTD_AFS_PARTS) += afs.o ++obj-$(CONFIG_MTD_PARSER_TPLINK_SAFELOADER) += tplink_safeloader.o + obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o + obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o +--- /dev/null ++++ b/drivers/mtd/parsers/tplink_safeloader.c +@@ -0,0 +1,150 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright © 2022 Rafał Miłecki ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TPLINK_SAFELOADER_DATA_OFFSET 4 ++#define TPLINK_SAFELOADER_MAX_PARTS 32 ++ ++struct safeloader_cmn_header { ++ __be32 size; ++ uint32_t unused; ++} __packed; ++ ++static void *mtd_parser_tplink_safeloader_read_table(struct mtd_info *mtd) ++{ ++ struct safeloader_cmn_header hdr; ++ struct device_node *np; ++ size_t bytes_read; ++ size_t offset; ++ size_t size; ++ char *buf; ++ int err; ++ ++ np = mtd_get_of_node(mtd); ++ if (mtd_is_partition(mtd)) ++ of_node_get(np); ++ else ++ np = of_get_child_by_name(np, "partitions"); ++ ++ if (of_property_read_u32(np, "partitions-table-offset", (u32 *)&offset)) { ++ pr_err("Failed to get partitions table offset\n"); ++ goto err_put; ++ } ++ ++ err = mtd_read(mtd, offset, sizeof(hdr), &bytes_read, (uint8_t *)&hdr); ++ if (err && !mtd_is_bitflip(err)) { ++ pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset); ++ goto err_put; ++ } ++ ++ size = be32_to_cpu(hdr.size); ++ ++ buf = kmalloc(size + 1, GFP_KERNEL); ++ if (!buf) ++ goto err_put; ++ ++ err = mtd_read(mtd, offset + sizeof(hdr), size, &bytes_read, buf); ++ if (err && !mtd_is_bitflip(err)) { ++ pr_err("Failed to read from %s at 0x%zx\n", mtd->name, offset + sizeof(hdr)); ++ goto err_kfree; ++ } ++ ++ buf[size] = '\0'; ++ ++ of_node_put(np); ++ ++ return buf; ++ ++err_kfree: ++ kfree(buf); ++err_put: ++ of_node_put(np); ++ return NULL; ++} ++ ++static int mtd_parser_tplink_safeloader_parse(struct mtd_info *mtd, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_partition *parts; ++ char name[65]; ++ size_t offset; ++ size_t bytes; ++ char *buf; ++ int idx; ++ int err; ++ ++ parts = kcalloc(TPLINK_SAFELOADER_MAX_PARTS, sizeof(*parts), GFP_KERNEL); ++ if (!parts) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ buf = mtd_parser_tplink_safeloader_read_table(mtd); ++ if (!buf) { ++ err = -ENOENT; ++ goto err_out; ++ } ++ ++ for (idx = 0, offset = TPLINK_SAFELOADER_DATA_OFFSET; ++ idx < TPLINK_SAFELOADER_MAX_PARTS && ++ sscanf(buf + offset, "partition %64s base 0x%llx size 0x%llx%zn\n", ++ name, &parts[idx].offset, &parts[idx].size, &bytes) == 3; ++ idx++, offset += bytes + 1) { ++ parts[idx].name = kstrdup(name, GFP_KERNEL); ++ if (!parts[idx].name) { ++ err = -ENOMEM; ++ goto err_free; ++ } ++ } ++ ++ if (idx == TPLINK_SAFELOADER_MAX_PARTS) ++ pr_warn("Reached maximum number of partitions!\n"); ++ ++ kfree(buf); ++ ++ *pparts = parts; ++ ++ return idx; ++ ++err_free: ++ for (idx -= 1; idx >= 0; idx--) ++ kfree(parts[idx].name); ++err_out: ++ return err; ++}; ++ ++static void mtd_parser_tplink_safeloader_cleanup(const struct mtd_partition *pparts, ++ int nr_parts) ++{ ++ int i; ++ ++ for (i = 0; i < nr_parts; i++) ++ kfree(pparts[i].name); ++ ++ kfree(pparts); ++} ++ ++static const struct of_device_id mtd_parser_tplink_safeloader_of_match_table[] = { ++ { .compatible = "tplink,safeloader-partitions" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, mtd_parser_tplink_safeloader_of_match_table); ++ ++static struct mtd_part_parser mtd_parser_tplink_safeloader = { ++ .parse_fn = mtd_parser_tplink_safeloader_parse, ++ .cleanup = mtd_parser_tplink_safeloader_cleanup, ++ .name = "tplink-safeloader", ++ .of_match_table = mtd_parser_tplink_safeloader_of_match_table, ++}; ++module_mtd_part_parser(mtd_parser_tplink_safeloader); ++ ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch b/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch new file mode 100644 index 00000000000..2358352e93c --- /dev/null +++ b/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch @@ -0,0 +1,49 @@ +From 6abef37d16d0c570ef5a149e63762fba2a30804b Mon Sep 17 00:00:00 2001 +From: "Leon M. George" +Date: Wed, 30 Mar 2022 16:16:56 +0200 +Subject: [PATCH] mtd: spi-nor: support eon en25qh256a variant + +The EN25QH256A variant of the EN25QH256 doesn't initialize correctly from SFDP +alone and only accesses memory below 8m (addr_width is 4 but read_opcode takes +only 3 bytes). + +Set SNOR_F_4B_OPCODES if the flash chip variant was detected using hwcaps. + +The fix submitted upstream uses the PARSE_SFDP initializer that is not +available in the kernel used with Openwrt. + +Signed-off-by: Leon M. George +--- + drivers/mtd/spi-nor/eon.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/mtd/spi-nor/eon.c ++++ b/drivers/mtd/spi-nor/eon.c +@@ -8,6 +8,16 @@ + + #include "core.h" + ++static void en25qh256_post_sfdp_fixups(struct spi_nor *nor) ++{ ++ if (nor->params->hwcaps.mask & SNOR_HWCAPS_READ_1_1_4) ++ nor->flags |= SNOR_F_4B_OPCODES; ++} ++ ++static const struct spi_nor_fixups en25qh256_fixups = { ++ .post_sfdp = en25qh256_post_sfdp_fixups, ++}; ++ + static const struct flash_info eon_parts[] = { + /* EON -- en25xxx */ + { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, +@@ -23,7 +33,9 @@ static const struct flash_info eon_parts + { "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, +- { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, ++ { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, ++ SPI_NOR_DUAL_READ) ++ .fixups = &en25qh256_fixups }, + { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, + }; + diff --git a/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch b/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch new file mode 100644 index 00000000000..9f1757caa79 --- /dev/null +++ b/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch @@ -0,0 +1,73 @@ +From e237285113963bd1dd2e925770aa8b3aa8a1894c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= +Date: Wed, 29 Jun 2022 14:57:34 +0200 +Subject: [PATCH 1/4] mtd: track maximum number of bitflips for each read + request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mtd_read_oob() callers are currently oblivious to the details of ECC +errors detected during the read operation - they only learn (through the +return value) whether any corrected bitflips or uncorrectable errors +occurred. More detailed ECC information can be useful to user-space +applications for making better-informed choices about moving data +around. + +Extend struct mtd_oob_ops with a pointer to a newly-introduced struct +mtd_req_stats and set its 'max_bitflips' field to the maximum number of +bitflips found in a single ECC step during the read operation performed +by mtd_read_oob(). This is a prerequisite for ultimately passing that +value back to user space. + +Suggested-by: Boris Brezillon +Signed-off-by: Michał Kępień +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-2-kernel@kempniu.pl +--- + drivers/mtd/mtdcore.c | 5 +++++ + include/linux/mtd/mtd.h | 5 +++++ + 2 files changed, 10 insertions(+) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -1676,6 +1676,9 @@ int mtd_read_oob(struct mtd_info *mtd, l + if (!master->_read_oob && (!master->_read || ops->oobbuf)) + return -EOPNOTSUPP; + ++ if (ops->stats) ++ memset(ops->stats, 0, sizeof(*ops->stats)); ++ + if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) + ret_code = mtd_io_emulated_slc(mtd, from, true, ops); + else +@@ -1693,6 +1696,8 @@ int mtd_read_oob(struct mtd_info *mtd, l + return ret_code; + if (mtd->ecc_strength == 0) + return 0; /* device lacks ecc */ ++ if (ops->stats) ++ ops->stats->max_bitflips = ret_code; + return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; + } + EXPORT_SYMBOL_GPL(mtd_read_oob); +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -40,6 +40,10 @@ struct mtd_erase_region_info { + unsigned long *lockmap; /* If keeping bitmap of locks */ + }; + ++struct mtd_req_stats { ++ unsigned int max_bitflips; ++}; ++ + /** + * struct mtd_oob_ops - oob operation operands + * @mode: operation mode +@@ -70,6 +74,7 @@ struct mtd_oob_ops { + uint32_t ooboffs; + uint8_t *datbuf; + uint8_t *oobbuf; ++ struct mtd_req_stats *stats; + }; + + #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 diff --git a/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch b/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch new file mode 100644 index 00000000000..1484624e4e5 --- /dev/null +++ b/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch @@ -0,0 +1,325 @@ +From e97709c9d18903f5acd5fbe2985dd054da0432b1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= +Date: Wed, 29 Jun 2022 14:57:35 +0200 +Subject: [PATCH 2/4] mtd: always initialize 'stats' in struct mtd_oob_ops +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As the 'stats' field in struct mtd_oob_ops is used in conditional +expressions, ensure it is always zero-initialized in all such structures +to prevent random stack garbage from being interpreted as a pointer. + +Strictly speaking, this problem currently only needs to be fixed for +struct mtd_oob_ops structures subsequently passed to mtd_read_oob(). +However, this commit goes a step further and makes all instances of +struct mtd_oob_ops in the tree zero-initialized, in hope of preventing +future problems, e.g. if struct mtd_req_stats gets extended with write +statistics at some point. + +Signed-off-by: Michał Kępień +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-3-kernel@kempniu.pl +--- + drivers/mtd/inftlcore.c | 6 +++--- + drivers/mtd/mtdswap.c | 6 +++--- + drivers/mtd/nand/onenand/onenand_base.c | 4 ++-- + drivers/mtd/nand/onenand/onenand_bbt.c | 2 +- + drivers/mtd/nand/raw/nand_bbt.c | 8 ++++---- + drivers/mtd/nand/raw/sm_common.c | 2 +- + drivers/mtd/nftlcore.c | 6 +++--- + drivers/mtd/sm_ftl.c | 4 ++-- + drivers/mtd/ssfdc.c | 2 +- + drivers/mtd/tests/nandbiterrs.c | 2 +- + drivers/mtd/tests/oobtest.c | 8 ++++---- + drivers/mtd/tests/readtest.c | 2 +- + fs/jffs2/wbuf.c | 6 +++--- + 13 files changed, 29 insertions(+), 29 deletions(-) + +--- a/drivers/mtd/inftlcore.c ++++ b/drivers/mtd/inftlcore.c +@@ -136,7 +136,7 @@ static void inftl_remove_dev(struct mtd_ + int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -156,7 +156,7 @@ int inftl_read_oob(struct mtd_info *mtd, + int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -176,7 +176,7 @@ int inftl_write_oob(struct mtd_info *mtd + static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, + size_t *retlen, uint8_t *buf, uint8_t *oob) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +--- a/drivers/mtd/mtdswap.c ++++ b/drivers/mtd/mtdswap.c +@@ -323,7 +323,7 @@ static int mtdswap_read_markers(struct m + struct mtdswap_oobdata *data, *data2; + int ret; + loff_t offset; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + offset = mtdswap_eb_offset(d, eb); + +@@ -370,7 +370,7 @@ static int mtdswap_write_marker(struct m + struct mtdswap_oobdata n; + int ret; + loff_t offset; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.ooboffs = 0; + ops.oobbuf = (uint8_t *)&n; +@@ -879,7 +879,7 @@ static unsigned int mtdswap_eblk_passes( + loff_t base, pos; + unsigned int *p1 = (unsigned int *)d->page_buf; + unsigned char *p2 = (unsigned char *)d->oob_buf; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + ops.mode = MTD_OPS_AUTO_OOB; +--- a/drivers/mtd/nand/onenand/onenand_base.c ++++ b/drivers/mtd/nand/onenand/onenand_base.c +@@ -2935,7 +2935,7 @@ static int do_otp_write(struct mtd_info + struct onenand_chip *this = mtd->priv; + unsigned char *pbuf = buf; + int ret; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + /* Force buffer page aligned */ + if (len < mtd->writesize) { +@@ -2977,7 +2977,7 @@ static int do_otp_lock(struct mtd_info * + size_t *retlen, u_char *buf) + { + struct onenand_chip *this = mtd->priv; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + if (FLEXONENAND(this)) { +--- a/drivers/mtd/nand/onenand/onenand_bbt.c ++++ b/drivers/mtd/nand/onenand/onenand_bbt.c +@@ -61,7 +61,7 @@ static int create_bbt(struct mtd_info *m + int startblock; + loff_t from; + size_t readlen, ooblen; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int rgn; + + printk(KERN_INFO "Scanning device for bad blocks\n"); +--- a/drivers/mtd/nand/raw/nand_bbt.c ++++ b/drivers/mtd/nand/raw/nand_bbt.c +@@ -313,7 +313,7 @@ static int scan_read_oob(struct nand_chi + size_t len) + { + struct mtd_info *mtd = nand_to_mtd(this); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res, ret = 0; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -354,7 +354,7 @@ static int scan_write_bbt(struct nand_ch + uint8_t *buf, uint8_t *oob) + { + struct mtd_info *mtd = nand_to_mtd(this); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.ooboffs = 0; +@@ -416,7 +416,7 @@ static int scan_block_fast(struct nand_c + { + struct mtd_info *mtd = nand_to_mtd(this); + +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret, page_offset; + + ops.ooblen = mtd->oobsize; +@@ -756,7 +756,7 @@ static int write_bbt(struct nand_chip *t + uint8_t rcode = td->reserved_block_code; + size_t retlen, len = 0; + loff_t to; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; +--- a/drivers/mtd/nand/raw/sm_common.c ++++ b/drivers/mtd/nand/raw/sm_common.c +@@ -99,7 +99,7 @@ static const struct mtd_ooblayout_ops oo + static int sm_block_markbad(struct nand_chip *chip, loff_t ofs) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct sm_oob oob; + int ret; + +--- a/drivers/mtd/nftlcore.c ++++ b/drivers/mtd/nftlcore.c +@@ -124,7 +124,7 @@ int nftl_read_oob(struct mtd_info *mtd, + size_t *retlen, uint8_t *buf) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -145,7 +145,7 @@ int nftl_write_oob(struct mtd_info *mtd, + size_t *retlen, uint8_t *buf) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +@@ -168,7 +168,7 @@ static int nftl_write(struct mtd_info *m + size_t *retlen, uint8_t *buf, uint8_t *oob) + { + loff_t mask = mtd->writesize - 1; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int res; + + ops.mode = MTD_OPS_PLACE_OOB; +--- a/drivers/mtd/sm_ftl.c ++++ b/drivers/mtd/sm_ftl.c +@@ -239,7 +239,7 @@ static int sm_read_sector(struct sm_ftl + uint8_t *buffer, struct sm_oob *oob) + { + struct mtd_info *mtd = ftl->trans->mtd; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct sm_oob tmp_oob; + int ret = -EIO; + int try = 0; +@@ -323,7 +323,7 @@ static int sm_write_sector(struct sm_ftl + int zone, int block, int boffset, + uint8_t *buffer, struct sm_oob *oob) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + struct mtd_info *mtd = ftl->trans->mtd; + int ret; + +--- a/drivers/mtd/ssfdc.c ++++ b/drivers/mtd/ssfdc.c +@@ -163,7 +163,7 @@ static int read_physical_sector(struct m + /* Read redundancy area (wrapper to MTD_READ_OOB */ + static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret; + + ops.mode = MTD_OPS_RAW; +--- a/drivers/mtd/tests/nandbiterrs.c ++++ b/drivers/mtd/tests/nandbiterrs.c +@@ -99,7 +99,7 @@ static int write_page(int log) + static int rewrite_page(int log) + { + int err = 0; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + if (log) + pr_info("rewrite page\n"); +--- a/drivers/mtd/tests/oobtest.c ++++ b/drivers/mtd/tests/oobtest.c +@@ -56,7 +56,7 @@ static void do_vary_offset(void) + static int write_eraseblock(int ebnum) + { + int i; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + +@@ -165,7 +165,7 @@ static size_t memffshow(loff_t addr, lof + static int verify_eraseblock(int ebnum) + { + int i; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + size_t bitflips; +@@ -260,7 +260,7 @@ static int verify_eraseblock(int ebnum) + + static int verify_eraseblock_in_one_go(int ebnum) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int err = 0; + loff_t addr = (loff_t)ebnum * mtd->erasesize; + size_t len = mtd->oobavail * pgcnt; +@@ -338,7 +338,7 @@ static int __init mtd_oobtest_init(void) + int err = 0; + unsigned int i; + uint64_t tmp; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + loff_t addr = 0, addr0; + + printk(KERN_INFO "\n"); +--- a/drivers/mtd/tests/readtest.c ++++ b/drivers/mtd/tests/readtest.c +@@ -47,7 +47,7 @@ static int read_eraseblock_by_page(int e + err = ret; + } + if (mtd->oobsize) { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_PLACE_OOB; + ops.len = 0; +--- a/fs/jffs2/wbuf.c ++++ b/fs/jffs2/wbuf.c +@@ -1035,7 +1035,7 @@ int jffs2_check_oob_empty(struct jffs2_s + { + int i, ret; + int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + + ops.mode = MTD_OPS_AUTO_OOB; + ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; +@@ -1076,7 +1076,7 @@ int jffs2_check_oob_empty(struct jffs2_s + int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, + struct jffs2_eraseblock *jeb) + { +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); + + ops.mode = MTD_OPS_AUTO_OOB; +@@ -1101,7 +1101,7 @@ int jffs2_write_nand_cleanmarker(struct + struct jffs2_eraseblock *jeb) + { + int ret; +- struct mtd_oob_ops ops; ++ struct mtd_oob_ops ops = { }; + int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); + + ops.mode = MTD_OPS_AUTO_OOB; diff --git a/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch b/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch new file mode 100644 index 00000000000..f2f45eb7bc7 --- /dev/null +++ b/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch @@ -0,0 +1,172 @@ +From 2ed18d818d1f7492172f8dd5904344c7d367e8ed Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= +Date: Wed, 29 Jun 2022 14:57:36 +0200 +Subject: [PATCH 3/4] mtd: add ECC error accounting for each read request +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend struct mtd_req_stats with two new fields holding the number of +corrected bitflips and uncorrectable errors detected during a read +operation. This is a prerequisite for ultimately passing those counters +to user space, where they can be useful to applications for making +better-informed choices about moving data around. + +Unlike 'max_bitflips' (which is set - in a common code path - to the +return value of a function called while the MTD device's mutex is held), +these counters have to be maintained in each MTD driver which defines +the '_read_oob' callback because the statistics need to be calculated +while the MTD device's mutex is held. + +Suggested-by: Boris Brezillon +Signed-off-by: Michał Kępień +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-4-kernel@kempniu.pl +--- + drivers/mtd/devices/docg3.c | 8 ++++++++ + drivers/mtd/nand/onenand/onenand_base.c | 12 ++++++++++++ + drivers/mtd/nand/raw/nand_base.c | 10 ++++++++++ + drivers/mtd/nand/spi/core.c | 10 ++++++++++ + include/linux/mtd/mtd.h | 2 ++ + 5 files changed, 42 insertions(+) + +--- a/drivers/mtd/devices/docg3.c ++++ b/drivers/mtd/devices/docg3.c +@@ -871,6 +871,7 @@ static int doc_read_oob(struct mtd_info + u8 *buf = ops->datbuf; + size_t len, ooblen, nbdata, nboob; + u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; ++ struct mtd_ecc_stats old_stats; + int max_bitflips = 0; + + if (buf) +@@ -895,6 +896,7 @@ static int doc_read_oob(struct mtd_info + ret = 0; + skip = from % DOC_LAYOUT_PAGE_SIZE; + mutex_lock(&docg3->cascade->lock); ++ old_stats = mtd->ecc_stats; + while (ret >= 0 && (len > 0 || ooblen > 0)) { + calc_block_sector(from - skip, &block0, &block1, &page, &ofs, + docg3->reliable); +@@ -966,6 +968,12 @@ static int doc_read_oob(struct mtd_info + } + + out: ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } + mutex_unlock(&docg3->cascade->lock); + return ret; + err_in_read: +--- a/drivers/mtd/nand/onenand/onenand_base.c ++++ b/drivers/mtd/nand/onenand/onenand_base.c +@@ -1440,6 +1440,7 @@ static int onenand_read_oob(struct mtd_i + struct mtd_oob_ops *ops) + { + struct onenand_chip *this = mtd->priv; ++ struct mtd_ecc_stats old_stats; + int ret; + + switch (ops->mode) { +@@ -1453,12 +1454,23 @@ static int onenand_read_oob(struct mtd_i + } + + onenand_get_device(mtd, FL_READING); ++ ++ old_stats = mtd->ecc_stats; ++ + if (ops->datbuf) + ret = ONENAND_IS_4KB_PAGE(this) ? + onenand_mlc_read_ops_nolock(mtd, from, ops) : + onenand_read_ops_nolock(mtd, from, ops); + else + ret = onenand_read_oob_nolock(mtd, from, ops); ++ ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + onenand_release_device(mtd); + + return ret; +--- a/drivers/mtd/nand/raw/nand_base.c ++++ b/drivers/mtd/nand/raw/nand_base.c +@@ -3815,6 +3815,7 @@ static int nand_read_oob(struct mtd_info + struct mtd_oob_ops *ops) + { + struct nand_chip *chip = mtd_to_nand(mtd); ++ struct mtd_ecc_stats old_stats; + int ret; + + ops->retlen = 0; +@@ -3826,11 +3827,20 @@ static int nand_read_oob(struct mtd_info + + nand_get_device(chip); + ++ old_stats = mtd->ecc_stats; ++ + if (!ops->datbuf) + ret = nand_do_read_oob(chip, from, ops); + else + ret = nand_do_read_ops(chip, from, ops); + ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + nand_release_device(chip); + return ret; + } +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -629,6 +629,7 @@ static int spinand_mtd_read(struct mtd_i + { + struct spinand_device *spinand = mtd_to_spinand(mtd); + struct nand_device *nand = mtd_to_nanddev(mtd); ++ struct mtd_ecc_stats old_stats; + unsigned int max_bitflips = 0; + struct nand_io_iter iter; + bool disable_ecc = false; +@@ -640,6 +641,8 @@ static int spinand_mtd_read(struct mtd_i + + mutex_lock(&spinand->lock); + ++ old_stats = mtd->ecc_stats; ++ + nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) { + if (disable_ecc) + iter.req.mode = MTD_OPS_RAW; +@@ -662,6 +665,13 @@ static int spinand_mtd_read(struct mtd_i + ops->oobretlen += iter.req.ooblen; + } + ++ if (ops->stats) { ++ ops->stats->uncorrectable_errors += ++ mtd->ecc_stats.failed - old_stats.failed; ++ ops->stats->corrected_bitflips += ++ mtd->ecc_stats.corrected - old_stats.corrected; ++ } ++ + mutex_unlock(&spinand->lock); + + if (ecc_failed && !ret) +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -41,6 +41,8 @@ struct mtd_erase_region_info { + }; + + struct mtd_req_stats { ++ unsigned int uncorrectable_errors; ++ unsigned int corrected_bitflips; + unsigned int max_bitflips; + }; + diff --git a/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch b/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch new file mode 100644 index 00000000000..182e4f6ab56 --- /dev/null +++ b/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch @@ -0,0 +1,321 @@ +From 2c9745d36e04ac27161acd78514f647b9b587ad4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= +Date: Wed, 29 Jun 2022 14:57:37 +0200 +Subject: [PATCH 4/4] mtdchar: add MEMREAD ioctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +User-space applications making use of MTD devices via /dev/mtd* +character devices currently have limited capabilities for reading data: + + - only deprecated methods of accessing OOB layout information exist, + + - there is no way to explicitly specify MTD operation mode to use; it + is auto-selected based on the MTD file mode (MTD_FILE_MODE_*) set + for the character device; in particular, this prevents using + MTD_OPS_AUTO_OOB for reads, + + - all existing user-space interfaces which cause mtd_read() or + mtd_read_oob() to be called (via mtdchar_read() and + mtdchar_read_oob(), respectively) return success even when those + functions return -EUCLEAN or -EBADMSG; this renders user-space + applications using these interfaces unaware of any corrected + bitflips or uncorrectable ECC errors detected during reads. + +Note that the existing MEMWRITE ioctl allows the MTD operation mode to +be explicitly set, allowing user-space applications to write page data +and OOB data without requiring them to know anything about the OOB +layout of the MTD device they are writing to (MTD_OPS_AUTO_OOB). Also, +the MEMWRITE ioctl does not mangle the return value of mtd_write_oob(). + +Add a new ioctl, MEMREAD, which addresses the above issues. It is +intended to be a read-side counterpart of the existing MEMWRITE ioctl. +Similarly to the latter, the read operation is performed in a loop which +processes at most mtd->erasesize bytes in each iteration. This is done +to prevent unbounded memory allocations caused by calling kmalloc() with +the 'size' argument taken directly from the struct mtd_read_req provided +by user space. However, the new ioctl is implemented so that the values +it returns match those that would have been returned if just a single +mtd_read_oob() call was issued to handle the entire read operation in +one go. + +Note that while just returning -EUCLEAN or -EBADMSG to user space would +already be a valid and useful indication of the ECC algorithm detecting +errors during a read operation, that signal would not be granular enough +to cover all use cases. For example, knowing the maximum number of +bitflips detected in a single ECC step during a read operation performed +on a given page may be useful when dealing with an MTD partition whose +ECC layout varies across pages (e.g. a partition consisting of a +bootloader area using a "custom" ECC layout followed by data pages using +a "standard" ECC layout). To address that, include ECC statistics in +the structure returned to user space by the new MEMREAD ioctl. + +Link: https://www.infradead.org/pipermail/linux-mtd/2016-April/067085.html + +Suggested-by: Boris Brezillon +Signed-off-by: Michał Kępień +Acked-by: Richard Weinberger +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-5-kernel@kempniu.pl +--- + drivers/mtd/mtdchar.c | 139 +++++++++++++++++++++++++++++++++++++ + include/uapi/mtd/mtd-abi.h | 64 +++++++++++++++-- + 2 files changed, 198 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/mtdchar.c ++++ b/drivers/mtd/mtdchar.c +@@ -621,6 +621,137 @@ static int mtdchar_write_ioctl(struct mt + return ret; + } + ++static int mtdchar_read_ioctl(struct mtd_info *mtd, ++ struct mtd_read_req __user *argp) ++{ ++ struct mtd_info *master = mtd_get_master(mtd); ++ struct mtd_read_req req; ++ void __user *usr_data, *usr_oob; ++ uint8_t *datbuf = NULL, *oobbuf = NULL; ++ size_t datbuf_len, oobbuf_len; ++ size_t orig_len, orig_ooblen; ++ int ret = 0; ++ ++ if (copy_from_user(&req, argp, sizeof(req))) ++ return -EFAULT; ++ ++ orig_len = req.len; ++ orig_ooblen = req.ooblen; ++ ++ usr_data = (void __user *)(uintptr_t)req.usr_data; ++ usr_oob = (void __user *)(uintptr_t)req.usr_oob; ++ ++ if (!master->_read_oob) ++ return -EOPNOTSUPP; ++ ++ if (!usr_data) ++ req.len = 0; ++ ++ if (!usr_oob) ++ req.ooblen = 0; ++ ++ req.ecc_stats.uncorrectable_errors = 0; ++ req.ecc_stats.corrected_bitflips = 0; ++ req.ecc_stats.max_bitflips = 0; ++ ++ req.len &= 0xffffffff; ++ req.ooblen &= 0xffffffff; ++ ++ if (req.start + req.len > mtd->size) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ datbuf_len = min_t(size_t, req.len, mtd->erasesize); ++ if (datbuf_len > 0) { ++ datbuf = kvmalloc(datbuf_len, GFP_KERNEL); ++ if (!datbuf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ oobbuf_len = min_t(size_t, req.ooblen, mtd->erasesize); ++ if (oobbuf_len > 0) { ++ oobbuf = kvmalloc(oobbuf_len, GFP_KERNEL); ++ if (!oobbuf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ } ++ ++ while (req.len > 0 || (!usr_data && req.ooblen > 0)) { ++ struct mtd_req_stats stats; ++ struct mtd_oob_ops ops = { ++ .mode = req.mode, ++ .len = min_t(size_t, req.len, datbuf_len), ++ .ooblen = min_t(size_t, req.ooblen, oobbuf_len), ++ .datbuf = datbuf, ++ .oobbuf = oobbuf, ++ .stats = &stats, ++ }; ++ ++ /* ++ * Shorten non-page-aligned, eraseblock-sized reads so that the ++ * read ends on an eraseblock boundary. This is necessary in ++ * order to prevent OOB data for some pages from being ++ * duplicated in the output of non-page-aligned reads requiring ++ * multiple mtd_read_oob() calls to be completed. ++ */ ++ if (ops.len == mtd->erasesize) ++ ops.len -= mtd_mod_by_ws(req.start + ops.len, mtd); ++ ++ ret = mtd_read_oob(mtd, (loff_t)req.start, &ops); ++ ++ req.ecc_stats.uncorrectable_errors += ++ stats.uncorrectable_errors; ++ req.ecc_stats.corrected_bitflips += stats.corrected_bitflips; ++ req.ecc_stats.max_bitflips = ++ max(req.ecc_stats.max_bitflips, stats.max_bitflips); ++ ++ if (ret && !mtd_is_bitflip_or_eccerr(ret)) ++ break; ++ ++ if (copy_to_user(usr_data, ops.datbuf, ops.retlen) || ++ copy_to_user(usr_oob, ops.oobbuf, ops.oobretlen)) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ req.start += ops.retlen; ++ req.len -= ops.retlen; ++ usr_data += ops.retlen; ++ ++ req.ooblen -= ops.oobretlen; ++ usr_oob += ops.oobretlen; ++ } ++ ++ /* ++ * As multiple iterations of the above loop (and therefore multiple ++ * mtd_read_oob() calls) may be necessary to complete the read request, ++ * adjust the final return code to ensure it accounts for all detected ++ * ECC errors. ++ */ ++ if (!ret || mtd_is_bitflip(ret)) { ++ if (req.ecc_stats.uncorrectable_errors > 0) ++ ret = -EBADMSG; ++ else if (req.ecc_stats.corrected_bitflips > 0) ++ ret = -EUCLEAN; ++ } ++ ++out: ++ req.len = orig_len - req.len; ++ req.ooblen = orig_ooblen - req.ooblen; ++ ++ if (copy_to_user(argp, &req, sizeof(req))) ++ ret = -EFAULT; ++ ++ kvfree(datbuf); ++ kvfree(oobbuf); ++ ++ return ret; ++} ++ + static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) + { + struct mtd_file_info *mfi = file->private_data; +@@ -643,6 +774,7 @@ static int mtdchar_ioctl(struct file *fi + case MEMGETINFO: + case MEMREADOOB: + case MEMREADOOB64: ++ case MEMREAD: + case MEMISLOCKED: + case MEMGETOOBSEL: + case MEMGETBADBLOCK: +@@ -817,6 +949,13 @@ static int mtdchar_ioctl(struct file *fi + break; + } + ++ case MEMREAD: ++ { ++ ret = mtdchar_read_ioctl(mtd, ++ (struct mtd_read_req __user *)arg); ++ break; ++ } ++ + case MEMLOCK: + { + struct erase_info_user einfo; +--- a/include/uapi/mtd/mtd-abi.h ++++ b/include/uapi/mtd/mtd-abi.h +@@ -55,9 +55,9 @@ struct mtd_oob_buf64 { + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * +- * These modes can be passed to ioctl(MEMWRITE) and are also used internally. +- * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. +- * %MTD_FILE_MODE_RAW. ++ * These modes can be passed to ioctl(MEMWRITE) and ioctl(MEMREAD); they are ++ * also used internally. See notes on "MTD file modes" for discussion on ++ * %MTD_OPS_RAW vs. %MTD_FILE_MODE_RAW. + */ + enum { + MTD_OPS_PLACE_OOB = 0, +@@ -91,6 +91,53 @@ struct mtd_write_req { + __u8 padding[7]; + }; + ++/** ++ * struct mtd_read_req_ecc_stats - ECC statistics for a read operation ++ * ++ * @uncorrectable_errors: the number of uncorrectable errors that happened ++ * during the read operation ++ * @corrected_bitflips: the number of bitflips corrected during the read ++ * operation ++ * @max_bitflips: the maximum number of bitflips detected in any single ECC ++ * step for the data read during the operation; this information ++ * can be used to decide whether the data stored in a specific ++ * region of the MTD device should be moved somewhere else to ++ * avoid data loss. ++ */ ++struct mtd_read_req_ecc_stats { ++ __u32 uncorrectable_errors; ++ __u32 corrected_bitflips; ++ __u32 max_bitflips; ++}; ++ ++/** ++ * struct mtd_read_req - data structure for requesting a read operation ++ * ++ * @start: start address ++ * @len: length of data buffer (only lower 32 bits are used) ++ * @ooblen: length of OOB buffer (only lower 32 bits are used) ++ * @usr_data: user-provided data buffer ++ * @usr_oob: user-provided OOB buffer ++ * @mode: MTD mode (see "MTD operation modes") ++ * @padding: reserved, must be set to 0 ++ * @ecc_stats: ECC statistics for the read operation ++ * ++ * This structure supports ioctl(MEMREAD) operations, allowing data and/or OOB ++ * reads in various modes. To read from OOB-only, set @usr_data == NULL, and to ++ * read data-only, set @usr_oob == NULL. However, setting both @usr_data and ++ * @usr_oob to NULL is not allowed. ++ */ ++struct mtd_read_req { ++ __u64 start; ++ __u64 len; ++ __u64 ooblen; ++ __u64 usr_data; ++ __u64 usr_oob; ++ __u8 mode; ++ __u8 padding[7]; ++ struct mtd_read_req_ecc_stats ecc_stats; ++}; ++ + #define MTD_ABSENT 0 + #define MTD_RAM 1 + #define MTD_ROM 2 +@@ -207,6 +254,12 @@ struct otp_info { + #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) + /* Erase a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ + #define OTPERASE _IOW('M', 25, struct otp_info) ++/* ++ * Most generic read interface; can read in-band and/or out-of-band in various ++ * modes (see "struct mtd_read_req"). This ioctl is not supported for flashes ++ * without OOB, e.g., NOR flash. ++ */ ++#define MEMREAD _IOWR('M', 26, struct mtd_read_req) + + /* + * Obsolete legacy interface. Keep it in order not to break userspace +@@ -270,8 +323,9 @@ struct mtd_ecc_stats { + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode +- * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is +- * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). ++ * (e.g., when using ioctl(MEMWRITE) or ioctl(MEMREAD)), but in some cases, the ++ * MTD_FILE_MODE is used out of necessity (e.g., `write()', ++ * ioctl(MEMWRITEOOB64)). + */ + enum mtd_file_modes { + MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, diff --git a/target/linux/generic/backport-6.1/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch b/target/linux/generic/backport-6.1/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch new file mode 100644 index 00000000000..7dbc2717250 --- /dev/null +++ b/target/linux/generic/backport-6.1/423-v6.3-mtd-spinand-macronix-use-scratch-buffer-for-DMA-oper.patch @@ -0,0 +1,35 @@ +From ebed787a0becb9354f0a23620a5130cccd6c730c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 19 Jan 2023 03:45:43 +0000 +Subject: [PATCH] mtd: spinand: macronix: use scratch buffer for DMA operation + +The mx35lf1ge4ab_get_eccsr() function uses an SPI DMA operation to +read the eccsr, hence the buffer should not be on stack. Since commit +380583227c0c7f ("spi: spi-mem: Add extra sanity checks on the op param") +the kernel emmits a warning and blocks such operations. + +Use the scratch buffer to get eccsr instead of trying to directly read +into a stack-allocated variable. + +Signed-off-by: Daniel Golle +Reviewed-by: Dhruva Gole +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/Y8i85zM0u4XdM46z@makrotopia.org +--- + drivers/mtd/nand/spi/macronix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/nand/spi/macronix.c ++++ b/drivers/mtd/nand/spi/macronix.c +@@ -83,9 +83,10 @@ static int mx35lf1ge4ab_ecc_get_status(s + * in order to avoid forcing the wear-leveling layer to move + * data around if it's not necessary. + */ +- if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr)) ++ if (mx35lf1ge4ab_get_eccsr(spinand, spinand->scratchbuf)) + return nanddev_get_ecc_conf(nand)->strength; + ++ eccsr = *spinand->scratchbuf; + if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || + !eccsr)) + return nanddev_get_ecc_conf(nand)->strength; diff --git a/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch new file mode 100644 index 00000000000..2d89a5db126 --- /dev/null +++ b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch @@ -0,0 +1,47 @@ +From 281f7a6c1a33fffcde32001bacbb4f672140fbf9 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Wed, 8 Mar 2023 09:20:21 +0100 +Subject: [PATCH] mtd: core: prepare mtd_otp_nvmem_add() to handle + -EPROBE_DEFER + +NVMEM soon will get the ability for nvmem layouts and these might +not be ready when nvmem_register() is called and thus it might +return -EPROBE_DEFER. Don't print the error message in this case. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc +--- + drivers/mtd/mtdcore.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -960,8 +960,8 @@ static int mtd_otp_nvmem_add(struct mtd_ + nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, + mtd_nvmem_user_otp_reg_read); + if (IS_ERR(nvmem)) { +- dev_err(dev, "Failed to register OTP NVMEM device\n"); +- return PTR_ERR(nvmem); ++ err = PTR_ERR(nvmem); ++ goto err; + } + mtd->otp_user_nvmem = nvmem; + } +@@ -978,7 +978,6 @@ static int mtd_otp_nvmem_add(struct mtd_ + nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, + mtd_nvmem_fact_otp_reg_read); + if (IS_ERR(nvmem)) { +- dev_err(dev, "Failed to register OTP NVMEM device\n"); + err = PTR_ERR(nvmem); + goto err; + } +@@ -991,7 +990,7 @@ static int mtd_otp_nvmem_add(struct mtd_ + err: + if (mtd->otp_user_nvmem) + nvmem_unregister(mtd->otp_user_nvmem); +- return err; ++ return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n"); + } + + /** diff --git a/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch b/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch new file mode 100644 index 00000000000..9e383de92cd --- /dev/null +++ b/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch @@ -0,0 +1,165 @@ +From 8610037e8106b48c79cfe0afb92b2b2466e51c3d Mon Sep 17 00:00:00 2001 +From: Joe Damato +Date: Tue, 1 Mar 2022 23:55:47 -0800 +Subject: [PATCH] page_pool: Add allocation stats + +Add per-pool statistics counters for the allocation path of a page pool. +These stats are incremented in softirq context, so no locking or per-cpu +variables are needed. + +This code is disabled by default and a kernel config option is provided for +users who wish to enable them. + +The statistics added are: + - fast: successful fast path allocations + - slow: slow path order-0 allocations + - slow_high_order: slow path high order allocations + - empty: ptr ring is empty, so a slow path allocation was forced. + - refill: an allocation which triggered a refill of the cache + - waive: pages obtained from the ptr ring that cannot be added to + the cache due to a NUMA mismatch. + +Signed-off-by: Joe Damato +Acked-by: Jesper Dangaard Brouer +Reviewed-by: Ilias Apalodimas +Signed-off-by: David S. Miller +--- + include/net/page_pool.h | 18 ++++++++++++++++++ + net/Kconfig | 13 +++++++++++++ + net/core/page_pool.c | 24 ++++++++++++++++++++---- + 3 files changed, 51 insertions(+), 4 deletions(-) + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -82,6 +82,19 @@ struct page_pool_params { + unsigned int offset; /* DMA addr offset */ + }; + ++#ifdef CONFIG_PAGE_POOL_STATS ++struct page_pool_alloc_stats { ++ u64 fast; /* fast path allocations */ ++ u64 slow; /* slow-path order 0 allocations */ ++ u64 slow_high_order; /* slow-path high order allocations */ ++ u64 empty; /* failed refills due to empty ptr ring, forcing ++ * slow path allocation ++ */ ++ u64 refill; /* allocations via successful refill */ ++ u64 waive; /* failed refills due to numa zone mismatch */ ++}; ++#endif ++ + struct page_pool { + struct page_pool_params p; + +@@ -132,6 +145,11 @@ struct page_pool { + refcount_t user_cnt; + + u64 destroy_cnt; ++ ++#ifdef CONFIG_PAGE_POOL_STATS ++ /* these stats are incremented while in softirq context */ ++ struct page_pool_alloc_stats alloc_stats; ++#endif + }; + + struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -434,6 +434,19 @@ config NET_DEVLINK + config PAGE_POOL + bool + ++config PAGE_POOL_STATS ++ default n ++ bool "Page pool stats" ++ depends on PAGE_POOL ++ help ++ Enable page pool statistics to track page allocation and recycling ++ in page pools. This option incurs additional CPU cost in allocation ++ and recycle paths and additional memory cost to store the statistics. ++ These statistics are only available if this option is enabled and if ++ the driver using the page pool supports exporting this data. ++ ++ If unsure, say N. ++ + config FAILOVER + tristate "Generic failover module" + help +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -26,6 +26,13 @@ + + #define BIAS_MAX LONG_MAX + ++#ifdef CONFIG_PAGE_POOL_STATS ++/* alloc_stat_inc is intended to be used in softirq context */ ++#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) ++#else ++#define alloc_stat_inc(pool, __stat) ++#endif ++ + static int page_pool_init(struct page_pool *pool, + const struct page_pool_params *params) + { +@@ -117,8 +124,10 @@ static struct page *page_pool_refill_all + int pref_nid; /* preferred NUMA node */ + + /* Quicker fallback, avoid locks when ring is empty */ +- if (__ptr_ring_empty(r)) ++ if (__ptr_ring_empty(r)) { ++ alloc_stat_inc(pool, empty); + return NULL; ++ } + + /* Softirq guarantee CPU and thus NUMA node is stable. This, + * assumes CPU refilling driver RX-ring will also run RX-NAPI. +@@ -148,14 +157,17 @@ static struct page *page_pool_refill_all + * This limit stress on page buddy alloactor. + */ + page_pool_return_page(pool, page); ++ alloc_stat_inc(pool, waive); + page = NULL; + break; + } + } while (pool->alloc.count < PP_ALLOC_CACHE_REFILL); + + /* Return last page */ +- if (likely(pool->alloc.count > 0)) ++ if (likely(pool->alloc.count > 0)) { + page = pool->alloc.cache[--pool->alloc.count]; ++ alloc_stat_inc(pool, refill); ++ } + + spin_unlock(&r->consumer_lock); + return page; +@@ -170,6 +182,7 @@ static struct page *__page_pool_get_cach + if (likely(pool->alloc.count)) { + /* Fast-path */ + page = pool->alloc.cache[--pool->alloc.count]; ++ alloc_stat_inc(pool, fast); + } else { + page = page_pool_refill_alloc_cache(pool); + } +@@ -241,6 +254,7 @@ static struct page *__page_pool_alloc_pa + return NULL; + } + ++ alloc_stat_inc(pool, slow_high_order); + page_pool_set_pp_info(pool, page); + + /* Track how many pages are held 'in-flight' */ +@@ -295,10 +309,12 @@ static struct page *__page_pool_alloc_pa + } + + /* Return last page */ +- if (likely(pool->alloc.count > 0)) ++ if (likely(pool->alloc.count > 0)) { + page = pool->alloc.cache[--pool->alloc.count]; +- else ++ alloc_stat_inc(pool, slow); ++ } else { + page = NULL; ++ } + + /* When page just alloc'ed is should/must have refcnt 1. */ + return page; diff --git a/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch b/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch new file mode 100644 index 00000000000..fb11f0035f8 --- /dev/null +++ b/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch @@ -0,0 +1,140 @@ +From ad6fa1e1ab1b8164f1ba296b1b4dc556a483bcad Mon Sep 17 00:00:00 2001 +From: Joe Damato +Date: Tue, 1 Mar 2022 23:55:48 -0800 +Subject: [PATCH 2/3] page_pool: Add recycle stats + +Add per-cpu stats tracking page pool recycling events: + - cached: recycling placed page in the page pool cache + - cache_full: page pool cache was full + - ring: page placed into the ptr ring + - ring_full: page released from page pool because the ptr ring was full + - released_refcnt: page released (and not recycled) because refcnt > 1 + +Signed-off-by: Joe Damato +Acked-by: Jesper Dangaard Brouer +Reviewed-by: Ilias Apalodimas +Signed-off-by: David S. Miller +--- + include/net/page_pool.h | 16 ++++++++++++++++ + net/core/page_pool.c | 30 ++++++++++++++++++++++++++++-- + 2 files changed, 44 insertions(+), 2 deletions(-) + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -93,6 +93,18 @@ struct page_pool_alloc_stats { + u64 refill; /* allocations via successful refill */ + u64 waive; /* failed refills due to numa zone mismatch */ + }; ++ ++struct page_pool_recycle_stats { ++ u64 cached; /* recycling placed page in the cache. */ ++ u64 cache_full; /* cache was full */ ++ u64 ring; /* recycling placed page back into ptr ring */ ++ u64 ring_full; /* page was released from page-pool because ++ * PTR ring was full. ++ */ ++ u64 released_refcnt; /* page released because of elevated ++ * refcnt ++ */ ++}; + #endif + + struct page_pool { +@@ -136,6 +148,10 @@ struct page_pool { + */ + struct ptr_ring ring; + ++#ifdef CONFIG_PAGE_POOL_STATS ++ /* recycle stats are per-cpu to avoid locking */ ++ struct page_pool_recycle_stats __percpu *recycle_stats; ++#endif + atomic_t pages_state_release_cnt; + + /* A page_pool is strictly tied to a single RX-queue being +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -29,8 +29,15 @@ + #ifdef CONFIG_PAGE_POOL_STATS + /* alloc_stat_inc is intended to be used in softirq context */ + #define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) ++/* recycle_stat_inc is safe to use when preemption is possible. */ ++#define recycle_stat_inc(pool, __stat) \ ++ do { \ ++ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ ++ this_cpu_inc(s->__stat); \ ++ } while (0) + #else + #define alloc_stat_inc(pool, __stat) ++#define recycle_stat_inc(pool, __stat) + #endif + + static int page_pool_init(struct page_pool *pool, +@@ -80,6 +87,12 @@ static int page_pool_init(struct page_po + pool->p.flags & PP_FLAG_PAGE_FRAG) + return -EINVAL; + ++#ifdef CONFIG_PAGE_POOL_STATS ++ pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); ++ if (!pool->recycle_stats) ++ return -ENOMEM; ++#endif ++ + if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) + return -ENOMEM; + +@@ -412,7 +425,12 @@ static bool page_pool_recycle_in_ring(st + else + ret = ptr_ring_produce_bh(&pool->ring, page); + +- return (ret == 0) ? true : false; ++ if (!ret) { ++ recycle_stat_inc(pool, ring); ++ return true; ++ } ++ ++ return false; + } + + /* Only allow direct recycling in special circumstances, into the +@@ -423,11 +441,14 @@ static bool page_pool_recycle_in_ring(st + static bool page_pool_recycle_in_cache(struct page *page, + struct page_pool *pool) + { +- if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) ++ if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) { ++ recycle_stat_inc(pool, cache_full); + return false; ++ } + + /* Caller MUST have verified/know (page_ref_count(page) == 1) */ + pool->alloc.cache[pool->alloc.count++] = page; ++ recycle_stat_inc(pool, cached); + return true; + } + +@@ -482,6 +503,7 @@ __page_pool_put_page(struct page_pool *p + * doing refcnt based recycle tricks, meaning another process + * will be invoking put_page. + */ ++ recycle_stat_inc(pool, released_refcnt); + /* Do not replace this with page_pool_return_page() */ + page_pool_release_page(pool, page); + put_page(page); +@@ -495,6 +517,7 @@ void page_pool_put_page(struct page_pool + page = __page_pool_put_page(pool, page, dma_sync_size, allow_direct); + if (page && !page_pool_recycle_in_ring(pool, page)) { + /* Cache full, fallback to free pages */ ++ recycle_stat_inc(pool, ring_full); + page_pool_return_page(pool, page); + } + } +@@ -641,6 +664,9 @@ static void page_pool_free(struct page_p + if (pool->p.flags & PP_FLAG_DMA_MAP) + put_device(pool->p.dev); + ++#ifdef CONFIG_PAGE_POOL_STATS ++ free_percpu(pool->recycle_stats); ++#endif + kfree(pool); + } + diff --git a/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch b/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch new file mode 100644 index 00000000000..41188fb7f27 --- /dev/null +++ b/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch @@ -0,0 +1,77 @@ +From 6b95e3388b1ea0ca63500c5a6e39162dbf828433 Mon Sep 17 00:00:00 2001 +From: Joe Damato +Date: Tue, 1 Mar 2022 23:55:49 -0800 +Subject: [PATCH 3/3] page_pool: Add function to batch and return stats + +Adds a function page_pool_get_stats which can be used by drivers to obtain +stats for a specified page_pool. + +Signed-off-by: Joe Damato +Acked-by: Jesper Dangaard Brouer +Reviewed-by: Ilias Apalodimas +Signed-off-by: David S. Miller +--- + include/net/page_pool.h | 17 +++++++++++++++++ + net/core/page_pool.c | 25 +++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -105,6 +105,23 @@ struct page_pool_recycle_stats { + * refcnt + */ + }; ++ ++/* This struct wraps the above stats structs so users of the ++ * page_pool_get_stats API can pass a single argument when requesting the ++ * stats for the page pool. ++ */ ++struct page_pool_stats { ++ struct page_pool_alloc_stats alloc_stats; ++ struct page_pool_recycle_stats recycle_stats; ++}; ++ ++/* ++ * Drivers that wish to harvest page pool stats and report them to users ++ * (perhaps via ethtool, debugfs, or another mechanism) can allocate a ++ * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool. ++ */ ++bool page_pool_get_stats(struct page_pool *pool, ++ struct page_pool_stats *stats); + #endif + + struct page_pool { +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -35,6 +35,31 @@ + struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ + this_cpu_inc(s->__stat); \ + } while (0) ++ ++bool page_pool_get_stats(struct page_pool *pool, ++ struct page_pool_stats *stats) ++{ ++ int cpu = 0; ++ ++ if (!stats) ++ return false; ++ ++ memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); ++ ++ for_each_possible_cpu(cpu) { ++ const struct page_pool_recycle_stats *pcpu = ++ per_cpu_ptr(pool->recycle_stats, cpu); ++ ++ stats->recycle_stats.cached += pcpu->cached; ++ stats->recycle_stats.cache_full += pcpu->cache_full; ++ stats->recycle_stats.ring += pcpu->ring; ++ stats->recycle_stats.ring_full += pcpu->ring_full; ++ stats->recycle_stats.released_refcnt += pcpu->released_refcnt; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL(page_pool_get_stats); + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch b/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch new file mode 100644 index 00000000000..6ae3fb71331 --- /dev/null +++ b/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch @@ -0,0 +1,55 @@ +From 590032a4d2133ecc10d3078a8db1d85a4842f12c Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 11 Apr 2022 16:05:26 +0200 +Subject: [PATCH] page_pool: Add recycle stats to page_pool_put_page_bulk + +Add missing recycle stats to page_pool_put_page_bulk routine. + +Reviewed-by: Joe Damato +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Ilias Apalodimas +Link: https://lore.kernel.org/r/3712178b51c007cfaed910ea80e68f00c916b1fa.1649685634.git.lorenzo@kernel.org +Signed-off-by: Paolo Abeni +--- + net/core/page_pool.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -36,6 +36,12 @@ + this_cpu_inc(s->__stat); \ + } while (0) + ++#define recycle_stat_add(pool, __stat, val) \ ++ do { \ ++ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ ++ this_cpu_add(s->__stat, val); \ ++ } while (0) ++ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats) + { +@@ -63,6 +69,7 @@ EXPORT_SYMBOL(page_pool_get_stats); + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) ++#define recycle_stat_add(pool, __stat, val) + #endif + + static int page_pool_init(struct page_pool *pool, +@@ -569,9 +576,13 @@ void page_pool_put_page_bulk(struct page + /* Bulk producer into ptr_ring page_pool cache */ + page_pool_ring_lock(pool); + for (i = 0; i < bulk_len; i++) { +- if (__ptr_ring_produce(&pool->ring, data[i])) +- break; /* ring full */ ++ if (__ptr_ring_produce(&pool->ring, data[i])) { ++ /* ring full */ ++ recycle_stat_inc(pool, ring_full); ++ break; ++ } + } ++ recycle_stat_add(pool, ring, i); + page_pool_ring_unlock(pool); + + /* Hopefully all pages was return into ptr_ring */ diff --git a/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch b/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch new file mode 100644 index 00000000000..e5cf91ceeed --- /dev/null +++ b/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch @@ -0,0 +1,147 @@ +From f3c5264f452a5b0ac1de1f2f657efbabdea3c76a Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 12 Apr 2022 18:31:58 +0200 +Subject: [PATCH] net: page_pool: introduce ethtool stats + +Introduce page_pool APIs to report stats through ethtool and reduce +duplicated code in each driver. + +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Jakub Kicinski +Reviewed-by: Ilias Apalodimas +Signed-off-by: David S. Miller +--- + include/net/page_pool.h | 21 ++++++++++++++ + net/core/page_pool.c | 63 ++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 83 insertions(+), 1 deletion(-) + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -115,6 +115,10 @@ struct page_pool_stats { + struct page_pool_recycle_stats recycle_stats; + }; + ++int page_pool_ethtool_stats_get_count(void); ++u8 *page_pool_ethtool_stats_get_strings(u8 *data); ++u64 *page_pool_ethtool_stats_get(u64 *data, void *stats); ++ + /* + * Drivers that wish to harvest page pool stats and report them to users + * (perhaps via ethtool, debugfs, or another mechanism) can allocate a +@@ -122,6 +126,23 @@ struct page_pool_stats { + */ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats); ++#else ++ ++static inline int page_pool_ethtool_stats_get_count(void) ++{ ++ return 0; ++} ++ ++static inline u8 *page_pool_ethtool_stats_get_strings(u8 *data) ++{ ++ return data; ++} ++ ++static inline u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) ++{ ++ return data; ++} ++ + #endif + + struct page_pool { +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -18,6 +18,7 @@ + #include + #include /* for __put_page() */ + #include ++#include + + #include + +@@ -42,6 +43,20 @@ + this_cpu_add(s->__stat, val); \ + } while (0) + ++static const char pp_stats[][ETH_GSTRING_LEN] = { ++ "rx_pp_alloc_fast", ++ "rx_pp_alloc_slow", ++ "rx_pp_alloc_slow_ho", ++ "rx_pp_alloc_empty", ++ "rx_pp_alloc_refill", ++ "rx_pp_alloc_waive", ++ "rx_pp_recycle_cached", ++ "rx_pp_recycle_cache_full", ++ "rx_pp_recycle_ring", ++ "rx_pp_recycle_ring_full", ++ "rx_pp_recycle_released_ref", ++}; ++ + bool page_pool_get_stats(struct page_pool *pool, + struct page_pool_stats *stats) + { +@@ -50,7 +65,13 @@ bool page_pool_get_stats(struct page_poo + if (!stats) + return false; + +- memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); ++ /* The caller is responsible to initialize stats. */ ++ stats->alloc_stats.fast += pool->alloc_stats.fast; ++ stats->alloc_stats.slow += pool->alloc_stats.slow; ++ stats->alloc_stats.slow_high_order += pool->alloc_stats.slow_high_order; ++ stats->alloc_stats.empty += pool->alloc_stats.empty; ++ stats->alloc_stats.refill += pool->alloc_stats.refill; ++ stats->alloc_stats.waive += pool->alloc_stats.waive; + + for_each_possible_cpu(cpu) { + const struct page_pool_recycle_stats *pcpu = +@@ -66,6 +87,46 @@ bool page_pool_get_stats(struct page_poo + return true; + } + EXPORT_SYMBOL(page_pool_get_stats); ++ ++u8 *page_pool_ethtool_stats_get_strings(u8 *data) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pp_stats); i++) { ++ memcpy(data, pp_stats[i], ETH_GSTRING_LEN); ++ data += ETH_GSTRING_LEN; ++ } ++ ++ return data; ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get_strings); ++ ++int page_pool_ethtool_stats_get_count(void) ++{ ++ return ARRAY_SIZE(pp_stats); ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get_count); ++ ++u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) ++{ ++ struct page_pool_stats *pool_stats = stats; ++ ++ *data++ = pool_stats->alloc_stats.fast; ++ *data++ = pool_stats->alloc_stats.slow; ++ *data++ = pool_stats->alloc_stats.slow_high_order; ++ *data++ = pool_stats->alloc_stats.empty; ++ *data++ = pool_stats->alloc_stats.refill; ++ *data++ = pool_stats->alloc_stats.waive; ++ *data++ = pool_stats->recycle_stats.cached; ++ *data++ = pool_stats->recycle_stats.cache_full; ++ *data++ = pool_stats->recycle_stats.ring; ++ *data++ = pool_stats->recycle_stats.ring_full; ++ *data++ = pool_stats->recycle_stats.released_refcnt; ++ ++ return data; ++} ++EXPORT_SYMBOL(page_pool_ethtool_stats_get); ++ + #else + #define alloc_stat_inc(pool, __stat) + #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch b/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch new file mode 100644 index 00000000000..4a914404a2f --- /dev/null +++ b/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch @@ -0,0 +1,99 @@ +From 2e88d4ff03013937028f5397268b21e10cf68713 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 21 Jan 2022 11:09:45 +0100 +Subject: [PATCH] xdp: introduce flags field in xdp_buff/xdp_frame + +Introduce flags field in xdp_frame and xdp_buffer data structures +to define additional buffer features. At the moment the only +supported buffer feature is frags bit (XDP_FLAGS_HAS_FRAGS). +frags bit is used to specify if this is a linear buffer +(XDP_FLAGS_HAS_FRAGS not set) or a frags frame (XDP_FLAGS_HAS_FRAGS +set). In the latter case the driver is expected to initialize the +skb_shared_info structure at the end of the first buffer to link together +subsequent buffers belonging to the same frame. + +Acked-by: Toke Hoiland-Jorgensen +Acked-by: John Fastabend +Acked-by: Jesper Dangaard Brouer +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/e389f14f3a162c0a5bc6a2e1aa8dd01a90be117d.1642758637.git.lorenzo@kernel.org +Signed-off-by: Alexei Starovoitov +--- + include/net/xdp.h | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -66,6 +66,10 @@ struct xdp_txq_info { + struct net_device *dev; + }; + ++enum xdp_buff_flags { ++ XDP_FLAGS_HAS_FRAGS = BIT(0), /* non-linear xdp buff */ ++}; ++ + struct xdp_buff { + void *data; + void *data_end; +@@ -74,13 +78,30 @@ struct xdp_buff { + struct xdp_rxq_info *rxq; + struct xdp_txq_info *txq; + u32 frame_sz; /* frame size to deduce data_hard_end/reserved tailroom*/ ++ u32 flags; /* supported values defined in xdp_buff_flags */ + }; + ++static __always_inline bool xdp_buff_has_frags(struct xdp_buff *xdp) ++{ ++ return !!(xdp->flags & XDP_FLAGS_HAS_FRAGS); ++} ++ ++static __always_inline void xdp_buff_set_frags_flag(struct xdp_buff *xdp) ++{ ++ xdp->flags |= XDP_FLAGS_HAS_FRAGS; ++} ++ ++static __always_inline void xdp_buff_clear_frags_flag(struct xdp_buff *xdp) ++{ ++ xdp->flags &= ~XDP_FLAGS_HAS_FRAGS; ++} ++ + static __always_inline void + xdp_init_buff(struct xdp_buff *xdp, u32 frame_sz, struct xdp_rxq_info *rxq) + { + xdp->frame_sz = frame_sz; + xdp->rxq = rxq; ++ xdp->flags = 0; + } + + static __always_inline void +@@ -122,8 +143,14 @@ struct xdp_frame { + */ + struct xdp_mem_info mem; + struct net_device *dev_rx; /* used by cpumap */ ++ u32 flags; /* supported values defined in xdp_buff_flags */ + }; + ++static __always_inline bool xdp_frame_has_frags(struct xdp_frame *frame) ++{ ++ return !!(frame->flags & XDP_FLAGS_HAS_FRAGS); ++} ++ + #define XDP_BULK_QUEUE_SIZE 16 + struct xdp_frame_bulk { + int count; +@@ -180,6 +207,7 @@ void xdp_convert_frame_to_buff(struct xd + xdp->data_end = frame->data + frame->len; + xdp->data_meta = frame->data - frame->metasize; + xdp->frame_sz = frame->frame_sz; ++ xdp->flags = frame->flags; + } + + static inline +@@ -206,6 +234,7 @@ int xdp_update_frame_from_buff(struct xd + xdp_frame->headroom = headroom - sizeof(*xdp_frame); + xdp_frame->metasize = metasize; + xdp_frame->frame_sz = xdp->frame_sz; ++ xdp_frame->flags = xdp->flags; + + return 0; + } diff --git a/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch b/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch new file mode 100644 index 00000000000..86d24367dd6 --- /dev/null +++ b/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch @@ -0,0 +1,137 @@ +From 7c48cb0176c6d6d3b55029f7ff4ffa05faee6446 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 21 Jan 2022 11:09:50 +0100 +Subject: [PATCH] xdp: add frags support to xdp_return_{buff/frame} + +Take into account if the received xdp_buff/xdp_frame is non-linear +recycling/returning the frame memory to the allocator or into +xdp_frame_bulk. + +Acked-by: Toke Hoiland-Jorgensen +Acked-by: John Fastabend +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/a961069febc868508ce1bdf5e53a343eb4e57cb2.1642758637.git.lorenzo@kernel.org +Signed-off-by: Alexei Starovoitov +--- + include/net/xdp.h | 18 ++++++++++++++-- + net/core/xdp.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 69 insertions(+), 3 deletions(-) + +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -275,10 +275,24 @@ void __xdp_release_frame(void *data, str + static inline void xdp_release_frame(struct xdp_frame *xdpf) + { + struct xdp_mem_info *mem = &xdpf->mem; ++ struct skb_shared_info *sinfo; ++ int i; + + /* Curr only page_pool needs this */ +- if (mem->type == MEM_TYPE_PAGE_POOL) +- __xdp_release_frame(xdpf->data, mem); ++ if (mem->type != MEM_TYPE_PAGE_POOL) ++ return; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_release_frame(page_address(page), mem); ++ } ++out: ++ __xdp_release_frame(xdpf->data, mem); + } + + int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, +--- a/net/core/xdp.c ++++ b/net/core/xdp.c +@@ -376,12 +376,38 @@ static void __xdp_return(void *data, str + + void xdp_return_frame(struct xdp_frame *xdpf) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdpf->mem, false, NULL); ++ } ++out: + __xdp_return(xdpf->data, &xdpf->mem, false, NULL); + } + EXPORT_SYMBOL_GPL(xdp_return_frame); + + void xdp_return_frame_rx_napi(struct xdp_frame *xdpf) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdpf->mem, true, NULL); ++ } ++out: + __xdp_return(xdpf->data, &xdpf->mem, true, NULL); + } + EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi); +@@ -417,7 +443,7 @@ void xdp_return_frame_bulk(struct xdp_fr + struct xdp_mem_allocator *xa; + + if (mem->type != MEM_TYPE_PAGE_POOL) { +- __xdp_return(xdpf->data, &xdpf->mem, false, NULL); ++ xdp_return_frame(xdpf); + return; + } + +@@ -436,12 +462,38 @@ void xdp_return_frame_bulk(struct xdp_fr + bq->xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params); + } + ++ if (unlikely(xdp_frame_has_frags(xdpf))) { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ skb_frag_t *frag = &sinfo->frags[i]; ++ ++ bq->q[bq->count++] = skb_frag_address(frag); ++ if (bq->count == XDP_BULK_QUEUE_SIZE) ++ xdp_flush_frame_bulk(bq); ++ } ++ } + bq->q[bq->count++] = xdpf->data; + } + EXPORT_SYMBOL_GPL(xdp_return_frame_bulk); + + void xdp_return_buff(struct xdp_buff *xdp) + { ++ struct skb_shared_info *sinfo; ++ int i; ++ ++ if (likely(!xdp_buff_has_frags(xdp))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_buff(xdp); ++ for (i = 0; i < sinfo->nr_frags; i++) { ++ struct page *page = skb_frag_page(&sinfo->frags[i]); ++ ++ __xdp_return(page_address(page), &xdp->rxq->mem, true, xdp); ++ } ++out: + __xdp_return(xdp->data, &xdp->rxq->mem, true, xdp); + } + diff --git a/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch b/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch new file mode 100644 index 00000000000..36f55d511ad --- /dev/null +++ b/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch @@ -0,0 +1,31 @@ +From d16697cb6261d4cc23422e6b1cb2759df8aa76d0 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 21 Jan 2022 11:09:44 +0100 +Subject: [PATCH] net: skbuff: add size metadata to skb_shared_info for xdp + +Introduce xdp_frags_size field in skb_shared_info data structure +to store xdp_buff/xdp_frame frame paged size (xdp_frags_size will +be used in xdp frags support). In order to not increase +skb_shared_info size we will use a hole due to skb_shared_info +alignment. + +Acked-by: Toke Hoiland-Jorgensen +Acked-by: John Fastabend +Acked-by: Jesper Dangaard Brouer +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/8a849819a3e0a143d540f78a3a5add76e17e980d.1642758637.git.lorenzo@kernel.org +Signed-off-by: Alexei Starovoitov +--- + include/linux/skbuff.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -568,6 +568,7 @@ struct skb_shared_info { + * Warning : all fields before dataref are cleared in __alloc_skb() + */ + atomic_t dataref; ++ unsigned int xdp_frags_size; + + /* Intermediate layers must ensure that destructor_arg + * remains valid until skb destructor */ diff --git a/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch b/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch new file mode 100644 index 00000000000..3bdba8728cf --- /dev/null +++ b/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch @@ -0,0 +1,65 @@ +From 5142239a22219921a7863cf00c9ab853c00689d8 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 11 Mar 2022 10:14:18 +0100 +Subject: [PATCH] net: veth: Account total xdp_frame len running ndo_xdp_xmit + +Even if this is a theoretical issue since it is not possible to perform +XDP_REDIRECT on a non-linear xdp_frame, veth driver does not account +paged area in ndo_xdp_xmit function pointer. +Introduce xdp_get_frame_len utility routine to get the xdp_frame full +length and account total frame size running XDP_REDIRECT of a +non-linear xdp frame into a veth device. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Borkmann +Acked-by: Toke Hoiland-Jorgensen +Acked-by: John Fastabend +Link: https://lore.kernel.org/bpf/54f9fd3bb65d190daf2c0bbae2f852ff16cfbaa0.1646989407.git.lorenzo@kernel.org +--- + drivers/net/veth.c | 4 ++-- + include/net/xdp.h | 14 ++++++++++++++ + 2 files changed, 16 insertions(+), 2 deletions(-) + +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -501,7 +501,7 @@ static int veth_xdp_xmit(struct net_devi + struct xdp_frame *frame = frames[i]; + void *ptr = veth_xdp_to_ptr(frame); + +- if (unlikely(frame->len > max_len || ++ if (unlikely(xdp_get_frame_len(frame) > max_len || + __ptr_ring_produce(&rq->xdp_ring, ptr))) + break; + nxmit++; +@@ -862,7 +862,7 @@ static int veth_xdp_rcv(struct veth_rq * + /* ndo_xdp_xmit */ + struct xdp_frame *frame = veth_ptr_to_xdp(ptr); + +- stats->xdp_bytes += frame->len; ++ stats->xdp_bytes += xdp_get_frame_len(frame); + frame = veth_xdp_rcv_one(rq, frame, bq, stats); + if (frame) { + /* XDP_PASS */ +--- a/include/net/xdp.h ++++ b/include/net/xdp.h +@@ -295,6 +295,20 @@ out: + __xdp_release_frame(xdpf->data, mem); + } + ++static __always_inline unsigned int xdp_get_frame_len(struct xdp_frame *xdpf) ++{ ++ struct skb_shared_info *sinfo; ++ unsigned int len = xdpf->len; ++ ++ if (likely(!xdp_frame_has_frags(xdpf))) ++ goto out; ++ ++ sinfo = xdp_get_shared_info_from_frame(xdpf); ++ len += sinfo->xdp_frags_size; ++out: ++ return len; ++} ++ + int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, + struct net_device *dev, u32 queue_index, unsigned int napi_id); + void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq); diff --git a/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch b/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch new file mode 100644 index 00000000000..31b44f11707 --- /dev/null +++ b/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch @@ -0,0 +1,40 @@ +From 7cda76d858a4e71ac4a04066c093679a12e1312c Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 11 Mar 2022 10:14:20 +0100 +Subject: [PATCH] veth: Allow jumbo frames in xdp mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Allow increasing the MTU over page boundaries on veth devices +if the attached xdp program declares to support xdp fragments. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Borkmann +Acked-by: Toke Høiland-Jørgensen +Acked-by: John Fastabend +Link: https://lore.kernel.org/bpf/d5dc039c3d4123426e7023a488c449181a7bc57f.1646989407.git.lorenzo@kernel.org +--- + drivers/net/veth.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/net/veth.c ++++ b/drivers/net/veth.c +@@ -1471,9 +1471,14 @@ static int veth_xdp_set(struct net_devic + goto err; + } + +- max_mtu = PAGE_SIZE - VETH_XDP_HEADROOM - +- peer->hard_header_len - +- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); ++ max_mtu = SKB_WITH_OVERHEAD(PAGE_SIZE - VETH_XDP_HEADROOM) - ++ peer->hard_header_len; ++ /* Allow increasing the max_mtu if the program supports ++ * XDP fragments. ++ */ ++ //if (prog->aux->xdp_has_frags) ++ max_mtu += PAGE_SIZE * MAX_SKB_FRAGS; ++ + if (peer->mtu > max_mtu) { + NL_SET_ERR_MSG_MOD(extack, "Peer MTU is too large to set XDP"); + err = -ERANGE; diff --git a/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch b/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch new file mode 100644 index 00000000000..71e11405958 --- /dev/null +++ b/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch @@ -0,0 +1,56 @@ +From: Qingfang DENG +Date: Fri, 3 Feb 2023 09:16:11 +0800 +Subject: [PATCH] net: page_pool: use in_softirq() instead + +We use BH context only for synchronization, so we don't care if it's +actually serving softirq or not. + +As a side node, in case of threaded NAPI, in_serving_softirq() will +return false because it's in process context with BH off, making +page_pool_recycle_in_cache() unreachable. + +Signed-off-by: Qingfang DENG +--- + +--- a/include/net/page_pool.h ++++ b/include/net/page_pool.h +@@ -357,7 +357,7 @@ static inline void page_pool_nid_changed + static inline void page_pool_ring_lock(struct page_pool *pool) + __acquires(&pool->ring.producer_lock) + { +- if (in_serving_softirq()) ++ if (in_softirq()) + spin_lock(&pool->ring.producer_lock); + else + spin_lock_bh(&pool->ring.producer_lock); +@@ -366,7 +366,7 @@ static inline void page_pool_ring_lock(s + static inline void page_pool_ring_unlock(struct page_pool *pool) + __releases(&pool->ring.producer_lock) + { +- if (in_serving_softirq()) ++ if (in_softirq()) + spin_unlock(&pool->ring.producer_lock); + else + spin_unlock_bh(&pool->ring.producer_lock); +--- a/net/core/page_pool.c ++++ b/net/core/page_pool.c +@@ -512,8 +512,8 @@ static void page_pool_return_page(struct + static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page) + { + int ret; +- /* BH protection not needed if current is serving softirq */ +- if (in_serving_softirq()) ++ /* BH protection not needed if current is softirq */ ++ if (in_softirq()) + ret = ptr_ring_produce(&pool->ring, page); + else + ret = ptr_ring_produce_bh(&pool->ring, page); +@@ -576,7 +576,7 @@ __page_pool_put_page(struct page_pool *p + page_pool_dma_sync_for_device(pool, page, + dma_sync_size); + +- if (allow_direct && in_serving_softirq() && ++ if (allow_direct && in_softirq() && + page_pool_recycle_in_cache(page, pool)) + return NULL; + diff --git a/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch b/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch new file mode 100644 index 00000000000..c5d5d2c3a9c --- /dev/null +++ b/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch @@ -0,0 +1,41 @@ +From 7390609b0121a1b982c5ecdfcd72dc328e5784ee Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:42 +0000 +Subject: [PATCH] net: add helper eth_addr_add() + +Add a helper to add an offset to a ethernet address. This comes in handy +if you have a base ethernet address for multiple interfaces. + +Signed-off-by: Michael Walle +Reviewed-by: Andrew Lunn +Acked-by: Jakub Kicinski +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-9-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/etherdevice.h | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/include/linux/etherdevice.h ++++ b/include/linux/etherdevice.h +@@ -478,6 +478,20 @@ static inline void eth_addr_inc(u8 *addr + } + + /** ++ * eth_addr_add() - Add (or subtract) an offset to/from the given MAC address. ++ * ++ * @offset: Offset to add. ++ * @addr: Pointer to a six-byte array containing Ethernet address to increment. ++ */ ++static inline void eth_addr_add(u8 *addr, long offset) ++{ ++ u64 u = ether_addr_to_u64(addr); ++ ++ u += offset; ++ u64_to_ether_addr(u, addr); ++} ++ ++/** + * is_etherdev_addr - Tell if given Ethernet address belongs to the device. + * @dev: Pointer to a device structure + * @addr: Pointer to a six-byte array containing the Ethernet address diff --git a/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch b/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch new file mode 100644 index 00000000000..f2b651f0c61 --- /dev/null +++ b/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch @@ -0,0 +1,279 @@ +From dc452a471dbae8aca8257c565174212620880093 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Fri, 10 Dec 2021 01:34:37 +0200 +Subject: net: dsa: introduce tagger-owned storage for private and shared data + +Ansuel is working on register access over Ethernet for the qca8k switch +family. This requires the qca8k tagging protocol driver to receive +frames which aren't intended for the network stack, but instead for the +qca8k switch driver itself. + +The dp->priv is currently the prevailing method for passing data back +and forth between the tagging protocol driver and the switch driver. +However, this method is riddled with caveats. + +The DSA design allows in principle for any switch driver to return any +protocol it desires in ->get_tag_protocol(). The dsa_loop driver can be +modified to do just that. But in the current design, the memory behind +dp->priv has to be allocated by the switch driver, so if the tagging +protocol is paired to an unexpected switch driver, we may end up in NULL +pointer dereferences inside the kernel, or worse (a switch driver may +allocate dp->priv according to the expectations of a different tagger). + +The latter possibility is even more plausible considering that DSA +switches can dynamically change tagging protocols in certain cases +(dsa <-> edsa, ocelot <-> ocelot-8021q), and the current design lends +itself to mistakes that are all too easy to make. + +This patch proposes that the tagging protocol driver should manage its +own memory, instead of relying on the switch driver to do so. +After analyzing the different in-tree needs, it can be observed that the +required tagger storage is per switch, therefore a ds->tagger_data +pointer is introduced. In principle, per-port storage could also be +introduced, although there is no need for it at the moment. Future +changes will replace the current usage of dp->priv with ds->tagger_data. + +We define a "binding" event between the DSA switch tree and the tagging +protocol. During this binding event, the tagging protocol's ->connect() +method is called first, and this may allocate some memory for each +switch of the tree. Then a cross-chip notifier is emitted for the +switches within that tree, and they are given the opportunity to fix up +the tagger's memory (for example, they might set up some function +pointers that represent virtual methods for consuming packets). +Because the memory is owned by the tagger, there exists a ->disconnect() +method for the tagger (which is the place to free the resources), but +there doesn't exist a ->disconnect() method for the switch driver. +This is part of the design. The switch driver should make minimal use of +the public part of the tagger data, and only after type-checking it +using the supplied "proto" argument. + +In the code there are in fact two binding events, one is the initial +event in dsa_switch_setup_tag_protocol(). At this stage, the cross chip +notifier chains aren't initialized, so we call each switch's connect() +method by hand. Then there is dsa_tree_bind_tag_proto() during +dsa_tree_change_tag_proto(), and here we have an old protocol and a new +one. We first connect to the new one before disconnecting from the old +one, to simplify error handling a bit and to ensure we remain in a valid +state at all times. + +Co-developed-by: Ansuel Smith +Signed-off-by: Ansuel Smith +Signed-off-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 12 +++++++++ + net/dsa/dsa2.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++--- + net/dsa/dsa_priv.h | 1 + + net/dsa/switch.c | 14 +++++++++++ + 4 files changed, 96 insertions(+), 4 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -80,12 +80,15 @@ enum dsa_tag_protocol { + }; + + struct dsa_switch; ++struct dsa_switch_tree; + + struct dsa_device_ops { + struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); + struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev); + void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, + int *offset); ++ int (*connect)(struct dsa_switch_tree *dst); ++ void (*disconnect)(struct dsa_switch_tree *dst); + unsigned int needed_headroom; + unsigned int needed_tailroom; + const char *name; +@@ -329,6 +332,8 @@ struct dsa_switch { + */ + void *priv; + ++ void *tagger_data; ++ + /* + * Configuration data for this switch. + */ +@@ -584,6 +589,13 @@ struct dsa_switch_ops { + enum dsa_tag_protocol mprot); + int (*change_tag_protocol)(struct dsa_switch *ds, int port, + enum dsa_tag_protocol proto); ++ /* ++ * Method for switch drivers to connect to the tagging protocol driver ++ * in current use. The switch driver can provide handlers for certain ++ * types of packets for switch management. ++ */ ++ int (*connect_tag_protocol)(struct dsa_switch *ds, ++ enum dsa_tag_protocol proto); + + /* Optional switch-wide initialization and destruction methods */ + int (*setup)(struct dsa_switch *ds); +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -230,8 +230,12 @@ static struct dsa_switch_tree *dsa_tree_ + + static void dsa_tree_free(struct dsa_switch_tree *dst) + { +- if (dst->tag_ops) ++ if (dst->tag_ops) { ++ if (dst->tag_ops->disconnect) ++ dst->tag_ops->disconnect(dst); ++ + dsa_tag_driver_put(dst->tag_ops); ++ } + list_del(&dst->list); + kfree(dst); + } +@@ -805,7 +809,7 @@ static int dsa_switch_setup_tag_protocol + int port, err; + + if (tag_ops->proto == dst->default_proto) +- return 0; ++ goto connect; + + for (port = 0; port < ds->num_ports; port++) { + if (!dsa_is_cpu_port(ds, port)) +@@ -821,6 +825,17 @@ static int dsa_switch_setup_tag_protocol + } + } + ++connect: ++ if (ds->ops->connect_tag_protocol) { ++ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); ++ if (err) { ++ dev_err(ds->dev, ++ "Unable to connect to tag protocol \"%s\": %pe\n", ++ tag_ops->name, ERR_PTR(err)); ++ return err; ++ } ++ } ++ + return 0; + } + +@@ -1132,6 +1147,46 @@ static void dsa_tree_teardown(struct dsa + dst->setup = false; + } + ++static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst, ++ const struct dsa_device_ops *tag_ops) ++{ ++ const struct dsa_device_ops *old_tag_ops = dst->tag_ops; ++ struct dsa_notifier_tag_proto_info info; ++ int err; ++ ++ dst->tag_ops = tag_ops; ++ ++ /* Notify the new tagger about the connection to this tree */ ++ if (tag_ops->connect) { ++ err = tag_ops->connect(dst); ++ if (err) ++ goto out_revert; ++ } ++ ++ /* Notify the switches from this tree about the connection ++ * to the new tagger ++ */ ++ info.tag_ops = tag_ops; ++ err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_CONNECT, &info); ++ if (err && err != -EOPNOTSUPP) ++ goto out_disconnect; ++ ++ /* Notify the old tagger about the disconnection from this tree */ ++ if (old_tag_ops->disconnect) ++ old_tag_ops->disconnect(dst); ++ ++ return 0; ++ ++out_disconnect: ++ /* Revert the new tagger's connection to this tree */ ++ if (tag_ops->disconnect) ++ tag_ops->disconnect(dst); ++out_revert: ++ dst->tag_ops = old_tag_ops; ++ ++ return err; ++} ++ + /* Since the dsa/tagging sysfs device attribute is per master, the assumption + * is that all DSA switches within a tree share the same tagger, otherwise + * they would have formed disjoint trees (different "dsa,member" values). +@@ -1164,12 +1219,15 @@ int dsa_tree_change_tag_proto(struct dsa + goto out_unlock; + } + ++ /* Notify the tag protocol change */ + info.tag_ops = tag_ops; + err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info); + if (err) +- goto out_unwind_tagger; ++ return err; + +- dst->tag_ops = tag_ops; ++ err = dsa_tree_bind_tag_proto(dst, tag_ops); ++ if (err) ++ goto out_unwind_tagger; + + rtnl_unlock(); + +@@ -1257,6 +1315,7 @@ static int dsa_port_parse_cpu(struct dsa + struct dsa_switch *ds = dp->ds; + struct dsa_switch_tree *dst = ds->dst; + enum dsa_tag_protocol default_proto; ++ int err; + + /* Find out which protocol the switch would prefer. */ + default_proto = dsa_get_tag_protocol(dp, master); +@@ -1311,6 +1370,12 @@ static int dsa_port_parse_cpu(struct dsa + */ + dsa_tag_driver_put(tag_ops); + } else { ++ if (tag_ops->connect) { ++ err = tag_ops->connect(dst); ++ if (err) ++ return err; ++ } ++ + dst->tag_ops = tag_ops; + } + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -37,6 +37,7 @@ enum { + DSA_NOTIFIER_VLAN_DEL, + DSA_NOTIFIER_MTU, + DSA_NOTIFIER_TAG_PROTO, ++ DSA_NOTIFIER_TAG_PROTO_CONNECT, + DSA_NOTIFIER_MRP_ADD, + DSA_NOTIFIER_MRP_DEL, + DSA_NOTIFIER_MRP_ADD_RING_ROLE, +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -616,6 +616,17 @@ static int dsa_switch_change_tag_proto(s + return 0; + } + ++static int dsa_switch_connect_tag_proto(struct dsa_switch *ds, ++ struct dsa_notifier_tag_proto_info *info) ++{ ++ const struct dsa_device_ops *tag_ops = info->tag_ops; ++ ++ if (!ds->ops->connect_tag_protocol) ++ return -EOPNOTSUPP; ++ ++ return ds->ops->connect_tag_protocol(ds, tag_ops->proto); ++} ++ + static int dsa_switch_mrp_add(struct dsa_switch *ds, + struct dsa_notifier_mrp_info *info) + { +@@ -735,6 +746,9 @@ static int dsa_switch_event(struct notif + case DSA_NOTIFIER_TAG_PROTO: + err = dsa_switch_change_tag_proto(ds, info); + break; ++ case DSA_NOTIFIER_TAG_PROTO_CONNECT: ++ err = dsa_switch_connect_tag_proto(ds, info); ++ break; + case DSA_NOTIFIER_MRP_ADD: + err = dsa_switch_mrp_add(ds, info); + break; diff --git a/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch b/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch new file mode 100644 index 00000000000..0c50ae6fb9d --- /dev/null +++ b/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch @@ -0,0 +1,274 @@ +From 7f2973149c22e7a6fee4c0c9fa6b8e4108e9c208 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Tue, 14 Dec 2021 03:45:36 +0200 +Subject: net: dsa: make tagging protocols connect to individual switches from + a tree + +On the NXP Bluebox 3 board which uses a multi-switch setup with sja1105, +the mechanism through which the tagger connects to the switch tree is +broken, due to improper DSA code design. At the time when tag_ops->connect() +is called in dsa_port_parse_cpu(), DSA hasn't finished "touching" all +the ports, so it doesn't know how large the tree is and how many ports +it has. It has just seen the first CPU port by this time. As a result, +this function will call the tagger's ->connect method too early, and the +tagger will connect only to the first switch from the tree. + +This could be perhaps addressed a bit more simply by just moving the +tag_ops->connect(dst) call a bit later (for example in dsa_tree_setup), +but there is already a design inconsistency at present: on the switch +side, the notification is on a per-switch basis, but on the tagger side, +it is on a per-tree basis. Furthermore, the persistent storage itself is +per switch (ds->tagger_data). And the tagger connect and disconnect +procedures (at least the ones that exist currently) could see a fair bit +of simplification if they didn't have to iterate through the switches of +a tree. + +To fix the issue, this change transforms tag_ops->connect(dst) into +tag_ops->connect(ds) and moves it somewhere where we already iterate +over all switches of a tree. That is in dsa_switch_setup_tag_protocol(), +which is a good placement because we already have there the connection +call to the switch side of things. + +As for the dsa_tree_bind_tag_proto() method (called from the code path +that changes the tag protocol), things are a bit more complicated +because we receive the tree as argument, yet when we unwind on errors, +it would be nice to not call tag_ops->disconnect(ds) where we didn't +previously call tag_ops->connect(ds). We didn't have this problem before +because the tag_ops connection operations passed the entire dst before, +and this is more fine grained now. To solve the error rewind case using +the new API, we have to create yet one more cross-chip notifier for +disconnection, and stay connected with the old tag protocol to all the +switches in the tree until we've succeeded to connect with the new one +as well. So if something fails half way, the whole tree is still +connected to the old tagger. But there may still be leaks if the tagger +fails to connect to the 2nd out of 3 switches in a tree: somebody needs +to tell the tagger to disconnect from the first switch. Nothing comes +for free, and this was previously handled privately by the tagging +protocol driver before, but now we need to emit a disconnect cross-chip +notifier for that, because DSA has to take care of the unwind path. We +assume that the tagging protocol has connected to a switch if it has set +ds->tagger_data to something, otherwise we avoid calling its +disconnection method in the error rewind path. + +The rest of the changes are in the tagging protocol drivers, and have to +do with the replacement of dst with ds. The iteration is removed and the +error unwind path is simplified, as mentioned above. + +Signed-off-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 5 ++-- + net/dsa/dsa2.c | 44 +++++++++++++----------------- + net/dsa/dsa_priv.h | 1 + + net/dsa/switch.c | 52 ++++++++++++++++++++++++++++++++--- + net/dsa/tag_ocelot_8021q.c | 53 +++++++++++------------------------- + net/dsa/tag_sja1105.c | 67 ++++++++++++++++------------------------------ + 6 files changed, 109 insertions(+), 113 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -80,15 +80,14 @@ enum dsa_tag_protocol { + }; + + struct dsa_switch; +-struct dsa_switch_tree; + + struct dsa_device_ops { + struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); + struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev); + void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, + int *offset); +- int (*connect)(struct dsa_switch_tree *dst); +- void (*disconnect)(struct dsa_switch_tree *dst); ++ int (*connect)(struct dsa_switch *ds); ++ void (*disconnect)(struct dsa_switch *ds); + unsigned int needed_headroom; + unsigned int needed_tailroom; + const char *name; +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -230,12 +230,8 @@ static struct dsa_switch_tree *dsa_tree_ + + static void dsa_tree_free(struct dsa_switch_tree *dst) + { +- if (dst->tag_ops) { +- if (dst->tag_ops->disconnect) +- dst->tag_ops->disconnect(dst); +- ++ if (dst->tag_ops) + dsa_tag_driver_put(dst->tag_ops); +- } + list_del(&dst->list); + kfree(dst); + } +@@ -826,17 +822,29 @@ static int dsa_switch_setup_tag_protocol + } + + connect: ++ if (tag_ops->connect) { ++ err = tag_ops->connect(ds); ++ if (err) ++ return err; ++ } ++ + if (ds->ops->connect_tag_protocol) { + err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); + if (err) { + dev_err(ds->dev, + "Unable to connect to tag protocol \"%s\": %pe\n", + tag_ops->name, ERR_PTR(err)); +- return err; ++ goto disconnect; + } + } + + return 0; ++ ++disconnect: ++ if (tag_ops->disconnect) ++ tag_ops->disconnect(ds); ++ ++ return err; + } + + static int dsa_switch_setup(struct dsa_switch *ds) +@@ -1156,13 +1164,6 @@ static int dsa_tree_bind_tag_proto(struc + + dst->tag_ops = tag_ops; + +- /* Notify the new tagger about the connection to this tree */ +- if (tag_ops->connect) { +- err = tag_ops->connect(dst); +- if (err) +- goto out_revert; +- } +- + /* Notify the switches from this tree about the connection + * to the new tagger + */ +@@ -1172,16 +1173,14 @@ static int dsa_tree_bind_tag_proto(struc + goto out_disconnect; + + /* Notify the old tagger about the disconnection from this tree */ +- if (old_tag_ops->disconnect) +- old_tag_ops->disconnect(dst); ++ info.tag_ops = old_tag_ops; ++ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info); + + return 0; + + out_disconnect: +- /* Revert the new tagger's connection to this tree */ +- if (tag_ops->disconnect) +- tag_ops->disconnect(dst); +-out_revert: ++ info.tag_ops = tag_ops; ++ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info); + dst->tag_ops = old_tag_ops; + + return err; +@@ -1315,7 +1314,6 @@ static int dsa_port_parse_cpu(struct dsa + struct dsa_switch *ds = dp->ds; + struct dsa_switch_tree *dst = ds->dst; + enum dsa_tag_protocol default_proto; +- int err; + + /* Find out which protocol the switch would prefer. */ + default_proto = dsa_get_tag_protocol(dp, master); +@@ -1370,12 +1368,6 @@ static int dsa_port_parse_cpu(struct dsa + */ + dsa_tag_driver_put(tag_ops); + } else { +- if (tag_ops->connect) { +- err = tag_ops->connect(dst); +- if (err) +- return err; +- } +- + dst->tag_ops = tag_ops; + } + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -38,6 +38,7 @@ enum { + DSA_NOTIFIER_MTU, + DSA_NOTIFIER_TAG_PROTO, + DSA_NOTIFIER_TAG_PROTO_CONNECT, ++ DSA_NOTIFIER_TAG_PROTO_DISCONNECT, + DSA_NOTIFIER_MRP_ADD, + DSA_NOTIFIER_MRP_DEL, + DSA_NOTIFIER_MRP_ADD_RING_ROLE, +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -616,15 +616,58 @@ static int dsa_switch_change_tag_proto(s + return 0; + } + +-static int dsa_switch_connect_tag_proto(struct dsa_switch *ds, +- struct dsa_notifier_tag_proto_info *info) ++/* We use the same cross-chip notifiers to inform both the tagger side, as well ++ * as the switch side, of connection and disconnection events. ++ * Since ds->tagger_data is owned by the tagger, it isn't a hard error if the ++ * switch side doesn't support connecting to this tagger, and therefore, the ++ * fact that we don't disconnect the tagger side doesn't constitute a memory ++ * leak: the tagger will still operate with persistent per-switch memory, just ++ * with the switch side unconnected to it. What does constitute a hard error is ++ * when the switch side supports connecting but fails. ++ */ ++static int ++dsa_switch_connect_tag_proto(struct dsa_switch *ds, ++ struct dsa_notifier_tag_proto_info *info) + { + const struct dsa_device_ops *tag_ops = info->tag_ops; ++ int err; ++ ++ /* Notify the new tagger about the connection to this switch */ ++ if (tag_ops->connect) { ++ err = tag_ops->connect(ds); ++ if (err) ++ return err; ++ } + + if (!ds->ops->connect_tag_protocol) + return -EOPNOTSUPP; + +- return ds->ops->connect_tag_protocol(ds, tag_ops->proto); ++ /* Notify the switch about the connection to the new tagger */ ++ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); ++ if (err) { ++ /* Revert the new tagger's connection to this tree */ ++ if (tag_ops->disconnect) ++ tag_ops->disconnect(ds); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static int ++dsa_switch_disconnect_tag_proto(struct dsa_switch *ds, ++ struct dsa_notifier_tag_proto_info *info) ++{ ++ const struct dsa_device_ops *tag_ops = info->tag_ops; ++ ++ /* Notify the tagger about the disconnection from this switch */ ++ if (tag_ops->disconnect && ds->tagger_data) ++ tag_ops->disconnect(ds); ++ ++ /* No need to notify the switch, since it shouldn't have any ++ * resources to tear down ++ */ ++ return 0; + } + + static int dsa_switch_mrp_add(struct dsa_switch *ds, +@@ -749,6 +792,9 @@ static int dsa_switch_event(struct notif + case DSA_NOTIFIER_TAG_PROTO_CONNECT: + err = dsa_switch_connect_tag_proto(ds, info); + break; ++ case DSA_NOTIFIER_TAG_PROTO_DISCONNECT: ++ err = dsa_switch_disconnect_tag_proto(ds, info); ++ break; + case DSA_NOTIFIER_MRP_ADD: + err = dsa_switch_mrp_add(ds, info); + break; diff --git a/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch b/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch new file mode 100644 index 00000000000..c83d659d1c0 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch @@ -0,0 +1,327 @@ +From: Felix Fietkau +Date: Sat, 5 Feb 2022 17:59:07 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent + DMA + +It improves performance by eliminating the need for a cache flush on rx and tx +In preparation for supporting WED (Wireless Ethernet Dispatch), also add a +function for disabling coherent DMA at runtime. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -840,7 +841,7 @@ static int mtk_init_fq_dma(struct mtk_et + dma_addr_t dma_addr; + int i; + +- eth->scratch_ring = dma_alloc_coherent(eth->dev, ++ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, + cnt * sizeof(struct mtk_tx_dma), + ð->phy_scratch_ring, + GFP_ATOMIC); +@@ -852,10 +853,10 @@ static int mtk_init_fq_dma(struct mtk_et + if (unlikely(!eth->scratch_head)) + return -ENOMEM; + +- dma_addr = dma_map_single(eth->dev, ++ dma_addr = dma_map_single(eth->dma_dev, + eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE, + DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) ++ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) + return -ENOMEM; + + phy_ring_tail = eth->phy_scratch_ring + +@@ -909,26 +910,26 @@ static void mtk_tx_unmap(struct mtk_eth + { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { +- dma_unmap_single(eth->dev, ++ dma_unmap_single(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { +- dma_unmap_page(eth->dev, ++ dma_unmap_page(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } + } else { + if (dma_unmap_len(tx_buf, dma_len0)) { +- dma_unmap_page(eth->dev, ++ dma_unmap_page(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr0), + dma_unmap_len(tx_buf, dma_len0), + DMA_TO_DEVICE); + } + + if (dma_unmap_len(tx_buf, dma_len1)) { +- dma_unmap_page(eth->dev, ++ dma_unmap_page(eth->dma_dev, + dma_unmap_addr(tx_buf, dma_addr1), + dma_unmap_len(tx_buf, dma_len1), + DMA_TO_DEVICE); +@@ -1006,9 +1007,9 @@ static int mtk_tx_map(struct sk_buff *sk + if (skb_vlan_tag_present(skb)) + txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); + +- mapped_addr = dma_map_single(eth->dev, skb->data, ++ mapped_addr = dma_map_single(eth->dma_dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) ++ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) + return -ENOMEM; + + WRITE_ONCE(itxd->txd1, mapped_addr); +@@ -1047,10 +1048,10 @@ static int mtk_tx_map(struct sk_buff *sk + + + frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); +- mapped_addr = skb_frag_dma_map(eth->dev, frag, offset, ++ mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset, + frag_map_size, + DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) ++ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) + goto err_dma; + + if (i == nr_frags - 1 && +@@ -1331,18 +1332,18 @@ static int mtk_poll_rx(struct napi_struc + netdev->stats.rx_dropped++; + goto release_desc; + } +- dma_addr = dma_map_single(eth->dev, ++ dma_addr = dma_map_single(eth->dma_dev, + new_data + NET_SKB_PAD + + eth->ip_align, + ring->buf_size, + DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) { ++ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { + skb_free_frag(new_data); + netdev->stats.rx_dropped++; + goto release_desc; + } + +- dma_unmap_single(eth->dev, trxd.rxd1, ++ dma_unmap_single(eth->dma_dev, trxd.rxd1, + ring->buf_size, DMA_FROM_DEVICE); + + /* receive data */ +@@ -1615,7 +1616,7 @@ static int mtk_tx_alloc(struct mtk_eth * + if (!ring->buf) + goto no_tx_mem; + +- ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, ++ ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, + &ring->phys, GFP_ATOMIC); + if (!ring->dma) + goto no_tx_mem; +@@ -1633,7 +1634,7 @@ static int mtk_tx_alloc(struct mtk_eth * + * descriptors in ring->dma_pdma. + */ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, ++ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, + &ring->phys_pdma, + GFP_ATOMIC); + if (!ring->dma_pdma) +@@ -1692,7 +1693,7 @@ static void mtk_tx_clean(struct mtk_eth + } + + if (ring->dma) { +- dma_free_coherent(eth->dev, ++ dma_free_coherent(eth->dma_dev, + MTK_DMA_SIZE * sizeof(*ring->dma), + ring->dma, + ring->phys); +@@ -1700,7 +1701,7 @@ static void mtk_tx_clean(struct mtk_eth + } + + if (ring->dma_pdma) { +- dma_free_coherent(eth->dev, ++ dma_free_coherent(eth->dma_dev, + MTK_DMA_SIZE * sizeof(*ring->dma_pdma), + ring->dma_pdma, + ring->phys_pdma); +@@ -1748,18 +1749,18 @@ static int mtk_rx_alloc(struct mtk_eth * + return -ENOMEM; + } + +- ring->dma = dma_alloc_coherent(eth->dev, ++ ring->dma = dma_alloc_coherent(eth->dma_dev, + rx_dma_size * sizeof(*ring->dma), + &ring->phys, GFP_ATOMIC); + if (!ring->dma) + return -ENOMEM; + + for (i = 0; i < rx_dma_size; i++) { +- dma_addr_t dma_addr = dma_map_single(eth->dev, ++ dma_addr_t dma_addr = dma_map_single(eth->dma_dev, + ring->data[i] + NET_SKB_PAD + eth->ip_align, + ring->buf_size, + DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) ++ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) + return -ENOMEM; + ring->dma[i].rxd1 = (unsigned int)dma_addr; + +@@ -1795,7 +1796,7 @@ static void mtk_rx_clean(struct mtk_eth + continue; + if (!ring->dma[i].rxd1) + continue; +- dma_unmap_single(eth->dev, ++ dma_unmap_single(eth->dma_dev, + ring->dma[i].rxd1, + ring->buf_size, + DMA_FROM_DEVICE); +@@ -1806,7 +1807,7 @@ static void mtk_rx_clean(struct mtk_eth + } + + if (ring->dma) { +- dma_free_coherent(eth->dev, ++ dma_free_coherent(eth->dma_dev, + ring->dma_size * sizeof(*ring->dma), + ring->dma, + ring->phys); +@@ -2162,7 +2163,7 @@ static void mtk_dma_free(struct mtk_eth + if (eth->netdev[i]) + netdev_reset_queue(eth->netdev[i]); + if (eth->scratch_ring) { +- dma_free_coherent(eth->dev, ++ dma_free_coherent(eth->dma_dev, + MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), + eth->scratch_ring, + eth->phy_scratch_ring); +@@ -2514,6 +2515,8 @@ static void mtk_dim_tx(struct work_struc + + static int mtk_hw_init(struct mtk_eth *eth) + { ++ u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | ++ ETHSYS_DMA_AG_MAP_PPE; + int i, val, ret; + + if (test_and_set_bit(MTK_HW_INIT, ð->state)) +@@ -2526,6 +2529,10 @@ static int mtk_hw_init(struct mtk_eth *e + if (ret) + goto err_disable_pm; + ++ if (eth->ethsys) ++ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask, ++ of_dma_is_coherent(eth->dma_dev->of_node) * dma_mask); ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + ret = device_reset(eth->dev); + if (ret) { +@@ -3079,6 +3086,35 @@ free_netdev: + return err; + } + ++void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) ++{ ++ struct net_device *dev, *tmp; ++ LIST_HEAD(dev_list); ++ int i; ++ ++ rtnl_lock(); ++ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ dev = eth->netdev[i]; ++ ++ if (!dev || !(dev->flags & IFF_UP)) ++ continue; ++ ++ list_add_tail(&dev->close_list, &dev_list); ++ } ++ ++ dev_close_many(&dev_list, false); ++ ++ eth->dma_dev = dma_dev; ++ ++ list_for_each_entry_safe(dev, tmp, &dev_list, close_list) { ++ list_del_init(&dev->close_list); ++ dev_open(dev, NULL); ++ } ++ ++ rtnl_unlock(); ++} ++ + static int mtk_probe(struct platform_device *pdev) + { + struct device_node *mac_np; +@@ -3092,6 +3128,7 @@ static int mtk_probe(struct platform_dev + eth->soc = of_device_get_match_data(&pdev->dev); + + eth->dev = &pdev->dev; ++ eth->dma_dev = &pdev->dev; + eth->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(eth->base)) + return PTR_ERR(eth->base); +@@ -3140,6 +3177,16 @@ static int mtk_probe(struct platform_dev + } + } + ++ if (of_dma_is_coherent(pdev->dev.of_node)) { ++ struct regmap *cci; ++ ++ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, ++ "mediatek,cci-control"); ++ /* enable CPU/bus coherency */ ++ if (!IS_ERR(cci)) ++ regmap_write(cci, 0, 3); ++ } ++ + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { + eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), + GFP_KERNEL); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -463,6 +463,12 @@ + #define RSTCTRL_FE BIT(6) + #define RSTCTRL_PPE BIT(31) + ++/* ethernet dma channel agent map */ ++#define ETHSYS_DMA_AG_MAP 0x408 ++#define ETHSYS_DMA_AG_MAP_PDMA BIT(0) ++#define ETHSYS_DMA_AG_MAP_QDMA BIT(1) ++#define ETHSYS_DMA_AG_MAP_PPE BIT(2) ++ + /* SGMII subsystem config registers */ + /* Register to auto-negotiation restart */ + #define SGMSYS_PCS_CONTROL_1 0x0 +@@ -880,6 +886,7 @@ struct mtk_sgmii { + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer ++ * @dev: The device pointer used for dma mapping/alloc + * @base: The mapped register i/o base + * @page_lock: Make sure that register operations are atomic + * @tx_irq__lock: Make sure that IRQ register operations are atomic +@@ -923,6 +930,7 @@ struct mtk_sgmii { + + struct mtk_eth { + struct device *dev; ++ struct device *dma_dev; + void __iomem *base; + spinlock_t page_lock; + spinlock_t tx_irq_lock; +@@ -1021,6 +1029,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk + int mtk_eth_offload_init(struct mtk_eth *eth); + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data); ++void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev); + + + #endif /* MTK_ETH_H */ diff --git a/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch b/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch new file mode 100644 index 00000000000..9f2512a1d05 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch @@ -0,0 +1,30 @@ +From: Felix Fietkau +Date: Mon, 7 Feb 2022 10:27:22 +0100 +Subject: [PATCH] arm64: dts: mediatek: mt7622: add support for coherent + DMA + +It improves performance by eliminating the need for a cache flush on rx and tx + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -357,7 +357,7 @@ + }; + + cci_control2: slave-if@5000 { +- compatible = "arm,cci-400-ctrl-if"; ++ compatible = "arm,cci-400-ctrl-if", "syscon"; + interface-type = "ace"; + reg = <0x5000 0x1000>; + }; +@@ -938,6 +938,8 @@ + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys>; ++ mediatek,cci-control = <&cci_control2>; ++ dma-coherent; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; diff --git a/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch b/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch new file mode 100644 index 00000000000..2f3a0827fe4 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch @@ -0,0 +1,1679 @@ +From: Felix Fietkau +Date: Sat, 5 Feb 2022 17:56:08 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for Wireless + Ethernet Dispatch (WED) + +The Wireless Ethernet Dispatch subsystem on the MT7622 SoC can be +configured to intercept and handle access to the DMA queues and +PCIe interrupts for a MT7615/MT7915 wireless card. +It can manage the internal WDMA (Wireless DMA) controller, which allows +ethernet packets to be passed from the packet switch engine (PSE) to the +wireless card, bypassing the CPU entirely. +This can be used to implement hardware flow offloading from ethernet to +WLAN. + +Signed-off-by: Felix Fietkau +--- + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.h + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_debugfs.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_ops.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_regs.h + create mode 100644 include/linux/soc/mediatek/mtk_wed.h + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -7,6 +7,10 @@ config NET_VENDOR_MEDIATEK + + if NET_VENDOR_MEDIATEK + ++config NET_MEDIATEK_SOC_WED ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ def_bool NET_MEDIATEK_SOC != n ++ + config NET_MEDIATEK_SOC + tristate "MediaTek SoC Gigabit Ethernet support" + depends on NET_DSA || !NET_DSA +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -5,4 +5,9 @@ + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o + mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o ++mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o ++ifdef CONFIG_DEBUG_FS ++mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o ++endif ++obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o + obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -24,6 +24,7 @@ + #include + + #include "mtk_eth_soc.h" ++#include "mtk_wed.h" + + static int mtk_msg_level = -1; + module_param_named(msg_level, mtk_msg_level, int, 0); +@@ -3209,6 +3210,22 @@ static int mtk_probe(struct platform_dev + } + } + ++ for (i = 0;; i++) { ++ struct device_node *np = of_parse_phandle(pdev->dev.of_node, ++ "mediatek,wed", i); ++ static const u32 wdma_regs[] = { ++ MTK_WDMA0_BASE, ++ MTK_WDMA1_BASE ++ }; ++ void __iomem *wdma; ++ ++ if (!np || i >= ARRAY_SIZE(wdma_regs)) ++ break; ++ ++ wdma = eth->base + wdma_regs[i]; ++ mtk_wed_add_hw(np, eth, wdma, i); ++ } ++ + for (i = 0; i < 3; i++) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0) + eth->irq[i] = eth->irq[0]; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -295,6 +295,9 @@ + #define MTK_GDM1_TX_GPCNT 0x2438 + #define MTK_STAT_OFFSET 0x40 + ++#define MTK_WDMA0_BASE 0x2800 ++#define MTK_WDMA1_BASE 0x2c00 ++ + /* QDMA descriptor txd4 */ + #define TX_DMA_CHKSUM (0x7 << 29) + #define TX_DMA_TSO BIT(28) +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -0,0 +1,875 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2021 Felix Fietkau */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "mtk_eth_soc.h" ++#include "mtk_wed_regs.h" ++#include "mtk_wed.h" ++#include "mtk_ppe.h" ++ ++#define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000) ++ ++#define MTK_WED_PKT_SIZE 1900 ++#define MTK_WED_BUF_SIZE 2048 ++#define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048) ++ ++#define MTK_WED_TX_RING_SIZE 2048 ++#define MTK_WED_WDMA_RING_SIZE 1024 ++ ++static struct mtk_wed_hw *hw_list[2]; ++static DEFINE_MUTEX(hw_lock); ++ ++static void ++wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) ++{ ++ regmap_update_bits(dev->hw->regs, reg, mask | val, val); ++} ++ ++static void ++wed_set(struct mtk_wed_device *dev, u32 reg, u32 mask) ++{ ++ return wed_m32(dev, reg, 0, mask); ++} ++ ++static void ++wed_clr(struct mtk_wed_device *dev, u32 reg, u32 mask) ++{ ++ return wed_m32(dev, reg, mask, 0); ++} ++ ++static void ++wdma_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) ++{ ++ wdma_w32(dev, reg, (wdma_r32(dev, reg) & ~mask) | val); ++} ++ ++static void ++wdma_set(struct mtk_wed_device *dev, u32 reg, u32 mask) ++{ ++ wdma_m32(dev, reg, 0, mask); ++} ++ ++static u32 ++mtk_wed_read_reset(struct mtk_wed_device *dev) ++{ ++ return wed_r32(dev, MTK_WED_RESET); ++} ++ ++static void ++mtk_wed_reset(struct mtk_wed_device *dev, u32 mask) ++{ ++ u32 status; ++ ++ wed_w32(dev, MTK_WED_RESET, mask); ++ if (readx_poll_timeout(mtk_wed_read_reset, dev, status, ++ !(status & mask), 0, 1000)) ++ WARN_ON_ONCE(1); ++} ++ ++static struct mtk_wed_hw * ++mtk_wed_assign(struct mtk_wed_device *dev) ++{ ++ struct mtk_wed_hw *hw; ++ ++ hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; ++ if (!hw || hw->wed_dev) ++ return NULL; ++ ++ hw->wed_dev = dev; ++ return hw; ++} ++ ++static int ++mtk_wed_buffer_alloc(struct mtk_wed_device *dev) ++{ ++ struct mtk_wdma_desc *desc; ++ dma_addr_t desc_phys; ++ void **page_list; ++ int token = dev->wlan.token_start; ++ int ring_size; ++ int n_pages; ++ int i, page_idx; ++ ++ ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1); ++ n_pages = ring_size / MTK_WED_BUF_PER_PAGE; ++ ++ page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL); ++ if (!page_list) ++ return -ENOMEM; ++ ++ dev->buf_ring.size = ring_size; ++ dev->buf_ring.pages = page_list; ++ ++ desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc), ++ &desc_phys, GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ dev->buf_ring.desc = desc; ++ dev->buf_ring.desc_phys = desc_phys; ++ ++ for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) { ++ dma_addr_t page_phys, buf_phys; ++ struct page *page; ++ void *buf; ++ int s; ++ ++ page = __dev_alloc_pages(GFP_KERNEL, 0); ++ if (!page) ++ return -ENOMEM; ++ ++ page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE, ++ DMA_BIDIRECTIONAL); ++ if (dma_mapping_error(dev->hw->dev, page_phys)) { ++ __free_page(page); ++ return -ENOMEM; ++ } ++ ++ page_list[page_idx++] = page; ++ dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE, ++ DMA_BIDIRECTIONAL); ++ ++ buf = page_to_virt(page); ++ buf_phys = page_phys; ++ ++ for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) { ++ u32 txd_size; ++ ++ txd_size = dev->wlan.init_buf(buf, buf_phys, token++); ++ ++ desc->buf0 = buf_phys; ++ desc->buf1 = buf_phys + txd_size; ++ desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, ++ txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ desc->info = 0; ++ desc++; ++ ++ buf += MTK_WED_BUF_SIZE; ++ buf_phys += MTK_WED_BUF_SIZE; ++ } ++ ++ dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE, ++ DMA_BIDIRECTIONAL); ++ } ++ ++ return 0; ++} ++ ++static void ++mtk_wed_free_buffer(struct mtk_wed_device *dev) ++{ ++ struct mtk_wdma_desc *desc = dev->buf_ring.desc; ++ void **page_list = dev->buf_ring.pages; ++ int page_idx; ++ int i; ++ ++ if (!page_list) ++ return; ++ ++ if (!desc) ++ goto free_pagelist; ++ ++ for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) { ++ void *page = page_list[page_idx++]; ++ ++ if (!page) ++ break; ++ ++ dma_unmap_page(dev->hw->dev, desc[i].buf0, ++ PAGE_SIZE, DMA_BIDIRECTIONAL); ++ __free_page(page); ++ } ++ ++ dma_free_coherent(dev->hw->dev, dev->buf_ring.size * sizeof(*desc), ++ desc, dev->buf_ring.desc_phys); ++ ++free_pagelist: ++ kfree(page_list); ++} ++ ++static void ++mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring) ++{ ++ if (!ring->desc) ++ return; ++ ++ dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc), ++ ring->desc, ring->desc_phys); ++} ++ ++static void ++mtk_wed_free_tx_rings(struct mtk_wed_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) ++ mtk_wed_free_ring(dev, &dev->tx_ring[i]); ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) ++ mtk_wed_free_ring(dev, &dev->tx_wdma[i]); ++} ++ ++static void ++mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en) ++{ ++ u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ ++ if (!dev->hw->num_flows) ++ mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; ++ ++ wed_w32(dev, MTK_WED_EXT_INT_MASK, en ? mask : 0); ++ wed_r32(dev, MTK_WED_EXT_INT_MASK); ++} ++ ++static void ++mtk_wed_stop(struct mtk_wed_device *dev) ++{ ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); ++ mtk_wed_set_ext_int(dev, false); ++ ++ wed_clr(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WPDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0); ++ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0); ++ wdma_w32(dev, MTK_WDMA_INT_MASK, 0); ++ wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); ++ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); ++ ++ wed_clr(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_TX_DMA_EN | ++ MTK_WED_GLO_CFG_RX_DMA_EN); ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); ++} ++ ++static void ++mtk_wed_detach(struct mtk_wed_device *dev) ++{ ++ struct device_node *wlan_node = dev->wlan.pci_dev->dev.of_node; ++ struct mtk_wed_hw *hw = dev->hw; ++ ++ mutex_lock(&hw_lock); ++ ++ mtk_wed_stop(dev); ++ ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); ++ ++ mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ ++ mtk_wed_free_buffer(dev); ++ mtk_wed_free_tx_rings(dev); ++ ++ if (of_dma_is_coherent(wlan_node)) ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, ++ BIT(hw->index), BIT(hw->index)); ++ ++ if (!hw_list[!hw->index]->wed_dev && ++ hw->eth->dma_dev != hw->eth->dev) ++ mtk_eth_set_dma_device(hw->eth, hw->eth->dev); ++ ++ memset(dev, 0, sizeof(*dev)); ++ module_put(THIS_MODULE); ++ ++ hw->wed_dev = NULL; ++ mutex_unlock(&hw_lock); ++} ++ ++static void ++mtk_wed_hw_init_early(struct mtk_wed_device *dev) ++{ ++ u32 mask, set; ++ u32 offset; ++ ++ mtk_wed_stop(dev); ++ mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ ++ mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE | ++ MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE | ++ MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE; ++ set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) | ++ MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP | ++ MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; ++ wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); ++ ++ wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES); ++ ++ offset = dev->hw->index ? 0x04000400 : 0; ++ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); ++ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); ++ ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index)); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); ++} ++ ++static void ++mtk_wed_hw_init(struct mtk_wed_device *dev) ++{ ++ if (dev->init_done) ++ return; ++ ++ dev->init_done = true; ++ mtk_wed_set_ext_int(dev, false); ++ wed_w32(dev, MTK_WED_TX_BM_CTRL, ++ MTK_WED_TX_BM_CTRL_PAUSE | ++ FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, ++ dev->buf_ring.size / 128) | ++ FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, ++ MTK_WED_TX_RING_SIZE / 256)); ++ ++ wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); ++ ++ wed_w32(dev, MTK_WED_TX_BM_TKID, ++ FIELD_PREP(MTK_WED_TX_BM_TKID_START, ++ dev->wlan.token_start) | ++ FIELD_PREP(MTK_WED_TX_BM_TKID_END, ++ dev->wlan.token_start + dev->wlan.nbuf - 1)); ++ ++ wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); ++ ++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | ++ MTK_WED_TX_BM_DYN_THR_HI); ++ ++ mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); ++ ++ wed_set(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ ++ wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); ++} ++ ++static void ++mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size) ++{ ++ int i; ++ ++ for (i = 0; i < size; i++) { ++ desc[i].buf0 = 0; ++ desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); ++ desc[i].buf1 = 0; ++ desc[i].info = 0; ++ } ++} ++ ++static u32 ++mtk_wed_check_busy(struct mtk_wed_device *dev) ++{ ++ if (wed_r32(dev, MTK_WED_GLO_CFG) & MTK_WED_GLO_CFG_TX_DMA_BUSY) ++ return true; ++ ++ if (wed_r32(dev, MTK_WED_WPDMA_GLO_CFG) & ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY) ++ return true; ++ ++ if (wed_r32(dev, MTK_WED_CTRL) & MTK_WED_CTRL_WDMA_INT_AGENT_BUSY) ++ return true; ++ ++ if (wed_r32(dev, MTK_WED_WDMA_GLO_CFG) & ++ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) ++ return true; ++ ++ if (wdma_r32(dev, MTK_WDMA_GLO_CFG) & ++ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) ++ return true; ++ ++ if (wed_r32(dev, MTK_WED_CTRL) & ++ (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY)) ++ return true; ++ ++ return false; ++} ++ ++static int ++mtk_wed_poll_busy(struct mtk_wed_device *dev) ++{ ++ int sleep = 15000; ++ int timeout = 100 * sleep; ++ u32 val; ++ ++ return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep, ++ timeout, false, dev); ++} ++ ++static void ++mtk_wed_reset_dma(struct mtk_wed_device *dev) ++{ ++ bool busy = false; ++ u32 val; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) { ++ struct mtk_wdma_desc *desc = dev->tx_ring[i].desc; ++ ++ if (!desc) ++ continue; ++ ++ mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE); ++ } ++ ++ if (mtk_wed_poll_busy(dev)) ++ busy = mtk_wed_check_busy(dev); ++ ++ if (busy) { ++ mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA); ++ } else { ++ wed_w32(dev, MTK_WED_RESET_IDX, ++ MTK_WED_RESET_IDX_TX | ++ MTK_WED_RESET_IDX_RX); ++ wed_w32(dev, MTK_WED_RESET_IDX, 0); ++ } ++ ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); ++ ++ if (busy) { ++ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); ++ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV); ++ } else { ++ wed_w32(dev, MTK_WED_WDMA_RESET_IDX, ++ MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV); ++ wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0); ++ ++ wed_set(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); ++ ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); ++ } ++ ++ for (i = 0; i < 100; i++) { ++ val = wed_r32(dev, MTK_WED_TX_BM_INTF); ++ if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40) ++ break; ++ } ++ ++ mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT); ++ mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); ++ ++ if (busy) { ++ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT); ++ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV); ++ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV); ++ } else { ++ wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, ++ MTK_WED_WPDMA_RESET_IDX_TX | ++ MTK_WED_WPDMA_RESET_IDX_RX); ++ wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); ++ } ++ ++} ++ ++static int ++mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, ++ int size) ++{ ++ ring->desc = dma_alloc_coherent(dev->hw->dev, ++ size * sizeof(*ring->desc), ++ &ring->desc_phys, GFP_KERNEL); ++ if (!ring->desc) ++ return -ENOMEM; ++ ++ ring->size = size; ++ mtk_wed_ring_reset(ring->desc, size); ++ ++ return 0; ++} ++ ++static int ++mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) ++{ ++ struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; ++ ++ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE)) ++ return -ENOMEM; ++ ++ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, ++ wdma->desc_phys); ++ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT, ++ size); ++ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); ++ ++ wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, ++ wdma->desc_phys); ++ wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT, ++ size); ++ ++ return 0; ++} ++ ++static void ++mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) ++{ ++ u32 wdma_mask; ++ u32 val; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) ++ if (!dev->tx_wdma[i].desc) ++ mtk_wed_wdma_ring_setup(dev, i, 16); ++ ++ wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); ++ ++ mtk_wed_hw_init(dev); ++ ++ wed_set(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WPDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ ++ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, ++ MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | ++ MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); ++ ++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, ++ MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); ++ ++ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); ++ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); ++ ++ wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); ++ wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); ++ ++ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask); ++ wed_w32(dev, MTK_WED_INT_MASK, irq_mask); ++ ++ wed_set(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_TX_DMA_EN | ++ MTK_WED_GLO_CFG_RX_DMA_EN); ++ wed_set(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); ++ wed_set(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); ++ ++ mtk_wed_set_ext_int(dev, true); ++ val = dev->wlan.wpdma_phys | ++ MTK_PCIE_MIRROR_MAP_EN | ++ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index); ++ ++ if (dev->hw->index) ++ val |= BIT(1); ++ val |= BIT(0); ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, val); ++ ++ dev->running = true; ++} ++ ++static int ++mtk_wed_attach(struct mtk_wed_device *dev) ++ __releases(RCU) ++{ ++ struct mtk_wed_hw *hw; ++ int ret = 0; ++ ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), ++ "mtk_wed_attach without holding the RCU read lock"); ++ ++ if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 || ++ !try_module_get(THIS_MODULE)) ++ ret = -ENODEV; ++ ++ rcu_read_unlock(); ++ ++ if (ret) ++ return ret; ++ ++ mutex_lock(&hw_lock); ++ ++ hw = mtk_wed_assign(dev); ++ if (!hw) { ++ module_put(THIS_MODULE); ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index); ++ ++ dev->hw = hw; ++ dev->dev = hw->dev; ++ dev->irq = hw->irq; ++ dev->wdma_idx = hw->index; ++ ++ if (hw->eth->dma_dev == hw->eth->dev && ++ of_dma_is_coherent(hw->eth->dev->of_node)) ++ mtk_eth_set_dma_device(hw->eth, hw->dev); ++ ++ ret = mtk_wed_buffer_alloc(dev); ++ if (ret) { ++ mtk_wed_detach(dev); ++ goto out; ++ } ++ ++ mtk_wed_hw_init_early(dev); ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0); ++ ++out: ++ mutex_unlock(&hw_lock); ++ ++ return ret; ++} ++ ++static int ++mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs) ++{ ++ struct mtk_wed_ring *ring = &dev->tx_ring[idx]; ++ ++ /* ++ * Tx ring redirection: ++ * Instead of configuring the WLAN PDMA TX ring directly, the WLAN ++ * driver allocated DMA ring gets configured into WED MTK_WED_RING_TX(n) ++ * registers. ++ * ++ * WED driver posts its own DMA ring as WLAN PDMA TX and configures it ++ * into MTK_WED_WPDMA_RING_TX(n) registers. ++ * It gets filled with packets picked up from WED TX ring and from ++ * WDMA RX. ++ */ ++ ++ BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); ++ ++ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) ++ return -ENOMEM; ++ ++ if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) ++ return -ENOMEM; ++ ++ ring->reg_base = MTK_WED_RING_TX(idx); ++ ring->wpdma = regs; ++ ++ /* WED -> WPDMA */ ++ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys); ++ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_TX_RING_SIZE); ++ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_CPU_IDX, 0); ++ ++ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE, ++ ring->desc_phys); ++ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT, ++ MTK_WED_TX_RING_SIZE); ++ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); ++ ++ return 0; ++} ++ ++static int ++mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs) ++{ ++ struct mtk_wed_ring *ring = &dev->txfree_ring; ++ int i; ++ ++ /* ++ * For txfree event handling, the same DMA ring is shared between WED ++ * and WLAN. The WLAN driver accesses the ring index registers through ++ * WED ++ */ ++ ring->reg_base = MTK_WED_RING_RX(1); ++ ring->wpdma = regs; ++ ++ for (i = 0; i < 12; i += 4) { ++ u32 val = readl(regs + i); ++ ++ wed_w32(dev, MTK_WED_RING_RX(1) + i, val); ++ wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val); ++ } ++ ++ return 0; ++} ++ ++static u32 ++mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) ++{ ++ u32 val; ++ ++ val = wed_r32(dev, MTK_WED_EXT_INT_STATUS); ++ wed_w32(dev, MTK_WED_EXT_INT_STATUS, val); ++ val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ if (!dev->hw->num_flows) ++ val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; ++ if (val && net_ratelimit()) ++ pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val); ++ ++ val = wed_r32(dev, MTK_WED_INT_STATUS); ++ val &= mask; ++ wed_w32(dev, MTK_WED_INT_STATUS, val); /* ACK */ ++ ++ return val; ++} ++ ++static void ++mtk_wed_irq_set_mask(struct mtk_wed_device *dev, u32 mask) ++{ ++ if (!dev->running) ++ return; ++ ++ mtk_wed_set_ext_int(dev, !!mask); ++ wed_w32(dev, MTK_WED_INT_MASK, mask); ++} ++ ++int mtk_wed_flow_add(int index) ++{ ++ struct mtk_wed_hw *hw = hw_list[index]; ++ int ret; ++ ++ if (!hw || !hw->wed_dev) ++ return -ENODEV; ++ ++ if (hw->num_flows) { ++ hw->num_flows++; ++ return 0; ++ } ++ ++ mutex_lock(&hw_lock); ++ if (!hw->wed_dev) { ++ ret = -ENODEV; ++ goto out; ++ } ++ ++ ret = hw->wed_dev->wlan.offload_enable(hw->wed_dev); ++ if (!ret) ++ hw->num_flows++; ++ mtk_wed_set_ext_int(hw->wed_dev, true); ++ ++out: ++ mutex_unlock(&hw_lock); ++ ++ return ret; ++} ++ ++void mtk_wed_flow_remove(int index) ++{ ++ struct mtk_wed_hw *hw = hw_list[index]; ++ ++ if (!hw) ++ return; ++ ++ if (--hw->num_flows) ++ return; ++ ++ mutex_lock(&hw_lock); ++ if (!hw->wed_dev) ++ goto out; ++ ++ hw->wed_dev->wlan.offload_disable(hw->wed_dev); ++ mtk_wed_set_ext_int(hw->wed_dev, true); ++ ++out: ++ mutex_unlock(&hw_lock); ++} ++ ++void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, ++ void __iomem *wdma, int index) ++{ ++ static const struct mtk_wed_ops wed_ops = { ++ .attach = mtk_wed_attach, ++ .tx_ring_setup = mtk_wed_tx_ring_setup, ++ .txfree_ring_setup = mtk_wed_txfree_ring_setup, ++ .start = mtk_wed_start, ++ .stop = mtk_wed_stop, ++ .reset_dma = mtk_wed_reset_dma, ++ .reg_read = wed_r32, ++ .reg_write = wed_w32, ++ .irq_get = mtk_wed_irq_get, ++ .irq_set_mask = mtk_wed_irq_set_mask, ++ .detach = mtk_wed_detach, ++ }; ++ struct device_node *eth_np = eth->dev->of_node; ++ struct platform_device *pdev; ++ struct mtk_wed_hw *hw; ++ struct regmap *regs; ++ int irq; ++ ++ if (!np) ++ return; ++ ++ pdev = of_find_device_by_node(np); ++ if (!pdev) ++ return; ++ ++ get_device(&pdev->dev); ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return; ++ ++ regs = syscon_regmap_lookup_by_phandle(np, NULL); ++ if (!regs) ++ return; ++ ++ rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); ++ ++ mutex_lock(&hw_lock); ++ ++ if (WARN_ON(hw_list[index])) ++ goto unlock; ++ ++ hw = kzalloc(sizeof(*hw), GFP_KERNEL); ++ hw->node = np; ++ hw->regs = regs; ++ hw->eth = eth; ++ hw->dev = &pdev->dev; ++ hw->wdma = wdma; ++ hw->index = index; ++ hw->irq = irq; ++ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,pcie-mirror"); ++ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,hifsys"); ++ if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { ++ kfree(hw); ++ goto unlock; ++ } ++ ++ if (!index) { ++ regmap_write(hw->mirror, 0, 0); ++ regmap_write(hw->mirror, 4, 0); ++ } ++ mtk_wed_hw_add_debugfs(hw); ++ ++ hw_list[index] = hw; ++ ++unlock: ++ mutex_unlock(&hw_lock); ++} ++ ++void mtk_wed_exit(void) ++{ ++ int i; ++ ++ rcu_assign_pointer(mtk_soc_wed_ops, NULL); ++ ++ synchronize_rcu(); ++ ++ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { ++ struct mtk_wed_hw *hw; ++ ++ hw = hw_list[i]; ++ if (!hw) ++ continue; ++ ++ hw_list[i] = NULL; ++ debugfs_remove(hw->debugfs_dir); ++ put_device(hw->dev); ++ kfree(hw); ++ } ++} +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2021 Felix Fietkau */ ++ ++#ifndef __MTK_WED_PRIV_H ++#define __MTK_WED_PRIV_H ++ ++#include ++#include ++#include ++ ++struct mtk_eth; ++ ++struct mtk_wed_hw { ++ struct device_node *node; ++ struct mtk_eth *eth; ++ struct regmap *regs; ++ struct regmap *hifsys; ++ struct device *dev; ++ void __iomem *wdma; ++ struct regmap *mirror; ++ struct dentry *debugfs_dir; ++ struct mtk_wed_device *wed_dev; ++ u32 debugfs_reg; ++ u32 num_flows; ++ char dirname[5]; ++ int irq; ++ int index; ++}; ++ ++ ++#ifdef CONFIG_NET_MEDIATEK_SOC_WED ++static inline void ++wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val) ++{ ++ regmap_write(dev->hw->regs, reg, val); ++} ++ ++static inline u32 ++wed_r32(struct mtk_wed_device *dev, u32 reg) ++{ ++ unsigned int val; ++ ++ regmap_read(dev->hw->regs, reg, &val); ++ ++ return val; ++} ++ ++static inline void ++wdma_w32(struct mtk_wed_device *dev, u32 reg, u32 val) ++{ ++ writel(val, dev->hw->wdma + reg); ++} ++ ++static inline u32 ++wdma_r32(struct mtk_wed_device *dev, u32 reg) ++{ ++ return readl(dev->hw->wdma + reg); ++} ++ ++static inline u32 ++wpdma_tx_r32(struct mtk_wed_device *dev, int ring, u32 reg) ++{ ++ if (!dev->tx_ring[ring].wpdma) ++ return 0; ++ ++ return readl(dev->tx_ring[ring].wpdma + reg); ++} ++ ++static inline void ++wpdma_tx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val) ++{ ++ if (!dev->tx_ring[ring].wpdma) ++ return; ++ ++ writel(val, dev->tx_ring[ring].wpdma + reg); ++} ++ ++static inline u32 ++wpdma_txfree_r32(struct mtk_wed_device *dev, u32 reg) ++{ ++ if (!dev->txfree_ring.wpdma) ++ return 0; ++ ++ return readl(dev->txfree_ring.wpdma + reg); ++} ++ ++static inline void ++wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val) ++{ ++ if (!dev->txfree_ring.wpdma) ++ return; ++ ++ writel(val, dev->txfree_ring.wpdma + reg); ++} ++ ++void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, ++ void __iomem *wdma, int index); ++void mtk_wed_exit(void); ++int mtk_wed_flow_add(int index); ++void mtk_wed_flow_remove(int index); ++#else ++static inline void ++mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, ++ void __iomem *wdma, int index) ++{ ++} ++static inline void ++mtk_wed_exit(void) ++{ ++} ++static inline int mtk_wed_flow_add(int index) ++{ ++ return -EINVAL; ++} ++static inline void mtk_wed_flow_remove(int index) ++{ ++} ++#endif ++ ++#ifdef CONFIG_DEBUG_FS ++void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw); ++#else ++static inline void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw) ++{ ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c +@@ -0,0 +1,175 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2021 Felix Fietkau */ ++ ++#include ++#include "mtk_wed.h" ++#include "mtk_wed_regs.h" ++ ++struct reg_dump { ++ const char *name; ++ u16 offset; ++ u8 type; ++ u8 base; ++}; ++ ++enum { ++ DUMP_TYPE_STRING, ++ DUMP_TYPE_WED, ++ DUMP_TYPE_WDMA, ++ DUMP_TYPE_WPDMA_TX, ++ DUMP_TYPE_WPDMA_TXFREE, ++}; ++ ++#define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING } ++#define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ } ++#define DUMP_RING(_prefix, _base, ...) \ ++ { _prefix " BASE", _base, __VA_ARGS__ }, \ ++ { _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \ ++ { _prefix " CIDX", _base + 0x8, __VA_ARGS__ }, \ ++ { _prefix " DIDX", _base + 0xc, __VA_ARGS__ } ++ ++#define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED) ++#define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED) ++ ++#define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA) ++#define DUMP_WDMA_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WDMA) ++ ++#define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n) ++#define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE) ++ ++static void ++print_reg_val(struct seq_file *s, const char *name, u32 val) ++{ ++ seq_printf(s, "%-32s %08x\n", name, val); ++} ++ ++static void ++dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev, ++ const struct reg_dump *regs, int n_regs) ++{ ++ const struct reg_dump *cur; ++ u32 val; ++ ++ for (cur = regs; cur < ®s[n_regs]; cur++) { ++ switch (cur->type) { ++ case DUMP_TYPE_STRING: ++ seq_printf(s, "%s======== %s:\n", ++ cur > regs ? "\n" : "", ++ cur->name); ++ continue; ++ case DUMP_TYPE_WED: ++ val = wed_r32(dev, cur->offset); ++ break; ++ case DUMP_TYPE_WDMA: ++ val = wdma_r32(dev, cur->offset); ++ break; ++ case DUMP_TYPE_WPDMA_TX: ++ val = wpdma_tx_r32(dev, cur->base, cur->offset); ++ break; ++ case DUMP_TYPE_WPDMA_TXFREE: ++ val = wpdma_txfree_r32(dev, cur->offset); ++ break; ++ } ++ print_reg_val(s, cur->name, val); ++ } ++} ++ ++ ++static int ++wed_txinfo_show(struct seq_file *s, void *data) ++{ ++ static const struct reg_dump regs[] = { ++ DUMP_STR("WED TX"), ++ DUMP_WED(WED_TX_MIB(0)), ++ DUMP_WED_RING(WED_RING_TX(0)), ++ ++ DUMP_WED(WED_TX_MIB(1)), ++ DUMP_WED_RING(WED_RING_TX(1)), ++ ++ DUMP_STR("WPDMA TX"), ++ DUMP_WED(WED_WPDMA_TX_MIB(0)), ++ DUMP_WED_RING(WED_WPDMA_RING_TX(0)), ++ DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(0)), ++ ++ DUMP_WED(WED_WPDMA_TX_MIB(1)), ++ DUMP_WED_RING(WED_WPDMA_RING_TX(1)), ++ DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(1)), ++ ++ DUMP_STR("WPDMA TX"), ++ DUMP_WPDMA_TX_RING(0), ++ DUMP_WPDMA_TX_RING(1), ++ ++ DUMP_STR("WED WDMA RX"), ++ DUMP_WED(WED_WDMA_RX_MIB(0)), ++ DUMP_WED_RING(WED_WDMA_RING_RX(0)), ++ DUMP_WED(WED_WDMA_RX_THRES(0)), ++ DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(0)), ++ DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(0)), ++ ++ DUMP_WED(WED_WDMA_RX_MIB(1)), ++ DUMP_WED_RING(WED_WDMA_RING_RX(1)), ++ DUMP_WED(WED_WDMA_RX_THRES(1)), ++ DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(1)), ++ DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(1)), ++ ++ DUMP_STR("WDMA RX"), ++ DUMP_WDMA(WDMA_GLO_CFG), ++ DUMP_WDMA_RING(WDMA_RING_RX(0)), ++ DUMP_WDMA_RING(WDMA_RING_RX(1)), ++ }; ++ struct mtk_wed_hw *hw = s->private; ++ struct mtk_wed_device *dev = hw->wed_dev; ++ ++ if (!dev) ++ return 0; ++ ++ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs)); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(wed_txinfo); ++ ++ ++static int ++mtk_wed_reg_set(void *data, u64 val) ++{ ++ struct mtk_wed_hw *hw = data; ++ ++ regmap_write(hw->regs, hw->debugfs_reg, val); ++ ++ return 0; ++} ++ ++static int ++mtk_wed_reg_get(void *data, u64 *val) ++{ ++ struct mtk_wed_hw *hw = data; ++ unsigned int regval; ++ int ret; ++ ++ ret = regmap_read(hw->regs, hw->debugfs_reg, ®val); ++ if (ret) ++ return ret; ++ ++ *val = regval; ++ ++ return 0; ++} ++ ++DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set, ++ "0x%08llx\n"); ++ ++void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw) ++{ ++ struct dentry *dir; ++ ++ snprintf(hw->dirname, sizeof(hw->dirname), "wed%d", hw->index); ++ dir = debugfs_create_dir(hw->dirname, NULL); ++ if (!dir) ++ return; ++ ++ hw->debugfs_dir = dir; ++ debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg); ++ debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval); ++ debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops); ++} +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_ops.c +@@ -0,0 +1,8 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2020 Felix Fietkau */ ++ ++#include ++#include ++ ++const struct mtk_wed_ops __rcu *mtk_soc_wed_ops; ++EXPORT_SYMBOL_GPL(mtk_soc_wed_ops); +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -0,0 +1,251 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2020 Felix Fietkau */ ++ ++#ifndef __MTK_WED_REGS_H ++#define __MTK_WED_REGS_H ++ ++#define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0) ++#define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15) ++#define MTK_WDMA_DESC_CTRL_BURST BIT(16) ++#define MTK_WDMA_DESC_CTRL_LEN0 GENMASK(29, 16) ++#define MTK_WDMA_DESC_CTRL_LAST_SEG0 BIT(30) ++#define MTK_WDMA_DESC_CTRL_DMA_DONE BIT(31) ++ ++struct mtk_wdma_desc { ++ __le32 buf0; ++ __le32 ctrl; ++ __le32 buf1; ++ __le32 info; ++} __packed __aligned(4); ++ ++#define MTK_WED_RESET 0x008 ++#define MTK_WED_RESET_TX_BM BIT(0) ++#define MTK_WED_RESET_TX_FREE_AGENT BIT(4) ++#define MTK_WED_RESET_WPDMA_TX_DRV BIT(8) ++#define MTK_WED_RESET_WPDMA_RX_DRV BIT(9) ++#define MTK_WED_RESET_WPDMA_INT_AGENT BIT(11) ++#define MTK_WED_RESET_WED_TX_DMA BIT(12) ++#define MTK_WED_RESET_WDMA_RX_DRV BIT(17) ++#define MTK_WED_RESET_WDMA_INT_AGENT BIT(19) ++#define MTK_WED_RESET_WED BIT(31) ++ ++#define MTK_WED_CTRL 0x00c ++#define MTK_WED_CTRL_WPDMA_INT_AGENT_EN BIT(0) ++#define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY BIT(1) ++#define MTK_WED_CTRL_WDMA_INT_AGENT_EN BIT(2) ++#define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3) ++#define MTK_WED_CTRL_WED_TX_BM_EN BIT(8) ++#define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9) ++#define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10) ++#define MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY BIT(11) ++#define MTK_WED_CTRL_RESERVE_EN BIT(12) ++#define MTK_WED_CTRL_RESERVE_BUSY BIT(13) ++#define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24) ++#define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28) ++ ++#define MTK_WED_EXT_INT_STATUS 0x020 ++#define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR BIT(0) ++#define MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD BIT(1) ++#define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID BIT(4) ++#define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH BIT(8) ++#define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH BIT(9) ++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH BIT(12) ++#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH BIT(13) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR BIT(16) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR BIT(17) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT BIT(18) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20) ++#define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21) ++#define MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR BIT(22) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24) ++#define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ ++ MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ ++ MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \ ++ MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \ ++ MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \ ++ MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \ ++ MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR | \ ++ MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR) ++ ++#define MTK_WED_EXT_INT_MASK 0x028 ++ ++#define MTK_WED_STATUS 0x060 ++#define MTK_WED_STATUS_TX GENMASK(15, 8) ++ ++#define MTK_WED_TX_BM_CTRL 0x080 ++#define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0) ++#define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16) ++#define MTK_WED_TX_BM_CTRL_PAUSE BIT(28) ++ ++#define MTK_WED_TX_BM_BASE 0x084 ++ ++#define MTK_WED_TX_BM_TKID 0x088 ++#define MTK_WED_TX_BM_TKID_START GENMASK(15, 0) ++#define MTK_WED_TX_BM_TKID_END GENMASK(31, 16) ++ ++#define MTK_WED_TX_BM_BUF_LEN 0x08c ++ ++#define MTK_WED_TX_BM_INTF 0x09c ++#define MTK_WED_TX_BM_INTF_TKID GENMASK(15, 0) ++#define MTK_WED_TX_BM_INTF_TKFIFO_FDEP GENMASK(23, 16) ++#define MTK_WED_TX_BM_INTF_TKID_VALID BIT(28) ++#define MTK_WED_TX_BM_INTF_TKID_READ BIT(29) ++ ++#define MTK_WED_TX_BM_DYN_THR 0x0a0 ++#define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0) ++#define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16) ++ ++#define MTK_WED_INT_STATUS 0x200 ++#define MTK_WED_INT_MASK 0x204 ++ ++#define MTK_WED_GLO_CFG 0x208 ++#define MTK_WED_GLO_CFG_TX_DMA_EN BIT(0) ++#define MTK_WED_GLO_CFG_TX_DMA_BUSY BIT(1) ++#define MTK_WED_GLO_CFG_RX_DMA_EN BIT(2) ++#define MTK_WED_GLO_CFG_RX_DMA_BUSY BIT(3) ++#define MTK_WED_GLO_CFG_RX_BT_SIZE GENMASK(5, 4) ++#define MTK_WED_GLO_CFG_TX_WB_DDONE BIT(6) ++#define MTK_WED_GLO_CFG_BIG_ENDIAN BIT(7) ++#define MTK_WED_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8) ++#define MTK_WED_GLO_CFG_TX_BT_SIZE_LO BIT(9) ++#define MTK_WED_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10) ++#define MTK_WED_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) ++#define MTK_WED_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13) ++#define MTK_WED_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22) ++#define MTK_WED_GLO_CFG_SW_RESET BIT(24) ++#define MTK_WED_GLO_CFG_FIRST_TOKEN_ONLY BIT(26) ++#define MTK_WED_GLO_CFG_OMIT_RX_INFO BIT(27) ++#define MTK_WED_GLO_CFG_OMIT_TX_INFO BIT(28) ++#define MTK_WED_GLO_CFG_BYTE_SWAP BIT(29) ++#define MTK_WED_GLO_CFG_RX_2B_OFFSET BIT(31) ++ ++#define MTK_WED_RESET_IDX 0x20c ++#define MTK_WED_RESET_IDX_TX GENMASK(3, 0) ++#define MTK_WED_RESET_IDX_RX GENMASK(17, 16) ++ ++#define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4) ++ ++#define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10) ++ ++#define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10) ++ ++#define MTK_WED_WPDMA_INT_TRIGGER 0x504 ++#define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1) ++#define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4) ++ ++#define MTK_WED_WPDMA_GLO_CFG 0x508 ++#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN BIT(0) ++#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY BIT(1) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN BIT(2) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY BIT(3) ++#define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE GENMASK(5, 4) ++#define MTK_WED_WPDMA_GLO_CFG_TX_WB_DDONE BIT(6) ++#define MTK_WED_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) ++#define MTK_WED_WPDMA_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8) ++#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_LO BIT(9) ++#define MTK_WED_WPDMA_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10) ++#define MTK_WED_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) ++#define MTK_WED_WPDMA_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13) ++#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22) ++#define MTK_WED_WPDMA_GLO_CFG_SW_RESET BIT(24) ++#define MTK_WED_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY BIT(26) ++#define MTK_WED_WPDMA_GLO_CFG_OMIT_RX_INFO BIT(27) ++#define MTK_WED_WPDMA_GLO_CFG_OMIT_TX_INFO BIT(28) ++#define MTK_WED_WPDMA_GLO_CFG_BYTE_SWAP BIT(29) ++#define MTK_WED_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) ++ ++#define MTK_WED_WPDMA_RESET_IDX 0x50c ++#define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0) ++#define MTK_WED_WPDMA_RESET_IDX_RX GENMASK(17, 16) ++ ++#define MTK_WED_WPDMA_INT_CTRL 0x520 ++#define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) ++ ++#define MTK_WED_WPDMA_INT_MASK 0x524 ++ ++#define MTK_WED_PCIE_CFG_BASE 0x560 ++ ++#define MTK_WED_PCIE_INT_TRIGGER 0x570 ++#define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16) ++ ++#define MTK_WED_WPDMA_CFG_BASE 0x580 ++ ++#define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4) ++#define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4) ++ ++#define MTK_WED_WPDMA_RING_TX(_n) (0x600 + (_n) * 0x10) ++#define MTK_WED_WPDMA_RING_RX(_n) (0x700 + (_n) * 0x10) ++#define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10) ++#define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4) ++ ++#define MTK_WED_WDMA_GLO_CFG 0xa04 ++#define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0) ++#define MTK_WED_WDMA_GLO_CFG_RX_DRV_EN BIT(2) ++#define MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY BIT(3) ++#define MTK_WED_WDMA_GLO_CFG_BT_SIZE GENMASK(5, 4) ++#define MTK_WED_WDMA_GLO_CFG_TX_WB_DDONE BIT(6) ++#define MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE BIT(13) ++#define MTK_WED_WDMA_GLO_CFG_WCOMPLETE_SEL BIT(16) ++#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_RXDMA_BYPASS BIT(17) ++#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_BYPASS BIT(18) ++#define MTK_WED_WDMA_GLO_CFG_FSM_RETURN_IDLE BIT(19) ++#define MTK_WED_WDMA_GLO_CFG_WAIT_COHERENT BIT(20) ++#define MTK_WED_WDMA_GLO_CFG_AXI_W_AFTER_AW BIT(21) ++#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY_SINGLE_W BIT(22) ++#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY BIT(23) ++#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP BIT(24) ++#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE BIT(25) ++#define MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE BIT(26) ++#define MTK_WED_WDMA_GLO_CFG_RXDRV_CLKGATE_BYPASS BIT(30) ++ ++#define MTK_WED_WDMA_RESET_IDX 0xa08 ++#define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16) ++#define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24) ++ ++#define MTK_WED_WDMA_INT_TRIGGER 0xa28 ++#define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16) ++ ++#define MTK_WED_WDMA_INT_CTRL 0xa2c ++#define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16) ++ ++#define MTK_WED_WDMA_OFFSET0 0xaa4 ++#define MTK_WED_WDMA_OFFSET1 0xaa8 ++ ++#define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4) ++#define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4) ++#define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4) ++ ++#define MTK_WED_RING_OFS_BASE 0x00 ++#define MTK_WED_RING_OFS_COUNT 0x04 ++#define MTK_WED_RING_OFS_CPU_IDX 0x08 ++#define MTK_WED_RING_OFS_DMA_IDX 0x0c ++ ++#define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) ++ ++#define MTK_WDMA_GLO_CFG 0x204 ++#define MTK_WDMA_GLO_CFG_RX_INFO_PRERES GENMASK(28, 26) ++ ++#define MTK_WDMA_RESET_IDX 0x208 ++#define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) ++#define MTK_WDMA_RESET_IDX_RX GENMASK(17, 16) ++ ++#define MTK_WDMA_INT_MASK 0x228 ++#define MTK_WDMA_INT_MASK_TX_DONE GENMASK(3, 0) ++#define MTK_WDMA_INT_MASK_RX_DONE GENMASK(17, 16) ++#define MTK_WDMA_INT_MASK_TX_DELAY BIT(28) ++#define MTK_WDMA_INT_MASK_TX_COHERENT BIT(29) ++#define MTK_WDMA_INT_MASK_RX_DELAY BIT(30) ++#define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31) ++ ++#define MTK_WDMA_INT_GRP1 0x250 ++#define MTK_WDMA_INT_GRP2 0x254 ++ ++#define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0) ++#define MTK_PCIE_MIRROR_MAP_EN BIT(0) ++#define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1) ++ ++/* DMA channel mapping */ ++#define HIFSYS_DMA_AG_MAP 0x008 ++ ++#endif +--- /dev/null ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -0,0 +1,131 @@ ++#ifndef __MTK_WED_H ++#define __MTK_WED_H ++ ++#include ++#include ++#include ++#include ++ ++#define MTK_WED_TX_QUEUES 2 ++ ++struct mtk_wed_hw; ++struct mtk_wdma_desc; ++ ++struct mtk_wed_ring { ++ struct mtk_wdma_desc *desc; ++ dma_addr_t desc_phys; ++ int size; ++ ++ u32 reg_base; ++ void __iomem *wpdma; ++}; ++ ++struct mtk_wed_device { ++#ifdef CONFIG_NET_MEDIATEK_SOC_WED ++ const struct mtk_wed_ops *ops; ++ struct device *dev; ++ struct mtk_wed_hw *hw; ++ bool init_done, running; ++ int wdma_idx; ++ int irq; ++ ++ struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES]; ++ struct mtk_wed_ring txfree_ring; ++ struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES]; ++ ++ struct { ++ int size; ++ void **pages; ++ struct mtk_wdma_desc *desc; ++ dma_addr_t desc_phys; ++ } buf_ring; ++ ++ /* filled by driver: */ ++ struct { ++ struct pci_dev *pci_dev; ++ ++ u32 wpdma_phys; ++ ++ u16 token_start; ++ unsigned int nbuf; ++ ++ u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); ++ int (*offload_enable)(struct mtk_wed_device *wed); ++ void (*offload_disable)(struct mtk_wed_device *wed); ++ } wlan; ++#endif ++}; ++ ++struct mtk_wed_ops { ++ int (*attach)(struct mtk_wed_device *dev); ++ int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring, ++ void __iomem *regs); ++ int (*txfree_ring_setup)(struct mtk_wed_device *dev, ++ void __iomem *regs); ++ void (*detach)(struct mtk_wed_device *dev); ++ ++ void (*stop)(struct mtk_wed_device *dev); ++ void (*start)(struct mtk_wed_device *dev, u32 irq_mask); ++ void (*reset_dma)(struct mtk_wed_device *dev); ++ ++ u32 (*reg_read)(struct mtk_wed_device *dev, u32 reg); ++ void (*reg_write)(struct mtk_wed_device *dev, u32 reg, u32 val); ++ ++ u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask); ++ void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask); ++}; ++ ++extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops; ++ ++static inline int ++mtk_wed_device_attach(struct mtk_wed_device *dev) ++{ ++ int ret = -ENODEV; ++ ++#ifdef CONFIG_NET_MEDIATEK_SOC_WED ++ rcu_read_lock(); ++ dev->ops = rcu_dereference(mtk_soc_wed_ops); ++ if (dev->ops) ++ ret = dev->ops->attach(dev); ++ else ++ rcu_read_unlock(); ++ ++ if (ret) ++ dev->ops = NULL; ++#endif ++ ++ return ret; ++} ++ ++#ifdef CONFIG_NET_MEDIATEK_SOC_WED ++#define mtk_wed_device_active(_dev) !!(_dev)->ops ++#define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev) ++#define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask) ++#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) \ ++ (_dev)->ops->tx_ring_setup(_dev, _ring, _regs) ++#define mtk_wed_device_txfree_ring_setup(_dev, _regs) \ ++ (_dev)->ops->txfree_ring_setup(_dev, _regs) ++#define mtk_wed_device_reg_read(_dev, _reg) \ ++ (_dev)->ops->reg_read(_dev, _reg) ++#define mtk_wed_device_reg_write(_dev, _reg, _val) \ ++ (_dev)->ops->reg_write(_dev, _reg, _val) ++#define mtk_wed_device_irq_get(_dev, _mask) \ ++ (_dev)->ops->irq_get(_dev, _mask) ++#define mtk_wed_device_irq_set_mask(_dev, _mask) \ ++ (_dev)->ops->irq_set_mask(_dev, _mask) ++#else ++static inline bool mtk_wed_device_active(struct mtk_wed_device *dev) ++{ ++ return false; ++} ++#define mtk_wed_device_detach(_dev) do {} while (0) ++#define mtk_wed_device_start(_dev, _mask) do {} while (0) ++#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV ++#define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV ++#define mtk_wed_device_reg_read(_dev, _reg) 0 ++#define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0) ++#define mtk_wed_device_irq_get(_dev, _mask) 0 ++#define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0) ++#endif ++ ++#endif diff --git a/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch b/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch new file mode 100644 index 00000000000..50d65b1eb6f --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch @@ -0,0 +1,269 @@ +From: Felix Fietkau +Date: Sat, 5 Feb 2022 18:29:22 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: implement flow offloading + to WED devices + +This allows hardware flow offloading from Ethernet to WLAN on MT7622 SoC + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_f + return 0; + } + ++int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, ++ int bss, int wcid) ++{ ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ u32 *ib2 = mtk_foe_entry_ib2(entry); ++ ++ *ib2 &= ~MTK_FOE_IB2_PORT_MG; ++ *ib2 |= MTK_FOE_IB2_WDMA_WINFO; ++ if (wdma_idx) ++ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; ++ ++ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); ++ ++ return 0; ++} ++ + static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry) + { + return !(entry->ib1 & MTK_FOE_IB1_STATIC) && +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -48,9 +48,9 @@ enum { + #define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5) + #define MTK_FOE_IB2_MULTICAST BIT(8) + +-#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12) +-#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16) +-#define MTK_FOE_IB2_WHNAT_NAT BIT(17) ++#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12) ++#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16) ++#define MTK_FOE_IB2_WDMA_WINFO BIT(17) + + #define MTK_FOE_IB2_PORT_MG GENMASK(17, 12) + +@@ -58,9 +58,9 @@ enum { + + #define MTK_FOE_IB2_DSCP GENMASK(31, 24) + +-#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0) +-#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6) +-#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14) ++#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0) ++#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6) ++#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14) + + enum { + MTK_FOE_STATE_INVALID, +@@ -281,6 +281,8 @@ int mtk_foe_entry_set_ipv6_tuple(struct + int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port); + int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); + int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); ++int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, ++ int bss, int wcid); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 timestamp); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -10,6 +10,7 @@ + #include + #include + #include "mtk_eth_soc.h" ++#include "mtk_wed.h" + + struct mtk_flow_data { + struct ethhdr eth; +@@ -39,6 +40,7 @@ struct mtk_flow_entry { + struct rhash_head node; + unsigned long cookie; + u16 hash; ++ s8 wed_index; + }; + + static const struct rhashtable_params mtk_flow_ht_params = { +@@ -80,6 +82,35 @@ mtk_flow_offload_mangle_eth(const struct + memcpy(dest, src, act->mangle.mask ? 2 : 4); + } + ++static int ++mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info) ++{ ++ struct net_device_path_ctx ctx = { ++ .dev = dev, ++ .daddr = addr, ++ }; ++ struct net_device_path path = {}; ++ ++ if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) ++ return -1; ++ ++ if (!dev->netdev_ops->ndo_fill_forward_path) ++ return -1; ++ ++ if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path)) ++ return -1; ++ ++ if (path.type != DEV_PATH_MTK_WDMA) ++ return -1; ++ ++ info->wdma_idx = path.mtk_wdma.wdma_idx; ++ info->queue = path.mtk_wdma.queue; ++ info->bss = path.mtk_wdma.bss; ++ info->wcid = path.mtk_wdma.wcid; ++ ++ return 0; ++} ++ + + static int + mtk_flow_mangle_ports(const struct flow_action_entry *act, +@@ -149,10 +180,20 @@ mtk_flow_get_dsa_port(struct net_device + + static int + mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe, +- struct net_device *dev) ++ struct net_device *dev, const u8 *dest_mac, ++ int *wed_index) + { ++ struct mtk_wdma_info info = {}; + int pse_port, dsa_port; + ++ if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { ++ mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss, ++ info.wcid); ++ pse_port = 3; ++ *wed_index = info.wdma_idx; ++ goto out; ++ } ++ + dsa_port = mtk_flow_get_dsa_port(&dev); + if (dsa_port >= 0) + mtk_foe_entry_set_dsa(foe, dsa_port); +@@ -164,6 +205,7 @@ mtk_flow_set_output_device(struct mtk_et + else + return -EOPNOTSUPP; + ++out: + mtk_foe_entry_set_pse_port(foe, pse_port); + + return 0; +@@ -179,6 +221,7 @@ mtk_flow_offload_replace(struct mtk_eth + struct net_device *odev = NULL; + struct mtk_flow_entry *entry; + int offload_type = 0; ++ int wed_index = -1; + u16 addr_type = 0; + u32 timestamp; + u8 l4proto = 0; +@@ -326,10 +369,14 @@ mtk_flow_offload_replace(struct mtk_eth + if (data.pppoe.num == 1) + mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); + +- err = mtk_flow_set_output_device(eth, &foe, odev); ++ err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest, ++ &wed_index); + if (err) + return err; + ++ if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0) ++ return err; ++ + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; +@@ -343,6 +390,7 @@ mtk_flow_offload_replace(struct mtk_eth + } + + entry->hash = hash; ++ entry->wed_index = wed_index; + err = rhashtable_insert_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (err < 0) +@@ -353,6 +401,8 @@ clear_flow: + mtk_foe_entry_clear(ð->ppe, hash); + free: + kfree(entry); ++ if (wed_index >= 0) ++ mtk_wed_flow_remove(wed_index); + return err; + } + +@@ -369,6 +419,8 @@ mtk_flow_offload_destroy(struct mtk_eth + mtk_foe_entry_clear(ð->ppe, entry->hash); + rhashtable_remove_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); ++ if (entry->wed_index >= 0) ++ mtk_wed_flow_remove(entry->wed_index); + kfree(entry); + + return 0; +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + struct mtk_eth; + +@@ -27,6 +28,12 @@ struct mtk_wed_hw { + int index; + }; + ++struct mtk_wdma_info { ++ u8 wdma_idx; ++ u8 queue; ++ u16 wcid; ++ u8 bss; ++}; + + #ifdef CONFIG_NET_MEDIATEK_SOC_WED + static inline void +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -872,6 +872,7 @@ enum net_device_path_type { + DEV_PATH_BRIDGE, + DEV_PATH_PPPOE, + DEV_PATH_DSA, ++ DEV_PATH_MTK_WDMA, + }; + + struct net_device_path { +@@ -897,6 +898,12 @@ struct net_device_path { + int port; + u16 proto; + } dsa; ++ struct { ++ u8 wdma_idx; ++ u8 queue; ++ u16 wcid; ++ u8 bss; ++ } mtk_wdma; + }; + }; + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -763,6 +763,10 @@ int dev_fill_forward_path(const struct n + if (WARN_ON_ONCE(last_dev == ctx.dev)) + return -1; + } ++ ++ if (!ctx.dev) ++ return ret; ++ + path = dev_fwd_path(stack); + if (!path) + return -1; diff --git a/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch b/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch new file mode 100644 index 00000000000..2c6e3fd3cd3 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch @@ -0,0 +1,62 @@ +From: Felix Fietkau +Date: Sat, 5 Feb 2022 18:36:36 +0100 +Subject: [PATCH] arm64: dts: mediatek: mt7622: introduce nodes for + Wireless Ethernet Dispatch + +Introduce wed0 and wed1 nodes in order to enable offloading forwarding +between ethernet and wireless devices on the mt7622 chipset. + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -894,6 +894,11 @@ + }; + }; + ++ hifsys: syscon@1af00000 { ++ compatible = "mediatek,mt7622-hifsys", "syscon"; ++ reg = <0 0x1af00000 0 0x70>; ++ }; ++ + ethsys: syscon@1b000000 { + compatible = "mediatek,mt7622-ethsys", + "syscon"; +@@ -912,6 +917,26 @@ + #dma-cells = <1>; + }; + ++ pcie_mirror: pcie-mirror@10000400 { ++ compatible = "mediatek,mt7622-pcie-mirror", ++ "syscon"; ++ reg = <0 0x10000400 0 0x10>; ++ }; ++ ++ wed0: wed@1020a000 { ++ compatible = "mediatek,mt7622-wed", ++ "syscon"; ++ reg = <0 0x1020a000 0 0x1000>; ++ interrupts = ; ++ }; ++ ++ wed1: wed@1020b000 { ++ compatible = "mediatek,mt7622-wed", ++ "syscon"; ++ reg = <0 0x1020b000 0 0x1000>; ++ interrupts = ; ++ }; ++ + eth: ethernet@1b100000 { + compatible = "mediatek,mt7622-eth", + "mediatek,mt2701-eth", +@@ -939,6 +964,9 @@ + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys>; + mediatek,cci-control = <&cci_control2>; ++ mediatek,wed = <&wed0>, <&wed1>; ++ mediatek,pcie-mirror = <&pcie_mirror>; ++ mediatek,hifsys = <&hifsys>; + dma-coherent; + #address-cells = <1>; + #size-cells = <0>; diff --git a/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch b/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch new file mode 100644 index 00000000000..9adb067015e --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch @@ -0,0 +1,79 @@ +From: David Bentham +Date: Mon, 21 Feb 2022 15:36:16 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add ipv6 flow offload + support + +Add the missing IPv6 flow offloading support for routing only. +Hardware flow offloading is done by the packet processing engine (PPE) +of the Ethernet MAC and as it doesn't support mangling of IPv6 packets, +IPv6 NAT cannot be supported. + +Signed-off-by: David Bentham +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -20,6 +21,11 @@ struct mtk_flow_data { + __be32 src_addr; + __be32 dst_addr; + } v4; ++ ++ struct { ++ struct in6_addr src_addr; ++ struct in6_addr dst_addr; ++ } v6; + }; + + __be16 src_port; +@@ -65,6 +71,14 @@ mtk_flow_set_ipv4_addr(struct mtk_foe_en + data->v4.dst_addr, data->dst_port); + } + ++static int ++mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data) ++{ ++ return mtk_foe_entry_set_ipv6_tuple(foe, ++ data->v6.src_addr.s6_addr32, data->src_port, ++ data->v6.dst_addr.s6_addr32, data->dst_port); ++} ++ + static void + mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth) + { +@@ -296,6 +310,9 @@ mtk_flow_offload_replace(struct mtk_eth + case FLOW_DISSECTOR_KEY_IPV4_ADDRS: + offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; + break; ++ case FLOW_DISSECTOR_KEY_IPV6_ADDRS: ++ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; ++ break; + default: + return -EOPNOTSUPP; + } +@@ -331,6 +348,17 @@ mtk_flow_offload_replace(struct mtk_eth + mtk_flow_set_ipv4_addr(&foe, &data, false); + } + ++ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { ++ struct flow_match_ipv6_addrs addrs; ++ ++ flow_rule_match_ipv6_addrs(rule, &addrs); ++ ++ data.v6.src_addr = addrs.key->src; ++ data.v6.dst_addr = addrs.key->dst; ++ ++ mtk_flow_set_ipv6_addr(&foe, &data); ++ } ++ + flow_action_for_each(i, act, &rule->action) { + if (act->id != FLOW_ACTION_MANGLE) + continue; diff --git a/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch b/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch new file mode 100644 index 00000000000..1950d81ebba --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch @@ -0,0 +1,29 @@ +From: Felix Fietkau +Date: Mon, 21 Feb 2022 15:37:21 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: support TC_SETUP_BLOCK for + PPE offload + +This allows offload entries to be created from user space + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -564,10 +564,13 @@ mtk_eth_setup_tc_block(struct net_device + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data) + { +- if (type == TC_SETUP_FT) ++ switch (type) { ++ case TC_SETUP_BLOCK: ++ case TC_SETUP_FT: + return mtk_eth_setup_tc_block(dev, type_data); +- +- return -EOPNOTSUPP; ++ default: ++ return -EOPNOTSUPP; ++ } + } + + int mtk_eth_offload_init(struct mtk_eth *eth) diff --git a/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch b/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch new file mode 100644 index 00000000000..f18a816b703 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch @@ -0,0 +1,159 @@ +From: Felix Fietkau +Date: Mon, 21 Feb 2022 15:38:20 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: allocate struct mtk_ppe + separately + +Preparation for adding more data to it, which will increase its size. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2335,7 +2335,7 @@ static int mtk_open(struct net_device *d + return err; + } + +- if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0) ++ if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0) + gdm_config = MTK_GDMA_TO_PPE; + + mtk_gdm_config(eth, gdm_config); +@@ -2409,7 +2409,7 @@ static int mtk_stop(struct net_device *d + mtk_dma_free(eth); + + if (eth->soc->offload_version) +- mtk_ppe_stop(ð->ppe); ++ mtk_ppe_stop(eth->ppe); + + return 0; + } +@@ -3301,10 +3301,11 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- err = mtk_ppe_init(ð->ppe, eth->dev, +- eth->base + MTK_ETH_PPE_BASE, 2); +- if (err) ++ eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2); ++ if (!eth->ppe) { ++ err = -ENOMEM; + goto err_free_dev; ++ } + + err = mtk_eth_offload_init(eth); + if (err) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -983,7 +983,7 @@ struct mtk_eth { + u32 rx_dma_l4_valid; + int ip_align; + +- struct mtk_ppe ppe; ++ struct mtk_ppe *ppe; + struct rhashtable flow_table; + }; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -384,10 +384,15 @@ int mtk_foe_entry_commit(struct mtk_ppe + return hash; + } + +-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, ++struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, + int version) + { + struct mtk_foe_entry *foe; ++ struct mtk_ppe *ppe; ++ ++ ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); ++ if (!ppe) ++ return NULL; + + /* need to allocate a separate device, since it PPE DMA access is + * not coherent. +@@ -399,13 +404,13 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st + foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), + &ppe->foe_phys, GFP_KERNEL); + if (!foe) +- return -ENOMEM; ++ return NULL; + + ppe->foe_table = foe; + + mtk_ppe_debugfs_init(ppe); + +- return 0; ++ return ppe; + } + + static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -246,8 +246,7 @@ struct mtk_ppe { + void *acct_table; + }; + +-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, +- int version); ++struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version); + int mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -411,7 +411,7 @@ mtk_flow_offload_replace(struct mtk_eth + + entry->cookie = f->cookie; + timestamp = mtk_eth_timestamp(eth); +- hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp); ++ hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp); + if (hash < 0) { + err = hash; + goto free; +@@ -426,7 +426,7 @@ mtk_flow_offload_replace(struct mtk_eth + + return 0; + clear_flow: +- mtk_foe_entry_clear(ð->ppe, hash); ++ mtk_foe_entry_clear(eth->ppe, hash); + free: + kfree(entry); + if (wed_index >= 0) +@@ -444,7 +444,7 @@ mtk_flow_offload_destroy(struct mtk_eth + if (!entry) + return -ENOENT; + +- mtk_foe_entry_clear(ð->ppe, entry->hash); ++ mtk_foe_entry_clear(eth->ppe, entry->hash); + rhashtable_remove_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (entry->wed_index >= 0) +@@ -466,7 +466,7 @@ mtk_flow_offload_stats(struct mtk_eth *e + if (!entry) + return -ENOENT; + +- timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash); ++ timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash); + if (timestamp < 0) + return -ETIMEDOUT; + +@@ -522,7 +522,7 @@ mtk_eth_setup_tc_block(struct net_device + struct flow_block_cb *block_cb; + flow_setup_cb_t *cb; + +- if (!eth->ppe.foe_table) ++ if (!eth->ppe || !eth->ppe->foe_table) + return -EOPNOTSUPP; + + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) +@@ -575,7 +575,7 @@ int mtk_eth_setup_tc(struct net_device * + + int mtk_eth_offload_init(struct mtk_eth *eth) + { +- if (!eth->ppe.foe_table) ++ if (!eth->ppe || !eth->ppe->foe_table) + return 0; + + return rhashtable_init(ð->flow_table, &mtk_flow_ht_params); diff --git a/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch b/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch new file mode 100644 index 00000000000..2609cbedec2 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch @@ -0,0 +1,424 @@ +From: Felix Fietkau +Date: Mon, 21 Feb 2022 15:39:18 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rework hardware flow table + management + +The hardware was designed to handle flow detection and creation of flow entries +by itself, relying on the software primarily for filling in egress routing +information. +When there is a hash collision between multiple flows, this allows the hardware +to maintain the entry for the most active flow. +Additionally, the hardware only keeps offloading active for entries with at +least 30 packets per second. + +With this rework, the code no longer creates a hardware entries directly. +Instead, the hardware entry is only created when the PPE reports a matching +unbound flow with the minimum target rate. +In order to reduce CPU overhead, looking for flows belonging to a hash entry +is rate limited to once every 100ms. + +This rework is also used as preparation for emulating bridge offload by +managing L4 offload entries on demand. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #include "mtk_eth_soc.h" +@@ -1293,7 +1294,7 @@ static int mtk_poll_rx(struct napi_struc + struct net_device *netdev; + unsigned int pktlen; + dma_addr_t dma_addr; +- u32 hash; ++ u32 hash, reason; + int mac; + + ring = mtk_get_rx_ring(eth); +@@ -1372,6 +1373,11 @@ static int mtk_poll_rx(struct napi_struc + skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); + } + ++ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); ++ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) ++ mtk_ppe_check_skb(eth->ppe, skb, ++ trxd.rxd4 & MTK_RXD4_FOE_ENTRY); ++ + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && + (trxd.rxd2 & RX_DMA_VTAG)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), +@@ -3301,7 +3307,7 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2); ++ eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2); + if (!eth->ppe) { + err = -ENOMEM; + goto err_free_dev; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -6,9 +6,12 @@ + #include + #include + #include ++#include "mtk_eth_soc.h" + #include "mtk_ppe.h" + #include "mtk_ppe_regs.h" + ++static DEFINE_SPINLOCK(ppe_lock); ++ + static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) + { + writel(val, ppe->base + reg); +@@ -41,6 +44,11 @@ static u32 ppe_clear(struct mtk_ppe *ppe + return ppe_m32(ppe, reg, val, 0); + } + ++static u32 mtk_eth_timestamp(struct mtk_eth *eth) ++{ ++ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; ++} ++ + static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) + { + int ret; +@@ -353,26 +361,59 @@ static inline bool mtk_foe_entry_usable( + FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; + } + +-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, +- u16 timestamp) ++static bool ++mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data) ++{ ++ int type, len; ++ ++ if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) ++ return false; ++ ++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ len = offsetof(struct mtk_foe_entry, ipv6._rsv); ++ else ++ len = offsetof(struct mtk_foe_entry, ipv4.ib2); ++ ++ return !memcmp(&entry->data.data, &data->data, len - 4); ++} ++ ++static void ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + struct mtk_foe_entry *hwe; +- u32 hash; ++ struct mtk_foe_entry foe; + ++ spin_lock_bh(&ppe_lock); ++ if (entry->hash == 0xffff) ++ goto out; ++ ++ hwe = &ppe->foe_table[entry->hash]; ++ memcpy(&foe, hwe, sizeof(foe)); ++ if (!mtk_flow_entry_match(entry, &foe)) { ++ entry->hash = 0xffff; ++ goto out; ++ } ++ ++ entry->data.ib1 = foe.ib1; ++ ++out: ++ spin_unlock_bh(&ppe_lock); ++} ++ ++static void ++__mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, ++ u16 hash) ++{ ++ struct mtk_foe_entry *hwe; ++ u16 timestamp; ++ ++ timestamp = mtk_eth_timestamp(ppe->eth); + timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; + entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; + entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); + +- hash = mtk_ppe_hash_entry(entry); + hwe = &ppe->foe_table[hash]; +- if (!mtk_foe_entry_usable(hwe)) { +- hwe++; +- hash++; +- +- if (!mtk_foe_entry_usable(hwe)) +- return -ENOSPC; +- } +- + memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); + wmb(); + hwe->ib1 = entry->ib1; +@@ -380,13 +421,77 @@ int mtk_foe_entry_commit(struct mtk_ppe + dma_wmb(); + + mtk_ppe_cache_clear(ppe); ++} + +- return hash; ++void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ spin_lock_bh(&ppe_lock); ++ hlist_del_init(&entry->list); ++ if (entry->hash != 0xffff) { ++ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; ++ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, ++ MTK_FOE_STATE_BIND); ++ dma_wmb(); ++ } ++ entry->hash = 0xffff; ++ spin_unlock_bh(&ppe_lock); ++} ++ ++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ u32 hash = mtk_ppe_hash_entry(&entry->data); ++ ++ entry->hash = 0xffff; ++ spin_lock_bh(&ppe_lock); ++ hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); ++ spin_unlock_bh(&ppe_lock); ++ ++ return 0; ++} ++ ++void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) ++{ ++ struct hlist_head *head = &ppe->foe_flow[hash / 2]; ++ struct mtk_flow_entry *entry; ++ struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; ++ bool found = false; ++ ++ if (hlist_empty(head)) ++ return; ++ ++ spin_lock_bh(&ppe_lock); ++ hlist_for_each_entry(entry, head, list) { ++ if (found || !mtk_flow_entry_match(entry, hwe)) { ++ if (entry->hash != 0xffff) ++ entry->hash = 0xffff; ++ continue; ++ } ++ ++ entry->hash = hash; ++ __mtk_foe_entry_commit(ppe, &entry->data, hash); ++ found = true; ++ } ++ spin_unlock_bh(&ppe_lock); ++} ++ ++int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; ++ u16 timestamp; ++ ++ mtk_flow_entry_update(ppe, entry); ++ timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ ++ if (timestamp > now) ++ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; ++ else ++ return now - timestamp; + } + +-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, + int version) + { ++ struct device *dev = eth->dev; + struct mtk_foe_entry *foe; + struct mtk_ppe *ppe; + +@@ -398,6 +503,7 @@ struct mtk_ppe *mtk_ppe_init(struct devi + * not coherent. + */ + ppe->base = base; ++ ppe->eth = eth; + ppe->dev = dev; + ppe->version = version; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -235,7 +235,17 @@ enum { + MTK_PPE_CPU_REASON_INVALID = 0x1f, + }; + ++struct mtk_flow_entry { ++ struct rhash_head node; ++ struct hlist_node list; ++ unsigned long cookie; ++ struct mtk_foe_entry data; ++ u16 hash; ++ s8 wed_index; ++}; ++ + struct mtk_ppe { ++ struct mtk_eth *eth; + struct device *dev; + void __iomem *base; + int version; +@@ -243,18 +253,33 @@ struct mtk_ppe { + struct mtk_foe_entry *foe_table; + dma_addr_t foe_phys; + ++ u16 foe_check_time[MTK_PPE_ENTRIES]; ++ struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; ++ + void *acct_table; + }; + +-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version); ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version); + int mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + ++void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); ++ + static inline void +-mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash) ++mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + { +- ppe->foe_table[hash].ib1 = 0; +- dma_wmb(); ++ u16 now, diff; ++ ++ if (!ppe) ++ return; ++ ++ now = (u16)jiffies; ++ diff = now - ppe->foe_check_time[hash]; ++ if (diff < HZ / 10) ++ return; ++ ++ ppe->foe_check_time[hash] = now; ++ __mtk_ppe_check_skb(ppe, skb, hash); + } + + static inline int +@@ -282,8 +307,9 @@ int mtk_foe_entry_set_vlan(struct mtk_fo + int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); + int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, + int bss, int wcid); +-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, +- u16 timestamp); ++int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); ++void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); ++int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); + + #endif +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -42,13 +42,6 @@ struct mtk_flow_data { + } pppoe; + }; + +-struct mtk_flow_entry { +- struct rhash_head node; +- unsigned long cookie; +- u16 hash; +- s8 wed_index; +-}; +- + static const struct rhashtable_params mtk_flow_ht_params = { + .head_offset = offsetof(struct mtk_flow_entry, node), + .key_offset = offsetof(struct mtk_flow_entry, cookie), +@@ -56,12 +49,6 @@ static const struct rhashtable_params mt + .automatic_shrinking = true, + }; + +-static u32 +-mtk_eth_timestamp(struct mtk_eth *eth) +-{ +- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; +-} +- + static int + mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data, + bool egress) +@@ -237,10 +224,8 @@ mtk_flow_offload_replace(struct mtk_eth + int offload_type = 0; + int wed_index = -1; + u16 addr_type = 0; +- u32 timestamp; + u8 l4proto = 0; + int err = 0; +- int hash; + int i; + + if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params)) +@@ -410,23 +395,21 @@ mtk_flow_offload_replace(struct mtk_eth + return -ENOMEM; + + entry->cookie = f->cookie; +- timestamp = mtk_eth_timestamp(eth); +- hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp); +- if (hash < 0) { +- err = hash; ++ memcpy(&entry->data, &foe, sizeof(entry->data)); ++ entry->wed_index = wed_index; ++ ++ if (mtk_foe_entry_commit(eth->ppe, entry) < 0) + goto free; +- } + +- entry->hash = hash; +- entry->wed_index = wed_index; + err = rhashtable_insert_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (err < 0) +- goto clear_flow; ++ goto clear; + + return 0; +-clear_flow: +- mtk_foe_entry_clear(eth->ppe, hash); ++ ++clear: ++ mtk_foe_entry_clear(eth->ppe, entry); + free: + kfree(entry); + if (wed_index >= 0) +@@ -444,7 +427,7 @@ mtk_flow_offload_destroy(struct mtk_eth + if (!entry) + return -ENOENT; + +- mtk_foe_entry_clear(eth->ppe, entry->hash); ++ mtk_foe_entry_clear(eth->ppe, entry); + rhashtable_remove_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (entry->wed_index >= 0) +@@ -458,7 +441,6 @@ static int + mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) + { + struct mtk_flow_entry *entry; +- int timestamp; + u32 idle; + + entry = rhashtable_lookup(ð->flow_table, &f->cookie, +@@ -466,11 +448,7 @@ mtk_flow_offload_stats(struct mtk_eth *e + if (!entry) + return -ENOENT; + +- timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash); +- if (timestamp < 0) +- return -ETIMEDOUT; +- +- idle = mtk_eth_timestamp(eth) - timestamp; ++ idle = mtk_foe_entry_idle_time(eth->ppe, entry); + f->stats.lastused = jiffies - idle * HZ; + + return 0; diff --git a/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch b/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch new file mode 100644 index 00000000000..2ff0b341f91 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch @@ -0,0 +1,44 @@ +From: Felix Fietkau +Date: Mon, 21 Feb 2022 15:55:19 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: remove bridge flow offload + type entry support + +According to MediaTek, this feature is not supported in current hardware + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -84,13 +84,6 @@ static u32 mtk_ppe_hash_entry(struct mtk + u32 hash; + + switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { +- case MTK_PPE_PKT_TYPE_BRIDGE: +- hv1 = e->bridge.src_mac_lo; +- hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16); +- hv2 = e->bridge.src_mac_hi >> 16; +- hv2 ^= e->bridge.dest_mac_lo; +- hv3 = e->bridge.dest_mac_hi; +- break; + case MTK_PPE_PKT_TYPE_IPV4_ROUTE: + case MTK_PPE_PKT_TYPE_IPV4_HNAPT: + hv1 = e->ipv4.orig.ports; +@@ -572,7 +565,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe) + MTK_PPE_FLOW_CFG_IP4_NAT | + MTK_PPE_FLOW_CFG_IP4_NAPT | + MTK_PPE_FLOW_CFG_IP4_DSLITE | +- MTK_PPE_FLOW_CFG_L2_BRIDGE | + MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; + ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -32,7 +32,6 @@ static const char *mtk_foe_pkt_type_str( + static const char * const type_str[] = { + [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T", + [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T", +- [MTK_PPE_PKT_TYPE_BRIDGE] = "L2", + [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE", + [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T", + [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T", diff --git a/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch b/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch new file mode 100644 index 00000000000..209c65e66aa --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch @@ -0,0 +1,553 @@ +From: Felix Fietkau +Date: Wed, 23 Feb 2022 10:56:34 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: support creating mac + address based offload entries + +This will be used to implement a limited form of bridge offloading. +Since the hardware does not support flow table entries with just source +and destination MAC address, the driver has to emulate it. + +The hardware automatically creates entries entries for incoming flows, even +when they are bridged instead of routed, and reports when packets for these +flows have reached the minimum PPS rate for offloading. + +After this happens, we look up the L2 flow offload entry based on the MAC +header and fill in the output routing information in the flow table. +The dynamically created per-flow entries are automatically removed when +either the hardware flowtable entry expires, is replaced, or if the offload +rule they belong to is removed + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -6,12 +6,22 @@ + #include + #include + #include ++#include ++#include ++#include + #include "mtk_eth_soc.h" + #include "mtk_ppe.h" + #include "mtk_ppe_regs.h" + + static DEFINE_SPINLOCK(ppe_lock); + ++static const struct rhashtable_params mtk_flow_l2_ht_params = { ++ .head_offset = offsetof(struct mtk_flow_entry, l2_node), ++ .key_offset = offsetof(struct mtk_flow_entry, data.bridge), ++ .key_len = offsetof(struct mtk_foe_bridge, key_end), ++ .automatic_shrinking = true, ++}; ++ + static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) + { + writel(val, ppe->base + reg); +@@ -123,6 +133,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e + { + int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); + ++ if (type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return &entry->bridge.l2; ++ + if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) + return &entry->ipv6.l2; + +@@ -134,6 +147,9 @@ mtk_foe_entry_ib2(struct mtk_foe_entry * + { + int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); + ++ if (type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return &entry->bridge.ib2; ++ + if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) + return &entry->ipv6.ib2; + +@@ -168,7 +184,12 @@ int mtk_foe_entry_prepare(struct mtk_foe + if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) + entry->ipv6.ports = ports_pad; + +- if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { ++ if (type == MTK_PPE_PKT_TYPE_BRIDGE) { ++ ether_addr_copy(entry->bridge.src_mac, src_mac); ++ ether_addr_copy(entry->bridge.dest_mac, dest_mac); ++ entry->bridge.ib2 = val; ++ l2 = &entry->bridge.l2; ++ } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { + entry->ipv6.ib2 = val; + l2 = &entry->ipv6.l2; + } else { +@@ -372,12 +393,96 @@ mtk_flow_entry_match(struct mtk_flow_ent + } + + static void ++__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ struct hlist_head *head; ++ struct hlist_node *tmp; ++ ++ if (entry->type == MTK_FLOW_TYPE_L2) { ++ rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, ++ mtk_flow_l2_ht_params); ++ ++ head = &entry->l2_flows; ++ hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) ++ __mtk_foe_entry_clear(ppe, entry); ++ return; ++ } ++ ++ hlist_del_init(&entry->list); ++ if (entry->hash != 0xffff) { ++ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; ++ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, ++ MTK_FOE_STATE_BIND); ++ dma_wmb(); ++ } ++ entry->hash = 0xffff; ++ ++ if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) ++ return; ++ ++ hlist_del_init(&entry->l2_data.list); ++ kfree(entry); ++} ++ ++static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) ++{ ++ u16 timestamp; ++ u16 now; ++ ++ now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; ++ timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ ++ if (timestamp > now) ++ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; ++ else ++ return now - timestamp; ++} ++ ++static void ++mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ struct mtk_flow_entry *cur; ++ struct mtk_foe_entry *hwe; ++ struct hlist_node *tmp; ++ int idle; ++ ++ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { ++ int cur_idle; ++ u32 ib1; ++ ++ hwe = &ppe->foe_table[cur->hash]; ++ ib1 = READ_ONCE(hwe->ib1); ++ ++ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { ++ cur->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, cur); ++ continue; ++ } ++ ++ cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); ++ if (cur_idle >= idle) ++ continue; ++ ++ idle = cur_idle; ++ entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ } ++} ++ ++static void + mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + struct mtk_foe_entry *hwe; + struct mtk_foe_entry foe; + + spin_lock_bh(&ppe_lock); ++ ++ if (entry->type == MTK_FLOW_TYPE_L2) { ++ mtk_flow_entry_update_l2(ppe, entry); ++ goto out; ++ } ++ + if (entry->hash == 0xffff) + goto out; + +@@ -419,21 +524,28 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + spin_lock_bh(&ppe_lock); +- hlist_del_init(&entry->list); +- if (entry->hash != 0xffff) { +- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; +- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, +- MTK_FOE_STATE_BIND); +- dma_wmb(); +- } +- entry->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, entry); + spin_unlock_bh(&ppe_lock); + } + ++static int ++mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ entry->type = MTK_FLOW_TYPE_L2; ++ ++ return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node, ++ mtk_flow_l2_ht_params); ++} ++ + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- u32 hash = mtk_ppe_hash_entry(&entry->data); ++ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ u32 hash; ++ ++ if (type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return mtk_foe_entry_commit_l2(ppe, entry); + ++ hash = mtk_ppe_hash_entry(&entry->data); + entry->hash = 0xffff; + spin_lock_bh(&ppe_lock); + hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); +@@ -442,18 +554,72 @@ int mtk_foe_entry_commit(struct mtk_ppe + return 0; + } + ++static void ++mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ u16 hash) ++{ ++ struct mtk_flow_entry *flow_info; ++ struct mtk_foe_entry foe, *hwe; ++ struct mtk_foe_mac_info *l2; ++ u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; ++ int type; ++ ++ flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), ++ GFP_ATOMIC); ++ if (!flow_info) ++ return; ++ ++ flow_info->l2_data.base_flow = entry; ++ flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; ++ flow_info->hash = hash; ++ hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); ++ hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); ++ ++ hwe = &ppe->foe_table[hash]; ++ memcpy(&foe, hwe, sizeof(foe)); ++ foe.ib1 &= ib1_mask; ++ foe.ib1 |= entry->data.ib1 & ~ib1_mask; ++ ++ l2 = mtk_foe_entry_l2(&foe); ++ memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); ++ ++ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); ++ if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) ++ memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); ++ else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) ++ l2->etype = ETH_P_IPV6; ++ ++ *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; ++ ++ __mtk_foe_entry_commit(ppe, &foe, hash); ++} ++ + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + { + struct hlist_head *head = &ppe->foe_flow[hash / 2]; +- struct mtk_flow_entry *entry; + struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; ++ struct mtk_flow_entry *entry; ++ struct mtk_foe_bridge key = {}; ++ struct ethhdr *eh; + bool found = false; +- +- if (hlist_empty(head)) +- return; ++ u8 *tag; + + spin_lock_bh(&ppe_lock); ++ ++ if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) ++ goto out; ++ + hlist_for_each_entry(entry, head, list) { ++ if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { ++ if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == ++ MTK_FOE_STATE_BIND)) ++ continue; ++ ++ entry->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, entry); ++ continue; ++ } ++ + if (found || !mtk_flow_entry_match(entry, hwe)) { + if (entry->hash != 0xffff) + entry->hash = 0xffff; +@@ -464,21 +630,50 @@ void __mtk_ppe_check_skb(struct mtk_ppe + __mtk_foe_entry_commit(ppe, &entry->data, hash); + found = true; + } ++ ++ if (found) ++ goto out; ++ ++ eh = eth_hdr(skb); ++ ether_addr_copy(key.dest_mac, eh->h_dest); ++ ether_addr_copy(key.src_mac, eh->h_source); ++ tag = skb->data - 2; ++ key.vlan = 0; ++ switch (skb->protocol) { ++#if IS_ENABLED(CONFIG_NET_DSA) ++ case htons(ETH_P_XDSA): ++ if (!netdev_uses_dsa(skb->dev) || ++ skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) ++ goto out; ++ ++ tag += 4; ++ if (get_unaligned_be16(tag) != ETH_P_8021Q) ++ break; ++ ++ fallthrough; ++#endif ++ case htons(ETH_P_8021Q): ++ key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK; ++ break; ++ default: ++ break; ++ } ++ ++ entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params); ++ if (!entry) ++ goto out; ++ ++ mtk_foe_entry_commit_subflow(ppe, entry, hash); ++ ++out: + spin_unlock_bh(&ppe_lock); + } + + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; +- u16 timestamp; +- + mtk_flow_entry_update(ppe, entry); +- timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; + +- if (timestamp > now) +- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; +- else +- return now - timestamp; ++ return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); + } + + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, +@@ -492,6 +687,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + if (!ppe) + return NULL; + ++ rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params); ++ + /* need to allocate a separate device, since it PPE DMA access is + * not coherent. + */ +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -6,6 +6,7 @@ + + #include + #include ++#include + + #define MTK_ETH_PPE_BASE 0xc00 + +@@ -84,19 +85,16 @@ struct mtk_foe_mac_info { + u16 src_mac_lo; + }; + ++/* software-only entry type */ + struct mtk_foe_bridge { +- u32 dest_mac_hi; +- +- u16 src_mac_lo; +- u16 dest_mac_lo; ++ u8 dest_mac[ETH_ALEN]; ++ u8 src_mac[ETH_ALEN]; ++ u16 vlan; + +- u32 src_mac_hi; ++ struct {} key_end; + + u32 ib2; + +- u32 _rsv[5]; +- +- u32 udf_tsid; + struct mtk_foe_mac_info l2; + }; + +@@ -235,13 +233,33 @@ enum { + MTK_PPE_CPU_REASON_INVALID = 0x1f, + }; + ++enum { ++ MTK_FLOW_TYPE_L4, ++ MTK_FLOW_TYPE_L2, ++ MTK_FLOW_TYPE_L2_SUBFLOW, ++}; ++ + struct mtk_flow_entry { ++ union { ++ struct hlist_node list; ++ struct { ++ struct rhash_head l2_node; ++ struct hlist_head l2_flows; ++ }; ++ }; ++ u8 type; ++ s8 wed_index; ++ u16 hash; ++ union { ++ struct mtk_foe_entry data; ++ struct { ++ struct mtk_flow_entry *base_flow; ++ struct hlist_node list; ++ struct {} end; ++ } l2_data; ++ }; + struct rhash_head node; +- struct hlist_node list; + unsigned long cookie; +- struct mtk_foe_entry data; +- u16 hash; +- s8 wed_index; + }; + + struct mtk_ppe { +@@ -256,6 +274,8 @@ struct mtk_ppe { + u16 foe_check_time[MTK_PPE_ENTRIES]; + struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; + ++ struct rhashtable l2_flows; ++ + void *acct_table; + }; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -31,6 +31,8 @@ struct mtk_flow_data { + __be16 src_port; + __be16 dst_port; + ++ u16 vlan_in; ++ + struct { + u16 id; + __be16 proto; +@@ -257,9 +259,45 @@ mtk_flow_offload_replace(struct mtk_eth + return -EOPNOTSUPP; + } + ++ switch (addr_type) { ++ case 0: ++ offload_type = MTK_PPE_PKT_TYPE_BRIDGE; ++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { ++ struct flow_match_eth_addrs match; ++ ++ flow_rule_match_eth_addrs(rule, &match); ++ memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN); ++ memcpy(data.eth.h_source, match.key->src, ETH_ALEN); ++ } else { ++ return -EOPNOTSUPP; ++ } ++ ++ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { ++ struct flow_match_vlan match; ++ ++ flow_rule_match_vlan(rule, &match); ++ ++ if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q)) ++ return -EOPNOTSUPP; ++ ++ data.vlan_in = match.key->vlan_id; ++ } ++ break; ++ case FLOW_DISSECTOR_KEY_IPV4_ADDRS: ++ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; ++ break; ++ case FLOW_DISSECTOR_KEY_IPV6_ADDRS: ++ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ + flow_action_for_each(i, act, &rule->action) { + switch (act->id) { + case FLOW_ACTION_MANGLE: ++ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return -EOPNOTSUPP; + if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH) + mtk_flow_offload_mangle_eth(act, &data.eth); + break; +@@ -291,17 +329,6 @@ mtk_flow_offload_replace(struct mtk_eth + } + } + +- switch (addr_type) { +- case FLOW_DISSECTOR_KEY_IPV4_ADDRS: +- offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; +- break; +- case FLOW_DISSECTOR_KEY_IPV6_ADDRS: +- offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; +- break; +- default: +- return -EOPNOTSUPP; +- } +- + if (!is_valid_ether_addr(data.eth.h_source) || + !is_valid_ether_addr(data.eth.h_dest)) + return -EINVAL; +@@ -315,10 +342,13 @@ mtk_flow_offload_replace(struct mtk_eth + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { + struct flow_match_ports ports; + ++ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return -EOPNOTSUPP; ++ + flow_rule_match_ports(rule, &ports); + data.src_port = ports.key->src; + data.dst_port = ports.key->dst; +- } else { ++ } else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) { + return -EOPNOTSUPP; + } + +@@ -348,6 +378,9 @@ mtk_flow_offload_replace(struct mtk_eth + if (act->id != FLOW_ACTION_MANGLE) + continue; + ++ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) ++ return -EOPNOTSUPP; ++ + switch (act->mangle.htype) { + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: +@@ -373,6 +406,9 @@ mtk_flow_offload_replace(struct mtk_eth + return err; + } + ++ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) ++ foe.bridge.vlan = data.vlan_in; ++ + if (data.vlan.num == 1) { + if (data.vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; diff --git a/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch b/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch new file mode 100644 index 00000000000..8f3dfe82399 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch @@ -0,0 +1,56 @@ +From: Felix Fietkau +Date: Fri, 8 Apr 2022 10:59:45 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc/wed: fix sparse endian warnings + +Descriptor fields are little-endian + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Reported-by: kernel test robot +Signed-off-by: Felix Fietkau +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -144,16 +144,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi + + for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) { + u32 txd_size; ++ u32 ctrl; + + txd_size = dev->wlan.init_buf(buf, buf_phys, token++); + +- desc->buf0 = buf_phys; +- desc->buf1 = buf_phys + txd_size; +- desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, +- txd_size) | +- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, +- MTK_WED_BUF_SIZE - txd_size) | +- MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ desc->buf0 = cpu_to_le32(buf_phys); ++ desc->buf1 = cpu_to_le32(buf_phys + txd_size); ++ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ desc->ctrl = cpu_to_le32(ctrl); + desc->info = 0; + desc++; + +@@ -184,12 +185,14 @@ mtk_wed_free_buffer(struct mtk_wed_devic + + for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) { + void *page = page_list[page_idx++]; ++ dma_addr_t buf_addr; + + if (!page) + break; + +- dma_unmap_page(dev->hw->dev, desc[i].buf0, +- PAGE_SIZE, DMA_BIDIRECTIONAL); ++ buf_addr = le32_to_cpu(desc[i].buf0); ++ dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE, ++ DMA_BIDIRECTIONAL); + __free_page(page); + } + diff --git a/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch new file mode 100644 index 00000000000..4ec8fe74bc7 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch @@ -0,0 +1,25 @@ +From: Yang Yingliang +Date: Fri, 8 Apr 2022 11:22:46 +0800 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix return value check in + mtk_wed_add_hw() + +If syscon_regmap_lookup_by_phandle() fails, it never return NULL pointer, +change the check to IS_ERR(). + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Reported-by: Hulk Robot +Signed-off-by: Yang Yingliang +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -816,7 +816,7 @@ void mtk_wed_add_hw(struct device_node * + return; + + regs = syscon_regmap_lookup_by_phandle(np, NULL); +- if (!regs) ++ if (IS_ERR(regs)) + return; + + rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); diff --git a/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch b/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch new file mode 100644 index 00000000000..a7c5f08f100 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch @@ -0,0 +1,35 @@ +From: Lorenzo Bianconi +Date: Mon, 11 Apr 2022 12:13:25 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: use standard property for + cci-control-port + +Rely on standard cci-control-port property to identify CCI port +reference. +Update mt7622 dts binding. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi ++++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi +@@ -963,7 +963,7 @@ + power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys>; +- mediatek,cci-control = <&cci_control2>; ++ cci-control-port = <&cci_control2>; + mediatek,wed = <&wed0>, <&wed1>; + mediatek,pcie-mirror = <&pcie_mirror>; + mediatek,hifsys = <&hifsys>; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3188,7 +3188,7 @@ static int mtk_probe(struct platform_dev + struct regmap *cci; + + cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, +- "mediatek,cci-control"); ++ "cci-control-port"); + /* enable CPU/bus coherency */ + if (!IS_ERR(cci)) + regmap_write(cci, 0, 3); diff --git a/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch b/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch new file mode 100644 index 00000000000..656b3a159e8 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch @@ -0,0 +1,33 @@ +From: Dan Carpenter +Date: Tue, 12 Apr 2022 12:24:19 +0300 +Subject: [PATCH] net: ethernet: mtk_eth_soc: use after free in + __mtk_ppe_check_skb() + +The __mtk_foe_entry_clear() function frees "entry" so we have to use +the _safe() version of hlist_for_each_entry() to prevent a use after +free. + +Fixes: 33fc42de3327 ("net: ethernet: mtk_eth_soc: support creating mac address based offload entries") +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -600,6 +600,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; ++ struct hlist_node *n; + struct ethhdr *eh; + bool found = false; + u8 *tag; +@@ -609,7 +610,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) + goto out; + +- hlist_for_each_entry(entry, head, list) { ++ hlist_for_each_entry_safe(entry, n, head, list) { + if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { + if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == + MTK_FOE_STATE_BIND)) diff --git a/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch b/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch new file mode 100644 index 00000000000..714163c86bb --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch @@ -0,0 +1,22 @@ +From: Dan Carpenter +Date: Thu, 21 Apr 2022 18:49:02 +0300 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add check for allocation failure + +Check if the kzalloc() failed. + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -827,6 +827,8 @@ void mtk_wed_add_hw(struct device_node * + goto unlock; + + hw = kzalloc(sizeof(*hw), GFP_KERNEL); ++ if (!hw) ++ goto unlock; + hw->node = np; + hw->regs = regs; + hw->eth = eth; diff --git a/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch b/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch new file mode 100644 index 00000000000..aa98745ac60 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch @@ -0,0 +1,26 @@ +From: Jakub Kicinski +Date: Fri, 20 May 2022 12:56:03 -0700 +Subject: [PATCH] eth: mtk_eth_soc: silence the GCC 12 array-bounds warning + +GCC 12 gets upset because in mtk_foe_entry_commit_subflow() +this driver allocates a partial structure. The writes are +within bounds. + +Silence these warnings for now, our build bot runs GCC 12 +so we won't allow any new instances. + +Signed-off-by: Jakub Kicinski +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -11,3 +11,8 @@ mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) + + endif + obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o + obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o ++ ++# FIXME: temporarily silence -Warray-bounds on non W=1+ builds ++ifndef KBUILD_EXTRA_WARN ++CFLAGS_mtk_ppe.o += -Wno-array-bounds ++endif diff --git a/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch b/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch new file mode 100644 index 00000000000..9b6321f1daf --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch @@ -0,0 +1,52 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:26 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on GFP_KERNEL for + dma_alloc_coherent whenever possible + +Rely on GFP_KERNEL for dma descriptors mappings in mtk_tx_alloc(), +mtk_rx_alloc() and mtk_init_fq_dma() since they are run in non-irq +context. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -846,7 +846,7 @@ static int mtk_init_fq_dma(struct mtk_et + eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, + cnt * sizeof(struct mtk_tx_dma), + ð->phy_scratch_ring, +- GFP_ATOMIC); ++ GFP_KERNEL); + if (unlikely(!eth->scratch_ring)) + return -ENOMEM; + +@@ -1624,7 +1624,7 @@ static int mtk_tx_alloc(struct mtk_eth * + goto no_tx_mem; + + ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, +- &ring->phys, GFP_ATOMIC); ++ &ring->phys, GFP_KERNEL); + if (!ring->dma) + goto no_tx_mem; + +@@ -1642,8 +1642,7 @@ static int mtk_tx_alloc(struct mtk_eth * + */ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, +- &ring->phys_pdma, +- GFP_ATOMIC); ++ &ring->phys_pdma, GFP_KERNEL); + if (!ring->dma_pdma) + goto no_tx_mem; + +@@ -1758,7 +1757,7 @@ static int mtk_rx_alloc(struct mtk_eth * + + ring->dma = dma_alloc_coherent(eth->dma_dev, + rx_dma_size * sizeof(*ring->dma), +- &ring->phys, GFP_ATOMIC); ++ &ring->phys, GFP_KERNEL); + if (!ring->dma) + return -ENOMEM; + diff --git a/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch b/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch new file mode 100644 index 00000000000..8e16ea25566 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch @@ -0,0 +1,206 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:27 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: move tx dma desc configuration in + mtk_tx_set_dma_desc + +Move tx dma descriptor configuration in mtk_tx_set_dma_desc routine. +This is a preliminary patch to introduce mt7986 ethernet support since +it relies on a different tx dma descriptor layout. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -972,18 +972,51 @@ static void setup_tx_buf(struct mtk_eth + } + } + ++static void mtk_tx_set_dma_desc(struct net_device *dev, struct mtk_tx_dma *desc, ++ struct mtk_tx_dma_desc_info *info) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ u32 data; ++ ++ WRITE_ONCE(desc->txd1, info->addr); ++ ++ data = TX_DMA_SWC | TX_DMA_PLEN0(info->size); ++ if (info->last) ++ data |= TX_DMA_LS0; ++ WRITE_ONCE(desc->txd3, data); ++ ++ data = (mac->id + 1) << TX_DMA_FPORT_SHIFT; /* forward port */ ++ if (info->first) { ++ if (info->gso) ++ data |= TX_DMA_TSO; ++ /* tx checksum offload */ ++ if (info->csum) ++ data |= TX_DMA_CHKSUM; ++ /* vlan header offload */ ++ if (info->vlan) ++ data |= TX_DMA_INS_VLAN | info->vlan_tci; ++ } ++ WRITE_ONCE(desc->txd4, data); ++} ++ + static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + int tx_num, struct mtk_tx_ring *ring, bool gso) + { ++ struct mtk_tx_dma_desc_info txd_info = { ++ .size = skb_headlen(skb), ++ .gso = gso, ++ .csum = skb->ip_summed == CHECKSUM_PARTIAL, ++ .vlan = skb_vlan_tag_present(skb), ++ .vlan_tci = skb_vlan_tag_get(skb), ++ .first = true, ++ .last = !skb_is_nonlinear(skb), ++ }; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_dma *itxd, *txd; + struct mtk_tx_dma *itxd_pdma, *txd_pdma; + struct mtk_tx_buf *itx_buf, *tx_buf; +- dma_addr_t mapped_addr; +- unsigned int nr_frags; + int i, n_desc = 1; +- u32 txd4 = 0, fport; + int k = 0; + + itxd = ring->next_free; +@@ -991,49 +1024,32 @@ static int mtk_tx_map(struct sk_buff *sk + if (itxd == ring->last_free) + return -ENOMEM; + +- /* set the forward port */ +- fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; +- txd4 |= fport; +- + itx_buf = mtk_desc_to_tx_buf(ring, itxd); + memset(itx_buf, 0, sizeof(*itx_buf)); + +- if (gso) +- txd4 |= TX_DMA_TSO; +- +- /* TX Checksum offload */ +- if (skb->ip_summed == CHECKSUM_PARTIAL) +- txd4 |= TX_DMA_CHKSUM; +- +- /* VLAN header offload */ +- if (skb_vlan_tag_present(skb)) +- txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); +- +- mapped_addr = dma_map_single(eth->dma_dev, skb->data, +- skb_headlen(skb), DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) ++ txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, ++ DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) + return -ENOMEM; + +- WRITE_ONCE(itxd->txd1, mapped_addr); ++ mtk_tx_set_dma_desc(dev, itxd, &txd_info); ++ + itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; + itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : + MTK_TX_FLAGS_FPORT1; +- setup_tx_buf(eth, itx_buf, itxd_pdma, mapped_addr, skb_headlen(skb), ++ setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, + k++); + + /* TX SG offload */ + txd = itxd; + txd_pdma = qdma_to_pdma(ring, txd); +- nr_frags = skb_shinfo(skb)->nr_frags; + +- for (i = 0; i < nr_frags; i++) { ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + unsigned int offset = 0; + int frag_size = skb_frag_size(frag); + + while (frag_size) { +- bool last_frag = false; +- unsigned int frag_map_size; + bool new_desc = true; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || +@@ -1048,23 +1064,17 @@ static int mtk_tx_map(struct sk_buff *sk + new_desc = false; + } + +- +- frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); +- mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset, +- frag_map_size, +- DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) ++ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); ++ txd_info.size = min(frag_size, MTK_TX_DMA_BUF_LEN); ++ txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && ++ !(frag_size - txd_info.size); ++ txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, ++ offset, txd_info.size, ++ DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) + goto err_dma; + +- if (i == nr_frags - 1 && +- (frag_size - frag_map_size) == 0) +- last_frag = true; +- +- WRITE_ONCE(txd->txd1, mapped_addr); +- WRITE_ONCE(txd->txd3, (TX_DMA_SWC | +- TX_DMA_PLEN0(frag_map_size) | +- last_frag * TX_DMA_LS0)); +- WRITE_ONCE(txd->txd4, fport); ++ mtk_tx_set_dma_desc(dev, txd, &txd_info); + + tx_buf = mtk_desc_to_tx_buf(ring, txd); + if (new_desc) +@@ -1074,20 +1084,17 @@ static int mtk_tx_map(struct sk_buff *sk + tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : + MTK_TX_FLAGS_FPORT1; + +- setup_tx_buf(eth, tx_buf, txd_pdma, mapped_addr, +- frag_map_size, k++); ++ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, ++ txd_info.size, k++); + +- frag_size -= frag_map_size; +- offset += frag_map_size; ++ frag_size -= txd_info.size; ++ offset += txd_info.size; + } + } + + /* store skb to cleanup */ + itx_buf->skb = skb; + +- WRITE_ONCE(itxd->txd4, txd4); +- WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | +- (!nr_frags * TX_DMA_LS0))); + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { + if (k & 0x1) + txd_pdma->txd2 |= TX_DMA_LS0; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -843,6 +843,17 @@ enum mkt_eth_capabilities { + MTK_MUX_U3_GMAC2_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) + ++struct mtk_tx_dma_desc_info { ++ dma_addr_t addr; ++ u32 size; ++ u16 vlan_tci; ++ u8 gso:1; ++ u8 csum:1; ++ u8 vlan:1; ++ u8 first:1; ++ u8 last:1; ++}; ++ + /* struct mtk_eth_data - This is the structure holding all differences + * among various plaforms + * @ana_rgc3: The offset for register ANA_RGC3 related to diff --git a/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch new file mode 100644 index 00000000000..f5206bba00b --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch @@ -0,0 +1,167 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:28 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add txd_size to mtk_soc_data + +In order to remove mtk_tx_dma size dependency, introduce txd_size in +mtk_soc_data data structure. Rely on txd_size in mtk_init_fq_dma() and +mtk_dma_free() routines. +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -838,20 +838,20 @@ static void *mtk_max_lro_buf_alloc(gfp_t + /* the qdma core needs scratch memory to be setup */ + static int mtk_init_fq_dma(struct mtk_eth *eth) + { ++ const struct mtk_soc_data *soc = eth->soc; + dma_addr_t phy_ring_tail; + int cnt = MTK_DMA_SIZE; + dma_addr_t dma_addr; + int i; + + eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, +- cnt * sizeof(struct mtk_tx_dma), ++ cnt * soc->txrx.txd_size, + ð->phy_scratch_ring, + GFP_KERNEL); + if (unlikely(!eth->scratch_ring)) + return -ENOMEM; + +- eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, +- GFP_KERNEL); ++ eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, GFP_KERNEL); + if (unlikely(!eth->scratch_head)) + return -ENOMEM; + +@@ -861,16 +861,19 @@ static int mtk_init_fq_dma(struct mtk_et + if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) + return -ENOMEM; + +- phy_ring_tail = eth->phy_scratch_ring + +- (sizeof(struct mtk_tx_dma) * (cnt - 1)); ++ phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); + + for (i = 0; i < cnt; i++) { +- eth->scratch_ring[i].txd1 = +- (dma_addr + (i * MTK_QDMA_PAGE_SIZE)); ++ struct mtk_tx_dma *txd; ++ ++ txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; ++ txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; + if (i < cnt - 1) +- eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring + +- ((i + 1) * sizeof(struct mtk_tx_dma))); +- eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE); ++ txd->txd2 = eth->phy_scratch_ring + ++ (i + 1) * soc->txrx.txd_size; ++ ++ txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); ++ txd->txd4 = 0; + } + + mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); +@@ -2170,6 +2173,7 @@ static int mtk_dma_init(struct mtk_eth * + + static void mtk_dma_free(struct mtk_eth *eth) + { ++ const struct mtk_soc_data *soc = eth->soc; + int i; + + for (i = 0; i < MTK_MAC_COUNT; i++) +@@ -2177,9 +2181,8 @@ static void mtk_dma_free(struct mtk_eth + netdev_reset_queue(eth->netdev[i]); + if (eth->scratch_ring) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), +- eth->scratch_ring, +- eth->phy_scratch_ring); ++ MTK_DMA_SIZE * soc->txrx.txd_size, ++ eth->scratch_ring, eth->phy_scratch_ring); + eth->scratch_ring = NULL; + eth->phy_scratch_ring = 0; + } +@@ -3391,6 +3394,9 @@ static const struct mtk_soc_data mt2701_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + static const struct mtk_soc_data mt7621_data = { +@@ -3399,6 +3405,9 @@ static const struct mtk_soc_data mt7621_ + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + static const struct mtk_soc_data mt7622_data = { +@@ -3408,6 +3417,9 @@ static const struct mtk_soc_data mt7622_ + .required_clks = MT7622_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + static const struct mtk_soc_data mt7623_data = { +@@ -3416,6 +3428,9 @@ static const struct mtk_soc_data mt7623_ + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, + .offload_version = 2, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + static const struct mtk_soc_data mt7629_data = { +@@ -3424,6 +3439,9 @@ static const struct mtk_soc_data mt7629_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7629_CLKS_BITMAP, + .required_pctl = false, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + static const struct mtk_soc_data rt5350_data = { +@@ -3431,6 +3449,9 @@ static const struct mtk_soc_data rt5350_ + .hw_features = MTK_HW_FEATURES_MT7628, + .required_clks = MT7628_CLKS_BITMAP, + .required_pctl = false, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma), ++ }, + }; + + const struct of_device_id of_mtk_match[] = { +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -864,6 +864,7 @@ struct mtk_tx_dma_desc_info { + * the target SoC + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. ++ * @txd_size Tx DMA descriptor size. + */ + struct mtk_soc_data { + u32 ana_rgc3; +@@ -872,6 +873,9 @@ struct mtk_soc_data { + bool required_pctl; + u8 offload_version; + netdev_features_t hw_features; ++ struct { ++ u32 txd_size; ++ } txrx; + }; + + /* currently no SoC has more than 2 macs */ diff --git a/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch b/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch new file mode 100644 index 00000000000..ebe1ee3d59a --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch @@ -0,0 +1,78 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:29 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in + mtk_tx_alloc/mtk_tx_clean + +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1625,8 +1625,10 @@ static int mtk_napi_rx(struct napi_struc + + static int mtk_tx_alloc(struct mtk_eth *eth) + { ++ const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; +- int i, sz = sizeof(*ring->dma); ++ int i, sz = soc->txrx.txd_size; ++ struct mtk_tx_dma *txd; + + ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), + GFP_KERNEL); +@@ -1642,8 +1644,10 @@ static int mtk_tx_alloc(struct mtk_eth * + int next = (i + 1) % MTK_DMA_SIZE; + u32 next_ptr = ring->phys + next * sz; + +- ring->dma[i].txd2 = next_ptr; +- ring->dma[i].txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; ++ txd = (void *)ring->dma + i * sz; ++ txd->txd2 = next_ptr; ++ txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; ++ txd->txd4 = 0; + } + + /* On MT7688 (PDMA only) this driver uses the ring->dma structs +@@ -1665,7 +1669,7 @@ static int mtk_tx_alloc(struct mtk_eth * + ring->dma_size = MTK_DMA_SIZE; + atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); + ring->next_free = &ring->dma[0]; +- ring->last_free = &ring->dma[MTK_DMA_SIZE - 1]; ++ ring->last_free = (void *)txd; + ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); + ring->thresh = MAX_SKB_FRAGS; + +@@ -1698,6 +1702,7 @@ no_tx_mem: + + static void mtk_tx_clean(struct mtk_eth *eth) + { ++ const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; + int i; + +@@ -1710,17 +1715,15 @@ static void mtk_tx_clean(struct mtk_eth + + if (ring->dma) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * sizeof(*ring->dma), +- ring->dma, +- ring->phys); ++ MTK_DMA_SIZE * soc->txrx.txd_size, ++ ring->dma, ring->phys); + ring->dma = NULL; + } + + if (ring->dma_pdma) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * sizeof(*ring->dma_pdma), +- ring->dma_pdma, +- ring->phys_pdma); ++ MTK_DMA_SIZE * soc->txrx.txd_size, ++ ring->dma_pdma, ring->phys_pdma); + ring->dma_pdma = NULL; + } + } diff --git a/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch b/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch new file mode 100644 index 00000000000..053412e7490 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch @@ -0,0 +1,109 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:30 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in + mtk_desc_to_tx_buf + +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -891,10 +891,11 @@ static inline void *mtk_qdma_phys_to_vir + return ret + (desc - ring->phys); + } + +-static inline struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, +- struct mtk_tx_dma *txd) ++static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, ++ struct mtk_tx_dma *txd, ++ u32 txd_size) + { +- int idx = txd - ring->dma; ++ int idx = ((void *)txd - (void *)ring->dma) / txd_size; + + return &ring->buf[idx]; + } +@@ -1016,6 +1017,7 @@ static int mtk_tx_map(struct sk_buff *sk + }; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; ++ const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_dma *itxd, *txd; + struct mtk_tx_dma *itxd_pdma, *txd_pdma; + struct mtk_tx_buf *itx_buf, *tx_buf; +@@ -1027,7 +1029,7 @@ static int mtk_tx_map(struct sk_buff *sk + if (itxd == ring->last_free) + return -ENOMEM; + +- itx_buf = mtk_desc_to_tx_buf(ring, itxd); ++ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size); + memset(itx_buf, 0, sizeof(*itx_buf)); + + txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, +@@ -1055,7 +1057,7 @@ static int mtk_tx_map(struct sk_buff *sk + while (frag_size) { + bool new_desc = true; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || + (i & 0x1)) { + txd = mtk_qdma_phys_to_virt(ring, txd->txd2); + txd_pdma = qdma_to_pdma(ring, txd); +@@ -1079,7 +1081,8 @@ static int mtk_tx_map(struct sk_buff *sk + + mtk_tx_set_dma_desc(dev, txd, &txd_info); + +- tx_buf = mtk_desc_to_tx_buf(ring, txd); ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, ++ soc->txrx.txd_size); + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); + tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; +@@ -1098,7 +1101,7 @@ static int mtk_tx_map(struct sk_buff *sk + /* store skb to cleanup */ + itx_buf->skb = skb; + +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (k & 0x1) + txd_pdma->txd2 |= TX_DMA_LS0; + else +@@ -1116,7 +1119,7 @@ static int mtk_tx_map(struct sk_buff *sk + */ + wmb(); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || + !netdev_xmit_more()) + mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); +@@ -1130,13 +1133,13 @@ static int mtk_tx_map(struct sk_buff *sk + + err_dma: + do { +- tx_buf = mtk_desc_to_tx_buf(ring, itxd); ++ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size); + + /* unmap dma */ + mtk_tx_unmap(eth, tx_buf, false); + + itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) + itxd_pdma->txd2 = TX_DMA_DESP2_DEF; + + itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); +@@ -1450,7 +1453,8 @@ static int mtk_poll_tx_qdma(struct mtk_e + if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0) + break; + +- tx_buf = mtk_desc_to_tx_buf(ring, desc); ++ tx_buf = mtk_desc_to_tx_buf(ring, desc, ++ eth->soc->txrx.txd_size); + if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) + mac = 1; + diff --git a/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch b/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch new file mode 100644 index 00000000000..251d583f296 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch @@ -0,0 +1,39 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:31 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in txd_to_idx + +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -906,9 +906,10 @@ static struct mtk_tx_dma *qdma_to_pdma(s + return ring->dma_pdma - ring->dma + dma; + } + +-static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma) ++static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma, ++ u32 txd_size) + { +- return ((void *)dma - (void *)ring->dma) / sizeof(*dma); ++ return ((void *)dma - (void *)ring->dma) / txd_size; + } + + static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, +@@ -1124,8 +1125,10 @@ static int mtk_tx_map(struct sk_buff *sk + !netdev_xmit_more()) + mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); + } else { +- int next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd), +- ring->dma_size); ++ int next_idx; ++ ++ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->txrx.txd_size), ++ ring->dma_size); + mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); + } + diff --git a/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch new file mode 100644 index 00000000000..ec206f28d64 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch @@ -0,0 +1,102 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:32 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add rxd_size to mtk_soc_data + +Similar to tx counterpart, introduce rxd_size in mtk_soc_data data +structure. +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1776,7 +1776,7 @@ static int mtk_rx_alloc(struct mtk_eth * + } + + ring->dma = dma_alloc_coherent(eth->dma_dev, +- rx_dma_size * sizeof(*ring->dma), ++ rx_dma_size * eth->soc->txrx.rxd_size, + &ring->phys, GFP_KERNEL); + if (!ring->dma) + return -ENOMEM; +@@ -1834,9 +1834,8 @@ static void mtk_rx_clean(struct mtk_eth + + if (ring->dma) { + dma_free_coherent(eth->dma_dev, +- ring->dma_size * sizeof(*ring->dma), +- ring->dma, +- ring->phys); ++ ring->dma_size * eth->soc->txrx.rxd_size, ++ ring->dma, ring->phys); + ring->dma = NULL; + } + } +@@ -3406,6 +3405,7 @@ static const struct mtk_soc_data mt2701_ + .required_pctl = true, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +@@ -3417,6 +3417,7 @@ static const struct mtk_soc_data mt7621_ + .offload_version = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +@@ -3429,6 +3430,7 @@ static const struct mtk_soc_data mt7622_ + .offload_version = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +@@ -3440,6 +3442,7 @@ static const struct mtk_soc_data mt7623_ + .offload_version = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +@@ -3451,6 +3454,7 @@ static const struct mtk_soc_data mt7629_ + .required_pctl = false, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +@@ -3461,6 +3465,7 @@ static const struct mtk_soc_data rt5350_ + .required_pctl = false, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), ++ .rxd_size = sizeof(struct mtk_rx_dma), + }, + }; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -865,6 +865,7 @@ struct mtk_tx_dma_desc_info { + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. + * @txd_size Tx DMA descriptor size. ++ * @rxd_size Rx DMA descriptor size. + */ + struct mtk_soc_data { + u32 ana_rgc3; +@@ -875,6 +876,7 @@ struct mtk_soc_data { + netdev_features_t hw_features; + struct { + u32 txd_size; ++ u32 rxd_size; + } txrx; + }; + diff --git a/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch new file mode 100644 index 00000000000..eb92b8c7a22 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch @@ -0,0 +1,46 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:33 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size field in + mtk_poll_tx/mtk_poll_rx + +This is a preliminary to ad mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1265,9 +1265,12 @@ static struct mtk_rx_ring *mtk_get_rx_ri + return ð->rx_ring[0]; + + for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) { ++ struct mtk_rx_dma *rxd; ++ + ring = ð->rx_ring[i]; + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- if (ring->dma[idx].rxd2 & RX_DMA_DONE) { ++ rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; ++ if (rxd->rxd2 & RX_DMA_DONE) { + ring->calc_idx_update = true; + return ring; + } +@@ -1318,7 +1321,7 @@ static int mtk_poll_rx(struct napi_struc + goto rx_done; + + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- rxd = &ring->dma[idx]; ++ rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; + data = ring->data[idx]; + + if (!mtk_rx_get_desc(&trxd, rxd)) +@@ -1510,7 +1513,7 @@ static int mtk_poll_tx_pdma(struct mtk_e + + mtk_tx_unmap(eth, tx_buf, true); + +- desc = &ring->dma[cpu]; ++ desc = (void *)ring->dma + cpu * eth->soc->txrx.txd_size; + ring->last_free = desc; + atomic_inc(&ring->free_count); + diff --git a/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch new file mode 100644 index 00000000000..456eec247c5 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch @@ -0,0 +1,68 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:34 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on rxd_size field in + mtk_rx_alloc/mtk_rx_clean + +Remove mtk_rx_dma structure layout dependency in mtk_rx_alloc/mtk_rx_clean. +Initialize to 0 rxd3 and rxd4 in mtk_rx_alloc. +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1785,18 +1785,25 @@ static int mtk_rx_alloc(struct mtk_eth * + return -ENOMEM; + + for (i = 0; i < rx_dma_size; i++) { ++ struct mtk_rx_dma *rxd; ++ + dma_addr_t dma_addr = dma_map_single(eth->dma_dev, + ring->data[i] + NET_SKB_PAD + eth->ip_align, + ring->buf_size, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) + return -ENOMEM; +- ring->dma[i].rxd1 = (unsigned int)dma_addr; ++ ++ rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; ++ rxd->rxd1 = (unsigned int)dma_addr; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) +- ring->dma[i].rxd2 = RX_DMA_LSO; ++ rxd->rxd2 = RX_DMA_LSO; + else +- ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ ++ rxd->rxd3 = 0; ++ rxd->rxd4 = 0; + } + ring->dma_size = rx_dma_size; + ring->calc_idx_update = false; +@@ -1821,14 +1828,17 @@ static void mtk_rx_clean(struct mtk_eth + + if (ring->data && ring->dma) { + for (i = 0; i < ring->dma_size; i++) { ++ struct mtk_rx_dma *rxd; ++ + if (!ring->data[i]) + continue; +- if (!ring->dma[i].rxd1) ++ ++ rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; ++ if (!rxd->rxd1) + continue; +- dma_unmap_single(eth->dma_dev, +- ring->dma[i].rxd1, +- ring->buf_size, +- DMA_FROM_DEVICE); ++ ++ dma_unmap_single(eth->dma_dev, rxd->rxd1, ++ ring->buf_size, DMA_FROM_DEVICE); + skb_free_frag(ring->data[i]); + } + kfree(ring->data); diff --git a/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch b/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch new file mode 100644 index 00000000000..272f782877f --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch @@ -0,0 +1,814 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:35 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce device register map + +Introduce reg_map structure to add the capability to support different +register definitions. Move register definitions in mtk_regmap structure. +This is a preliminary patch to introduce mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -34,6 +34,59 @@ MODULE_PARM_DESC(msg_level, "Message lev + #define MTK_ETHTOOL_STAT(x) { #x, \ + offsetof(struct mtk_hw_stats, x) / sizeof(u64) } + ++static const struct mtk_reg_map mtk_reg_map = { ++ .tx_irq_mask = 0x1a1c, ++ .tx_irq_status = 0x1a18, ++ .pdma = { ++ .rx_ptr = 0x0900, ++ .rx_cnt_cfg = 0x0904, ++ .pcrx_ptr = 0x0908, ++ .glo_cfg = 0x0a04, ++ .rst_idx = 0x0a08, ++ .delay_irq = 0x0a0c, ++ .irq_status = 0x0a20, ++ .irq_mask = 0x0a28, ++ .int_grp = 0x0a50, ++ }, ++ .qdma = { ++ .qtx_cfg = 0x1800, ++ .rx_ptr = 0x1900, ++ .rx_cnt_cfg = 0x1904, ++ .qcrx_ptr = 0x1908, ++ .glo_cfg = 0x1a04, ++ .rst_idx = 0x1a08, ++ .delay_irq = 0x1a0c, ++ .fc_th = 0x1a10, ++ .int_grp = 0x1a20, ++ .hred = 0x1a44, ++ .ctx_ptr = 0x1b00, ++ .dtx_ptr = 0x1b04, ++ .crx_ptr = 0x1b10, ++ .drx_ptr = 0x1b14, ++ .fq_head = 0x1b20, ++ .fq_tail = 0x1b24, ++ .fq_count = 0x1b28, ++ .fq_blen = 0x1b2c, ++ }, ++ .gdm1_cnt = 0x2400, ++}; ++ ++static const struct mtk_reg_map mt7628_reg_map = { ++ .tx_irq_mask = 0x0a28, ++ .tx_irq_status = 0x0a20, ++ .pdma = { ++ .rx_ptr = 0x0900, ++ .rx_cnt_cfg = 0x0904, ++ .pcrx_ptr = 0x0908, ++ .glo_cfg = 0x0a04, ++ .rst_idx = 0x0a08, ++ .delay_irq = 0x0a0c, ++ .irq_status = 0x0a20, ++ .irq_mask = 0x0a28, ++ .int_grp = 0x0a50, ++ }, ++}; ++ + /* strings used by ethtool */ + static const struct mtk_ethtool_stats { + char str[ETH_GSTRING_LEN]; +@@ -619,8 +672,8 @@ static inline void mtk_tx_irq_disable(st + u32 val; + + spin_lock_irqsave(ð->tx_irq_lock, flags); +- val = mtk_r32(eth, eth->tx_int_mask_reg); +- mtk_w32(eth, val & ~mask, eth->tx_int_mask_reg); ++ val = mtk_r32(eth, eth->soc->reg_map->tx_irq_mask); ++ mtk_w32(eth, val & ~mask, eth->soc->reg_map->tx_irq_mask); + spin_unlock_irqrestore(ð->tx_irq_lock, flags); + } + +@@ -630,8 +683,8 @@ static inline void mtk_tx_irq_enable(str + u32 val; + + spin_lock_irqsave(ð->tx_irq_lock, flags); +- val = mtk_r32(eth, eth->tx_int_mask_reg); +- mtk_w32(eth, val | mask, eth->tx_int_mask_reg); ++ val = mtk_r32(eth, eth->soc->reg_map->tx_irq_mask); ++ mtk_w32(eth, val | mask, eth->soc->reg_map->tx_irq_mask); + spin_unlock_irqrestore(ð->tx_irq_lock, flags); + } + +@@ -641,8 +694,8 @@ static inline void mtk_rx_irq_disable(st + u32 val; + + spin_lock_irqsave(ð->rx_irq_lock, flags); +- val = mtk_r32(eth, MTK_PDMA_INT_MASK); +- mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK); ++ val = mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask); ++ mtk_w32(eth, val & ~mask, eth->soc->reg_map->pdma.irq_mask); + spin_unlock_irqrestore(ð->rx_irq_lock, flags); + } + +@@ -652,8 +705,8 @@ static inline void mtk_rx_irq_enable(str + u32 val; + + spin_lock_irqsave(ð->rx_irq_lock, flags); +- val = mtk_r32(eth, MTK_PDMA_INT_MASK); +- mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK); ++ val = mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask); ++ mtk_w32(eth, val | mask, eth->soc->reg_map->pdma.irq_mask); + spin_unlock_irqrestore(ð->rx_irq_lock, flags); + } + +@@ -704,39 +757,39 @@ void mtk_stats_update_mac(struct mtk_mac + hw_stats->rx_checksum_errors += + mtk_r32(mac->hw, MT7628_SDM_CS_ERR); + } else { ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + unsigned int offs = hw_stats->reg_offset; + u64 stats; + +- hw_stats->rx_bytes += mtk_r32(mac->hw, +- MTK_GDM1_RX_GBCNT_L + offs); +- stats = mtk_r32(mac->hw, MTK_GDM1_RX_GBCNT_H + offs); ++ hw_stats->rx_bytes += mtk_r32(mac->hw, reg_map->gdm1_cnt + offs); ++ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x4 + offs); + if (stats) + hw_stats->rx_bytes += (stats << 32); + hw_stats->rx_packets += +- mtk_r32(mac->hw, MTK_GDM1_RX_GPCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x8 + offs); + hw_stats->rx_overflow += +- mtk_r32(mac->hw, MTK_GDM1_RX_OERCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x10 + offs); + hw_stats->rx_fcs_errors += +- mtk_r32(mac->hw, MTK_GDM1_RX_FERCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x14 + offs); + hw_stats->rx_short_errors += +- mtk_r32(mac->hw, MTK_GDM1_RX_SERCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x18 + offs); + hw_stats->rx_long_errors += +- mtk_r32(mac->hw, MTK_GDM1_RX_LENCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x1c + offs); + hw_stats->rx_checksum_errors += +- mtk_r32(mac->hw, MTK_GDM1_RX_CERCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x20 + offs); + hw_stats->rx_flow_control_packets += +- mtk_r32(mac->hw, MTK_GDM1_RX_FCCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x24 + offs); + hw_stats->tx_skip += +- mtk_r32(mac->hw, MTK_GDM1_TX_SKIPCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs); + hw_stats->tx_collisions += +- mtk_r32(mac->hw, MTK_GDM1_TX_COLCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs); + hw_stats->tx_bytes += +- mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_L + offs); +- stats = mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_H + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs); ++ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs); + if (stats) + hw_stats->tx_bytes += (stats << 32); + hw_stats->tx_packets += +- mtk_r32(mac->hw, MTK_GDM1_TX_GPCNT + offs); ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs); + } + + u64_stats_update_end(&hw_stats->syncp); +@@ -876,10 +929,10 @@ static int mtk_init_fq_dma(struct mtk_et + txd->txd4 = 0; + } + +- mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); +- mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL); +- mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT); +- mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN); ++ mtk_w32(eth, eth->phy_scratch_ring, soc->reg_map->qdma.fq_head); ++ mtk_w32(eth, phy_ring_tail, soc->reg_map->qdma.fq_tail); ++ mtk_w32(eth, (cnt << 16) | cnt, soc->reg_map->qdma.fq_count); ++ mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, soc->reg_map->qdma.fq_blen); + + return 0; + } +@@ -1123,7 +1176,7 @@ static int mtk_tx_map(struct sk_buff *sk + if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || + !netdev_xmit_more()) +- mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); ++ mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); + } else { + int next_idx; + +@@ -1440,6 +1493,7 @@ rx_done: + static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, + unsigned int *done, unsigned int *bytes) + { ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma *desc; + struct sk_buff *skb; +@@ -1447,7 +1501,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + u32 cpu, dma; + + cpu = ring->last_free_ptr; +- dma = mtk_r32(eth, MTK_QTX_DRX_PTR); ++ dma = mtk_r32(eth, reg_map->qdma.drx_ptr); + + desc = mtk_qdma_phys_to_virt(ring, cpu); + +@@ -1482,7 +1536,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + } + + ring->last_free_ptr = cpu; +- mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); ++ mtk_w32(eth, cpu, reg_map->qdma.crx_ptr); + + return budget; + } +@@ -1575,24 +1629,25 @@ static void mtk_handle_status_irq(struct + static int mtk_napi_tx(struct napi_struct *napi, int budget) + { + struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int tx_done = 0; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) + mtk_handle_status_irq(eth); +- mtk_w32(eth, MTK_TX_DONE_INT, eth->tx_int_status_reg); ++ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->tx_irq_status); + tx_done = mtk_poll_tx(eth, budget); + + if (unlikely(netif_msg_intr(eth))) { + dev_info(eth->dev, + "done tx %d, intr 0x%08x/0x%x\n", tx_done, +- mtk_r32(eth, eth->tx_int_status_reg), +- mtk_r32(eth, eth->tx_int_mask_reg)); ++ mtk_r32(eth, reg_map->tx_irq_status), ++ mtk_r32(eth, reg_map->tx_irq_mask)); + } + + if (tx_done == budget) + return budget; + +- if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT) ++ if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT) + return budget; + + if (napi_complete_done(napi, tx_done)) +@@ -1604,6 +1659,7 @@ static int mtk_napi_tx(struct napi_struc + static int mtk_napi_rx(struct napi_struct *napi, int budget) + { + struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int rx_done_total = 0; + + mtk_handle_status_irq(eth); +@@ -1611,21 +1667,21 @@ static int mtk_napi_rx(struct napi_struc + do { + int rx_done; + +- mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS); ++ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.irq_status); + rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth); + rx_done_total += rx_done; + + if (unlikely(netif_msg_intr(eth))) { + dev_info(eth->dev, + "done rx %d, intr 0x%08x/0x%x\n", rx_done, +- mtk_r32(eth, MTK_PDMA_INT_STATUS), +- mtk_r32(eth, MTK_PDMA_INT_MASK)); ++ mtk_r32(eth, reg_map->pdma.irq_status), ++ mtk_r32(eth, reg_map->pdma.irq_mask)); + } + + if (rx_done_total == budget) + return budget; + +- } while (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT); ++ } while (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT); + + if (napi_complete_done(napi, rx_done_total)) + mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); +@@ -1688,20 +1744,20 @@ static int mtk_tx_alloc(struct mtk_eth * + */ + wmb(); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- mtk_w32(eth, ring->phys, MTK_QTX_CTX_PTR); +- mtk_w32(eth, ring->phys, MTK_QTX_DTX_PTR); ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); ++ mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); + mtk_w32(eth, + ring->phys + ((MTK_DMA_SIZE - 1) * sz), +- MTK_QTX_CRX_PTR); +- mtk_w32(eth, ring->last_free_ptr, MTK_QTX_DRX_PTR); ++ soc->reg_map->qdma.crx_ptr); ++ mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, +- MTK_QTX_CFG(0)); ++ soc->reg_map->qdma.qtx_cfg); + } else { + mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); + mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0); + mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); +- mtk_w32(eth, MT7628_PST_DTX_IDX0, MTK_PDMA_RST_IDX); ++ mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx); + } + + return 0; +@@ -1740,6 +1796,7 @@ static void mtk_tx_clean(struct mtk_eth + + static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) + { ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct mtk_rx_ring *ring; + int rx_data_len, rx_dma_size; + int i; +@@ -1808,16 +1865,18 @@ static int mtk_rx_alloc(struct mtk_eth * + ring->dma_size = rx_dma_size; + ring->calc_idx_update = false; + ring->calc_idx = rx_dma_size - 1; +- ring->crx_idx_reg = MTK_PRX_CRX_IDX_CFG(ring_no); ++ ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + ring_no * MTK_QRX_OFFSET; + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + +- mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); +- mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); ++ mtk_w32(eth, ring->phys, ++ reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET + offset); ++ mtk_w32(eth, rx_dma_size, ++ reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET + offset); + mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); +- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), reg_map->pdma.rst_idx + offset); + + return 0; + } +@@ -2126,9 +2185,9 @@ static int mtk_dma_busy_wait(struct mtk_ + u32 val; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +- reg = MTK_QDMA_GLO_CFG; ++ reg = eth->soc->reg_map->qdma.glo_cfg; + else +- reg = MTK_PDMA_GLO_CFG; ++ reg = eth->soc->reg_map->pdma.glo_cfg; + + ret = readx_poll_timeout_atomic(__raw_readl, eth->base + reg, val, + !(val & (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)), +@@ -2186,8 +2245,8 @@ static int mtk_dma_init(struct mtk_eth * + * automatically + */ + mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | +- FC_THRES_MIN, MTK_QDMA_FC_THRES); +- mtk_w32(eth, 0x0, MTK_QDMA_HRED2); ++ FC_THRES_MIN, eth->soc->reg_map->qdma.fc_th); ++ mtk_w32(eth, 0x0, eth->soc->reg_map->qdma.hred); + } + + return 0; +@@ -2261,13 +2320,14 @@ static irqreturn_t mtk_handle_irq_tx(int + static irqreturn_t mtk_handle_irq(int irq, void *_eth) + { + struct mtk_eth *eth = _eth; ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + +- if (mtk_r32(eth, MTK_PDMA_INT_MASK) & MTK_RX_DONE_INT) { +- if (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT) ++ if (mtk_r32(eth, reg_map->pdma.irq_mask) & MTK_RX_DONE_INT) { ++ if (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT) + mtk_handle_irq_rx(irq, _eth); + } +- if (mtk_r32(eth, eth->tx_int_mask_reg) & MTK_TX_DONE_INT) { +- if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT) ++ if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) { ++ if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT) + mtk_handle_irq_tx(irq, _eth); + } + +@@ -2291,6 +2351,7 @@ static void mtk_poll_controller(struct n + static int mtk_start_dma(struct mtk_eth *eth) + { + u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int err; + + err = mtk_dma_init(eth); +@@ -2305,16 +2366,15 @@ static int mtk_start_dma(struct mtk_eth + MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | + MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | + MTK_RX_BT_32DWORDS, +- MTK_QDMA_GLO_CFG); +- ++ reg_map->qdma.glo_cfg); + mtk_w32(eth, + MTK_RX_DMA_EN | rx_2b_offset | + MTK_RX_BT_32DWORDS | MTK_MULTI_EN, +- MTK_PDMA_GLO_CFG); ++ reg_map->pdma.glo_cfg); + } else { + mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN | + MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS, +- MTK_PDMA_GLO_CFG); ++ reg_map->pdma.glo_cfg); + } + + return 0; +@@ -2440,8 +2500,8 @@ static int mtk_stop(struct net_device *d + cancel_work_sync(ð->tx_dim.work); + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +- mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); +- mtk_stop_dma(eth, MTK_PDMA_GLO_CFG); ++ mtk_stop_dma(eth, eth->soc->reg_map->qdma.glo_cfg); ++ mtk_stop_dma(eth, eth->soc->reg_map->pdma.glo_cfg); + + mtk_dma_free(eth); + +@@ -2495,6 +2555,7 @@ static void mtk_dim_rx(struct work_struc + { + struct dim *dim = container_of(work, struct dim, work); + struct mtk_eth *eth = container_of(dim, struct mtk_eth, rx_dim); ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct dim_cq_moder cur_profile; + u32 val, cur; + +@@ -2502,7 +2563,7 @@ static void mtk_dim_rx(struct work_struc + dim->profile_ix); + spin_lock_bh(ð->dim_lock); + +- val = mtk_r32(eth, MTK_PDMA_DELAY_INT); ++ val = mtk_r32(eth, reg_map->pdma.delay_irq); + val &= MTK_PDMA_DELAY_TX_MASK; + val |= MTK_PDMA_DELAY_RX_EN; + +@@ -2512,9 +2573,9 @@ static void mtk_dim_rx(struct work_struc + cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); + val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT; + +- mtk_w32(eth, val, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, val, reg_map->pdma.delay_irq); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +- mtk_w32(eth, val, MTK_QDMA_DELAY_INT); ++ mtk_w32(eth, val, reg_map->qdma.delay_irq); + + spin_unlock_bh(ð->dim_lock); + +@@ -2525,6 +2586,7 @@ static void mtk_dim_tx(struct work_struc + { + struct dim *dim = container_of(work, struct dim, work); + struct mtk_eth *eth = container_of(dim, struct mtk_eth, tx_dim); ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct dim_cq_moder cur_profile; + u32 val, cur; + +@@ -2532,7 +2594,7 @@ static void mtk_dim_tx(struct work_struc + dim->profile_ix); + spin_lock_bh(ð->dim_lock); + +- val = mtk_r32(eth, MTK_PDMA_DELAY_INT); ++ val = mtk_r32(eth, reg_map->pdma.delay_irq); + val &= MTK_PDMA_DELAY_RX_MASK; + val |= MTK_PDMA_DELAY_TX_EN; + +@@ -2542,9 +2604,9 @@ static void mtk_dim_tx(struct work_struc + cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); + val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT; + +- mtk_w32(eth, val, MTK_PDMA_DELAY_INT); ++ mtk_w32(eth, val, reg_map->pdma.delay_irq); + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +- mtk_w32(eth, val, MTK_QDMA_DELAY_INT); ++ mtk_w32(eth, val, reg_map->qdma.delay_irq); + + spin_unlock_bh(ð->dim_lock); + +@@ -2555,6 +2617,7 @@ static int mtk_hw_init(struct mtk_eth *e + { + u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | + ETHSYS_DMA_AG_MAP_PPE; ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int i, val, ret; + + if (test_and_set_bit(MTK_HW_INIT, ð->state)) +@@ -2629,10 +2692,10 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_rx_irq_disable(eth, ~0); + + /* FE int grouping */ +- mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); +- mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); +- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); +- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); ++ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp); ++ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.int_grp + 4); ++ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp); ++ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->qdma.int_grp + 4); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + + return 0; +@@ -3171,14 +3234,6 @@ static int mtk_probe(struct platform_dev + if (IS_ERR(eth->base)) + return PTR_ERR(eth->base); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- eth->tx_int_mask_reg = MTK_QDMA_INT_MASK; +- eth->tx_int_status_reg = MTK_QDMA_INT_STATUS; +- } else { +- eth->tx_int_mask_reg = MTK_PDMA_INT_MASK; +- eth->tx_int_status_reg = MTK_PDMA_INT_STATUS; +- } +- + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; + eth->ip_align = NET_IP_ALIGN; +@@ -3412,6 +3467,7 @@ static int mtk_remove(struct platform_de + } + + static const struct mtk_soc_data mt2701_data = { ++ .reg_map = &mtk_reg_map, + .caps = MT7623_CAPS | MTK_HWLRO, + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7623_CLKS_BITMAP, +@@ -3423,6 +3479,7 @@ static const struct mtk_soc_data mt2701_ + }; + + static const struct mtk_soc_data mt7621_data = { ++ .reg_map = &mtk_reg_map, + .caps = MT7621_CAPS, + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7621_CLKS_BITMAP, +@@ -3435,6 +3492,7 @@ static const struct mtk_soc_data mt7621_ + }; + + static const struct mtk_soc_data mt7622_data = { ++ .reg_map = &mtk_reg_map, + .ana_rgc3 = 0x2028, + .caps = MT7622_CAPS | MTK_HWLRO, + .hw_features = MTK_HW_FEATURES, +@@ -3448,6 +3506,7 @@ static const struct mtk_soc_data mt7622_ + }; + + static const struct mtk_soc_data mt7623_data = { ++ .reg_map = &mtk_reg_map, + .caps = MT7623_CAPS | MTK_HWLRO, + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7623_CLKS_BITMAP, +@@ -3460,6 +3519,7 @@ static const struct mtk_soc_data mt7623_ + }; + + static const struct mtk_soc_data mt7629_data = { ++ .reg_map = &mtk_reg_map, + .ana_rgc3 = 0x128, + .caps = MT7629_CAPS | MTK_HWLRO, + .hw_features = MTK_HW_FEATURES, +@@ -3472,6 +3532,7 @@ static const struct mtk_soc_data mt7629_ + }; + + static const struct mtk_soc_data rt5350_data = { ++ .reg_map = &mt7628_reg_map, + .caps = MT7628_CAPS, + .hw_features = MTK_HW_FEATURES_MT7628, + .required_clks = MT7628_CLKS_BITMAP, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -48,6 +48,8 @@ + #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) + #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) + ++#define MTK_QRX_OFFSET 0x10 ++ + #define MTK_MAX_RX_RING_NUM 4 + #define MTK_HW_LRO_DMA_SIZE 8 + +@@ -100,18 +102,6 @@ + /* Unicast Filter MAC Address Register - High */ + #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) + +-/* PDMA RX Base Pointer Register */ +-#define MTK_PRX_BASE_PTR0 0x900 +-#define MTK_PRX_BASE_PTR_CFG(x) (MTK_PRX_BASE_PTR0 + (x * 0x10)) +- +-/* PDMA RX Maximum Count Register */ +-#define MTK_PRX_MAX_CNT0 0x904 +-#define MTK_PRX_MAX_CNT_CFG(x) (MTK_PRX_MAX_CNT0 + (x * 0x10)) +- +-/* PDMA RX CPU Pointer Register */ +-#define MTK_PRX_CRX_IDX0 0x908 +-#define MTK_PRX_CRX_IDX_CFG(x) (MTK_PRX_CRX_IDX0 + (x * 0x10)) +- + /* PDMA HW LRO Control Registers */ + #define MTK_PDMA_LRO_CTRL_DW0 0x980 + #define MTK_LRO_EN BIT(0) +@@ -126,18 +116,19 @@ + #define MTK_ADMA_MODE BIT(15) + #define MTK_LRO_MIN_RXD_SDL (MTK_HW_LRO_SDL_REMAIN_ROOM << 16) + +-/* PDMA Global Configuration Register */ +-#define MTK_PDMA_GLO_CFG 0xa04 ++#define MTK_RX_DMA_LRO_EN BIT(8) + #define MTK_MULTI_EN BIT(10) + #define MTK_PDMA_SIZE_8DWORDS (1 << 4) + ++/* PDMA Global Configuration Register */ ++#define MTK_PDMA_LRO_SDL 0x3000 ++#define MTK_RX_CFG_SDL_OFFSET 16 ++ + /* PDMA Reset Index Register */ +-#define MTK_PDMA_RST_IDX 0xa08 + #define MTK_PST_DRX_IDX0 BIT(16) + #define MTK_PST_DRX_IDX_CFG(x) (MTK_PST_DRX_IDX0 << (x)) + + /* PDMA Delay Interrupt Register */ +-#define MTK_PDMA_DELAY_INT 0xa0c + #define MTK_PDMA_DELAY_RX_MASK GENMASK(15, 0) + #define MTK_PDMA_DELAY_RX_EN BIT(15) + #define MTK_PDMA_DELAY_RX_PINT_SHIFT 8 +@@ -151,19 +142,9 @@ + #define MTK_PDMA_DELAY_PINT_MASK 0x7f + #define MTK_PDMA_DELAY_PTIME_MASK 0xff + +-/* PDMA Interrupt Status Register */ +-#define MTK_PDMA_INT_STATUS 0xa20 +- +-/* PDMA Interrupt Mask Register */ +-#define MTK_PDMA_INT_MASK 0xa28 +- + /* PDMA HW LRO Alter Flow Delta Register */ + #define MTK_PDMA_LRO_ALT_SCORE_DELTA 0xa4c + +-/* PDMA Interrupt grouping registers */ +-#define MTK_PDMA_INT_GRP1 0xa50 +-#define MTK_PDMA_INT_GRP2 0xa54 +- + /* PDMA HW LRO IP Setting Registers */ + #define MTK_LRO_RX_RING0_DIP_DW0 0xb04 + #define MTK_LRO_DIP_DW0_CFG(x) (MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40)) +@@ -185,26 +166,9 @@ + #define MTK_RING_MAX_AGG_CNT_H ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3) + + /* QDMA TX Queue Configuration Registers */ +-#define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) + #define QDMA_RES_THRES 4 + +-/* QDMA TX Queue Scheduler Registers */ +-#define MTK_QTX_SCH(x) (0x1804 + (x * 0x10)) +- +-/* QDMA RX Base Pointer Register */ +-#define MTK_QRX_BASE_PTR0 0x1900 +- +-/* QDMA RX Maximum Count Register */ +-#define MTK_QRX_MAX_CNT0 0x1904 +- +-/* QDMA RX CPU Pointer Register */ +-#define MTK_QRX_CRX_IDX0 0x1908 +- +-/* QDMA RX DMA Pointer Register */ +-#define MTK_QRX_DRX_IDX0 0x190C +- + /* QDMA Global Configuration Register */ +-#define MTK_QDMA_GLO_CFG 0x1A04 + #define MTK_RX_2B_OFFSET BIT(31) + #define MTK_RX_BT_32DWORDS (3 << 11) + #define MTK_NDP_CO_PRO BIT(10) +@@ -216,20 +180,12 @@ + #define MTK_TX_DMA_EN BIT(0) + #define MTK_DMA_BUSY_TIMEOUT_US 1000000 + +-/* QDMA Reset Index Register */ +-#define MTK_QDMA_RST_IDX 0x1A08 +- +-/* QDMA Delay Interrupt Register */ +-#define MTK_QDMA_DELAY_INT 0x1A0C +- + /* QDMA Flow Control Register */ +-#define MTK_QDMA_FC_THRES 0x1A10 + #define FC_THRES_DROP_MODE BIT(20) + #define FC_THRES_DROP_EN (7 << 16) + #define FC_THRES_MIN 0x4444 + + /* QDMA Interrupt Status Register */ +-#define MTK_QDMA_INT_STATUS 0x1A18 + #define MTK_RX_DONE_DLY BIT(30) + #define MTK_TX_DONE_DLY BIT(28) + #define MTK_RX_DONE_INT3 BIT(19) +@@ -244,55 +200,8 @@ + #define MTK_TX_DONE_INT MTK_TX_DONE_DLY + + /* QDMA Interrupt grouping registers */ +-#define MTK_QDMA_INT_GRP1 0x1a20 +-#define MTK_QDMA_INT_GRP2 0x1a24 + #define MTK_RLS_DONE_INT BIT(0) + +-/* QDMA Interrupt Status Register */ +-#define MTK_QDMA_INT_MASK 0x1A1C +- +-/* QDMA Interrupt Mask Register */ +-#define MTK_QDMA_HRED2 0x1A44 +- +-/* QDMA TX Forward CPU Pointer Register */ +-#define MTK_QTX_CTX_PTR 0x1B00 +- +-/* QDMA TX Forward DMA Pointer Register */ +-#define MTK_QTX_DTX_PTR 0x1B04 +- +-/* QDMA TX Release CPU Pointer Register */ +-#define MTK_QTX_CRX_PTR 0x1B10 +- +-/* QDMA TX Release DMA Pointer Register */ +-#define MTK_QTX_DRX_PTR 0x1B14 +- +-/* QDMA FQ Head Pointer Register */ +-#define MTK_QDMA_FQ_HEAD 0x1B20 +- +-/* QDMA FQ Head Pointer Register */ +-#define MTK_QDMA_FQ_TAIL 0x1B24 +- +-/* QDMA FQ Free Page Counter Register */ +-#define MTK_QDMA_FQ_CNT 0x1B28 +- +-/* QDMA FQ Free Page Buffer Length Register */ +-#define MTK_QDMA_FQ_BLEN 0x1B2C +- +-/* GMA1 counter / statics register */ +-#define MTK_GDM1_RX_GBCNT_L 0x2400 +-#define MTK_GDM1_RX_GBCNT_H 0x2404 +-#define MTK_GDM1_RX_GPCNT 0x2408 +-#define MTK_GDM1_RX_OERCNT 0x2410 +-#define MTK_GDM1_RX_FERCNT 0x2414 +-#define MTK_GDM1_RX_SERCNT 0x2418 +-#define MTK_GDM1_RX_LENCNT 0x241c +-#define MTK_GDM1_RX_CERCNT 0x2420 +-#define MTK_GDM1_RX_FCCNT 0x2424 +-#define MTK_GDM1_TX_SKIPCNT 0x2428 +-#define MTK_GDM1_TX_COLCNT 0x242c +-#define MTK_GDM1_TX_GBCNT_L 0x2430 +-#define MTK_GDM1_TX_GBCNT_H 0x2434 +-#define MTK_GDM1_TX_GPCNT 0x2438 + #define MTK_STAT_OFFSET 0x40 + + #define MTK_WDMA0_BASE 0x2800 +@@ -854,8 +763,46 @@ struct mtk_tx_dma_desc_info { + u8 last:1; + }; + ++struct mtk_reg_map { ++ u32 tx_irq_mask; ++ u32 tx_irq_status; ++ struct { ++ u32 rx_ptr; /* rx base pointer */ ++ u32 rx_cnt_cfg; /* rx max count configuration */ ++ u32 pcrx_ptr; /* rx cpu pointer */ ++ u32 glo_cfg; /* global configuration */ ++ u32 rst_idx; /* reset index */ ++ u32 delay_irq; /* delay interrupt */ ++ u32 irq_status; /* interrupt status */ ++ u32 irq_mask; /* interrupt mask */ ++ u32 int_grp; ++ } pdma; ++ struct { ++ u32 qtx_cfg; /* tx queue configuration */ ++ u32 rx_ptr; /* rx base pointer */ ++ u32 rx_cnt_cfg; /* rx max count configuration */ ++ u32 qcrx_ptr; /* rx cpu pointer */ ++ u32 glo_cfg; /* global configuration */ ++ u32 rst_idx; /* reset index */ ++ u32 delay_irq; /* delay interrupt */ ++ u32 fc_th; /* flow control */ ++ u32 int_grp; ++ u32 hred; /* interrupt mask */ ++ u32 ctx_ptr; /* tx acquire cpu pointer */ ++ u32 dtx_ptr; /* tx acquire dma pointer */ ++ u32 crx_ptr; /* tx release cpu pointer */ ++ u32 drx_ptr; /* tx release dma pointer */ ++ u32 fq_head; /* fq head pointer */ ++ u32 fq_tail; /* fq tail pointer */ ++ u32 fq_count; /* fq free page count */ ++ u32 fq_blen; /* fq free page buffer length */ ++ } qdma; ++ u32 gdm1_cnt; ++}; ++ + /* struct mtk_eth_data - This is the structure holding all differences + * among various plaforms ++ * @reg_map Soc register map. + * @ana_rgc3: The offset for register ANA_RGC3 related to + * sgmiisys syscon + * @caps Flags shown the extra capability for the SoC +@@ -868,6 +815,7 @@ struct mtk_tx_dma_desc_info { + * @rxd_size Rx DMA descriptor size. + */ + struct mtk_soc_data { ++ const struct mtk_reg_map *reg_map; + u32 ana_rgc3; + u32 caps; + u32 required_clks; +@@ -995,8 +943,6 @@ struct mtk_eth { + u32 tx_bytes; + struct dim tx_dim; + +- u32 tx_int_mask_reg; +- u32 tx_int_status_reg; + u32 rx_dma_l4_valid; + int ip_align; + diff --git a/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch b/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch new file mode 100644 index 00000000000..4d6c94b13b8 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch @@ -0,0 +1,917 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:36 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support + +Introduce MTK_NETSYS_V2 support. MTK_NETSYS_V2 defines 32B TX/RX DMA +descriptors. +This is a preliminary patch to add mt7986 ethernet support. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -863,8 +863,8 @@ static inline int mtk_max_buf_size(int f + return buf_size; + } + +-static inline bool mtk_rx_get_desc(struct mtk_rx_dma *rxd, +- struct mtk_rx_dma *dma_rxd) ++static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd, ++ struct mtk_rx_dma_v2 *dma_rxd) + { + rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); + if (!(rxd->rxd2 & RX_DMA_DONE)) +@@ -873,6 +873,10 @@ static inline bool mtk_rx_get_desc(struc + rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); + rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); + rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ rxd->rxd5 = READ_ONCE(dma_rxd->rxd5); ++ rxd->rxd6 = READ_ONCE(dma_rxd->rxd6); ++ } + + return true; + } +@@ -917,7 +921,7 @@ static int mtk_init_fq_dma(struct mtk_et + phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); + + for (i = 0; i < cnt; i++) { +- struct mtk_tx_dma *txd; ++ struct mtk_tx_dma_v2 *txd; + + txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; + txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; +@@ -927,6 +931,12 @@ static int mtk_init_fq_dma(struct mtk_et + + txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); + txd->txd4 = 0; ++ if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { ++ txd->txd5 = 0; ++ txd->txd6 = 0; ++ txd->txd7 = 0; ++ txd->txd8 = 0; ++ } + } + + mtk_w32(eth, eth->phy_scratch_ring, soc->reg_map->qdma.fq_head); +@@ -1030,10 +1040,12 @@ static void setup_tx_buf(struct mtk_eth + } + } + +-static void mtk_tx_set_dma_desc(struct net_device *dev, struct mtk_tx_dma *desc, +- struct mtk_tx_dma_desc_info *info) ++static void mtk_tx_set_dma_desc_v1(struct net_device *dev, void *txd, ++ struct mtk_tx_dma_desc_info *info) + { + struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ struct mtk_tx_dma *desc = txd; + u32 data; + + WRITE_ONCE(desc->txd1, info->addr); +@@ -1057,6 +1069,59 @@ static void mtk_tx_set_dma_desc(struct n + WRITE_ONCE(desc->txd4, data); + } + ++static void mtk_tx_set_dma_desc_v2(struct net_device *dev, void *txd, ++ struct mtk_tx_dma_desc_info *info) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_tx_dma_v2 *desc = txd; ++ struct mtk_eth *eth = mac->hw; ++ u32 data; ++ ++ WRITE_ONCE(desc->txd1, info->addr); ++ ++ data = TX_DMA_PLEN0(info->size); ++ if (info->last) ++ data |= TX_DMA_LS0; ++ WRITE_ONCE(desc->txd3, data); ++ ++ if (!info->qid && mac->id) ++ info->qid = MTK_QDMA_GMAC2_QID; ++ ++ data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ ++ data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); ++ WRITE_ONCE(desc->txd4, data); ++ ++ data = 0; ++ if (info->first) { ++ if (info->gso) ++ data |= TX_DMA_TSO_V2; ++ /* tx checksum offload */ ++ if (info->csum) ++ data |= TX_DMA_CHKSUM_V2; ++ } ++ WRITE_ONCE(desc->txd5, data); ++ ++ data = 0; ++ if (info->first && info->vlan) ++ data |= TX_DMA_INS_VLAN_V2 | info->vlan_tci; ++ WRITE_ONCE(desc->txd6, data); ++ ++ WRITE_ONCE(desc->txd7, 0); ++ WRITE_ONCE(desc->txd8, 0); ++} ++ ++static void mtk_tx_set_dma_desc(struct net_device *dev, void *txd, ++ struct mtk_tx_dma_desc_info *info) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ mtk_tx_set_dma_desc_v2(dev, txd, info); ++ else ++ mtk_tx_set_dma_desc_v1(dev, txd, info); ++} ++ + static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, + int tx_num, struct mtk_tx_ring *ring, bool gso) + { +@@ -1065,6 +1130,7 @@ static int mtk_tx_map(struct sk_buff *sk + .gso = gso, + .csum = skb->ip_summed == CHECKSUM_PARTIAL, + .vlan = skb_vlan_tag_present(skb), ++ .qid = skb->mark & MTK_QDMA_TX_MASK, + .vlan_tci = skb_vlan_tag_get(skb), + .first = true, + .last = !skb_is_nonlinear(skb), +@@ -1124,7 +1190,9 @@ static int mtk_tx_map(struct sk_buff *sk + } + + memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); +- txd_info.size = min(frag_size, MTK_TX_DMA_BUF_LEN); ++ txd_info.size = min_t(unsigned int, frag_size, ++ soc->txrx.dma_max_len); ++ txd_info.qid = skb->mark & MTK_QDMA_TX_MASK; + txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && + !(frag_size - txd_info.size); + txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, +@@ -1205,17 +1273,16 @@ err_dma: + return -ENOMEM; + } + +-static inline int mtk_cal_txd_req(struct sk_buff *skb) ++static int mtk_cal_txd_req(struct mtk_eth *eth, struct sk_buff *skb) + { +- int i, nfrags; ++ int i, nfrags = 1; + skb_frag_t *frag; + +- nfrags = 1; + if (skb_is_gso(skb)) { + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + nfrags += DIV_ROUND_UP(skb_frag_size(frag), +- MTK_TX_DMA_BUF_LEN); ++ eth->soc->txrx.dma_max_len); + } + } else { + nfrags += skb_shinfo(skb)->nr_frags; +@@ -1267,7 +1334,7 @@ static netdev_tx_t mtk_start_xmit(struct + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto drop; + +- tx_num = mtk_cal_txd_req(skb); ++ tx_num = mtk_cal_txd_req(eth, skb); + if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { + netif_stop_queue(dev); + netif_err(eth, tx_queued, dev, +@@ -1359,7 +1426,7 @@ static int mtk_poll_rx(struct napi_struc + int idx; + struct sk_buff *skb; + u8 *data, *new_data; +- struct mtk_rx_dma *rxd, trxd; ++ struct mtk_rx_dma_v2 *rxd, trxd; + int done = 0, bytes = 0; + + while (done < budget) { +@@ -1367,7 +1434,7 @@ static int mtk_poll_rx(struct napi_struc + unsigned int pktlen; + dma_addr_t dma_addr; + u32 hash, reason; +- int mac; ++ int mac = 0; + + ring = mtk_get_rx_ring(eth); + if (unlikely(!ring)) +@@ -1377,16 +1444,15 @@ static int mtk_poll_rx(struct napi_struc + rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; + data = ring->data[idx]; + +- if (!mtk_rx_get_desc(&trxd, rxd)) ++ if (!mtk_rx_get_desc(eth, &trxd, rxd)) + break; + + /* find out which mac the packet come from. values start at 1 */ +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) || +- (trxd.rxd4 & RX_DMA_SPECIAL_TAG)) +- mac = 0; +- else +- mac = ((trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & +- RX_DMA_FPORT_MASK) - 1; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1; ++ else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && ++ !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) ++ mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1; + + if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || + !eth->netdev[mac])) +@@ -1432,7 +1498,7 @@ static int mtk_poll_rx(struct napi_struc + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; + skb_put(skb, pktlen); +- if (trxd.rxd4 & eth->rx_dma_l4_valid) ++ if (trxd.rxd4 & eth->soc->txrx.rx_dma_l4_valid) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb_checksum_none_assert(skb); +@@ -1450,10 +1516,25 @@ static int mtk_poll_rx(struct napi_struc + mtk_ppe_check_skb(eth->ppe, skb, + trxd.rxd4 & MTK_RXD4_FOE_ENTRY); + +- if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && +- (trxd.rxd2 & RX_DMA_VTAG)) +- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), +- RX_DMA_VID(trxd.rxd3)); ++ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (trxd.rxd3 & RX_DMA_VTAG_V2) ++ __vlan_hwaccel_put_tag(skb, ++ htons(RX_DMA_VPID(trxd.rxd4)), ++ RX_DMA_VID(trxd.rxd4)); ++ } else if (trxd.rxd2 & RX_DMA_VTAG) { ++ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ++ RX_DMA_VID(trxd.rxd3)); ++ } ++ ++ /* If the device is attached to a dsa switch, the special ++ * tag inserted in VLAN field by hw switch can * be offloaded ++ * by RX HW VLAN offload. Clear vlan info. ++ */ ++ if (netdev_uses_dsa(netdev)) ++ __vlan_hwaccel_clear_tag(skb); ++ } ++ + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + +@@ -1465,7 +1546,7 @@ release_desc: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; + else +- rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); + + ring->calc_idx = idx; + +@@ -1667,7 +1748,8 @@ static int mtk_napi_rx(struct napi_struc + do { + int rx_done; + +- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.irq_status); ++ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, ++ reg_map->pdma.irq_status); + rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth); + rx_done_total += rx_done; + +@@ -1681,10 +1763,11 @@ static int mtk_napi_rx(struct napi_struc + if (rx_done_total == budget) + return budget; + +- } while (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT); ++ } while (mtk_r32(eth, reg_map->pdma.irq_status) & ++ eth->soc->txrx.rx_irq_done_mask); + + if (napi_complete_done(napi, rx_done_total)) +- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); + + return rx_done_total; + } +@@ -1694,7 +1777,7 @@ static int mtk_tx_alloc(struct mtk_eth * + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; + int i, sz = soc->txrx.txd_size; +- struct mtk_tx_dma *txd; ++ struct mtk_tx_dma_v2 *txd; + + ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), + GFP_KERNEL); +@@ -1714,13 +1797,19 @@ static int mtk_tx_alloc(struct mtk_eth * + txd->txd2 = next_ptr; + txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; + txd->txd4 = 0; ++ if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { ++ txd->txd5 = 0; ++ txd->txd6 = 0; ++ txd->txd7 = 0; ++ txd->txd8 = 0; ++ } + } + + /* On MT7688 (PDMA only) this driver uses the ring->dma structs + * only as the framework. The real HW descriptors are the PDMA + * descriptors in ring->dma_pdma. + */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, + &ring->phys_pdma, GFP_KERNEL); + if (!ring->dma_pdma) +@@ -1800,13 +1889,11 @@ static int mtk_rx_alloc(struct mtk_eth * + struct mtk_rx_ring *ring; + int rx_data_len, rx_dma_size; + int i; +- u32 offset = 0; + + if (rx_flag == MTK_RX_FLAGS_QDMA) { + if (ring_no) + return -EINVAL; + ring = ð->rx_ring_qdma; +- offset = 0x1000; + } else { + ring = ð->rx_ring[ring_no]; + } +@@ -1842,7 +1929,7 @@ static int mtk_rx_alloc(struct mtk_eth * + return -ENOMEM; + + for (i = 0; i < rx_dma_size; i++) { +- struct mtk_rx_dma *rxd; ++ struct mtk_rx_dma_v2 *rxd; + + dma_addr_t dma_addr = dma_map_single(eth->dma_dev, + ring->data[i] + NET_SKB_PAD + eth->ip_align, +@@ -1857,26 +1944,47 @@ static int mtk_rx_alloc(struct mtk_eth * + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; + else +- rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); ++ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); + + rxd->rxd3 = 0; + rxd->rxd4 = 0; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ rxd->rxd5 = 0; ++ rxd->rxd6 = 0; ++ rxd->rxd7 = 0; ++ rxd->rxd8 = 0; ++ } + } + ring->dma_size = rx_dma_size; + ring->calc_idx_update = false; + ring->calc_idx = rx_dma_size - 1; +- ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + ring_no * MTK_QRX_OFFSET; ++ if (rx_flag == MTK_RX_FLAGS_QDMA) ++ ring->crx_idx_reg = reg_map->qdma.qcrx_ptr + ++ ring_no * MTK_QRX_OFFSET; ++ else ++ ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + ++ ring_no * MTK_QRX_OFFSET; + /* make sure that all changes to the dma ring are flushed before we + * continue + */ + wmb(); + +- mtk_w32(eth, ring->phys, +- reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET + offset); +- mtk_w32(eth, rx_dma_size, +- reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET + offset); +- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); +- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), reg_map->pdma.rst_idx + offset); ++ if (rx_flag == MTK_RX_FLAGS_QDMA) { ++ mtk_w32(eth, ring->phys, ++ reg_map->qdma.rx_ptr + ring_no * MTK_QRX_OFFSET); ++ mtk_w32(eth, rx_dma_size, ++ reg_map->qdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), ++ reg_map->qdma.rst_idx); ++ } else { ++ mtk_w32(eth, ring->phys, ++ reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET); ++ mtk_w32(eth, rx_dma_size, ++ reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET); ++ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), ++ reg_map->pdma.rst_idx); ++ } ++ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); + + return 0; + } +@@ -2298,7 +2406,7 @@ static irqreturn_t mtk_handle_irq_rx(int + eth->rx_events++; + if (likely(napi_schedule_prep(ð->rx_napi))) { + __napi_schedule(ð->rx_napi); +- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); + } + + return IRQ_HANDLED; +@@ -2322,8 +2430,10 @@ static irqreturn_t mtk_handle_irq(int ir + struct mtk_eth *eth = _eth; + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + +- if (mtk_r32(eth, reg_map->pdma.irq_mask) & MTK_RX_DONE_INT) { +- if (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT) ++ if (mtk_r32(eth, reg_map->pdma.irq_mask) & ++ eth->soc->txrx.rx_irq_done_mask) { ++ if (mtk_r32(eth, reg_map->pdma.irq_status) & ++ eth->soc->txrx.rx_irq_done_mask) + mtk_handle_irq_rx(irq, _eth); + } + if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) { +@@ -2341,16 +2451,16 @@ static void mtk_poll_controller(struct n + struct mtk_eth *eth = mac->hw; + + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); + mtk_handle_irq_rx(eth->irq[2], dev); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); + } + #endif + + static int mtk_start_dma(struct mtk_eth *eth) + { +- u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; ++ u32 val, rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int err; + +@@ -2361,12 +2471,19 @@ static int mtk_start_dma(struct mtk_eth + } + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { +- mtk_w32(eth, +- MTK_TX_WB_DDONE | MTK_TX_DMA_EN | +- MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | +- MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | +- MTK_RX_BT_32DWORDS, +- reg_map->qdma.glo_cfg); ++ val = mtk_r32(eth, reg_map->qdma.glo_cfg); ++ val |= MTK_TX_DMA_EN | MTK_RX_DMA_EN | ++ MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | ++ MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_MUTLI_CNT | MTK_RESV_BUF | ++ MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | ++ MTK_CHK_DDONE_EN; ++ else ++ val |= MTK_RX_BT_32DWORDS; ++ mtk_w32(eth, val, reg_map->qdma.glo_cfg); ++ + mtk_w32(eth, + MTK_RX_DMA_EN | rx_2b_offset | + MTK_RX_BT_32DWORDS | MTK_MULTI_EN, +@@ -2440,7 +2557,7 @@ static int mtk_open(struct net_device *d + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); + refcount_set(ð->dma_refcnt, 1); + } + else +@@ -2492,7 +2609,7 @@ static int mtk_stop(struct net_device *d + mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); + + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); ++ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); + napi_disable(ð->tx_napi); + napi_disable(ð->rx_napi); + +@@ -2652,9 +2769,25 @@ static int mtk_hw_init(struct mtk_eth *e + return 0; + } + +- /* Non-MT7628 handling... */ +- ethsys_reset(eth, RSTCTRL_FE); +- ethsys_reset(eth, RSTCTRL_PPE); ++ val = RSTCTRL_FE | RSTCTRL_PPE; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); ++ ++ val |= RSTCTRL_ETH; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ val |= RSTCTRL_PPE1; ++ } ++ ++ ethsys_reset(eth, val); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, ++ 0x3ffffff); ++ ++ /* Set FE to PDMAv2 if necessary */ ++ val = mtk_r32(eth, MTK_FE_GLO_MISC); ++ mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC); ++ } + + if (eth->pctl) { + /* Set GE2 driving and slew rate */ +@@ -2693,11 +2826,47 @@ static int mtk_hw_init(struct mtk_eth *e + + /* FE int grouping */ + mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp); +- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.int_grp + 4); ++ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->pdma.int_grp + 4); + mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp); +- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->qdma.int_grp + 4); ++ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ /* PSE should not drop port8 and port9 packets */ ++ mtk_w32(eth, 0x00000300, PSE_DROP_CFG); ++ ++ /* PSE Free Queue Flow Control */ ++ mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); ++ ++ /* PSE config input queue threshold */ ++ mtk_w32(eth, 0x001a000e, PSE_IQ_REV(1)); ++ mtk_w32(eth, 0x01ff001a, PSE_IQ_REV(2)); ++ mtk_w32(eth, 0x000e01ff, PSE_IQ_REV(3)); ++ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(4)); ++ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(5)); ++ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(6)); ++ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(7)); ++ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(8)); ++ ++ /* PSE config output queue threshold */ ++ mtk_w32(eth, 0x000f000a, PSE_OQ_TH(1)); ++ mtk_w32(eth, 0x001a000f, PSE_OQ_TH(2)); ++ mtk_w32(eth, 0x000f001a, PSE_OQ_TH(3)); ++ mtk_w32(eth, 0x01ff000f, PSE_OQ_TH(4)); ++ mtk_w32(eth, 0x000f000f, PSE_OQ_TH(5)); ++ mtk_w32(eth, 0x0006000f, PSE_OQ_TH(6)); ++ mtk_w32(eth, 0x00060006, PSE_OQ_TH(7)); ++ mtk_w32(eth, 0x00060006, PSE_OQ_TH(8)); ++ ++ /* GDM and CDM Threshold */ ++ mtk_w32(eth, 0x00000004, MTK_GDM2_THRES); ++ mtk_w32(eth, 0x00000004, MTK_CDMW0_THRES); ++ mtk_w32(eth, 0x00000004, MTK_CDMW1_THRES); ++ mtk_w32(eth, 0x00000004, MTK_CDME0_THRES); ++ mtk_w32(eth, 0x00000004, MTK_CDME1_THRES); ++ mtk_w32(eth, 0x00000004, MTK_CDMM_THRES); ++ } ++ + return 0; + + err_disable_pm: +@@ -3234,12 +3403,8 @@ static int mtk_probe(struct platform_dev + if (IS_ERR(eth->base)) + return PTR_ERR(eth->base); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { +- eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + eth->ip_align = NET_IP_ALIGN; +- } else { +- eth->rx_dma_l4_valid = RX_DMA_L4_VALID; +- } + + spin_lock_init(ð->page_lock); + spin_lock_init(ð->tx_irq_lock); +@@ -3475,6 +3640,10 @@ static const struct mtk_soc_data mt2701_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +@@ -3488,6 +3657,10 @@ static const struct mtk_soc_data mt7621_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +@@ -3502,6 +3675,10 @@ static const struct mtk_soc_data mt7622_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +@@ -3515,6 +3692,10 @@ static const struct mtk_soc_data mt7623_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +@@ -3528,6 +3709,10 @@ static const struct mtk_soc_data mt7629_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +@@ -3540,6 +3725,10 @@ static const struct mtk_soc_data rt5350_ + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), ++ .rx_irq_done_mask = MTK_RX_DONE_INT, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN, ++ .dma_len_offset = 16, + }, + }; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -23,6 +23,7 @@ + #define MTK_MAX_RX_LENGTH 1536 + #define MTK_MAX_RX_LENGTH_2K 2048 + #define MTK_TX_DMA_BUF_LEN 0x3fff ++#define MTK_TX_DMA_BUF_LEN_V2 0xffff + #define MTK_DMA_SIZE 512 + #define MTK_NAPI_WEIGHT 64 + #define MTK_MAC_COUNT 2 +@@ -83,6 +84,10 @@ + #define MTK_CDMQ_IG_CTRL 0x1400 + #define MTK_CDMQ_STAG_EN BIT(0) + ++/* CDMP Ingress Control Register */ ++#define MTK_CDMP_IG_CTRL 0x400 ++#define MTK_CDMP_STAG_EN BIT(0) ++ + /* CDMP Exgress Control Register */ + #define MTK_CDMP_EG_CTRL 0x404 + +@@ -102,13 +107,38 @@ + /* Unicast Filter MAC Address Register - High */ + #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) + ++/* FE global misc reg*/ ++#define MTK_FE_GLO_MISC 0x124 ++ ++/* PSE Free Queue Flow Control */ ++#define PSE_FQFC_CFG1 0x100 ++#define PSE_FQFC_CFG2 0x104 ++#define PSE_DROP_CFG 0x108 ++ ++/* PSE Input Queue Reservation Register*/ ++#define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) ++ ++/* PSE Output Queue Threshold Register*/ ++#define PSE_OQ_TH(x) (0x160 + (((x) - 1) << 2)) ++ ++/* GDM and CDM Threshold */ ++#define MTK_GDM2_THRES 0x1530 ++#define MTK_CDMW0_THRES 0x164c ++#define MTK_CDMW1_THRES 0x1650 ++#define MTK_CDME0_THRES 0x1654 ++#define MTK_CDME1_THRES 0x1658 ++#define MTK_CDMM_THRES 0x165c ++ + /* PDMA HW LRO Control Registers */ + #define MTK_PDMA_LRO_CTRL_DW0 0x980 + #define MTK_LRO_EN BIT(0) + #define MTK_L3_CKS_UPD_EN BIT(7) ++#define MTK_L3_CKS_UPD_EN_V2 BIT(19) + #define MTK_LRO_ALT_PKT_CNT_MODE BIT(21) + #define MTK_LRO_RING_RELINQUISH_REQ (0x7 << 26) ++#define MTK_LRO_RING_RELINQUISH_REQ_V2 (0xf << 24) + #define MTK_LRO_RING_RELINQUISH_DONE (0x7 << 29) ++#define MTK_LRO_RING_RELINQUISH_DONE_V2 (0xf << 28) + + #define MTK_PDMA_LRO_CTRL_DW1 0x984 + #define MTK_PDMA_LRO_CTRL_DW2 0x988 +@@ -180,6 +210,13 @@ + #define MTK_TX_DMA_EN BIT(0) + #define MTK_DMA_BUSY_TIMEOUT_US 1000000 + ++/* QDMA V2 Global Configuration Register */ ++#define MTK_CHK_DDONE_EN BIT(28) ++#define MTK_DMAD_WR_WDONE BIT(26) ++#define MTK_WCOMP_EN BIT(24) ++#define MTK_RESV_BUF (0x40 << 16) ++#define MTK_MUTLI_CNT (0x4 << 12) ++ + /* QDMA Flow Control Register */ + #define FC_THRES_DROP_MODE BIT(20) + #define FC_THRES_DROP_EN (7 << 16) +@@ -199,11 +236,32 @@ + #define MTK_RX_DONE_INT MTK_RX_DONE_DLY + #define MTK_TX_DONE_INT MTK_TX_DONE_DLY + ++#define MTK_RX_DONE_INT_V2 BIT(14) ++ + /* QDMA Interrupt grouping registers */ + #define MTK_RLS_DONE_INT BIT(0) + + #define MTK_STAT_OFFSET 0x40 + ++/* QDMA TX NUM */ ++#define MTK_QDMA_TX_NUM 16 ++#define MTK_QDMA_TX_MASK (MTK_QDMA_TX_NUM - 1) ++#define QID_BITS_V2(x) (((x) & 0x3f) << 16) ++#define MTK_QDMA_GMAC2_QID 8 ++ ++#define MTK_TX_DMA_BUF_SHIFT 8 ++ ++/* QDMA V2 descriptor txd6 */ ++#define TX_DMA_INS_VLAN_V2 BIT(16) ++/* QDMA V2 descriptor txd5 */ ++#define TX_DMA_CHKSUM_V2 (0x7 << 28) ++#define TX_DMA_TSO_V2 BIT(31) ++ ++/* QDMA V2 descriptor txd4 */ ++#define TX_DMA_FPORT_SHIFT_V2 8 ++#define TX_DMA_FPORT_MASK_V2 0xf ++#define TX_DMA_SWC_V2 BIT(30) ++ + #define MTK_WDMA0_BASE 0x2800 + #define MTK_WDMA1_BASE 0x2c00 + +@@ -217,10 +275,9 @@ + /* QDMA descriptor txd3 */ + #define TX_DMA_OWNER_CPU BIT(31) + #define TX_DMA_LS0 BIT(30) +-#define TX_DMA_PLEN0(_x) (((_x) & MTK_TX_DMA_BUF_LEN) << 16) +-#define TX_DMA_PLEN1(_x) ((_x) & MTK_TX_DMA_BUF_LEN) ++#define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) ++#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len) + #define TX_DMA_SWC BIT(14) +-#define TX_DMA_SDL(_x) (((_x) & 0x3fff) << 16) + + /* PDMA on MT7628 */ + #define TX_DMA_DONE BIT(31) +@@ -230,12 +287,14 @@ + /* QDMA descriptor rxd2 */ + #define RX_DMA_DONE BIT(31) + #define RX_DMA_LSO BIT(30) +-#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16) +-#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff) ++#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) ++#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->txrx.dma_len_offset) & eth->soc->txrx.dma_max_len) + #define RX_DMA_VTAG BIT(15) + + /* QDMA descriptor rxd3 */ +-#define RX_DMA_VID(_x) ((_x) & 0xfff) ++#define RX_DMA_VID(x) ((x) & VLAN_VID_MASK) ++#define RX_DMA_TCI(x) ((x) & (VLAN_PRIO_MASK | VLAN_VID_MASK)) ++#define RX_DMA_VPID(x) (((x) >> 16) & 0xffff) + + /* QDMA descriptor rxd4 */ + #define MTK_RXD4_FOE_ENTRY GENMASK(13, 0) +@@ -246,10 +305,15 @@ + /* QDMA descriptor rxd4 */ + #define RX_DMA_L4_VALID BIT(24) + #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ +-#define RX_DMA_FPORT_SHIFT 19 +-#define RX_DMA_FPORT_MASK 0x7 + #define RX_DMA_SPECIAL_TAG BIT(22) + ++#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) ++#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) ++ ++/* PDMA V2 descriptor rxd3 */ ++#define RX_DMA_VTAG_V2 BIT(0) ++#define RX_DMA_L4_VALID_V2 BIT(2) ++ + /* PHY Indirect Access Control registers */ + #define MTK_PHY_IAC 0x10004 + #define PHY_IAC_ACCESS BIT(31) +@@ -371,6 +435,16 @@ + #define ETHSYS_TRGMII_MT7621_DDR_PLL BIT(5) + + /* ethernet reset control register */ ++#define ETHSYS_RSTCTRL 0x34 ++#define RSTCTRL_FE BIT(6) ++#define RSTCTRL_PPE BIT(31) ++#define RSTCTRL_PPE1 BIT(30) ++#define RSTCTRL_ETH BIT(23) ++ ++/* ethernet reset check idle register */ ++#define ETHSYS_FE_RST_CHK_IDLE_EN 0x28 ++ ++/* ethernet reset control register */ + #define ETHSYS_RSTCTRL 0x34 + #define RSTCTRL_FE BIT(6) + #define RSTCTRL_PPE BIT(31) +@@ -454,6 +528,17 @@ struct mtk_rx_dma { + unsigned int rxd4; + } __packed __aligned(4); + ++struct mtk_rx_dma_v2 { ++ unsigned int rxd1; ++ unsigned int rxd2; ++ unsigned int rxd3; ++ unsigned int rxd4; ++ unsigned int rxd5; ++ unsigned int rxd6; ++ unsigned int rxd7; ++ unsigned int rxd8; ++} __packed __aligned(4); ++ + struct mtk_tx_dma { + unsigned int txd1; + unsigned int txd2; +@@ -461,6 +546,17 @@ struct mtk_tx_dma { + unsigned int txd4; + } __packed __aligned(4); + ++struct mtk_tx_dma_v2 { ++ unsigned int txd1; ++ unsigned int txd2; ++ unsigned int txd3; ++ unsigned int txd4; ++ unsigned int txd5; ++ unsigned int txd6; ++ unsigned int txd7; ++ unsigned int txd8; ++} __packed __aligned(4); ++ + struct mtk_eth; + struct mtk_mac; + +@@ -647,7 +743,9 @@ enum mkt_eth_capabilities { + MTK_SHARED_INT_BIT, + MTK_TRGMII_MT7621_CLK_BIT, + MTK_QDMA_BIT, ++ MTK_NETSYS_V2_BIT, + MTK_SOC_MT7628_BIT, ++ MTK_RSTCTRL_PPE1_BIT, + + /* MUX BITS*/ + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, +@@ -679,7 +777,9 @@ enum mkt_eth_capabilities { + #define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT) + #define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) + #define MTK_QDMA BIT(MTK_QDMA_BIT) ++#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) + #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) ++#define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) + + #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ + BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) +@@ -756,6 +856,7 @@ struct mtk_tx_dma_desc_info { + dma_addr_t addr; + u32 size; + u16 vlan_tci; ++ u16 qid; + u8 gso:1; + u8 csum:1; + u8 vlan:1; +@@ -813,6 +914,10 @@ struct mtk_reg_map { + * the extra setup for those pins used by GMAC. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. ++ * @rx_irq_done_mask Rx irq done register mask. ++ * @rx_dma_l4_valid Rx DMA valid register mask. ++ * @dma_max_len Max DMA tx/rx buffer length. ++ * @dma_len_offset Tx/Rx DMA length field offset. + */ + struct mtk_soc_data { + const struct mtk_reg_map *reg_map; +@@ -825,6 +930,10 @@ struct mtk_soc_data { + struct { + u32 txd_size; + u32 rxd_size; ++ u32 rx_irq_done_mask; ++ u32 rx_dma_l4_valid; ++ u32 dma_max_len; ++ u32 dma_len_offset; + } txrx; + }; + +@@ -943,7 +1052,6 @@ struct mtk_eth { + u32 tx_bytes; + struct dim tx_dim; + +- u32 rx_dma_l4_valid; + int ip_align; + + struct mtk_ppe *ppe; diff --git a/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch b/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch new file mode 100644 index 00000000000..1ecb5e71b3a --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch @@ -0,0 +1,135 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:37 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: convert ring dma pointer to void + +Simplify the code converting {tx,rx} ring dma pointer to void + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -947,18 +947,15 @@ static int mtk_init_fq_dma(struct mtk_et + return 0; + } + +-static inline void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) ++static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) + { +- void *ret = ring->dma; +- +- return ret + (desc - ring->phys); ++ return ring->dma + (desc - ring->phys); + } + + static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, +- struct mtk_tx_dma *txd, +- u32 txd_size) ++ void *txd, u32 txd_size) + { +- int idx = ((void *)txd - (void *)ring->dma) / txd_size; ++ int idx = (txd - ring->dma) / txd_size; + + return &ring->buf[idx]; + } +@@ -966,13 +963,12 @@ static struct mtk_tx_buf *mtk_desc_to_tx + static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, + struct mtk_tx_dma *dma) + { +- return ring->dma_pdma - ring->dma + dma; ++ return ring->dma_pdma - (struct mtk_tx_dma *)ring->dma + dma; + } + +-static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma, +- u32 txd_size) ++static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size) + { +- return ((void *)dma - (void *)ring->dma) / txd_size; ++ return (dma - ring->dma) / txd_size; + } + + static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, +@@ -1389,7 +1385,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri + + ring = ð->rx_ring[i]; + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; ++ rxd = ring->dma + idx * eth->soc->txrx.rxd_size; + if (rxd->rxd2 & RX_DMA_DONE) { + ring->calc_idx_update = true; + return ring; +@@ -1441,7 +1437,7 @@ static int mtk_poll_rx(struct napi_struc + goto rx_done; + + idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); +- rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; ++ rxd = ring->dma + idx * eth->soc->txrx.rxd_size; + data = ring->data[idx]; + + if (!mtk_rx_get_desc(eth, &trxd, rxd)) +@@ -1648,7 +1644,7 @@ static int mtk_poll_tx_pdma(struct mtk_e + + mtk_tx_unmap(eth, tx_buf, true); + +- desc = (void *)ring->dma + cpu * eth->soc->txrx.txd_size; ++ desc = ring->dma + cpu * eth->soc->txrx.txd_size; + ring->last_free = desc; + atomic_inc(&ring->free_count); + +@@ -1793,7 +1789,7 @@ static int mtk_tx_alloc(struct mtk_eth * + int next = (i + 1) % MTK_DMA_SIZE; + u32 next_ptr = ring->phys + next * sz; + +- txd = (void *)ring->dma + i * sz; ++ txd = ring->dma + i * sz; + txd->txd2 = next_ptr; + txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; + txd->txd4 = 0; +@@ -1823,7 +1819,7 @@ static int mtk_tx_alloc(struct mtk_eth * + + ring->dma_size = MTK_DMA_SIZE; + atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); +- ring->next_free = &ring->dma[0]; ++ ring->next_free = ring->dma; + ring->last_free = (void *)txd; + ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); + ring->thresh = MAX_SKB_FRAGS; +@@ -1938,7 +1934,7 @@ static int mtk_rx_alloc(struct mtk_eth * + if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) + return -ENOMEM; + +- rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; ++ rxd = ring->dma + i * eth->soc->txrx.rxd_size; + rxd->rxd1 = (unsigned int)dma_addr; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) +@@ -2000,7 +1996,7 @@ static void mtk_rx_clean(struct mtk_eth + if (!ring->data[i]) + continue; + +- rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; ++ rxd = ring->dma + i * eth->soc->txrx.rxd_size; + if (!rxd->rxd1) + continue; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -689,7 +689,7 @@ struct mtk_tx_buf { + * are present + */ + struct mtk_tx_ring { +- struct mtk_tx_dma *dma; ++ void *dma; + struct mtk_tx_buf *buf; + dma_addr_t phys; + struct mtk_tx_dma *next_free; +@@ -719,7 +719,7 @@ enum mtk_rx_flags { + * @calc_idx: The current head of ring + */ + struct mtk_rx_ring { +- struct mtk_rx_dma *dma; ++ void *dma; + u8 **data; + dma_addr_t phys; + u16 frag_size; diff --git a/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch b/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch new file mode 100644 index 00000000000..f7318e68bbd --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch @@ -0,0 +1,33 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:38 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: convert scratch_ring pointer to + void + +Simplify the code converting scratch_ring pointer to void + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -923,7 +923,7 @@ static int mtk_init_fq_dma(struct mtk_et + for (i = 0; i < cnt; i++) { + struct mtk_tx_dma_v2 *txd; + +- txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; ++ txd = eth->scratch_ring + i * soc->txrx.txd_size; + txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; + if (i < cnt - 1) + txd->txd2 = eth->phy_scratch_ring + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1029,7 +1029,7 @@ struct mtk_eth { + struct mtk_rx_ring rx_ring_qdma; + struct napi_struct tx_napi; + struct napi_struct rx_napi; +- struct mtk_tx_dma *scratch_ring; ++ void *scratch_ring; + dma_addr_t phy_scratch_ring; + void *scratch_head; + struct clk *clks[MTK_CLK_MAX]; diff --git a/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch b/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch new file mode 100644 index 00000000000..a4698d7814d --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch @@ -0,0 +1,138 @@ +From: Lorenzo Bianconi +Date: Fri, 20 May 2022 20:11:39 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce support for mt7986 + chipset + +Add support for mt7986-eth driver available on mt7986 soc. + +Tested-by: Sam Shih +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -87,6 +87,43 @@ static const struct mtk_reg_map mt7628_r + }, + }; + ++static const struct mtk_reg_map mt7986_reg_map = { ++ .tx_irq_mask = 0x461c, ++ .tx_irq_status = 0x4618, ++ .pdma = { ++ .rx_ptr = 0x6100, ++ .rx_cnt_cfg = 0x6104, ++ .pcrx_ptr = 0x6108, ++ .glo_cfg = 0x6204, ++ .rst_idx = 0x6208, ++ .delay_irq = 0x620c, ++ .irq_status = 0x6220, ++ .irq_mask = 0x6228, ++ .int_grp = 0x6250, ++ }, ++ .qdma = { ++ .qtx_cfg = 0x4400, ++ .rx_ptr = 0x4500, ++ .rx_cnt_cfg = 0x4504, ++ .qcrx_ptr = 0x4508, ++ .glo_cfg = 0x4604, ++ .rst_idx = 0x4608, ++ .delay_irq = 0x460c, ++ .fc_th = 0x4610, ++ .int_grp = 0x4620, ++ .hred = 0x4644, ++ .ctx_ptr = 0x4700, ++ .dtx_ptr = 0x4704, ++ .crx_ptr = 0x4710, ++ .drx_ptr = 0x4714, ++ .fq_head = 0x4720, ++ .fq_tail = 0x4724, ++ .fq_count = 0x4728, ++ .fq_blen = 0x472c, ++ }, ++ .gdm1_cnt = 0x1c00, ++}; ++ + /* strings used by ethtool */ + static const struct mtk_ethtool_stats { + char str[ETH_GSTRING_LEN]; +@@ -110,7 +147,7 @@ static const char * const mtk_clks_sourc + "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", + "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", +- "sgmii_ck", "eth2pll", ++ "sgmii_ck", "eth2pll", "wocpu0", "wocpu1", "netsys0", "netsys1" + }; + + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) +@@ -3712,6 +3749,21 @@ static const struct mtk_soc_data mt7629_ + }, + }; + ++static const struct mtk_soc_data mt7986_data = { ++ .reg_map = &mt7986_reg_map, ++ .ana_rgc3 = 0x128, ++ .caps = MT7986_CAPS, ++ .required_clks = MT7986_CLKS_BITMAP, ++ .required_pctl = false, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++ .rx_irq_done_mask = MTK_RX_DONE_INT_V2, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ }, ++}; ++ + static const struct mtk_soc_data rt5350_data = { + .reg_map = &mt7628_reg_map, + .caps = MT7628_CAPS, +@@ -3734,6 +3786,7 @@ const struct of_device_id of_mtk_match[] + { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, + { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, + { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, ++ { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, + { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, + {}, + }; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -624,6 +624,10 @@ enum mtk_clks_map { + MTK_CLK_SGMII2_CDR_FB, + MTK_CLK_SGMII_CK, + MTK_CLK_ETH2PLL, ++ MTK_CLK_WOCPU0, ++ MTK_CLK_WOCPU1, ++ MTK_CLK_NETSYS0, ++ MTK_CLK_NETSYS1, + MTK_CLK_MAX + }; + +@@ -654,6 +658,16 @@ enum mtk_clks_map { + BIT(MTK_CLK_SGMII2_CDR_FB) | \ + BIT(MTK_CLK_SGMII_CK) | \ + BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) ++#define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ ++ BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ ++ BIT(MTK_CLK_SGMII_TX_250M) | \ ++ BIT(MTK_CLK_SGMII_RX_250M) | \ ++ BIT(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII2_CDR_FB)) + + enum mtk_dev_state { + MTK_HW_INIT, +@@ -852,6 +866,10 @@ enum mkt_eth_capabilities { + MTK_MUX_U3_GMAC2_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) + ++#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ ++ MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) ++ + struct mtk_tx_dma_desc_info { + dma_addr_t addr; + u32 size; diff --git a/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch b/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch new file mode 100644 index 00000000000..e490333a9bb --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch @@ -0,0 +1,25 @@ +From: Dan Carpenter +Date: Thu, 19 May 2022 17:08:00 +0300 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix error code in + mtk_flow_offload_replace() + +Preserve the error code from mtk_foe_entry_commit(). Do not return +success. + +Fixes: c4f033d9e03e ("net: ethernet: mtk_eth_soc: rework hardware flow table management") +Signed-off-by: Dan Carpenter +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -434,7 +434,8 @@ mtk_flow_offload_replace(struct mtk_eth + memcpy(&entry->data, &foe, sizeof(entry->data)); + entry->wed_index = wed_index; + +- if (mtk_foe_entry_commit(eth->ppe, entry) < 0) ++ err = mtk_foe_entry_commit(eth->ppe, entry); ++ if (err < 0) + goto free; + + err = rhashtable_insert_fast(ð->flow_table, &entry->node, diff --git a/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch b/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch new file mode 100644 index 00000000000..d76df75dda8 --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch @@ -0,0 +1,47 @@ +From: Lorenzo Bianconi +Date: Mon, 6 Jun 2022 21:49:00 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: enable rx cksum offload for + MTK_NETSYS_V2 + +Enable rx checksum offload for mt7986 chipset. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/c8699805c18f7fd38315fcb8da2787676d83a32c.1654544585.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1463,8 +1463,8 @@ static int mtk_poll_rx(struct napi_struc + int done = 0, bytes = 0; + + while (done < budget) { ++ unsigned int pktlen, *rxdcsum; + struct net_device *netdev; +- unsigned int pktlen; + dma_addr_t dma_addr; + u32 hash, reason; + int mac = 0; +@@ -1531,7 +1531,13 @@ static int mtk_poll_rx(struct napi_struc + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; + skb_put(skb, pktlen); +- if (trxd.rxd4 & eth->soc->txrx.rx_dma_l4_valid) ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ rxdcsum = &trxd.rxd3; ++ else ++ rxdcsum = &trxd.rxd4; ++ ++ if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb_checksum_none_assert(skb); +@@ -3759,6 +3765,7 @@ static const struct mtk_soc_data mt7986_ + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), + .rx_irq_done_mask = MTK_RX_DONE_INT_V2, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2, + .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, + .dma_len_offset = 8, + }, diff --git a/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch b/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch new file mode 100644 index 00000000000..5303ca48a7e --- /dev/null +++ b/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch @@ -0,0 +1,28 @@ +From: Jakub Kicinski +Date: Thu, 19 May 2022 18:25:55 -0700 +Subject: [PATCH] eth: mtk_ppe: fix up after merge + +I missed this in the barrage of GCC 12 warnings. Commit cf2df74e202d +("net: fix dev_fill_forward_path with pppoe + bridge") changed +the pointer into an array. + +Fixes: d7e6f5836038 ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net") +Link: https://lore.kernel.org/r/20220520012555.2262461-1-kuba@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -90,10 +90,11 @@ mtk_flow_get_wdma_info(struct net_device + { + struct net_device_path_ctx ctx = { + .dev = dev, +- .daddr = addr, + }; + struct net_device_path path = {}; + ++ memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); ++ + if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) + return -1; + diff --git a/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch b/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch new file mode 100644 index 00000000000..919da4d1ef1 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch @@ -0,0 +1,948 @@ +From 4973056cceacc70966396039fae99867dfafd796 Mon Sep 17 00:00:00 2001 +From: Sean Anderson +Date: Fri, 22 Oct 2021 18:41:04 -0400 +Subject: [PATCH] net: convert users of bitmap_foo() to linkmode_foo() + +This converts instances of + bitmap_foo(args..., __ETHTOOL_LINK_MODE_MASK_NBITS) +to + linkmode_foo(args...) + +I manually fixed up some lines to prevent them from being excessively +long. Otherwise, this change was generated with the following semantic +patch: + +// Generated with +// echo linux/linkmode.h > includes +// git grep -Flf includes include/ | cut -f 2- -d / | cat includes - \ +// | sort | uniq | tee new_includes | wc -l && mv new_includes includes +// and repeating until the number stopped going up +@i@ +@@ + +( + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +| + #include +) + +@depends on i@ +expression list args; +@@ + +( +- bitmap_zero(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_zero(args) +| +- bitmap_copy(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_copy(args) +| +- bitmap_and(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_and(args) +| +- bitmap_or(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_or(args) +| +- bitmap_empty(args, ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_empty(args) +| +- bitmap_andnot(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_andnot(args) +| +- bitmap_equal(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_equal(args) +| +- bitmap_intersects(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_intersects(args) +| +- bitmap_subset(args, __ETHTOOL_LINK_MODE_MASK_NBITS) ++ linkmode_subset(args) +) + +Add missing linux/mii.h include to mellanox. -DaveM + +Signed-off-by: Sean Anderson +Signed-off-by: David S. Miller +--- + drivers/net/dsa/b53/b53_common.c | 6 ++---- + drivers/net/dsa/bcm_sf2.c | 8 +++---- + drivers/net/dsa/hirschmann/hellcreek.c | 6 ++---- + drivers/net/dsa/lantiq_gswip.c | 14 ++++++------- + drivers/net/dsa/microchip/ksz8795.c | 8 +++---- + drivers/net/dsa/mv88e6xxx/chip.c | 5 ++--- + drivers/net/dsa/ocelot/felix_vsc9959.c | 8 +++---- + drivers/net/dsa/ocelot/seville_vsc9953.c | 8 +++---- + drivers/net/dsa/qca/ar9331.c | 10 ++++----- + drivers/net/dsa/sja1105/sja1105_main.c | 7 +++---- + drivers/net/dsa/xrs700x/xrs700x.c | 8 +++---- + drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 8 +++---- + drivers/net/ethernet/atheros/ag71xx.c | 8 +++---- + drivers/net/ethernet/cadence/macb_main.c | 11 +++++----- + .../net/ethernet/freescale/enetc/enetc_pf.c | 8 +++---- + .../net/ethernet/huawei/hinic/hinic_ethtool.c | 10 ++++----- + .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 5 ++--- + drivers/net/ethernet/marvell/mvneta.c | 10 ++++----- + .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 +++---- + .../marvell/octeontx2/nic/otx2_ethtool.c | 5 ++--- + drivers/net/ethernet/marvell/pxa168_eth.c | 3 +-- + .../net/ethernet/mellanox/mlx4/en_ethtool.c | 21 +++++++------------ + .../microchip/sparx5/sparx5_phylink.c | 7 +++---- + drivers/net/ethernet/mscc/ocelot_net.c | 7 +++---- + .../ethernet/pensando/ionic/ionic_ethtool.c | 3 +-- + .../net/ethernet/xilinx/xilinx_axienet_main.c | 8 +++---- + drivers/net/pcs/pcs-xpcs.c | 2 +- + drivers/net/phy/sfp-bus.c | 2 +- + net/ethtool/ioctl.c | 7 +++---- + 29 files changed, 87 insertions(+), 133 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1349,10 +1349,8 @@ void b53_phylink_validate(struct dsa_swi + phylink_set(mask, 100baseT_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + phylink_helper_basex_speed(state); + } +--- a/drivers/net/dsa/bcm_sf2.c ++++ b/drivers/net/dsa/bcm_sf2.c +@@ -686,7 +686,7 @@ static void bcm_sf2_sw_validate(struct d + state->interface != PHY_INTERFACE_MODE_GMII && + state->interface != PHY_INTERFACE_MODE_INTERNAL && + state->interface != PHY_INTERFACE_MODE_MOCA) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + if (port != core_readl(priv, CORE_IMP0_PRT_ID)) + dev_err(ds->dev, + "Unsupported interface: %d for port %d\n", +@@ -714,10 +714,8 @@ static void bcm_sf2_sw_validate(struct d + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, +--- a/drivers/net/dsa/hirschmann/hellcreek.c ++++ b/drivers/net/dsa/hirschmann/hellcreek.c +@@ -1476,10 +1476,8 @@ static void hellcreek_phylink_validate(s + else + phylink_set(mask, 1000baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static int +--- a/drivers/net/dsa/lantiq_gswip.c ++++ b/drivers/net/dsa/lantiq_gswip.c +@@ -1452,10 +1452,8 @@ static void gswip_phylink_set_capab(unsi + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void gswip_xrx200_phylink_validate(struct dsa_switch *ds, int port, +@@ -1483,7 +1481,7 @@ static void gswip_xrx200_phylink_validat + goto unsupported; + break; + default: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported port: %i\n", port); + return; + } +@@ -1493,7 +1491,7 @@ static void gswip_xrx200_phylink_validat + return; + + unsupported: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(state->interface), port); + } +@@ -1523,7 +1521,7 @@ static void gswip_xrx300_phylink_validat + goto unsupported; + break; + default: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported port: %i\n", port); + return; + } +@@ -1533,7 +1531,7 @@ static void gswip_xrx300_phylink_validat + return; + + unsupported: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(state->interface), port); + } +--- a/drivers/net/dsa/microchip/ksz8795.c ++++ b/drivers/net/dsa/microchip/ksz8795.c +@@ -1542,15 +1542,13 @@ static void ksz8_validate(struct dsa_swi + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + return; + + unsupported: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported interface: %s, port: %d\n", + phy_modes(state->interface), port); + } +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -683,9 +683,8 @@ static void mv88e6xxx_validate(struct ds + if (chip->info->ops->phylink_validate) + chip->info->ops->phylink_validate(chip, port, mask, state); + +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + /* We can only operate at 2500BaseX or 1000BaseX. If requested + * to advertise both, only report advertising at 2500BaseX. +--- a/drivers/net/dsa/ocelot/felix_vsc9959.c ++++ b/drivers/net/dsa/ocelot/felix_vsc9959.c +@@ -944,7 +944,7 @@ static void vsc9959_phylink_validate(str + + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != ocelot_port->phy_mode) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -966,10 +966,8 @@ static void vsc9959_phylink_validate(str + phylink_set(mask, 2500baseX_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port, +--- a/drivers/net/dsa/ocelot/seville_vsc9953.c ++++ b/drivers/net/dsa/ocelot/seville_vsc9953.c +@@ -1000,7 +1000,7 @@ static void vsc9953_phylink_validate(str + + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != ocelot_port->phy_mode) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -1019,10 +1019,8 @@ static void vsc9953_phylink_validate(str + phylink_set(mask, 2500baseX_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static int vsc9953_prevalidate_phy_mode(struct ocelot *ocelot, int port, +--- a/drivers/net/dsa/qca/ar9331.c ++++ b/drivers/net/dsa/qca/ar9331.c +@@ -522,7 +522,7 @@ static void ar9331_sw_phylink_validate(s + goto unsupported; + break; + default: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported port: %i\n", port); + return; + } +@@ -536,15 +536,13 @@ static void ar9331_sw_phylink_validate(s + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + return; + + unsupported: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported interface: %d, port: %d\n", + state->interface, port); + } +--- a/drivers/net/dsa/sja1105/sja1105_main.c ++++ b/drivers/net/dsa/sja1105/sja1105_main.c +@@ -1360,7 +1360,7 @@ static void sja1105_phylink_validate(str + */ + if (state->interface != PHY_INTERFACE_MODE_NA && + sja1105_phy_mode_mismatch(priv, port, state->interface)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -1380,9 +1380,8 @@ static void sja1105_phylink_validate(str + phylink_set(mask, 2500baseX_Full); + } + +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static int +--- a/drivers/net/dsa/xrs700x/xrs700x.c ++++ b/drivers/net/dsa/xrs700x/xrs700x.c +@@ -457,7 +457,7 @@ static void xrs700x_phylink_validate(str + phylink_set(mask, 1000baseT_Full); + break; + default: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + dev_err(ds->dev, "Unsupported port: %i\n", port); + return; + } +@@ -468,10 +468,8 @@ static void xrs700x_phylink_validate(str + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Full); + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void xrs700x_mac_link_up(struct dsa_switch *ds, int port, +--- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c +@@ -369,9 +369,8 @@ static int xgbe_set_link_ksettings(struc + __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising, + __ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported); + +- bitmap_and(advertising, +- cmd->link_modes.advertising, lks->link_modes.supported, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(advertising, cmd->link_modes.advertising, ++ lks->link_modes.supported); + + if ((cmd->base.autoneg == AUTONEG_ENABLE) && + bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) { +@@ -384,8 +383,7 @@ static int xgbe_set_link_ksettings(struc + pdata->phy.autoneg = cmd->base.autoneg; + pdata->phy.speed = speed; + pdata->phy.duplex = cmd->base.duplex; +- bitmap_copy(lks->link_modes.advertising, advertising, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_copy(lks->link_modes.advertising, advertising); + + if (cmd->base.autoneg == AUTONEG_ENABLE) + XGBE_SET_ADV(lks, Autoneg); +--- a/drivers/net/ethernet/atheros/ag71xx.c ++++ b/drivers/net/ethernet/atheros/ag71xx.c +@@ -1082,14 +1082,12 @@ static void ag71xx_mac_validate(struct p + phylink_set(mask, 1000baseX_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + return; + unsupported: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + } + + static void ag71xx_mac_pcs_get_state(struct phylink_config *config, +--- a/drivers/net/ethernet/cadence/macb_main.c ++++ b/drivers/net/ethernet/cadence/macb_main.c +@@ -523,21 +523,21 @@ static void macb_validate(struct phylink + state->interface != PHY_INTERFACE_MODE_SGMII && + state->interface != PHY_INTERFACE_MODE_10GBASER && + !phy_interface_mode_is_rgmii(state->interface)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + + if (!macb_is_gem(bp) && + (state->interface == PHY_INTERFACE_MODE_GMII || + phy_interface_mode_is_rgmii(state->interface))) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + + if (state->interface == PHY_INTERFACE_MODE_10GBASER && + !(bp->caps & MACB_CAPS_HIGH_SPEED && + bp->caps & MACB_CAPS_PCS)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -576,9 +576,8 @@ static void macb_validate(struct phylink + phylink_set(mask, 1000baseT_Half); + } + out: +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c +@@ -965,7 +965,7 @@ static void enetc_pl_mac_validate(struct + state->interface != PHY_INTERFACE_MODE_2500BASEX && + state->interface != PHY_INTERFACE_MODE_USXGMII && + !phy_interface_mode_is_rgmii(state->interface)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -988,10 +988,8 @@ static void enetc_pl_mac_validate(struct + phylink_set(mask, 2500baseX_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void enetc_pl_mac_config(struct phylink_config *config, +--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c ++++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c +@@ -322,12 +322,10 @@ static int hinic_get_link_ksettings(stru + } + } + +- bitmap_copy(link_ksettings->link_modes.supported, +- (unsigned long *)&settings.supported, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_copy(link_ksettings->link_modes.advertising, +- (unsigned long *)&settings.advertising, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_copy(link_ksettings->link_modes.supported, ++ (unsigned long *)&settings.supported); ++ linkmode_copy(link_ksettings->link_modes.advertising, ++ (unsigned long *)&settings.advertising); + + return 0; + } +--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c ++++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +@@ -467,9 +467,8 @@ static int ixgbe_set_link_ksettings(stru + * this function does not support duplex forcing, but can + * limit the advertising of the adapter to the specified speed + */ +- if (!bitmap_subset(cmd->link_modes.advertising, +- cmd->link_modes.supported, +- __ETHTOOL_LINK_MODE_MASK_NBITS)) ++ if (!linkmode_subset(cmd->link_modes.advertising, ++ cmd->link_modes.supported)) + return -EINVAL; + + /* only allow one speed at a time if no autoneg */ +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -3835,14 +3835,14 @@ static void mvneta_validate(struct phyli + */ + if (phy_interface_mode_is_8023z(state->interface)) { + if (!phylink_test(state->advertising, Autoneg)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + } else if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != PHY_INTERFACE_MODE_QSGMII && + state->interface != PHY_INTERFACE_MODE_SGMII && + !phy_interface_mode_is_rgmii(state->interface)) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -3871,10 +3871,8 @@ static void mvneta_validate(struct phyli + phylink_set(mask, 100baseT_Full); + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + /* We can only operate at 2500BaseX or 1000BaseX. If requested + * to advertise both, only report advertising at 2500BaseX. +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +@@ -6347,15 +6347,14 @@ static void mvpp2_phylink_validate(struc + goto empty_set; + } + +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + + phylink_helper_basex_speed(state); + return; + + empty_set: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + } + + static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode, +--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c ++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +@@ -1168,9 +1168,8 @@ static int otx2_set_link_ksettings(struc + otx2_get_link_ksettings(netdev, &cur_ks); + + /* Check requested modes against supported modes by hardware */ +- if (!bitmap_subset(cmd->link_modes.advertising, +- cur_ks.link_modes.supported, +- __ETHTOOL_LINK_MODE_MASK_NBITS)) ++ if (!linkmode_subset(cmd->link_modes.advertising, ++ cur_ks.link_modes.supported)) + return -EINVAL; + + mutex_lock(&mbox->lock); +--- a/drivers/net/ethernet/marvell/pxa168_eth.c ++++ b/drivers/net/ethernet/marvell/pxa168_eth.c +@@ -977,8 +977,7 @@ static int pxa168_init_phy(struct net_de + cmd.base.phy_address = pep->phy_addr; + cmd.base.speed = pep->phy_speed; + cmd.base.duplex = pep->phy_duplex; +- bitmap_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES); + cmd.base.autoneg = AUTONEG_ENABLE; + + if (cmd.base.speed != 0) +--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + + #include "mlx4_en.h" + #include "en_port.h" +@@ -643,10 +644,8 @@ static unsigned long *ptys2ethtool_link_ + unsigned int i; \ + cfg = &ptys2ethtool_map[reg_]; \ + cfg->speed = speed_; \ +- bitmap_zero(cfg->supported, \ +- __ETHTOOL_LINK_MODE_MASK_NBITS); \ +- bitmap_zero(cfg->advertised, \ +- __ETHTOOL_LINK_MODE_MASK_NBITS); \ ++ linkmode_zero(cfg->supported); \ ++ linkmode_zero(cfg->advertised); \ + for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \ + __set_bit(modes[i], cfg->supported); \ + __set_bit(modes[i], cfg->advertised); \ +@@ -702,10 +701,8 @@ static void ptys2ethtool_update_link_mod + int i; + for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { + if (eth_proto & MLX4_PROT_MASK(i)) +- bitmap_or(link_modes, link_modes, +- ptys2ethtool_link_mode(&ptys2ethtool_map[i], +- report), +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_or(link_modes, link_modes, ++ ptys2ethtool_link_mode(&ptys2ethtool_map[i], report)); + } + } + +@@ -716,11 +713,9 @@ static u32 ethtool2ptys_link_modes(const + u32 ptys_modes = 0; + + for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { +- if (bitmap_intersects( +- ptys2ethtool_link_mode(&ptys2ethtool_map[i], +- report), +- link_modes, +- __ETHTOOL_LINK_MODE_MASK_NBITS)) ++ ulong *map_mode = ptys2ethtool_link_mode(&ptys2ethtool_map[i], ++ report); ++ if (linkmode_intersects(map_mode, link_modes)) + ptys_modes |= 1 << i; + } + return ptys_modes; +--- a/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c ++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c +@@ -92,12 +92,11 @@ static void sparx5_phylink_validate(stru + } + break; + default: +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void sparx5_phylink_mac_config(struct phylink_config *config, +--- a/drivers/net/ethernet/mscc/ocelot_net.c ++++ b/drivers/net/ethernet/mscc/ocelot_net.c +@@ -1509,7 +1509,7 @@ static void vsc7514_phylink_validate(str + + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != ocelot_port->phy_mode) { +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + +@@ -1528,9 +1528,8 @@ static void vsc7514_phylink_validate(str + phylink_set(mask, 2500baseT_Full); + phylink_set(mask, 2500baseX_Full); + +- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void vsc7514_phylink_mac_config(struct phylink_config *config, +--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c ++++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +@@ -228,8 +228,7 @@ static int ionic_get_link_ksettings(stru + break; + } + +- bitmap_copy(ks->link_modes.advertising, ks->link_modes.supported, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_copy(ks->link_modes.advertising, ks->link_modes.supported); + + ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); + ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); +--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c ++++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +@@ -1565,7 +1565,7 @@ static void axienet_validate(struct phyl + netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n", + phy_modes(state->interface), + phy_modes(lp->phy_mode)); +- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(supported); + return; + } + } +@@ -1598,10 +1598,8 @@ static void axienet_validate(struct phyl + break; + } + +- bitmap_and(supported, supported, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); +- bitmap_and(state->advertising, state->advertising, mask, +- __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); + } + + static void axienet_mac_pcs_get_state(struct phylink_config *config, +--- a/drivers/net/pcs/pcs-xpcs.c ++++ b/drivers/net/pcs/pcs-xpcs.c +@@ -637,7 +637,7 @@ void xpcs_validate(struct dw_xpcs *xpcs, + if (state->interface == PHY_INTERFACE_MODE_NA) + return; + +- bitmap_zero(xpcs_supported, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(xpcs_supported); + + compat = xpcs_find_compat(xpcs->id, state->interface); + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -379,7 +379,7 @@ void sfp_parse_support(struct sfp_bus *b + if (bus->sfp_quirk) + bus->sfp_quirk->modes(id, modes); + +- bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_or(support, support, modes); + + phylink_set(support, Autoneg); + phylink_set(support, Pause); +--- a/net/ethtool/ioctl.c ++++ b/net/ethtool/ioctl.c +@@ -335,7 +335,7 @@ EXPORT_SYMBOL(ethtool_intersect_link_mas + void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, + u32 legacy_u32) + { +- bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(dst); + dst[0] = legacy_u32; + } + EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode); +@@ -350,11 +350,10 @@ bool ethtool_convert_link_mode_to_legacy + if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(ext); + +- bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS); ++ linkmode_zero(ext); + bitmap_fill(ext, 32); + bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS); +- if (bitmap_intersects(ext, src, +- __ETHTOOL_LINK_MODE_MASK_NBITS)) { ++ if (linkmode_intersects(ext, src)) { + /* src mask goes beyond bit 31 */ + retval = false; + } diff --git a/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch b/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch new file mode 100644 index 00000000000..885c2fcf252 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch @@ -0,0 +1,24 @@ +From 38c310eb46f5f80213a92093af11af270c209a76 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 26 Oct 2021 11:06:06 +0100 +Subject: [PATCH] net: phylink: add MAC phy_interface_t bitmap + +Add a phy_interface_t bitmap so the MAC driver can specifiy which PHY +interface modes it supports. + +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + include/linux/phylink.h | 1 + + 1 file changed, 1 insertion(+) + +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -78,6 +78,7 @@ struct phylink_config { + bool ovr_an_inband; + void (*get_fixed_state)(struct phylink_config *config, + struct phylink_link_state *state); ++ DECLARE_PHY_INTERFACE_MASK(supported_interfaces); + }; + + /** diff --git a/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch b/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch new file mode 100644 index 00000000000..9800884f6e9 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch @@ -0,0 +1,98 @@ +From d25f3a74f30aace819163dfa54f2a4b8ca1dc932 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 26 Oct 2021 11:06:11 +0100 +Subject: [PATCH] net: phylink: use supported_interfaces for phylink + validation + +If the network device supplies a supported interface bitmap, we can use +that during phylink's validation to simplify MAC drivers in two ways by +using the supported_interfaces bitmap to: + +1. reject unsupported interfaces before calling into the MAC driver. +2. generate the set of all supported link modes across all supported + interfaces (used mainly for SFP, but also some 10G PHYs.) + +Suggested-by: Sean Anderson +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 36 ++++++++++++++++++++++++++++++++++++ + include/linux/phylink.h | 12 ++++++++++-- + 2 files changed, 46 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -155,9 +155,45 @@ static const char *phylink_an_mode_str(u + return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; + } + ++static int phylink_validate_any(struct phylink *pl, unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, }; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(s); ++ struct phylink_link_state t; ++ int intf; ++ ++ for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { ++ if (test_bit(intf, pl->config->supported_interfaces)) { ++ linkmode_copy(s, supported); ++ ++ t = *state; ++ t.interface = intf; ++ pl->mac_ops->validate(pl->config, s, &t); ++ linkmode_or(all_s, all_s, s); ++ linkmode_or(all_adv, all_adv, t.advertising); ++ } ++ } ++ ++ linkmode_copy(supported, all_s); ++ linkmode_copy(state->advertising, all_adv); ++ ++ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ++} ++ + static int phylink_validate(struct phylink *pl, unsigned long *supported, + struct phylink_link_state *state) + { ++ if (!phy_interface_empty(pl->config->supported_interfaces)) { ++ if (state->interface == PHY_INTERFACE_MODE_NA) ++ return phylink_validate_any(pl, supported, state); ++ ++ if (!test_bit(state->interface, ++ pl->config->supported_interfaces)) ++ return -EINVAL; ++ } ++ + pl->mac_ops->validate(pl->config, supported, state); + + return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -68,6 +68,8 @@ enum phylink_op_type { + * @ovr_an_inband: if true, override PCS to MLO_AN_INBAND + * @get_fixed_state: callback to execute to determine the fixed link state, + * if MAC link is at %MLO_AN_FIXED mode. ++ * @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx ++ * are supported by the MAC/PCS. + */ + struct phylink_config { + struct device *dev; +@@ -136,8 +138,14 @@ struct phylink_mac_ops { + * based on @state->advertising and/or @state->speed and update + * @state->interface accordingly. See phylink_helper_basex_speed(). + * +- * When @state->interface is %PHY_INTERFACE_MODE_NA, phylink expects the +- * MAC driver to return all supported link modes. ++ * When @config->supported_interfaces has been set, phylink will iterate ++ * over the supported interfaces to determine the full capability of the ++ * MAC. The validation function must not print errors if @state->interface ++ * is set to an unexpected value. ++ * ++ * When @config->supported_interfaces is empty, phylink will call this ++ * function with @state->interface set to %PHY_INTERFACE_MODE_NA, and ++ * expects the MAC driver to return all supported link modes. + * + * If the @state->interface mode is not supported, then the @supported + * mask must be cleared. diff --git a/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch new file mode 100644 index 00000000000..b10e6da0e9a --- /dev/null +++ b/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch @@ -0,0 +1,63 @@ +From c07c6e8eb4b38bae921f9e2f108d1e7f8e14226e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Thu, 28 Oct 2021 18:00:14 +0100 +Subject: [PATCH] net: dsa: populate supported_interfaces member +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add a new DSA switch operation, phylink_get_interfaces, which should +fill in which PHY_INTERFACE_MODE_* are supported by given port. + +Use this before phylink_create() to fill phylinks supported_interfaces +member, allowing phylink to determine which PHY_INTERFACE_MODEs are +supported. + +Signed-off-by: Marek Behún +[tweaked patch and description to add more complete support -- rmk] +Signed-off-by: Russell King +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 2 ++ + net/dsa/port.c | 4 ++++ + net/dsa/slave.c | 4 ++++ + 3 files changed, 10 insertions(+) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -626,6 +626,8 @@ struct dsa_switch_ops { + /* + * PHYLINK integration + */ ++ void (*phylink_get_interfaces)(struct dsa_switch *ds, int port, ++ unsigned long *supported_interfaces); + void (*phylink_validate)(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state); +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1188,6 +1188,10 @@ static int dsa_port_phylink_register(str + dp->pl_config.type = PHYLINK_DEV; + dp->pl_config.pcs_poll = ds->pcs_poll; + ++ if (ds->ops->phylink_get_interfaces) ++ ds->ops->phylink_get_interfaces(ds, dp->index, ++ dp->pl_config.supported_interfaces); ++ + dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), + mode, &dsa_port_phylink_mac_ops); + if (IS_ERR(dp->pl)) { +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1837,6 +1837,10 @@ static int dsa_slave_phy_setup(struct ne + dp->pl_config.poll_fixed_state = true; + } + ++ if (ds->ops->phylink_get_interfaces) ++ ds->ops->phylink_get_interfaces(ds, dp->index, ++ dp->pl_config.supported_interfaces); ++ + dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, + &dsa_port_phylink_mac_ops); + if (IS_ERR(dp->pl)) { diff --git a/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch b/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch new file mode 100644 index 00000000000..9b67a8a5185 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch @@ -0,0 +1,149 @@ +From 21bd64bd717dedac96f53b668144cbe37d3c12d4 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 30 Nov 2021 13:09:55 +0000 +Subject: [PATCH] net: dsa: consolidate phylink creation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The code in port.c and slave.c creating the phylink instance is very +similar - let's consolidate this into a single function. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Marek Behún +Reviewed-by: Andrew Lunn +Signed-off-by: Jakub Kicinski +--- + net/dsa/dsa_priv.h | 2 +- + net/dsa/port.c | 44 ++++++++++++++++++++++++++++---------------- + net/dsa/slave.c | 19 +++---------------- + 3 files changed, 32 insertions(+), 33 deletions(-) + +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -261,13 +261,13 @@ int dsa_port_mrp_add_ring_role(const str + const struct switchdev_obj_ring_role_mrp *mrp); + int dsa_port_mrp_del_ring_role(const struct dsa_port *dp, + const struct switchdev_obj_ring_role_mrp *mrp); ++int dsa_port_phylink_create(struct dsa_port *dp); + int dsa_port_link_register_of(struct dsa_port *dp); + void dsa_port_link_unregister_of(struct dsa_port *dp); + int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr); + void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr); + int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast); + void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast); +-extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; + + static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp, + const struct net_device *dev) +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1092,7 +1092,7 @@ static void dsa_port_phylink_mac_link_up + speed, duplex, tx_pause, rx_pause); + } + +-const struct phylink_mac_ops dsa_port_phylink_mac_ops = { ++static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { + .validate = dsa_port_phylink_validate, + .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, + .mac_config = dsa_port_phylink_mac_config, +@@ -1101,6 +1101,30 @@ const struct phylink_mac_ops dsa_port_ph + .mac_link_up = dsa_port_phylink_mac_link_up, + }; + ++int dsa_port_phylink_create(struct dsa_port *dp) ++{ ++ struct dsa_switch *ds = dp->ds; ++ phy_interface_t mode; ++ int err; ++ ++ err = of_get_phy_mode(dp->dn, &mode); ++ if (err) ++ mode = PHY_INTERFACE_MODE_NA; ++ ++ if (ds->ops->phylink_get_interfaces) ++ ds->ops->phylink_get_interfaces(ds, dp->index, ++ dp->pl_config.supported_interfaces); ++ ++ dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), ++ mode, &dsa_port_phylink_mac_ops); ++ if (IS_ERR(dp->pl)) { ++ pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); ++ return PTR_ERR(dp->pl); ++ } ++ ++ return 0; ++} ++ + static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable) + { + struct dsa_switch *ds = dp->ds; +@@ -1177,27 +1201,15 @@ static int dsa_port_phylink_register(str + { + struct dsa_switch *ds = dp->ds; + struct device_node *port_dn = dp->dn; +- phy_interface_t mode; + int err; + +- err = of_get_phy_mode(port_dn, &mode); +- if (err) +- mode = PHY_INTERFACE_MODE_NA; +- + dp->pl_config.dev = ds->dev; + dp->pl_config.type = PHYLINK_DEV; + dp->pl_config.pcs_poll = ds->pcs_poll; + +- if (ds->ops->phylink_get_interfaces) +- ds->ops->phylink_get_interfaces(ds, dp->index, +- dp->pl_config.supported_interfaces); +- +- dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), +- mode, &dsa_port_phylink_mac_ops); +- if (IS_ERR(dp->pl)) { +- pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); +- return PTR_ERR(dp->pl); +- } ++ err = dsa_port_phylink_create(dp); ++ if (err) ++ return err; + + err = phylink_of_phy_connect(dp->pl, port_dn, 0); + if (err && err != -ENODEV) { +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1817,14 +1817,9 @@ static int dsa_slave_phy_setup(struct ne + struct dsa_port *dp = dsa_slave_to_port(slave_dev); + struct device_node *port_dn = dp->dn; + struct dsa_switch *ds = dp->ds; +- phy_interface_t mode; + u32 phy_flags = 0; + int ret; + +- ret = of_get_phy_mode(port_dn, &mode); +- if (ret) +- mode = PHY_INTERFACE_MODE_NA; +- + dp->pl_config.dev = &slave_dev->dev; + dp->pl_config.type = PHYLINK_NETDEV; + +@@ -1837,17 +1832,9 @@ static int dsa_slave_phy_setup(struct ne + dp->pl_config.poll_fixed_state = true; + } + +- if (ds->ops->phylink_get_interfaces) +- ds->ops->phylink_get_interfaces(ds, dp->index, +- dp->pl_config.supported_interfaces); +- +- dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, +- &dsa_port_phylink_mac_ops); +- if (IS_ERR(dp->pl)) { +- netdev_err(slave_dev, +- "error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); +- return PTR_ERR(dp->pl); +- } ++ ret = dsa_port_phylink_create(dp); ++ if (ret) ++ return ret; + + if (ds->ops->get_phy_flags) + phy_flags = ds->ops->get_phy_flags(ds, dp->index); diff --git a/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch b/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch new file mode 100644 index 00000000000..d70b9aa6a47 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch @@ -0,0 +1,51 @@ +From 072eea6c22b2af680c3949e64f9adde278c71e68 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 30 Nov 2021 13:10:01 +0000 +Subject: [PATCH] net: dsa: replace phylink_get_interfaces() with + phylink_get_caps() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Phylink needs slightly more information than phylink_get_interfaces() +allows us to get from the DSA drivers - we need the MAC capabilities. +Replace the phylink_get_interfaces() method with phylink_get_caps() to +allow DSA drivers to fill in the phylink_config MAC capabilities field +as well. + +Signed-off-by: Russell King (Oracle) +Reviewed-by: Marek Behún +Reviewed-by: Andrew Lunn +Signed-off-by: Jakub Kicinski +--- + include/net/dsa.h | 4 ++-- + net/dsa/port.c | 5 ++--- + 2 files changed, 4 insertions(+), 5 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -626,8 +626,8 @@ struct dsa_switch_ops { + /* + * PHYLINK integration + */ +- void (*phylink_get_interfaces)(struct dsa_switch *ds, int port, +- unsigned long *supported_interfaces); ++ void (*phylink_get_caps)(struct dsa_switch *ds, int port, ++ struct phylink_config *config); + void (*phylink_validate)(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state); +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1111,9 +1111,8 @@ int dsa_port_phylink_create(struct dsa_p + if (err) + mode = PHY_INTERFACE_MODE_NA; + +- if (ds->ops->phylink_get_interfaces) +- ds->ops->phylink_get_interfaces(ds, dp->index, +- dp->pl_config.supported_interfaces); ++ if (ds->ops->phylink_get_caps) ++ ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); + + dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), + mode, &dsa_port_phylink_mac_ops); diff --git a/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch b/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch new file mode 100644 index 00000000000..2af5cb9d9db --- /dev/null +++ b/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch @@ -0,0 +1,59 @@ +From bde018222c6b084ac32933a9f933581dd83da18e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 17 Feb 2022 18:30:35 +0000 +Subject: [PATCH] net: dsa: add support for phylink mac_select_pcs() + +Add DSA support for the phylink mac_select_pcs() method so DSA drivers +can return provide phylink with the appropriate PCS for the PHY +interface mode. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 3 +++ + net/dsa/port.c | 15 +++++++++++++++ + 2 files changed, 18 insertions(+) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -631,6 +631,9 @@ struct dsa_switch_ops { + void (*phylink_validate)(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state); ++ struct phylink_pcs *(*phylink_mac_select_pcs)(struct dsa_switch *ds, ++ int port, ++ phy_interface_t iface); + int (*phylink_mac_link_state)(struct dsa_switch *ds, int port, + struct phylink_link_state *state); + void (*phylink_mac_config)(struct dsa_switch *ds, int port, +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1028,6 +1028,20 @@ static void dsa_port_phylink_mac_pcs_get + } + } + ++static struct phylink_pcs * ++dsa_port_phylink_mac_select_pcs(struct phylink_config *config, ++ phy_interface_t interface) ++{ ++ struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); ++ struct dsa_switch *ds = dp->ds; ++ struct phylink_pcs *pcs = NULL; ++ ++ if (ds->ops->phylink_mac_select_pcs) ++ pcs = ds->ops->phylink_mac_select_pcs(ds, dp->index, interface); ++ ++ return pcs; ++} ++ + static void dsa_port_phylink_mac_config(struct phylink_config *config, + unsigned int mode, + const struct phylink_link_state *state) +@@ -1094,6 +1108,7 @@ static void dsa_port_phylink_mac_link_up + + static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { + .validate = dsa_port_phylink_validate, ++ .mac_select_pcs = dsa_port_phylink_mac_select_pcs, + .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, + .mac_config = dsa_port_phylink_mac_config, + .mac_an_restart = dsa_port_phylink_mac_an_restart, diff --git a/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch b/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch new file mode 100644 index 00000000000..1a7817b0f96 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch @@ -0,0 +1,61 @@ +From 8e20f591f204f8db7f1182918f8e2285d3f589e0 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 26 Oct 2021 11:06:01 +0100 +Subject: [PATCH] net: phy: add phy_interface_t bitmap support + +Add support for a bitmap for phy interface modes, which includes: +- a macro to declare the interface bitmap +- an inline helper to zero the interface bitmap +- an inline helper to detect an empty interface bitmap +- inline helpers to do a bitwise AND and OR operations on two interface + bitmaps + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + include/linux/phy.h | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -155,6 +155,40 @@ typedef enum { + PHY_INTERFACE_MODE_MAX, + } phy_interface_t; + ++/* PHY interface mode bitmap handling */ ++#define DECLARE_PHY_INTERFACE_MASK(name) \ ++ DECLARE_BITMAP(name, PHY_INTERFACE_MODE_MAX) ++ ++static inline void phy_interface_zero(unsigned long *intf) ++{ ++ bitmap_zero(intf, PHY_INTERFACE_MODE_MAX); ++} ++ ++static inline bool phy_interface_empty(const unsigned long *intf) ++{ ++ return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX); ++} ++ ++static inline void phy_interface_and(unsigned long *dst, const unsigned long *a, ++ const unsigned long *b) ++{ ++ bitmap_and(dst, a, b, PHY_INTERFACE_MODE_MAX); ++} ++ ++static inline void phy_interface_or(unsigned long *dst, const unsigned long *a, ++ const unsigned long *b) ++{ ++ bitmap_or(dst, a, b, PHY_INTERFACE_MODE_MAX); ++} ++ ++static inline void phy_interface_set_rgmii(unsigned long *intf) ++{ ++ __set_bit(PHY_INTERFACE_MODE_RGMII, intf); ++ __set_bit(PHY_INTERFACE_MODE_RGMII_ID, intf); ++ __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, intf); ++ __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, intf); ++} ++ + /* + * phy_supported_speeds - return all speeds currently supported by a PHY device + */ diff --git a/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch b/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch new file mode 100644 index 00000000000..d826877e7dc --- /dev/null +++ b/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch @@ -0,0 +1,197 @@ +From d1e86325af377129adb7fc6f34eb044ca6068b47 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 15 Dec 2021 15:34:15 +0000 +Subject: [PATCH] net: phylink: add mac_select_pcs() method to phylink_mac_ops + +mac_select_pcs() allows us to have an explicit point to query which +PCS the MAC wishes to use for a particular PHY interface mode, thereby +allowing us to add support to validate the link settings with the PCS. + +Phylink will also use this to select the PCS to be used during a major +configuration event without the MAC driver needing to call +phylink_set_pcs(). + +Note that if mac_select_pcs() is present, the supported_interfaces +bitmap must be filled in; this avoids mac_select_pcs() being called +with PHY_INTERFACE_MODE_NA when we want to get support for all +interface types. Phylink will return an error in phylink_create() +unless this condition is satisfied. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 68 +++++++++++++++++++++++++++++++++------ + include/linux/phylink.h | 18 +++++++++++ + 2 files changed, 77 insertions(+), 9 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -155,6 +155,23 @@ static const char *phylink_an_mode_str(u + return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; + } + ++static int phylink_validate_mac_and_pcs(struct phylink *pl, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ struct phylink_pcs *pcs; ++ ++ if (pl->mac_ops->mac_select_pcs) { ++ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); ++ if (IS_ERR(pcs)) ++ return PTR_ERR(pcs); ++ } ++ ++ pl->mac_ops->validate(pl->config, supported, state); ++ ++ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ++} ++ + static int phylink_validate_any(struct phylink *pl, unsigned long *supported, + struct phylink_link_state *state) + { +@@ -170,9 +187,10 @@ static int phylink_validate_any(struct p + + t = *state; + t.interface = intf; +- pl->mac_ops->validate(pl->config, s, &t); +- linkmode_or(all_s, all_s, s); +- linkmode_or(all_adv, all_adv, t.advertising); ++ if (!phylink_validate_mac_and_pcs(pl, s, &t)) { ++ linkmode_or(all_s, all_s, s); ++ linkmode_or(all_adv, all_adv, t.advertising); ++ } + } + } + +@@ -194,9 +212,7 @@ static int phylink_validate(struct phyli + return -EINVAL; + } + +- pl->mac_ops->validate(pl->config, supported, state); +- +- return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ++ return phylink_validate_mac_and_pcs(pl, supported, state); + } + + static int phylink_parse_fixedlink(struct phylink *pl, +@@ -486,10 +502,21 @@ static void phylink_mac_pcs_an_restart(s + static void phylink_major_config(struct phylink *pl, bool restart, + const struct phylink_link_state *state) + { ++ struct phylink_pcs *pcs = NULL; + int err; + + phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); + ++ if (pl->mac_ops->mac_select_pcs) { ++ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); ++ if (IS_ERR(pcs)) { ++ phylink_err(pl, ++ "mac_select_pcs unexpectedly failed: %pe\n", ++ pcs); ++ return; ++ } ++ } ++ + if (pl->mac_ops->mac_prepare) { + err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, + state->interface); +@@ -500,6 +527,12 @@ static void phylink_major_config(struct + } + } + ++ /* If we have a new PCS, switch to the new PCS after preparing the MAC ++ * for the change. ++ */ ++ if (pcs) ++ phylink_set_pcs(pl, pcs); ++ + phylink_mac_config(pl, state); + + if (pl->pcs_ops) { +@@ -879,6 +912,14 @@ struct phylink *phylink_create(struct ph + struct phylink *pl; + int ret; + ++ /* Validate the supplied configuration */ ++ if (mac_ops->mac_select_pcs && ++ phy_interface_empty(config->supported_interfaces)) { ++ dev_err(config->dev, ++ "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ + pl = kzalloc(sizeof(*pl), GFP_KERNEL); + if (!pl) + return ERR_PTR(-ENOMEM); +@@ -946,9 +987,10 @@ EXPORT_SYMBOL_GPL(phylink_create); + * @pl: a pointer to a &struct phylink returned from phylink_create() + * @pcs: a pointer to the &struct phylink_pcs + * +- * Bind the MAC PCS to phylink. This may be called after phylink_create(), +- * in mac_prepare() or mac_config() methods if it is desired to dynamically +- * change the PCS. ++ * Bind the MAC PCS to phylink. This may be called after phylink_create(). ++ * If it is desired to dynamically change the PCS, then the preferred method ++ * is to use mac_select_pcs(), but it may also be called in mac_prepare() ++ * or mac_config(). + * + * Please note that there are behavioural changes with the mac_config() + * callback if a PCS is present (denoting a newer setup) so removing a PCS +@@ -959,6 +1001,14 @@ void phylink_set_pcs(struct phylink *pl, + { + pl->pcs = pcs; + pl->pcs_ops = pcs->ops; ++ ++ if (!pl->phylink_disable_state && ++ pl->cfg_link_an_mode == MLO_AN_INBAND) { ++ if (pl->config->pcs_poll || pcs->poll) ++ mod_timer(&pl->link_poll, jiffies + HZ); ++ else ++ del_timer(&pl->link_poll); ++ } + } + EXPORT_SYMBOL_GPL(phylink_set_pcs); + +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -86,6 +86,7 @@ struct phylink_config { + /** + * struct phylink_mac_ops - MAC operations structure. + * @validate: Validate and update the link configuration. ++ * @mac_select_pcs: Select a PCS for the interface mode. + * @mac_pcs_get_state: Read the current link state from the hardware. + * @mac_prepare: prepare for a major reconfiguration of the interface. + * @mac_config: configure the MAC for the selected mode and state. +@@ -100,6 +101,8 @@ struct phylink_mac_ops { + void (*validate)(struct phylink_config *config, + unsigned long *supported, + struct phylink_link_state *state); ++ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config, ++ phy_interface_t interface); + void (*mac_pcs_get_state)(struct phylink_config *config, + struct phylink_link_state *state); + int (*mac_prepare)(struct phylink_config *config, unsigned int mode, +@@ -152,6 +155,21 @@ struct phylink_mac_ops { + */ + void validate(struct phylink_config *config, unsigned long *supported, + struct phylink_link_state *state); ++/** ++ * mac_select_pcs: Select a PCS for the interface mode. ++ * @config: a pointer to a &struct phylink_config. ++ * @interface: PHY interface mode for PCS ++ * ++ * Return the &struct phylink_pcs for the specified interface mode, or ++ * NULL if none is required, or an error pointer on error. ++ * ++ * This must not modify any state. It is used to query which PCS should ++ * be used. Phylink will use this during validation to ensure that the ++ * configuration is valid, and when setting a configuration to internally ++ * set the PCS that will be used. ++ */ ++struct phylink_pcs *mac_select_pcs(struct phylink_config *config, ++ phy_interface_t interface); + + /** + * mac_pcs_get_state() - Read the current inband link state from the hardware diff --git a/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch b/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch new file mode 100644 index 00000000000..f30a566c81e --- /dev/null +++ b/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch @@ -0,0 +1,341 @@ +From 34ae2c09d46a2d0abd907e139b466f798e4095a8 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 15 Nov 2021 10:00:27 +0000 +Subject: [PATCH] net: phylink: add generic validate implementation + +Add a generic validate() implementation using the supported_interfaces +and a bitmask of MAC pause/speed/duplex capabilities. This allows us +to entirely eliminate many driver private validate() implementations. + +We expose the underlying phylink_get_linkmodes() function so that +drivers which have special needs can still benefit from conversion. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 252 ++++++++++++++++++++++++++++++++++++++ + include/linux/phylink.h | 31 +++++ + 2 files changed, 283 insertions(+) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -172,6 +172,258 @@ static int phylink_validate_mac_and_pcs( + return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; + } + ++static void phylink_caps_to_linkmodes(unsigned long *linkmodes, ++ unsigned long caps) ++{ ++ if (caps & MAC_SYM_PAUSE) ++ __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes); ++ ++ if (caps & MAC_ASYM_PAUSE) ++ __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes); ++ ++ if (caps & MAC_10HD) ++ __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes); ++ ++ if (caps & MAC_10FD) ++ __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes); ++ ++ if (caps & MAC_100HD) { ++ __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_100FD) { ++ __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_1000HD) ++ __set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, linkmodes); ++ ++ if (caps & MAC_1000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_2500FD) { ++ __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_5000FD) ++ __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, linkmodes); ++ ++ if (caps & MAC_10000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_25000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_40000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_50000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_56000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_100000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_200000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, linkmodes); ++ } ++ ++ if (caps & MAC_400000FD) { ++ __set_bit(ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, ++ linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, linkmodes); ++ __set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes); ++ } ++} ++ ++/** ++ * phylink_get_linkmodes() - get acceptable link modes ++ * @linkmodes: ethtool linkmode mask (must be already initialised) ++ * @interface: phy interface mode defined by &typedef phy_interface_t ++ * @mac_capabilities: bitmask of MAC capabilities ++ * ++ * Set all possible pause, speed and duplex linkmodes in @linkmodes that ++ * are supported by the @interface mode and @mac_capabilities. @linkmodes ++ * must have been initialised previously. ++ */ ++void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, ++ unsigned long mac_capabilities) ++{ ++ unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++ caps |= MAC_10000FD | MAC_5000FD | MAC_2500FD; ++ fallthrough; ++ ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_GMII: ++ caps |= MAC_1000HD | MAC_1000FD; ++ fallthrough; ++ ++ case PHY_INTERFACE_MODE_REVRMII: ++ case PHY_INTERFACE_MODE_RMII: ++ case PHY_INTERFACE_MODE_REVMII: ++ case PHY_INTERFACE_MODE_MII: ++ caps |= MAC_10HD | MAC_10FD; ++ fallthrough; ++ ++ case PHY_INTERFACE_MODE_100BASEX: ++ caps |= MAC_100HD | MAC_100FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_TBI: ++ case PHY_INTERFACE_MODE_MOCA: ++ case PHY_INTERFACE_MODE_RTBI: ++ case PHY_INTERFACE_MODE_1000BASEX: ++ caps |= MAC_1000HD; ++ fallthrough; ++ case PHY_INTERFACE_MODE_TRGMII: ++ caps |= MAC_1000FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_2500BASEX: ++ caps |= MAC_2500FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_5GBASER: ++ caps |= MAC_5000FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_XGMII: ++ case PHY_INTERFACE_MODE_RXAUI: ++ case PHY_INTERFACE_MODE_XAUI: ++ case PHY_INTERFACE_MODE_10GBASER: ++ case PHY_INTERFACE_MODE_10GKR: ++ caps |= MAC_10000FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_25GBASER: ++ caps |= MAC_25000FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_XLGMII: ++ caps |= MAC_40000FD; ++ break; ++ ++ case PHY_INTERFACE_MODE_INTERNAL: ++ caps |= ~0; ++ break; ++ ++ case PHY_INTERFACE_MODE_NA: ++ case PHY_INTERFACE_MODE_MAX: ++ case PHY_INTERFACE_MODE_SMII: ++ break; ++ } ++ ++ phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities); ++} ++EXPORT_SYMBOL_GPL(phylink_get_linkmodes); ++ ++/** ++ * phylink_generic_validate() - generic validate() callback implementation ++ * @config: a pointer to a &struct phylink_config. ++ * @supported: ethtool bitmask for supported link modes. ++ * @state: a pointer to a &struct phylink_link_state. ++ * ++ * Generic implementation of the validate() callback that MAC drivers can ++ * use when they pass the range of supported interfaces and MAC capabilities. ++ * This makes use of phylink_get_linkmodes(). ++ */ ++void phylink_generic_validate(struct phylink_config *config, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; ++ ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++ phylink_get_linkmodes(mask, state->interface, config->mac_capabilities); ++ ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); ++} ++EXPORT_SYMBOL_GPL(phylink_generic_validate); ++ + static int phylink_validate_any(struct phylink *pl, unsigned long *supported, + struct phylink_link_state *state) + { +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -20,6 +20,29 @@ enum { + MLO_AN_PHY = 0, /* Conventional PHY */ + MLO_AN_FIXED, /* Fixed-link mode */ + MLO_AN_INBAND, /* In-band protocol */ ++ ++ MAC_SYM_PAUSE = BIT(0), ++ MAC_ASYM_PAUSE = BIT(1), ++ MAC_10HD = BIT(2), ++ MAC_10FD = BIT(3), ++ MAC_10 = MAC_10HD | MAC_10FD, ++ MAC_100HD = BIT(4), ++ MAC_100FD = BIT(5), ++ MAC_100 = MAC_100HD | MAC_100FD, ++ MAC_1000HD = BIT(6), ++ MAC_1000FD = BIT(7), ++ MAC_1000 = MAC_1000HD | MAC_1000FD, ++ MAC_2500FD = BIT(8), ++ MAC_5000FD = BIT(9), ++ MAC_10000FD = BIT(10), ++ MAC_20000FD = BIT(11), ++ MAC_25000FD = BIT(12), ++ MAC_40000FD = BIT(13), ++ MAC_50000FD = BIT(14), ++ MAC_56000FD = BIT(15), ++ MAC_100000FD = BIT(16), ++ MAC_200000FD = BIT(17), ++ MAC_400000FD = BIT(18), + }; + + static inline bool phylink_autoneg_inband(unsigned int mode) +@@ -70,6 +93,7 @@ enum phylink_op_type { + * if MAC link is at %MLO_AN_FIXED mode. + * @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx + * are supported by the MAC/PCS. ++ * @mac_capabilities: MAC pause/speed/duplex capabilities. + */ + struct phylink_config { + struct device *dev; +@@ -81,6 +105,7 @@ struct phylink_config { + void (*get_fixed_state)(struct phylink_config *config, + struct phylink_link_state *state); + DECLARE_PHY_INTERFACE_MASK(supported_interfaces); ++ unsigned long mac_capabilities; + }; + + /** +@@ -462,6 +487,12 @@ void pcs_link_up(struct phylink_pcs *pcs + phy_interface_t interface, int speed, int duplex); + #endif + ++void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, ++ unsigned long mac_capabilities); ++void phylink_generic_validate(struct phylink_config *config, ++ unsigned long *supported, ++ struct phylink_link_state *state); ++ + struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *, + phy_interface_t iface, + const struct phylink_mac_ops *mac_ops); diff --git a/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch b/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch new file mode 100644 index 00000000000..a55623519ce --- /dev/null +++ b/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch @@ -0,0 +1,68 @@ +From 82b318983c515f29b8b3a0dad9f6a5fe8a68a7f4 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 20 Oct 2021 20:49:49 +0300 +Subject: [PATCH] net: dsa: introduce helpers for iterating through ports using + dp + +Since the DSA conversion from the ds->ports array into the dst->ports +list, the DSA API has encouraged driver writers, as well as the core +itself, to write inefficient code. + +Currently, code that wants to filter by a specific type of port when +iterating, like {!unused, user, cpu, dsa}, uses the dsa_is_*_port helper. +Under the hood, this uses dsa_to_port which iterates again through +dst->ports. But the driver iterates through the port list already, so +the complexity is quadratic for the typical case of a single-switch +tree. + +This patch introduces some iteration helpers where the iterator is +already a struct dsa_port *dp, so that the other variant of the +filtering functions, dsa_port_is_{unused,user,cpu_dsa}, can be used +directly on the iterator. This eliminates the second lookup. + +These functions can be used both by the core and by drivers. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -476,6 +476,34 @@ static inline bool dsa_is_user_port(stru + return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_USER; + } + ++#define dsa_tree_for_each_user_port(_dp, _dst) \ ++ list_for_each_entry((_dp), &(_dst)->ports, list) \ ++ if (dsa_port_is_user((_dp))) ++ ++#define dsa_switch_for_each_port(_dp, _ds) \ ++ list_for_each_entry((_dp), &(_ds)->dst->ports, list) \ ++ if ((_dp)->ds == (_ds)) ++ ++#define dsa_switch_for_each_port_safe(_dp, _next, _ds) \ ++ list_for_each_entry_safe((_dp), (_next), &(_ds)->dst->ports, list) \ ++ if ((_dp)->ds == (_ds)) ++ ++#define dsa_switch_for_each_port_continue_reverse(_dp, _ds) \ ++ list_for_each_entry_continue_reverse((_dp), &(_ds)->dst->ports, list) \ ++ if ((_dp)->ds == (_ds)) ++ ++#define dsa_switch_for_each_available_port(_dp, _ds) \ ++ dsa_switch_for_each_port((_dp), (_ds)) \ ++ if (!dsa_port_is_unused((_dp))) ++ ++#define dsa_switch_for_each_user_port(_dp, _ds) \ ++ dsa_switch_for_each_port((_dp), (_ds)) \ ++ if (dsa_port_is_user((_dp))) ++ ++#define dsa_switch_for_each_cpu_port(_dp, _ds) \ ++ dsa_switch_for_each_port((_dp), (_ds)) \ ++ if (dsa_port_is_cpu((_dp))) ++ + static inline u32 dsa_user_ports(struct dsa_switch *ds) + { + u32 mask = 0; diff --git a/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch b/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch new file mode 100644 index 00000000000..524ce9bd926 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch @@ -0,0 +1,106 @@ +From 0d22d4b626a4eaa3196019092eb6c1919e9f8caa Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 15 Dec 2021 15:34:20 +0000 +Subject: [PATCH] net: phylink: add pcs_validate() method + +Add a hook for PCS to validate the link parameters. This avoids MAC +drivers having to have knowledge of their PCS in their validate() +method, thereby allowing several MAC drivers to be simplfied. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/phy/phylink.c | 31 +++++++++++++++++++++++++++++++ + include/linux/phylink.h | 20 ++++++++++++++++++++ + 2 files changed, 51 insertions(+) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -160,13 +160,44 @@ static int phylink_validate_mac_and_pcs( + struct phylink_link_state *state) + { + struct phylink_pcs *pcs; ++ int ret; + ++ /* Get the PCS for this interface mode */ + if (pl->mac_ops->mac_select_pcs) { + pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); + if (IS_ERR(pcs)) + return PTR_ERR(pcs); ++ } else { ++ pcs = pl->pcs; + } + ++ if (pcs) { ++ /* The PCS, if present, must be setup before phylink_create() ++ * has been called. If the ops is not initialised, print an ++ * error and backtrace rather than oopsing the kernel. ++ */ ++ if (!pcs->ops) { ++ phylink_err(pl, "interface %s: uninitialised PCS\n", ++ phy_modes(state->interface)); ++ dump_stack(); ++ return -EINVAL; ++ } ++ ++ /* Validate the link parameters with the PCS */ ++ if (pcs->ops->pcs_validate) { ++ ret = pcs->ops->pcs_validate(pcs, supported, state); ++ if (ret < 0 || phylink_is_empty_linkmode(supported)) ++ return -EINVAL; ++ ++ /* Ensure the advertising mask is a subset of the ++ * supported mask. ++ */ ++ linkmode_and(state->advertising, state->advertising, ++ supported); ++ } ++ } ++ ++ /* Then validate the link parameters with the MAC */ + pl->mac_ops->validate(pl->config, supported, state); + + return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -398,6 +398,7 @@ struct phylink_pcs { + + /** + * struct phylink_pcs_ops - MAC PCS operations structure. ++ * @pcs_validate: validate the link configuration. + * @pcs_get_state: read the current MAC PCS link state from the hardware. + * @pcs_config: configure the MAC PCS for the selected mode and state. + * @pcs_an_restart: restart 802.3z BaseX autonegotiation. +@@ -405,6 +406,8 @@ struct phylink_pcs { + * (where necessary). + */ + struct phylink_pcs_ops { ++ int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, ++ const struct phylink_link_state *state); + void (*pcs_get_state)(struct phylink_pcs *pcs, + struct phylink_link_state *state); + int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode, +@@ -418,6 +421,23 @@ struct phylink_pcs_ops { + + #if 0 /* For kernel-doc purposes only. */ + /** ++ * pcs_validate() - validate the link configuration. ++ * @pcs: a pointer to a &struct phylink_pcs. ++ * @supported: ethtool bitmask for supported link modes. ++ * @state: a const pointer to a &struct phylink_link_state. ++ * ++ * Validate the interface mode, and advertising's autoneg bit, removing any ++ * media ethtool link modes that would not be supportable from the supported ++ * mask. Phylink will propagate the changes to the advertising mask. See the ++ * &struct phylink_mac_ops validate() method. ++ * ++ * Returns -EINVAL if the interface mode/autoneg mode is not supported. ++ * Returns non-zero positive if the link state can be supported. ++ */ ++int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported, ++ const struct phylink_link_state *state); ++ ++/** + * pcs_get_state() - Read the current inband link state from the hardware + * @pcs: a pointer to a &struct phylink_pcs. + * @state: a pointer to a &struct phylink_link_state. diff --git a/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch b/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch new file mode 100644 index 00000000000..16d5da9c70e --- /dev/null +++ b/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch @@ -0,0 +1,43 @@ +From 3e5b1feccea7db576353ffc302f78d522e4116e6 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 9 Dec 2021 13:11:32 +0000 +Subject: [PATCH] net: phylink: add legacy_pre_march2020 indicator + +Add a boolean to phylink_config to indicate whether a driver has not +been updated for the changes in commit 7cceb599d15d ("net: phylink: +avoid mac_config calls"), and thus are reliant on the old behaviour. + +We were currently keying the phylink behaviour on the presence of a +PCS, but this is sub-optimal for modern drivers that may not have a +PCS. + +This commit merely introduces the new flag, but does not add any use, +since we need all legacy drivers to set this flag before it can be +used. Once these legacy drivers have been updated, we can remove this +flag. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + include/linux/phylink.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -84,6 +84,8 @@ enum phylink_op_type { + * struct phylink_config - PHYLINK configuration structure + * @dev: a pointer to a struct device associated with the MAC + * @type: operation type of PHYLINK instance ++ * @legacy_pre_march2020: driver has not been updated for March 2020 updates ++ * (See commit 7cceb599d15d ("net: phylink: avoid mac_config calls") + * @pcs_poll: MAC PCS cannot provide link change interrupt + * @poll_fixed_state: if true, starts link_poll, + * if MAC link is at %MLO_AN_FIXED mode. +@@ -98,6 +100,7 @@ enum phylink_op_type { + struct phylink_config { + struct device *dev; + enum phylink_op_type type; ++ bool legacy_pre_march2020; + bool pcs_poll; + bool poll_fixed_state; + bool mac_managed_pm; diff --git a/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch b/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch new file mode 100644 index 00000000000..849881942e1 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch @@ -0,0 +1,36 @@ +From 0a9f0794d9bd67e590a9488afe87fbb0419d9539 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 9 Dec 2021 13:11:38 +0000 +Subject: [PATCH] net: dsa: mark DSA phylink as legacy_pre_march2020 + +The majority of DSA drivers do not make use of the PCS support, and +thus operate in legacy mode. In order to preserve this behaviour in +future, we need to set the legacy_pre_march2020 flag so phylink knows +this may require the legacy calls. + +There are some DSA drivers that do make use of PCS support, and these +will continue operating as before - legacy_pre_march2020 will not +prevent split-PCS support enabling the newer phylink behaviour. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + net/dsa/port.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1126,6 +1126,13 @@ int dsa_port_phylink_create(struct dsa_p + if (err) + mode = PHY_INTERFACE_MODE_NA; + ++ /* Presence of phylink_mac_link_state or phylink_mac_an_restart is ++ * an indicator of a legacy phylink driver. ++ */ ++ if (ds->ops->phylink_mac_link_state || ++ ds->ops->phylink_mac_an_restart) ++ dp->pl_config.legacy_pre_march2020 = true; ++ + if (ds->ops->phylink_get_caps) + ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); + diff --git a/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch b/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch new file mode 100644 index 00000000000..73e53068b8a --- /dev/null +++ b/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch @@ -0,0 +1,115 @@ +From 001f4261fe4d5ae710cf1f445b6cae6d9d3ae26e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 9 Dec 2021 13:11:48 +0000 +Subject: [PATCH] net: phylink: use legacy_pre_march2020 + +Use the legacy flag to indicate whether we should operate in legacy +mode. This allows us to stop using the presence of a PCS as an +indicator to the age of the phylink user, and make PCS presence +optional. + +Legacy mode involves: +1) calling mac_config() whenever the link comes up +2) calling mac_config() whenever the inband advertisement changes, + possibly followed by a call to mac_an_restart() +3) making use of mac_an_restart() +4) making use of mac_pcs_get_state() + +All the above functionality was moved to a seperate "PCS" block of +operations in March 2020. + +Update the documents to indicate that the differences that this flag +makes. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 12 ++++++------ + include/linux/phylink.h | 17 +++++++++++++++++ + 2 files changed, 23 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -777,7 +777,7 @@ static void phylink_mac_pcs_an_restart(s + phylink_autoneg_inband(pl->cur_link_an_mode)) { + if (pl->pcs_ops) + pl->pcs_ops->pcs_an_restart(pl->pcs); +- else ++ else if (pl->config->legacy_pre_march2020) + pl->mac_ops->mac_an_restart(pl->config); + } + } +@@ -855,7 +855,7 @@ static int phylink_change_inband_advert( + if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) + return 0; + +- if (!pl->pcs_ops) { ++ if (!pl->pcs_ops && pl->config->legacy_pre_march2020) { + /* Legacy method */ + phylink_mac_config(pl, &pl->link_config); + phylink_mac_pcs_an_restart(pl); +@@ -900,7 +900,8 @@ static void phylink_mac_pcs_get_state(st + + if (pl->pcs_ops) + pl->pcs_ops->pcs_get_state(pl->pcs, state); +- else if (pl->mac_ops->mac_pcs_get_state) ++ else if (pl->mac_ops->mac_pcs_get_state && ++ pl->config->legacy_pre_march2020) + pl->mac_ops->mac_pcs_get_state(pl->config, state); + else + state->link = 0; +@@ -1094,12 +1095,11 @@ static void phylink_resolve(struct work_ + } + phylink_major_config(pl, false, &link_state); + pl->link_config.interface = link_state.interface; +- } else if (!pl->pcs_ops) { ++ } else if (!pl->pcs_ops && pl->config->legacy_pre_march2020) { + /* The interface remains unchanged, only the speed, + * duplex or pause settings have changed. Call the + * old mac_config() method to configure the MAC/PCS +- * only if we do not have a PCS installed (an +- * unconverted user.) ++ * only if we do not have a legacy MAC driver. + */ + phylink_mac_config(pl, &link_state); + } +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -210,6 +210,10 @@ struct phylink_pcs *mac_select_pcs(struc + * negotiation completion state in @state->an_complete, and link up state + * in @state->link. If possible, @state->lp_advertising should also be + * populated. ++ * ++ * Note: This is a legacy method. This function will not be called unless ++ * legacy_pre_march2020 is set in &struct phylink_config and there is no ++ * PCS attached. + */ + void mac_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state); +@@ -250,6 +254,15 @@ int mac_prepare(struct phylink_config *c + * guaranteed to be correct, and so any mac_config() implementation must + * never reference these fields. + * ++ * Note: For legacy March 2020 drivers (drivers with legacy_pre_march2020 set ++ * in their &phylnk_config and which don't have a PCS), this function will be ++ * called on each link up event, and to also change the in-band advert. For ++ * non-legacy drivers, it will only be called to reconfigure the MAC for a ++ * "major" change in e.g. interface mode. It will not be called for changes ++ * in speed, duplex or pause modes or to change the in-band advertisement. ++ * In any case, it is strongly preferred that speed, duplex and pause settings ++ * are handled in the mac_link_up() method and not in this method. ++ * + * (this requires a rewrite - please refer to mac_link_up() for situations + * where the PCS and MAC are not tightly integrated.) + * +@@ -334,6 +347,10 @@ int mac_finish(struct phylink_config *co + /** + * mac_an_restart() - restart 802.3z BaseX autonegotiation + * @config: a pointer to a &struct phylink_config. ++ * ++ * Note: This is a legacy method. This function will not be called unless ++ * legacy_pre_march2020 is set in &struct phylink_config and there is no ++ * PCS attached. + */ + void mac_an_restart(struct phylink_config *config); + diff --git a/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch b/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch new file mode 100644 index 00000000000..9e5061aaed8 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch @@ -0,0 +1,88 @@ +From 1054457006d4a14de4ae4132030e33d7eedaeba1 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 21 Feb 2022 17:10:52 +0000 +Subject: [PATCH] net: phy: phylink: fix DSA mac_select_pcs() introduction + +Vladimir Oltean reports that probing on DSA drivers that aren't yet +populating supported_interfaces now fails. Fix this by allowing +phylink to detect whether DSA actually provides an underlying +mac_select_pcs() implementation. + +Reported-by: Vladimir Oltean +Fixes: bde018222c6b ("net: dsa: add support for phylink mac_select_pcs()") +Signed-off-by: Russell King (Oracle) +Tested-by: Vladimir Oltean +Link: https://lore.kernel.org/r/E1nMCD6-00A0wC-FG@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/phylink.c | 14 +++++++++++--- + net/dsa/port.c | 2 +- + 2 files changed, 12 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -74,6 +74,7 @@ struct phylink { + struct work_struct resolve; + + bool mac_link_dropped; ++ bool using_mac_select_pcs; + + struct sfp_bus *sfp_bus; + bool sfp_may_have_phy; +@@ -163,7 +164,7 @@ static int phylink_validate_mac_and_pcs( + int ret; + + /* Get the PCS for this interface mode */ +- if (pl->mac_ops->mac_select_pcs) { ++ if (pl->using_mac_select_pcs) { + pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); + if (IS_ERR(pcs)) + return PTR_ERR(pcs); +@@ -790,7 +791,7 @@ static void phylink_major_config(struct + + phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); + +- if (pl->mac_ops->mac_select_pcs) { ++ if (pl->using_mac_select_pcs) { + pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); + if (IS_ERR(pcs)) { + phylink_err(pl, +@@ -1192,11 +1193,17 @@ struct phylink *phylink_create(struct ph + phy_interface_t iface, + const struct phylink_mac_ops *mac_ops) + { ++ bool using_mac_select_pcs = false; + struct phylink *pl; + int ret; + +- /* Validate the supplied configuration */ + if (mac_ops->mac_select_pcs && ++ mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != ++ ERR_PTR(-EOPNOTSUPP)) ++ using_mac_select_pcs = true; ++ ++ /* Validate the supplied configuration */ ++ if (using_mac_select_pcs && + phy_interface_empty(config->supported_interfaces)) { + dev_err(config->dev, + "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); +@@ -1220,6 +1227,7 @@ struct phylink *phylink_create(struct ph + return ERR_PTR(-EINVAL); + } + ++ pl->using_mac_select_pcs = using_mac_select_pcs; + pl->phy_state.interface = iface; + pl->link_interface = iface; + if (iface == PHY_INTERFACE_MODE_MOCA) +--- a/net/dsa/port.c ++++ b/net/dsa/port.c +@@ -1033,8 +1033,8 @@ dsa_port_phylink_mac_select_pcs(struct p + phy_interface_t interface) + { + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); ++ struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); + struct dsa_switch *ds = dp->ds; +- struct phylink_pcs *pcs = NULL; + + if (ds->ops->phylink_mac_select_pcs) + pcs = ds->ops->phylink_mac_select_pcs(ds, dp->index, interface); diff --git a/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch new file mode 100644 index 00000000000..f21fa4b2778 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch @@ -0,0 +1,48 @@ +From fdedb695e6a8657302341cda81d519ef04f9acaa Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 27 Oct 2021 10:03:43 +0100 +Subject: [PATCH] net: mvneta: populate supported_interfaces member + +Populate the phy_interface_t bitmap for the Marvell mvneta driver with +interfaces modes supported by the MAC. + +Signed-off-by: Russell King +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5180,6 +5180,31 @@ static int mvneta_probe(struct platform_ + + pp->phylink_config.dev = &dev->dev; + pp->phylink_config.type = PHYLINK_NETDEV; ++ phy_interface_set_rgmii(pp->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_QSGMII, ++ pp->phylink_config.supported_interfaces); ++ if (comphy) { ++ /* If a COMPHY is present, we can support any of the serdes ++ * modes and switch between them. ++ */ ++ __set_bit(PHY_INTERFACE_MODE_SGMII, ++ pp->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, ++ pp->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, ++ pp->phylink_config.supported_interfaces); ++ } else if (phy_mode == PHY_INTERFACE_MODE_2500BASEX) { ++ /* No COMPHY, with only 2500BASE-X mode supported */ ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, ++ pp->phylink_config.supported_interfaces); ++ } else if (phy_mode == PHY_INTERFACE_MODE_1000BASEX || ++ phy_mode == PHY_INTERFACE_MODE_SGMII) { ++ /* No COMPHY, we can switch between 1000BASE-X and SGMII */ ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, ++ pp->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_SGMII, ++ pp->phylink_config.supported_interfaces); ++ } + + phylink = phylink_create(&pp->phylink_config, pdev->dev.fwnode, + phy_mode, &mvneta_phylink_ops); diff --git a/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch b/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch new file mode 100644 index 00000000000..e287e39d6a4 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch @@ -0,0 +1,35 @@ +From d9ca72807ecb236f679b960c70ef5b7d4a5f0222 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 27 Oct 2021 10:03:48 +0100 +Subject: [PATCH] net: mvneta: remove interface checks in mvneta_validate() + +As phylink checks the interface mode against the supported_interfaces +bitmap, we no longer need to validate the interface mode in the +validation function. Remove this to simplify it. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -3833,15 +3833,8 @@ static void mvneta_validate(struct phyli + * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... + * When = 1 (1000BASE-X) this field must be set to 1." + */ +- if (phy_interface_mode_is_8023z(state->interface)) { +- if (!phylink_test(state->advertising, Autoneg)) { +- linkmode_zero(supported); +- return; +- } +- } else if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_QSGMII && +- state->interface != PHY_INTERFACE_MODE_SGMII && +- !phy_interface_mode_is_rgmii(state->interface)) { ++ if (phy_interface_mode_is_8023z(state->interface) && ++ !phylink_test(state->advertising, Autoneg)) { + linkmode_zero(supported); + return; + } diff --git a/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch b/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch new file mode 100644 index 00000000000..9121612bf82 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch @@ -0,0 +1,55 @@ +From 099cbfa286ab937d8213c2dc5c0b401969b78042 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 27 Oct 2021 10:03:53 +0100 +Subject: [PATCH] net: mvneta: drop use of phylink_helper_basex_speed() + +Now that we have a better method to select SFP interface modes, we +no longer need to use phylink_helper_basex_speed() in a driver's +validation function, and we can also get rid of our hack to indicate +both 1000base-X and 2500base-X if the comphy is present to make that +work. Remove this hack and use of phylink_helper_basex_speed(). + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -3824,8 +3824,6 @@ static void mvneta_validate(struct phyli + unsigned long *supported, + struct phylink_link_state *state) + { +- struct net_device *ndev = to_net_dev(config->dev); +- struct mvneta_port *pp = netdev_priv(ndev); + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + /* We only support QSGMII, SGMII, 802.3z and RGMII modes. +@@ -3847,11 +3845,12 @@ static void mvneta_validate(struct phyli + phylink_set(mask, Pause); + + /* Half-duplex at speeds higher than 100Mbit is unsupported */ +- if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) { ++ if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + } +- if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) { ++ ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(mask, 2500baseT_Full); + phylink_set(mask, 2500baseX_Full); + } +@@ -3866,11 +3865,6 @@ static void mvneta_validate(struct phyli + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); +- +- /* We can only operate at 2500BaseX or 1000BaseX. If requested +- * to advertise both, only report advertising at 2500BaseX. +- */ +- phylink_helper_basex_speed(state); + } + + static void mvneta_mac_pcs_get_state(struct phylink_config *config, diff --git a/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch b/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch new file mode 100644 index 00000000000..209dfbc0de9 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch @@ -0,0 +1,72 @@ +From 02a0988b98930491db95966fb8086072e47dabb6 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 15 Nov 2021 10:00:32 +0000 +Subject: [PATCH] net: mvneta: use phylink_generic_validate() + +Convert mvneta to use phylink_generic_validate() for the bulk of its +validate() implementation. This network adapter has a restriction +that for 802.3z links, autonegotiation must be enabled. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 34 ++++----------------------- + 1 file changed, 4 insertions(+), 30 deletions(-) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -3824,8 +3824,6 @@ static void mvneta_validate(struct phyli + unsigned long *supported, + struct phylink_link_state *state) + { +- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- + /* We only support QSGMII, SGMII, 802.3z and RGMII modes. + * When in 802.3z mode, we must have AN enabled: + * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... +@@ -3837,34 +3835,7 @@ static void mvneta_validate(struct phyli + return; + } + +- /* Allow all the expected bits */ +- phylink_set(mask, Autoneg); +- phylink_set_port_modes(mask); +- +- /* Asymmetric pause is unsupported */ +- phylink_set(mask, Pause); +- +- /* Half-duplex at speeds higher than 100Mbit is unsupported */ +- if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseX_Full); +- } +- +- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { +- phylink_set(mask, 2500baseT_Full); +- phylink_set(mask, 2500baseX_Full); +- } +- +- if (!phy_interface_mode_is_8023z(state->interface)) { +- /* 10M and 100M are only supported in non-802.3z mode */ +- phylink_set(mask, 10baseT_Half); +- phylink_set(mask, 10baseT_Full); +- phylink_set(mask, 100baseT_Half); +- phylink_set(mask, 100baseT_Full); +- } +- +- linkmode_and(supported, supported, mask); +- linkmode_and(state->advertising, state->advertising, mask); ++ phylink_generic_validate(config, supported, state); + } + + static void mvneta_mac_pcs_get_state(struct phylink_config *config, +@@ -5167,6 +5138,9 @@ static int mvneta_probe(struct platform_ + + pp->phylink_config.dev = &dev->dev; + pp->phylink_config.type = PHYLINK_NETDEV; ++ pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | ++ MAC_100 | MAC_1000FD | MAC_2500FD; ++ + phy_interface_set_rgmii(pp->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_QSGMII, + pp->phylink_config.supported_interfaces); diff --git a/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch b/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch new file mode 100644 index 00000000000..31717565bf1 --- /dev/null +++ b/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch @@ -0,0 +1,29 @@ +From 2106be4fdf3223d9c5bd485e6ef094139e3197ba Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Sun, 12 Dec 2021 13:01:21 +0000 +Subject: [PATCH] net: mvneta: mark as a legacy_pre_march2020 driver +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +mvneta provides mac_an_restart and mac_pcs_get_state methods, so needs +to be marked as a legacy driver. Marek spotted that mvneta had stopped +working in 2500base-X mode - thanks for reporting. + +Reported-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/marvell/mvneta.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/marvell/mvneta.c ++++ b/drivers/net/ethernet/marvell/mvneta.c +@@ -5138,6 +5138,7 @@ static int mvneta_probe(struct platform_ + + pp->phylink_config.dev = &dev->dev; + pp->phylink_config.type = PHYLINK_NETDEV; ++ pp->phylink_config.legacy_pre_march2020 = true; + pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | + MAC_100 | MAC_1000FD | MAC_2500FD; + diff --git a/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch new file mode 100644 index 00000000000..b6fe0dad4c8 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch @@ -0,0 +1,43 @@ +From 83800d29f0c578e82554e7d4c6bfdbdf9b6cf428 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 16 Nov 2021 10:06:43 +0000 +Subject: [PATCH] net: mtk_eth_soc: populate supported_interfaces member + +Populate the phy interface mode bitmap for the Mediatek driver with +interfaces modes supported by the MAC. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3355,6 +3355,26 @@ static int mtk_add_mac(struct mtk_eth *e + + mac->phylink_config.dev = ð->netdev[id]->dev; + mac->phylink_config.type = PHYLINK_NETDEV; ++ __set_bit(PHY_INTERFACE_MODE_MII, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_GMII, ++ mac->phylink_config.supported_interfaces); ++ ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) ++ phy_interface_set_rgmii(mac->phylink_config.supported_interfaces); ++ ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && !mac->id) ++ __set_bit(PHY_INTERFACE_MODE_TRGMII, ++ mac->phylink_config.supported_interfaces); ++ ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { ++ __set_bit(PHY_INTERFACE_MODE_SGMII, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, ++ mac->phylink_config.supported_interfaces); ++ } + + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), diff --git a/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch b/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch new file mode 100644 index 00000000000..0a33ab00934 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch @@ -0,0 +1,75 @@ +From db81ca153814475d7e07365d46a4d1134bd122e2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 16 Nov 2021 10:06:48 +0000 +Subject: [PATCH] net: mtk_eth_soc: remove interface checks in mtk_validate() + +As phylink checks the interface mode against the supported_interfaces +bitmap, we no longer need to validate the interface mode, nor handle +PHY_INTERFACE_MODE_NA in the validation function. Remove these to +simplify the implementation. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 --------------------- + 1 file changed, 34 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -568,24 +568,8 @@ static void mtk_validate(struct phylink_ + unsigned long *supported, + struct phylink_link_state *state) + { +- struct mtk_mac *mac = container_of(config, struct mtk_mac, +- phylink_config); + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_MII && +- state->interface != PHY_INTERFACE_MODE_GMII && +- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) && +- phy_interface_mode_is_rgmii(state->interface)) && +- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && +- !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII) && +- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) && +- (state->interface == PHY_INTERFACE_MODE_SGMII || +- phy_interface_mode_is_8023z(state->interface)))) { +- linkmode_zero(supported); +- return; +- } +- + phylink_set_port_modes(mask); + phylink_set(mask, Autoneg); + +@@ -612,7 +596,6 @@ static void mtk_validate(struct phylink_ + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_RMII: + case PHY_INTERFACE_MODE_REVMII: +- case PHY_INTERFACE_MODE_NA: + default: + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); +@@ -621,23 +604,6 @@ static void mtk_validate(struct phylink_ + break; + } + +- if (state->interface == PHY_INTERFACE_MODE_NA) { +- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseX_Full); +- phylink_set(mask, 2500baseX_Full); +- } +- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) { +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseT_Half); +- phylink_set(mask, 1000baseX_Full); +- } +- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) { +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseT_Half); +- } +- } +- + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + diff --git a/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch b/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch new file mode 100644 index 00000000000..f8cc8105a4c --- /dev/null +++ b/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch @@ -0,0 +1,42 @@ +From 71d927494463c4f016d828e1134da26b7e961af5 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 16 Nov 2021 10:06:53 +0000 +Subject: [PATCH] net: mtk_eth_soc: drop use of phylink_helper_basex_speed() + +Now that we have a better method to select SFP interface modes, we +no longer need to use phylink_helper_basex_speed() in a driver's +validation function, and we can also get rid of our hack to indicate +both 1000base-X and 2500base-X if the comphy is present to make that +work. Remove this hack and use of phylink_helper_basex_speed(). + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -578,8 +578,9 @@ static void mtk_validate(struct phylink_ + phylink_set(mask, 1000baseT_Full); + break; + case PHY_INTERFACE_MODE_1000BASEX: +- case PHY_INTERFACE_MODE_2500BASEX: + phylink_set(mask, 1000baseX_Full); ++ break; ++ case PHY_INTERFACE_MODE_2500BASEX: + phylink_set(mask, 2500baseX_Full); + break; + case PHY_INTERFACE_MODE_GMII: +@@ -609,11 +610,6 @@ static void mtk_validate(struct phylink_ + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); +- +- /* We can only operate at 2500BaseX or 1000BaseX. If requested +- * to advertise both, only report advertising at 2500BaseX. +- */ +- phylink_helper_basex_speed(state); + } + + static const struct phylink_mac_ops mtk_phylink_ops = { diff --git a/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch b/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch new file mode 100644 index 00000000000..f695991ec1f --- /dev/null +++ b/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch @@ -0,0 +1,84 @@ +From a4238f6ce151afa331375d74a5033b76da637644 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 16 Nov 2021 10:06:58 +0000 +Subject: [PATCH] net: mtk_eth_soc: use phylink_generic_validate() + +mtk_eth_soc has no special behaviour in its validation implementation, +so can be switched to phylink_generic_validate(). + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 53 ++------------------- + 1 file changed, 4 insertions(+), 49 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -564,56 +564,8 @@ static void mtk_mac_link_up(struct phyli + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + +-static void mtk_validate(struct phylink_config *config, +- unsigned long *supported, +- struct phylink_link_state *state) +-{ +- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- +- phylink_set_port_modes(mask); +- phylink_set(mask, Autoneg); +- +- switch (state->interface) { +- case PHY_INTERFACE_MODE_TRGMII: +- phylink_set(mask, 1000baseT_Full); +- break; +- case PHY_INTERFACE_MODE_1000BASEX: +- phylink_set(mask, 1000baseX_Full); +- break; +- case PHY_INTERFACE_MODE_2500BASEX: +- phylink_set(mask, 2500baseX_Full); +- break; +- case PHY_INTERFACE_MODE_GMII: +- case PHY_INTERFACE_MODE_RGMII: +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- case PHY_INTERFACE_MODE_RGMII_TXID: +- phylink_set(mask, 1000baseT_Half); +- fallthrough; +- case PHY_INTERFACE_MODE_SGMII: +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseX_Full); +- fallthrough; +- case PHY_INTERFACE_MODE_MII: +- case PHY_INTERFACE_MODE_RMII: +- case PHY_INTERFACE_MODE_REVMII: +- default: +- phylink_set(mask, 10baseT_Half); +- phylink_set(mask, 10baseT_Full); +- phylink_set(mask, 100baseT_Half); +- phylink_set(mask, 100baseT_Full); +- break; +- } +- +- phylink_set(mask, Pause); +- phylink_set(mask, Asym_Pause); +- +- linkmode_and(supported, supported, mask); +- linkmode_and(state->advertising, state->advertising, mask); +-} +- + static const struct phylink_mac_ops mtk_phylink_ops = { +- .validate = mtk_validate, ++ .validate = phylink_generic_validate, + .mac_pcs_get_state = mtk_mac_pcs_get_state, + .mac_an_restart = mtk_mac_an_restart, + .mac_config = mtk_mac_config, +@@ -3317,6 +3269,9 @@ static int mtk_add_mac(struct mtk_eth *e + + mac->phylink_config.dev = ð->netdev[id]->dev; + mac->phylink_config.type = PHYLINK_NETDEV; ++ mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | ++ MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; ++ + __set_bit(PHY_INTERFACE_MODE_MII, + mac->phylink_config.supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_GMII, diff --git a/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch b/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch new file mode 100644 index 00000000000..cbff1bfbbc4 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch @@ -0,0 +1,29 @@ +From b06515367facfadcf5e70cf6f39db749cf4eb5e3 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 9 Dec 2021 13:11:43 +0000 +Subject: [PATCH] net: mtk_eth_soc: mark as a legacy_pre_march2020 driver + +mtk_eth_soc has not been updated for commit 7cceb599d15d ("net: phylink: +avoid mac_config calls"), and makes use of state->speed and +state->duplex in contravention of the phylink documentation. This makes +reliant on the legacy behaviours, so mark it as a legacy driver. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3269,6 +3269,10 @@ static int mtk_add_mac(struct mtk_eth *e + + mac->phylink_config.dev = ð->netdev[id]->dev; + mac->phylink_config.type = PHYLINK_NETDEV; ++ /* This driver makes use of state->speed/state->duplex in ++ * mac_config ++ */ ++ mac->phylink_config.legacy_pre_march2020 = true; + mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; + diff --git a/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch b/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch new file mode 100644 index 00000000000..c0b4a61cb6e --- /dev/null +++ b/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch @@ -0,0 +1,40 @@ +From 889e3691b9d6573de133da1f5e78f590e52152cd Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Thu, 28 Apr 2022 14:23:13 -0700 +Subject: [PATCH] eth: mtk_eth_soc: remove a copy of the NAPI_POLL_WEIGHT + define + +Defining local versions of NAPI_POLL_WEIGHT with the same +values in the drivers just makes refactoring harder. + +Signed-off-by: Jakub Kicinski +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 - + 2 files changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3568,9 +3568,9 @@ static int mtk_probe(struct platform_dev + */ + init_dummy_netdev(ð->dummy_dev); + netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, +- MTK_NAPI_WEIGHT); ++ NAPI_POLL_WEIGHT); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, +- MTK_NAPI_WEIGHT); ++ NAPI_POLL_WEIGHT); + + platform_set_drvdata(pdev, eth); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -25,7 +25,6 @@ + #define MTK_TX_DMA_BUF_LEN 0x3fff + #define MTK_TX_DMA_BUF_LEN_V2 0xffff + #define MTK_DMA_SIZE 512 +-#define MTK_NAPI_WEIGHT 64 + #define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN) + #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) diff --git a/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch b/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch new file mode 100644 index 00000000000..5940ac27df9 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch @@ -0,0 +1,35 @@ +From 0600bdde1fae75fb9bad72033d28edddc72b44b2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:54:31 +0100 +Subject: [PATCH 01/12] net: mtk_eth_soc: remove unused mac->mode + +mac->mode is only ever written to in one location, and is thus +superflous. Remove it. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 - + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 - + 2 files changed, 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3264,7 +3264,6 @@ static int mtk_add_mac(struct mtk_eth *e + + /* mac config is not set */ + mac->interface = PHY_INTERFACE_MODE_NA; +- mac->mode = MLO_AN_PHY; + mac->speed = SPEED_UNKNOWN; + + mac->phylink_config.dev = ð->netdev[id]->dev; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1086,7 +1086,6 @@ struct mtk_eth { + struct mtk_mac { + int id; + phy_interface_t interface; +- unsigned int mode; + int speed; + struct device_node *of_node; + struct phylink *phylink; diff --git a/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch b/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch new file mode 100644 index 00000000000..a15914bd553 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch @@ -0,0 +1,40 @@ +From 5a7a2f4b29d7546244da7d8bbc1962fce5b230f2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:54:36 +0100 +Subject: [PATCH 02/12] net: mtk_eth_soc: remove unused sgmii flags + +The "flags" member of struct mtk_sgmii appears to be unused, as are +the MTK_SGMII_PHYSPEED_* and MTK_HAS_FLAGS() macros. Remove them. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -957,23 +957,15 @@ struct mtk_soc_data { + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + +-#define MTK_SGMII_PHYSPEED_AN BIT(31) +-#define MTK_SGMII_PHYSPEED_MASK GENMASK(2, 0) +-#define MTK_SGMII_PHYSPEED_1000 BIT(0) +-#define MTK_SGMII_PHYSPEED_2500 BIT(1) +-#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) +- + /* struct mtk_sgmii - This is the structure holding sgmii regmap and its + * characteristics + * @regmap: The register map pointing at the range used to setup + * SGMII modes +- * @flags: The enum refers to which mode the sgmii wants to run on + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + */ + + struct mtk_sgmii { + struct regmap *regmap[MTK_MAX_DEVS]; +- u32 flags[MTK_MAX_DEVS]; + u32 ana_rgc3; + }; + diff --git a/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch b/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch new file mode 100644 index 00000000000..e16bc875e52 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch @@ -0,0 +1,40 @@ +From bc5e93e0cd22e360eda23859b939280205567580 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:54:42 +0100 +Subject: [PATCH 03/12] net: mtk_eth_soc: add mask and update PCS speed + definitions + +The PCS speed setting is a two bit field, but it is defined as two +separate bits. Add a bitfield mask for the speed definitions, an + use the FIELD_PREP() macro to define each PCS speed. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include "mtk_ppe.h" + + #define MTK_QDMA_PAGE_SIZE 2048 +@@ -474,9 +475,10 @@ + #define SGMSYS_SGMII_MODE 0x20 + #define SGMII_IF_MODE_BIT0 BIT(0) + #define SGMII_SPEED_DUPLEX_AN BIT(1) +-#define SGMII_SPEED_10 0x0 +-#define SGMII_SPEED_100 BIT(2) +-#define SGMII_SPEED_1000 BIT(3) ++#define SGMII_SPEED_MASK GENMASK(3, 2) ++#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) ++#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) ++#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) + #define SGMII_DUPLEX_FULL BIT(4) + #define SGMII_IF_MODE_BIT5 BIT(5) + #define SGMII_REMOTE_FAULT_DIS BIT(8) diff --git a/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch b/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch new file mode 100644 index 00000000000..fb1ee4e310e --- /dev/null +++ b/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch @@ -0,0 +1,60 @@ +From 7da3f901f8ecb425105fad39a0f5de73306abe52 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:54:47 +0100 +Subject: [PATCH 04/12] net: mtk_eth_soc: correct 802.3z speed setting + +Phylink does not guarantee that state->speed will be set correctly in +the mac_config() call, so it's a bug that the driver makes use of it. +Moreover, it is making use of it in a function that is only ever called +for 1000BASE-X and 2500BASE-X which operate at a fixed speed which +happens to be the same setting irrespective of the interface mode. We +can simply remove the switch statement and just set the SGMII interface +speed. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 +++++------------- + 1 file changed, 5 insertions(+), 13 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -34,6 +34,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + return 0; + } + ++/* For SGMII interface mode */ + int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) + { + unsigned int val; +@@ -60,6 +61,9 @@ int mtk_sgmii_setup_mode_an(struct mtk_s + return 0; + } + ++/* For 1000BASE-X and 2500BASE-X interface modes, which operate at a ++ * fixed speed. ++ */ + int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, + const struct phylink_link_state *state) + { +@@ -82,19 +86,7 @@ int mtk_sgmii_setup_mode_force(struct mt + /* SGMII force mode setting */ + regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); + val &= ~SGMII_IF_MODE_MASK; +- +- switch (state->speed) { +- case SPEED_10: +- val |= SGMII_SPEED_10; +- break; +- case SPEED_100: +- val |= SGMII_SPEED_100; +- break; +- case SPEED_2500: +- case SPEED_1000: +- val |= SGMII_SPEED_1000; +- break; +- } ++ val |= SGMII_SPEED_1000; + + if (state->duplex == DUPLEX_FULL) + val |= SGMII_DUPLEX_FULL; diff --git a/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch b/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch new file mode 100644 index 00000000000..78444903a8c --- /dev/null +++ b/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch @@ -0,0 +1,101 @@ +From a459187390bb221827f9c07866c3a5ffbdf9622b Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 18 May 2022 15:54:52 +0100 +Subject: [PATCH 05/12] net: mtk_eth_soc: correct 802.3z duplex setting + +Phylink does not guarantee that state->duplex will be set correctly in +the mac_config() call, so it's a bug that the driver makes use of it. + +Move the 802.3z PCS duplex configuration to mac_link_up(). + +Signed-off-by: Russell King +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 +++++++++++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + drivers/net/ethernet/mediatek/mtk_sgmii.c | 22 +++++++++++++++------ + 3 files changed, 29 insertions(+), 10 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -533,8 +533,18 @@ static void mtk_mac_link_up(struct phyli + { + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); +- u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); ++ u32 mcr; + ++ if (phy_interface_mode_is_8023z(interface)) { ++ struct mtk_eth *eth = mac->hw; ++ ++ /* Decide how GMAC and SGMIISYS be mapped */ ++ int sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? ++ 0 : mac->id; ++ mtk_sgmii_link_up(eth->sgmii, sid, speed, duplex); ++ } ++ ++ mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | + MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | + MAC_MCR_FORCE_RX_FC); +@@ -3268,9 +3278,7 @@ static int mtk_add_mac(struct mtk_eth *e + + mac->phylink_config.dev = ð->netdev[id]->dev; + mac->phylink_config.type = PHYLINK_NETDEV; +- /* This driver makes use of state->speed/state->duplex in +- * mac_config +- */ ++ /* This driver makes use of state->speed in mac_config */ + mac->phylink_config.legacy_pre_march2020 = true; + mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1104,6 +1104,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); + int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, + const struct phylink_link_state *state); ++void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); + void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); + + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -83,14 +83,10 @@ int mtk_sgmii_setup_mode_force(struct mt + val &= ~SGMII_AN_ENABLE; + regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); + +- /* SGMII force mode setting */ ++ /* Set the speed etc but leave the duplex unchanged */ + regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); +- val &= ~SGMII_IF_MODE_MASK; ++ val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; + val |= SGMII_SPEED_1000; +- +- if (state->duplex == DUPLEX_FULL) +- val |= SGMII_DUPLEX_FULL; +- + regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); + + /* Release PHYA power down state */ +@@ -101,6 +97,20 @@ int mtk_sgmii_setup_mode_force(struct mt + return 0; + } + ++/* For 1000BASE-X and 2500BASE-X interface modes */ ++void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) ++{ ++ unsigned int val; ++ ++ /* SGMII force duplex setting */ ++ regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); ++ val &= ~SGMII_DUPLEX_FULL; ++ if (duplex == DUPLEX_FULL) ++ val |= SGMII_DUPLEX_FULL; ++ ++ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++} ++ + void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) + { + struct mtk_sgmii *ss = eth->sgmii; diff --git a/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch b/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch new file mode 100644 index 00000000000..6556bb7d07d --- /dev/null +++ b/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch @@ -0,0 +1,60 @@ +From 4ce5a0bd3958ed248f0325bfcb95339f7c74feb2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:54:57 +0100 +Subject: [PATCH 06/12] net: mtk_eth_soc: stop passing phylink state to sgmii + setup + +Now that mtk_sgmii_setup_mode_force() only uses the interface mode +from the phylink state, pass just the interface mode into this +function. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 4 ++-- + 3 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -437,7 +437,7 @@ static void mtk_mac_config(struct phylin + /* Setup SGMIISYS with the determined property */ + if (state->interface != PHY_INTERFACE_MODE_SGMII) + err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, +- state); ++ state->interface); + else if (phylink_autoneg_inband(mode)) + err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1103,7 +1103,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + u32 ana_rgc3); + int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); + int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, +- const struct phylink_link_state *state); ++ phy_interface_t interface); + void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); + void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -65,7 +65,7 @@ int mtk_sgmii_setup_mode_an(struct mtk_s + * fixed speed. + */ + int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, +- const struct phylink_link_state *state) ++ phy_interface_t interface) + { + unsigned int val; + +@@ -74,7 +74,7 @@ int mtk_sgmii_setup_mode_force(struct mt + + regmap_read(ss->regmap[id], ss->ana_rgc3, &val); + val &= ~RG_PHY_SPEED_MASK; +- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) + val |= RG_PHY_SPEED_3_125G; + regmap_write(ss->regmap[id], ss->ana_rgc3, val); + diff --git a/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch b/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch new file mode 100644 index 00000000000..0e22c7fd674 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch @@ -0,0 +1,89 @@ +From 1ec619ee4a052fb9ac48b57554ac2722a0bfe73c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:02 +0100 +Subject: [PATCH 07/12] net: mtk_eth_soc: provide mtk_sgmii_config() + +Provide mtk_sgmii_config() to wrap up the decisions about which SGMII +configuration will be called. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +------ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 ++--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 20 +++++++++++++++++--- + 3 files changed, 20 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -435,12 +435,7 @@ static void mtk_mac_config(struct phylin + 0 : mac->id; + + /* Setup SGMIISYS with the determined property */ +- if (state->interface != PHY_INTERFACE_MODE_SGMII) +- err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, +- state->interface); +- else if (phylink_autoneg_inband(mode)) +- err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); +- ++ err = mtk_sgmii_config(eth->sgmii, sid, mode, state->interface); + if (err) + goto init_err; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1101,9 +1101,8 @@ u32 mtk_r32(struct mtk_eth *eth, unsigne + + int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, + u32 ana_rgc3); +-int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); +-int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, +- phy_interface_t interface); ++int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, ++ phy_interface_t interface); + void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); + void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -35,7 +35,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + } + + /* For SGMII interface mode */ +-int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) ++static int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) + { + unsigned int val; + +@@ -64,8 +64,8 @@ int mtk_sgmii_setup_mode_an(struct mtk_s + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a + * fixed speed. + */ +-int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, +- phy_interface_t interface) ++static int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, ++ phy_interface_t interface) + { + unsigned int val; + +@@ -97,6 +97,20 @@ int mtk_sgmii_setup_mode_force(struct mt + return 0; + } + ++int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, ++ phy_interface_t interface) ++{ ++ int err = 0; ++ ++ /* Setup SGMIISYS with the determined property */ ++ if (interface != PHY_INTERFACE_MODE_SGMII) ++ err = mtk_sgmii_setup_mode_force(ss, id, interface); ++ else if (phylink_autoneg_inband(mode)) ++ err = mtk_sgmii_setup_mode_an(ss, id); ++ ++ return err; ++} ++ + /* For 1000BASE-X and 2500BASE-X interface modes */ + void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) + { diff --git a/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch b/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch new file mode 100644 index 00000000000..8080a2ca441 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch @@ -0,0 +1,38 @@ +From 650a49bc65df6b0e0051a8f62d7c22d95a8f350d Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:07 +0100 +Subject: [PATCH 08/12] net: mtk_eth_soc: add fixme comment for state->speed + use + +Add a fixme comment for the last remaining incorrect usage of +state->speed in the mac_config() method, which is strangely in a code +path which is only run when the PHY interface mode changes. + +This means if we are in RGMII mode, changes in state->speed will not +cause the INTF_MODE, TRGMII_RCK_CTRL and TRGMII_TCK_CTRL registers to +be set according to the speed, nor will the TRGPLL clock be set to the +correct value. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -374,6 +374,14 @@ static void mtk_mac_config(struct phylin + state->interface)) + goto err_phy; + } else { ++ /* FIXME: this is incorrect. Not only does it ++ * use state->speed (which is not guaranteed ++ * to be correct) but it also makes use of it ++ * in a code path that will only be reachable ++ * when the PHY interface mode changes, not ++ * when the speed changes. Consequently, RGMII ++ * is probably broken. ++ */ + mtk_gmac0_rgmii_adjust(mac->hw, + state->interface, + state->speed); diff --git a/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch b/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch new file mode 100644 index 00000000000..337c6112d66 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch @@ -0,0 +1,79 @@ +From 0e37ad71b2ff772009595002da2860999e98e14e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:12 +0100 +Subject: [PATCH 09/12] net: mtk_eth_soc: move MAC_MCR setting to mac_finish() + +Move the setting of the MTK_MAC_MCR register from the end of mac_config +into the phylink mac_finish() method, to keep it as the very last write +that is done during configuration. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++------- + 1 file changed, 22 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -316,8 +316,8 @@ static void mtk_mac_config(struct phylin + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + struct mtk_eth *eth = mac->hw; +- u32 mcr_cur, mcr_new, sid, i; + int val, ge_mode, err = 0; ++ u32 sid, i; + + /* MT76x8 has no hardware settings between for the MAC */ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +@@ -455,6 +455,25 @@ static void mtk_mac_config(struct phylin + return; + } + ++ return; ++ ++err_phy: ++ dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, ++ mac->id, phy_modes(state->interface)); ++ return; ++ ++init_err: ++ dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, ++ mac->id, phy_modes(state->interface), err); ++} ++ ++static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ u32 mcr_cur, mcr_new; ++ + /* Setup gmac */ + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur; +@@ -466,16 +485,7 @@ static void mtk_mac_config(struct phylin + if (mcr_new != mcr_cur) + mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); + +- return; +- +-err_phy: +- dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, +- mac->id, phy_modes(state->interface)); +- return; +- +-init_err: +- dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, +- mac->id, phy_modes(state->interface), err); ++ return 0; + } + + static void mtk_mac_pcs_get_state(struct phylink_config *config, +@@ -582,6 +592,7 @@ static const struct phylink_mac_ops mtk_ + .mac_pcs_get_state = mtk_mac_pcs_get_state, + .mac_an_restart = mtk_mac_an_restart, + .mac_config = mtk_mac_config, ++ .mac_finish = mtk_mac_finish, + .mac_link_down = mtk_mac_link_down, + .mac_link_up = mtk_mac_link_up, + }; diff --git a/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch b/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch new file mode 100644 index 00000000000..b03ef436bdb --- /dev/null +++ b/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch @@ -0,0 +1,57 @@ +From 21089867278deb2a110b685e3cd33f64f9ce41e2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:17 +0100 +Subject: [PATCH 10/12] net: mtk_eth_soc: move restoration of SYSCFG0 to + mac_finish() + +The SGMIISYS configuration is performed while ETHSYS_SYSCFG0 is in a +disabled state. In order to preserve this when we switch to phylink_pcs +we need to move the restoration of this register to the mac_finish() +callback. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + 2 files changed, 10 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -447,8 +447,8 @@ static void mtk_mac_config(struct phylin + if (err) + goto init_err; + +- regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, +- SYSCFG0_SGMII_MASK, val); ++ /* Save the syscfg0 value for mac_finish */ ++ mac->syscfg0 = val; + } else if (phylink_autoneg_inband(mode)) { + dev_err(eth->dev, + "In-band mode not supported in non SGMII mode!\n"); +@@ -472,8 +472,15 @@ static int mtk_mac_finish(struct phylink + { + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); ++ struct mtk_eth *eth = mac->hw; + u32 mcr_cur, mcr_new; + ++ /* Enable SGMII */ ++ if (interface == PHY_INTERFACE_MODE_SGMII || ++ phy_interface_mode_is_8023z(interface)) ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, mac->syscfg0); ++ + /* Setup gmac */ + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1088,6 +1088,7 @@ struct mtk_mac { + struct mtk_hw_stats *hw_stats; + __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; + int hwlro_ip_cnt; ++ unsigned int syscfg0; + }; + + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ diff --git a/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch b/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch new file mode 100644 index 00000000000..4c84703cd94 --- /dev/null +++ b/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch @@ -0,0 +1,254 @@ +From 901f3fbe13c3e56f0742e02717ccbfabbc95c463 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:22 +0100 +Subject: [PATCH 11/12] net: mtk_eth_soc: convert code structure to suit split + PCS support + +Provide a mtk_pcs structure which encapsulates everything that the PCS +functions need (the regmap and ana_rgc3 offset), and use this in the +PCS functions. Provide shim functions to convert from the existing +"mtk_sgmii_*" interface to the converted PCS functions. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 123 +++++++++++--------- + 2 files changed, 79 insertions(+), 59 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -959,16 +959,23 @@ struct mtk_soc_data { + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + +-/* struct mtk_sgmii - This is the structure holding sgmii regmap and its +- * characteristics ++/* struct mtk_pcs - This structure holds each sgmii regmap and associated ++ * data + * @regmap: The register map pointing at the range used to setup + * SGMII modes + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + */ ++struct mtk_pcs { ++ struct regmap *regmap; ++ u32 ana_rgc3; ++}; + ++/* struct mtk_sgmii - This is the structure holding sgmii regmap and its ++ * characteristics ++ * @pcs Array of individual PCS structures ++ */ + struct mtk_sgmii { +- struct regmap *regmap[MTK_MAX_DEVS]; +- u32 ana_rgc3; ++ struct mtk_pcs pcs[MTK_MAX_DEVS]; + }; + + /* struct mtk_eth - This is the main datasructure for holding the state +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -9,90 +9,71 @@ + + #include + #include ++#include + #include + + #include "mtk_eth_soc.h" + +-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) +-{ +- struct device_node *np; +- int i; +- +- ss->ana_rgc3 = ana_rgc3; +- +- for (i = 0; i < MTK_MAX_DEVS; i++) { +- np = of_parse_phandle(r, "mediatek,sgmiisys", i); +- if (!np) +- break; +- +- ss->regmap[i] = syscon_node_to_regmap(np); +- of_node_put(np); +- if (IS_ERR(ss->regmap[i])) +- return PTR_ERR(ss->regmap[i]); +- } +- +- return 0; +-} +- + /* For SGMII interface mode */ +-static int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) ++static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { + unsigned int val; + +- if (!ss->regmap[id]) ++ if (!mpcs->regmap) + return -EINVAL; + + /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, + SGMII_LINK_TIMER_DEFAULT); + +- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); ++ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); + val |= SGMII_REMOTE_FAULT_DIS; +- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); + +- regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); + val |= SGMII_AN_RESTART; +- regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); ++ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); + +- regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); ++ regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; +- regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); + + return 0; ++ + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a + * fixed speed. + */ +-static int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, +- phy_interface_t interface) ++static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, ++ phy_interface_t interface) + { + unsigned int val; + +- if (!ss->regmap[id]) ++ if (!mpcs->regmap) + return -EINVAL; + +- regmap_read(ss->regmap[id], ss->ana_rgc3, &val); ++ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); + val &= ~RG_PHY_SPEED_MASK; + if (interface == PHY_INTERFACE_MODE_2500BASEX) + val |= RG_PHY_SPEED_3_125G; +- regmap_write(ss->regmap[id], ss->ana_rgc3, val); ++ regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); + + /* Disable SGMII AN */ +- regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); + val &= ~SGMII_AN_ENABLE; +- regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); ++ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); + + /* Set the speed etc but leave the duplex unchanged */ +- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); ++ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); + val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; + val |= SGMII_SPEED_1000; +- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); + + /* Release PHYA power down state */ +- regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); ++ regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; +- regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); + + return 0; + } +@@ -100,44 +81,76 @@ static int mtk_sgmii_setup_mode_force(st + int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, + phy_interface_t interface) + { ++ struct mtk_pcs *mpcs = &ss->pcs[id]; + int err = 0; + + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) +- err = mtk_sgmii_setup_mode_force(ss, id, interface); ++ err = mtk_pcs_setup_mode_force(mpcs, interface); + else if (phylink_autoneg_inband(mode)) +- err = mtk_sgmii_setup_mode_an(ss, id); ++ err = mtk_pcs_setup_mode_an(mpcs); + + return err; + } + +-/* For 1000BASE-X and 2500BASE-X interface modes */ +-void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) ++static void mtk_pcs_restart_an(struct mtk_pcs *mpcs) ++{ ++ unsigned int val; ++ ++ if (!mpcs->regmap) ++ return; ++ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); ++ val |= SGMII_AN_RESTART; ++ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); ++} ++ ++static void mtk_pcs_link_up(struct mtk_pcs *mpcs, int speed, int duplex) + { + unsigned int val; + + /* SGMII force duplex setting */ +- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); ++ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); + val &= ~SGMII_DUPLEX_FULL; + if (duplex == DUPLEX_FULL) + val |= SGMII_DUPLEX_FULL; + +- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); ++ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); ++} ++ ++/* For 1000BASE-X and 2500BASE-X interface modes */ ++void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) ++{ ++ mtk_pcs_link_up(&ss->pcs[id], speed, duplex); ++} ++ ++int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) ++{ ++ struct device_node *np; ++ int i; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ np = of_parse_phandle(r, "mediatek,sgmiisys", i); ++ if (!np) ++ break; ++ ++ ss->pcs[i].ana_rgc3 = ana_rgc3; ++ ss->pcs[i].regmap = syscon_node_to_regmap(np); ++ of_node_put(np); ++ if (IS_ERR(ss->pcs[i].regmap)) ++ return PTR_ERR(ss->pcs[i].regmap); ++ } ++ ++ return 0; + } + + void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) + { +- struct mtk_sgmii *ss = eth->sgmii; +- unsigned int val, sid; ++ unsigned int sid; + + /* Decide how GMAC and SGMIISYS be mapped */ + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? + 0 : mac_id; + +- if (!ss->regmap[sid]) +- return; +- +- regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val); ++ mtk_pcs_restart_an(ð->sgmii->pcs[sid]); + } diff --git a/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch new file mode 100644 index 00000000000..b585867935e --- /dev/null +++ b/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch @@ -0,0 +1,262 @@ +From 14a44ab0330d290fade1403a920e299cc56d7300 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Wed, 18 May 2022 15:55:28 +0100 +Subject: [PATCH 12/12] net: mtk_eth_soc: partially convert to phylink_pcs + +Partially convert mtk_eth_soc to phylink_pcs, moving the configuration, +link up and AN restart over. However, it seems mac_pcs_get_state() +doesn't actually get the state from the PCS, so we can't convert that +over without a better understanding of the hardware. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 49 ++++++++---------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 ++- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 55 +++++++++++---------- + 3 files changed, 53 insertions(+), 58 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -310,6 +310,25 @@ static void mtk_gmac0_rgmii_adjust(struc + mtk_w32(eth, val, TRGMII_TCK_CTRL); + } + ++static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, ++ phy_interface_t interface) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ struct mtk_eth *eth = mac->hw; ++ unsigned int sid; ++ ++ if (interface == PHY_INTERFACE_MODE_SGMII || ++ phy_interface_mode_is_8023z(interface)) { ++ sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? ++ 0 : mac->id; ++ ++ return mtk_sgmii_select_pcs(eth->sgmii, sid); ++ } ++ ++ return NULL; ++} ++ + static void mtk_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) + { +@@ -317,7 +336,7 @@ static void mtk_mac_config(struct phylin + phylink_config); + struct mtk_eth *eth = mac->hw; + int val, ge_mode, err = 0; +- u32 sid, i; ++ u32 i; + + /* MT76x8 has no hardware settings between for the MAC */ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +@@ -438,15 +457,6 @@ static void mtk_mac_config(struct phylin + SYSCFG0_SGMII_MASK, + ~(u32)SYSCFG0_SGMII_MASK); + +- /* Decide how GMAC and SGMIISYS be mapped */ +- sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? +- 0 : mac->id; +- +- /* Setup SGMIISYS with the determined property */ +- err = mtk_sgmii_config(eth->sgmii, sid, mode, state->interface); +- if (err) +- goto init_err; +- + /* Save the syscfg0 value for mac_finish */ + mac->syscfg0 = val; + } else if (phylink_autoneg_inband(mode)) { +@@ -527,14 +537,6 @@ static void mtk_mac_pcs_get_state(struct + state->pause |= MLO_PAUSE_TX; + } + +-static void mtk_mac_an_restart(struct phylink_config *config) +-{ +- struct mtk_mac *mac = container_of(config, struct mtk_mac, +- phylink_config); +- +- mtk_sgmii_restart_an(mac->hw, mac->id); +-} +- + static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) + { +@@ -555,15 +557,6 @@ static void mtk_mac_link_up(struct phyli + phylink_config); + u32 mcr; + +- if (phy_interface_mode_is_8023z(interface)) { +- struct mtk_eth *eth = mac->hw; +- +- /* Decide how GMAC and SGMIISYS be mapped */ +- int sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? +- 0 : mac->id; +- mtk_sgmii_link_up(eth->sgmii, sid, speed, duplex); +- } +- + mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | + MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | +@@ -596,8 +589,8 @@ static void mtk_mac_link_up(struct phyli + + static const struct phylink_mac_ops mtk_phylink_ops = { + .validate = phylink_generic_validate, ++ .mac_select_pcs = mtk_mac_select_pcs, + .mac_pcs_get_state = mtk_mac_pcs_get_state, +- .mac_an_restart = mtk_mac_an_restart, + .mac_config = mtk_mac_config, + .mac_finish = mtk_mac_finish, + .mac_link_down = mtk_mac_link_down, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -964,10 +964,12 @@ struct mtk_soc_data { + * @regmap: The register map pointing at the range used to setup + * SGMII modes + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap ++ * @pcs: Phylink PCS structure + */ + struct mtk_pcs { + struct regmap *regmap; + u32 ana_rgc3; ++ struct phylink_pcs pcs; + }; + + /* struct mtk_sgmii - This is the structure holding sgmii regmap and its +@@ -1107,12 +1109,9 @@ void mtk_stats_update_mac(struct mtk_mac + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + ++struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id); + int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, + u32 ana_rgc3); +-int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, +- phy_interface_t interface); +-void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); +-void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); + + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -14,14 +14,16 @@ + + #include "mtk_eth_soc.h" + ++static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mtk_pcs, pcs); ++} ++ + /* For SGMII interface mode */ + static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { + unsigned int val; + +- if (!mpcs->regmap) +- return -EINVAL; +- + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, + SGMII_LINK_TIMER_DEFAULT); +@@ -50,9 +52,6 @@ static int mtk_pcs_setup_mode_force(stru + { + unsigned int val; + +- if (!mpcs->regmap) +- return -EINVAL; +- + regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); + val &= ~RG_PHY_SPEED_MASK; + if (interface == PHY_INTERFACE_MODE_2500BASEX) +@@ -78,10 +77,12 @@ static int mtk_pcs_setup_mode_force(stru + return 0; + } + +-int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, +- phy_interface_t interface) ++static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) + { +- struct mtk_pcs *mpcs = &ss->pcs[id]; ++ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + int err = 0; + + /* Setup SGMIISYS with the determined property */ +@@ -93,22 +94,25 @@ int mtk_sgmii_config(struct mtk_sgmii *s + return err; + } + +-static void mtk_pcs_restart_an(struct mtk_pcs *mpcs) ++static void mtk_pcs_restart_an(struct phylink_pcs *pcs) + { ++ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int val; + +- if (!mpcs->regmap) +- return; +- + regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); + val |= SGMII_AN_RESTART; + regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); + } + +-static void mtk_pcs_link_up(struct mtk_pcs *mpcs, int speed, int duplex) ++static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, int speed, int duplex) + { ++ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int val; + ++ if (!phy_interface_mode_is_8023z(interface)) ++ return; ++ + /* SGMII force duplex setting */ + regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); + val &= ~SGMII_DUPLEX_FULL; +@@ -118,11 +122,11 @@ static void mtk_pcs_link_up(struct mtk_p + regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); + } + +-/* For 1000BASE-X and 2500BASE-X interface modes */ +-void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) +-{ +- mtk_pcs_link_up(&ss->pcs[id], speed, duplex); +-} ++static const struct phylink_pcs_ops mtk_pcs_ops = { ++ .pcs_config = mtk_pcs_config, ++ .pcs_an_restart = mtk_pcs_restart_an, ++ .pcs_link_up = mtk_pcs_link_up, ++}; + + int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) + { +@@ -139,18 +143,17 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + of_node_put(np); + if (IS_ERR(ss->pcs[i].regmap)) + return PTR_ERR(ss->pcs[i].regmap); ++ ++ ss->pcs[i].pcs.ops = &mtk_pcs_ops; + } + + return 0; + } + +-void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) ++struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) + { +- unsigned int sid; +- +- /* Decide how GMAC and SGMIISYS be mapped */ +- sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? +- 0 : mac_id; ++ if (!ss->pcs[id].regmap) ++ return NULL; + +- mtk_pcs_restart_an(ð->sgmii->pcs[sid]); ++ return &ss->pcs[id].pcs; + } diff --git a/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch b/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch new file mode 100644 index 00000000000..4142fd1d508 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch @@ -0,0 +1,106 @@ +From 505560028b6deb9b4385cf6100f05ca6f4aacaf8 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Mon, 6 Dec 2021 18:57:49 +0200 +Subject: [PATCH 01/13] net: dsa: mt7530: iterate using + dsa_switch_for_each_user_port in bridging ops + +Avoid repeated calls to dsa_to_port() (some hidden behind dsa_is_user_port +and some in plain sight) by keeping two struct dsa_port references: one +to the port passed as argument, and another to the other ports of the +switch that we're iterating over. + +dsa_to_port(ds, i) gets replaced by other_dp, i gets replaced by +other_port which is derived from other_dp->index, dsa_is_user_port is +handled by the DSA iterator. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530.c | 52 +++++++++++++++++++++++----------------- + 1 file changed, 30 insertions(+), 22 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1190,27 +1190,31 @@ static int + mt7530_port_bridge_join(struct dsa_switch *ds, int port, + struct net_device *bridge) + { +- struct mt7530_priv *priv = ds->priv; ++ struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; + u32 port_bitmap = BIT(MT7530_CPU_PORT); +- int i; ++ struct mt7530_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); + +- for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ dsa_switch_for_each_user_port(other_dp, ds) { ++ int other_port = other_dp->index; ++ ++ if (dp == other_dp) ++ continue; ++ + /* Add this port to the port matrix of the other ports in the + * same bridge. If the port is disabled, port matrix is kept + * and not being setup until the port becomes enabled. + */ +- if (dsa_is_user_port(ds, i) && i != port) { +- if (dsa_to_port(ds, i)->bridge_dev != bridge) +- continue; +- if (priv->ports[i].enable) +- mt7530_set(priv, MT7530_PCR_P(i), +- PCR_MATRIX(BIT(port))); +- priv->ports[i].pm |= PCR_MATRIX(BIT(port)); ++ if (other_dp->bridge_dev != bridge) ++ continue; + +- port_bitmap |= BIT(i); +- } ++ if (priv->ports[other_port].enable) ++ mt7530_set(priv, MT7530_PCR_P(other_port), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[other_port].pm |= PCR_MATRIX(BIT(port)); ++ ++ port_bitmap |= BIT(other_port); + } + + /* Add the all other ports to this port matrix. */ +@@ -1315,24 +1319,28 @@ static void + mt7530_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *bridge) + { ++ struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; + struct mt7530_priv *priv = ds->priv; +- int i; + + mutex_lock(&priv->reg_mutex); + +- for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ dsa_switch_for_each_user_port(other_dp, ds) { ++ int other_port = other_dp->index; ++ ++ if (dp == other_dp) ++ continue; ++ + /* Remove this port from the port matrix of the other ports + * in the same bridge. If the port is disabled, port matrix + * is kept and not being setup until the port becomes enabled. + */ +- if (dsa_is_user_port(ds, i) && i != port) { +- if (dsa_to_port(ds, i)->bridge_dev != bridge) +- continue; +- if (priv->ports[i].enable) +- mt7530_clear(priv, MT7530_PCR_P(i), +- PCR_MATRIX(BIT(port))); +- priv->ports[i].pm &= ~PCR_MATRIX(BIT(port)); +- } ++ if (other_dp->bridge_dev != bridge) ++ continue; ++ ++ if (priv->ports[other_port].enable) ++ mt7530_clear(priv, MT7530_PCR_P(other_port), ++ PCR_MATRIX(BIT(port))); ++ priv->ports[other_port].pm &= ~PCR_MATRIX(BIT(port)); + } + + /* Set the cpu port to be the only one in the port matrix of diff --git a/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch b/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch new file mode 100644 index 00000000000..435f282845f --- /dev/null +++ b/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch @@ -0,0 +1,166 @@ +From a1da54bcd664fc27169386db966575675ac3ccb0 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:01 +0100 +Subject: [PATCH 02/13] net: dsa: mt7530: populate supported_interfaces and + mac_capabilities +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Populate the supported interfaces and MAC capabilities for mt7530, +mt7531 and mt7621 DSA switches. Filling this in will enable phylink +to pre-check the PHY interface mode against the the supported +interfaces bitmap prior to calling the validate function, and will +eventually allow us to convert to using the generic validation. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 74 ++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.h | 2 ++ + 2 files changed, 76 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2412,6 +2412,32 @@ mt7531_setup(struct dsa_switch *ds) + return 0; + } + ++static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ switch (port) { ++ case 0 ... 4: /* Internal phy */ ++ __set_bit(PHY_INTERFACE_MODE_GMII, ++ config->supported_interfaces); ++ break; ++ ++ case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ ++ phy_interface_set_rgmii(config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_MII, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_GMII, ++ config->supported_interfaces); ++ break; ++ ++ case 6: /* 1st cpu port */ ++ __set_bit(PHY_INTERFACE_MODE_RGMII, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_TRGMII, ++ config->supported_interfaces); ++ break; ++ } ++} ++ + static bool + mt7530_phy_mode_supported(struct dsa_switch *ds, int port, + const struct phylink_link_state *state) +@@ -2448,6 +2474,37 @@ static bool mt7531_is_rgmii_port(struct + return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); + } + ++static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ switch (port) { ++ case 0 ... 4: /* Internal phy */ ++ __set_bit(PHY_INTERFACE_MODE_GMII, ++ config->supported_interfaces); ++ break; ++ ++ case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ ++ if (mt7531_is_rgmii_port(priv, port)) { ++ phy_interface_set_rgmii(config->supported_interfaces); ++ break; ++ } ++ fallthrough; ++ ++ case 6: /* 1st cpu port supports sgmii/8023z only */ ++ __set_bit(PHY_INTERFACE_MODE_SGMII, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_1000BASEX, ++ config->supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_2500BASEX, ++ config->supported_interfaces); ++ ++ config->mac_capabilities |= MAC_2500FD; ++ break; ++ } ++} ++ + static bool + mt7531_phy_mode_supported(struct dsa_switch *ds, int port, + const struct phylink_link_state *state) +@@ -2924,6 +2981,18 @@ mt7531_cpu_port_config(struct dsa_switch + return 0; + } + ++static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ /* This switch only supports full-duplex at 1Gbps */ ++ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | ++ MAC_10 | MAC_100 | MAC_1000FD; ++ ++ priv->info->mac_port_get_caps(ds, port, config); ++} ++ + static void + mt7530_mac_port_validate(struct dsa_switch *ds, int port, + unsigned long *supported) +@@ -3159,6 +3228,7 @@ static const struct dsa_switch_ops mt753 + .port_vlan_del = mt7530_port_vlan_del, + .port_mirror_add = mt753x_port_mirror_add, + .port_mirror_del = mt753x_port_mirror_del, ++ .phylink_get_caps = mt753x_phylink_get_caps, + .phylink_validate = mt753x_phylink_validate, + .phylink_mac_link_state = mt753x_phylink_mac_link_state, + .phylink_mac_config = mt753x_phylink_mac_config, +@@ -3176,6 +3246,7 @@ static const struct mt753x_info mt753x_t + .phy_read = mt7530_phy_read, + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, ++ .mac_port_get_caps = mt7530_mac_port_get_caps, + .phy_mode_supported = mt7530_phy_mode_supported, + .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, +@@ -3187,6 +3258,7 @@ static const struct mt753x_info mt753x_t + .phy_read = mt7530_phy_read, + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, ++ .mac_port_get_caps = mt7530_mac_port_get_caps, + .phy_mode_supported = mt7530_phy_mode_supported, + .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, +@@ -3199,6 +3271,7 @@ static const struct mt753x_info mt753x_t + .phy_write = mt7531_ind_phy_write, + .pad_setup = mt7531_pad_setup, + .cpu_port_config = mt7531_cpu_port_config, ++ .mac_port_get_caps = mt7531_mac_port_get_caps, + .phy_mode_supported = mt7531_phy_mode_supported, + .mac_port_validate = mt7531_mac_port_validate, + .mac_port_get_state = mt7531_phylink_mac_link_state, +@@ -3261,6 +3334,7 @@ mt7530_probe(struct mdio_device *mdiodev + */ + if (!priv->info->sw_setup || !priv->info->pad_setup || + !priv->info->phy_read || !priv->info->phy_write || ++ !priv->info->mac_port_get_caps || + !priv->info->phy_mode_supported || + !priv->info->mac_port_validate || + !priv->info->mac_port_get_state || !priv->info->mac_port_config) +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -769,6 +769,8 @@ struct mt753x_info { + int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val); + int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface); + int (*cpu_port_config)(struct dsa_switch *ds, int port); ++ void (*mac_port_get_caps)(struct dsa_switch *ds, int port, ++ struct phylink_config *config); + bool (*phy_mode_supported)(struct dsa_switch *ds, int port, + const struct phylink_link_state *state); + void (*mac_port_validate)(struct dsa_switch *ds, int port, diff --git a/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch b/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch new file mode 100644 index 00000000000..38a24dc46b0 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch @@ -0,0 +1,172 @@ +From e3f6719e2269868ca129b05da50cd55786848954 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:06 +0100 +Subject: [PATCH 03/13] net: dsa: mt7530: remove interface checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As phylink checks the interface mode against the supported_interfaces +bitmap, we no longer need to validate the interface mode, nor handle +PHY_INTERFACE_MODE_NA in the validation function. Remove these to +simplify the implementation. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 82 ---------------------------------------- + drivers/net/dsa/mt7530.h | 2 - + 2 files changed, 84 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2438,37 +2438,6 @@ static void mt7530_mac_port_get_caps(str + } + } + +-static bool +-mt7530_phy_mode_supported(struct dsa_switch *ds, int port, +- const struct phylink_link_state *state) +-{ +- struct mt7530_priv *priv = ds->priv; +- +- switch (port) { +- case 0 ... 4: /* Internal phy */ +- if (state->interface != PHY_INTERFACE_MODE_GMII) +- return false; +- break; +- case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ +- if (!phy_interface_mode_is_rgmii(state->interface) && +- state->interface != PHY_INTERFACE_MODE_MII && +- state->interface != PHY_INTERFACE_MODE_GMII) +- return false; +- break; +- case 6: /* 1st cpu port */ +- if (state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_TRGMII) +- return false; +- break; +- default: +- dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, +- port); +- return false; +- } +- +- return true; +-} +- + static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) + { + return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); +@@ -2505,44 +2474,6 @@ static void mt7531_mac_port_get_caps(str + } + } + +-static bool +-mt7531_phy_mode_supported(struct dsa_switch *ds, int port, +- const struct phylink_link_state *state) +-{ +- struct mt7530_priv *priv = ds->priv; +- +- switch (port) { +- case 0 ... 4: /* Internal phy */ +- if (state->interface != PHY_INTERFACE_MODE_GMII) +- return false; +- break; +- case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ +- if (mt7531_is_rgmii_port(priv, port)) +- return phy_interface_mode_is_rgmii(state->interface); +- fallthrough; +- case 6: /* 1st cpu port supports sgmii/8023z only */ +- if (state->interface != PHY_INTERFACE_MODE_SGMII && +- !phy_interface_mode_is_8023z(state->interface)) +- return false; +- break; +- default: +- dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, +- port); +- return false; +- } +- +- return true; +-} +- +-static bool +-mt753x_phy_mode_supported(struct dsa_switch *ds, int port, +- const struct phylink_link_state *state) +-{ +- struct mt7530_priv *priv = ds->priv; +- +- return priv->info->phy_mode_supported(ds, port, state); +-} +- + static int + mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) + { +@@ -2797,9 +2728,6 @@ mt753x_phylink_mac_config(struct dsa_swi + struct mt7530_priv *priv = ds->priv; + u32 mcr_cur, mcr_new; + +- if (!mt753x_phy_mode_supported(ds, port, state)) +- goto unsupported; +- + switch (port) { + case 0 ... 4: /* Internal phy */ + if (state->interface != PHY_INTERFACE_MODE_GMII) +@@ -3015,12 +2943,6 @@ mt753x_phylink_validate(struct dsa_switc + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + struct mt7530_priv *priv = ds->priv; + +- if (state->interface != PHY_INTERFACE_MODE_NA && +- !mt753x_phy_mode_supported(ds, port, state)) { +- linkmode_zero(supported); +- return; +- } +- + phylink_set_port_modes(mask); + + if (state->interface != PHY_INTERFACE_MODE_TRGMII && +@@ -3247,7 +3169,6 @@ static const struct mt753x_info mt753x_t + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .phy_mode_supported = mt7530_phy_mode_supported, + .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, +@@ -3259,7 +3180,6 @@ static const struct mt753x_info mt753x_t + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .phy_mode_supported = mt7530_phy_mode_supported, + .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, +@@ -3272,7 +3192,6 @@ static const struct mt753x_info mt753x_t + .pad_setup = mt7531_pad_setup, + .cpu_port_config = mt7531_cpu_port_config, + .mac_port_get_caps = mt7531_mac_port_get_caps, +- .phy_mode_supported = mt7531_phy_mode_supported, + .mac_port_validate = mt7531_mac_port_validate, + .mac_port_get_state = mt7531_phylink_mac_link_state, + .mac_port_config = mt7531_mac_config, +@@ -3335,7 +3254,6 @@ mt7530_probe(struct mdio_device *mdiodev + if (!priv->info->sw_setup || !priv->info->pad_setup || + !priv->info->phy_read || !priv->info->phy_write || + !priv->info->mac_port_get_caps || +- !priv->info->phy_mode_supported || + !priv->info->mac_port_validate || + !priv->info->mac_port_get_state || !priv->info->mac_port_config) + return -EINVAL; +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -771,8 +771,6 @@ struct mt753x_info { + int (*cpu_port_config)(struct dsa_switch *ds, int port); + void (*mac_port_get_caps)(struct dsa_switch *ds, int port, + struct phylink_config *config); +- bool (*phy_mode_supported)(struct dsa_switch *ds, int port, +- const struct phylink_link_state *state); + void (*mac_port_validate)(struct dsa_switch *ds, int port, + unsigned long *supported); + int (*mac_port_get_state)(struct dsa_switch *ds, int port, diff --git a/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch b/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch new file mode 100644 index 00000000000..e607a3c7d2c --- /dev/null +++ b/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch @@ -0,0 +1,34 @@ +From 58344a3b85f1bd5ffddfc2c11f6f2bf688b5f990 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:12 +0100 +Subject: [PATCH 04/13] net: dsa: mt7530: drop use of + phylink_helper_basex_speed() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that we have a better method to select SFP interface modes, we +no longer need to use phylink_helper_basex_speed() in a driver's +validation function. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 5 ----- + 1 file changed, 5 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2967,11 +2967,6 @@ mt753x_phylink_validate(struct dsa_switc + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); +- +- /* We can only operate at 2500BaseX or 1000BaseX. If requested +- * to advertise both, only report advertising at 2500BaseX. +- */ +- phylink_helper_basex_speed(state); + } + + static int diff --git a/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch b/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch new file mode 100644 index 00000000000..63a33176303 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch @@ -0,0 +1,86 @@ +From 3c1d788a62dc648d1846049b66119ebb69dedd52 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:17 +0100 +Subject: [PATCH 05/13] net: dsa: mt7530: only indicate linkmodes that can be + supported +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that mt7530 is not using the basex helper, it becomes unnecessary to +indicate support for both 1000baseX and 2500baseX when one of the 803.3z +PHY interface modes is being selected. Ensure that the driver indicates +only those linkmodes that can actually be supported by the PHY interface +mode. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 12 ++++++++---- + drivers/net/dsa/mt7530.h | 1 + + 2 files changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2545,12 +2545,13 @@ static int mt7531_rgmii_setup(struct mt7 + } + + static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, ++ phy_interface_t interface, + unsigned long *supported) + { + /* Port5 supports ethier RGMII or SGMII. + * Port6 supports SGMII only. + */ +- if (port == 6) { ++ if (port == 6 && interface == PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(supported, 2500baseX_Full); + phylink_set(supported, 2500baseT_Full); + } +@@ -2923,16 +2924,18 @@ static void mt753x_phylink_get_caps(stru + + static void + mt7530_mac_port_validate(struct dsa_switch *ds, int port, ++ phy_interface_t interface, + unsigned long *supported) + { + } + + static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, ++ phy_interface_t interface, + unsigned long *supported) + { + struct mt7530_priv *priv = ds->priv; + +- mt7531_sgmii_validate(priv, port, supported); ++ mt7531_sgmii_validate(priv, port, interface, supported); + } + + static void +@@ -2955,12 +2958,13 @@ mt753x_phylink_validate(struct dsa_switc + } + + /* This switch only supports 1G full-duplex. */ +- if (state->interface != PHY_INTERFACE_MODE_MII) { ++ if (state->interface != PHY_INTERFACE_MODE_MII && ++ state->interface != PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(mask, 1000baseT_Full); + phylink_set(mask, 1000baseX_Full); + } + +- priv->info->mac_port_validate(ds, port, mask); ++ priv->info->mac_port_validate(ds, port, state->interface, mask); + + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -772,6 +772,7 @@ struct mt753x_info { + void (*mac_port_get_caps)(struct dsa_switch *ds, int port, + struct phylink_config *config); + void (*mac_port_validate)(struct dsa_switch *ds, int port, ++ phy_interface_t interface, + unsigned long *supported); + int (*mac_port_get_state)(struct dsa_switch *ds, int port, + struct phylink_link_state *state); diff --git a/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch b/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch new file mode 100644 index 00000000000..97699d4c5e3 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch @@ -0,0 +1,131 @@ +From 1c2211cb15dd3957fb26c0e1615eceb5db851ad6 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:22 +0100 +Subject: [PATCH 06/13] net: dsa: mt7530: switch to use phylink_get_linkmodes() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Switch mt7530 to use phylink_get_linkmodes() to generate the ethtool +linkmodes that can be supported. We are unable to use the generic +helper for this as pause modes are dependent on the interface as +the Autoneg bit depends on the interface mode. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 57 ++++------------------------------------ + 1 file changed, 5 insertions(+), 52 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2544,19 +2544,6 @@ static int mt7531_rgmii_setup(struct mt7 + return 0; + } + +-static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, +- phy_interface_t interface, +- unsigned long *supported) +-{ +- /* Port5 supports ethier RGMII or SGMII. +- * Port6 supports SGMII only. +- */ +- if (port == 6 && interface == PHY_INTERFACE_MODE_2500BASEX) { +- phylink_set(supported, 2500baseX_Full); +- phylink_set(supported, 2500baseT_Full); +- } +-} +- + static void + mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, + unsigned int mode, phy_interface_t interface, +@@ -2923,51 +2910,21 @@ static void mt753x_phylink_get_caps(stru + } + + static void +-mt7530_mac_port_validate(struct dsa_switch *ds, int port, +- phy_interface_t interface, +- unsigned long *supported) +-{ +-} +- +-static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, +- phy_interface_t interface, +- unsigned long *supported) +-{ +- struct mt7530_priv *priv = ds->priv; +- +- mt7531_sgmii_validate(priv, port, interface, supported); +-} +- +-static void + mt753x_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) + { + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- struct mt7530_priv *priv = ds->priv; ++ u32 caps; ++ ++ caps = dsa_to_port(ds, port)->pl_config.mac_capabilities; + + phylink_set_port_modes(mask); ++ phylink_get_linkmodes(mask, state->interface, caps); + + if (state->interface != PHY_INTERFACE_MODE_TRGMII && +- !phy_interface_mode_is_8023z(state->interface)) { +- phylink_set(mask, 10baseT_Half); +- phylink_set(mask, 10baseT_Full); +- phylink_set(mask, 100baseT_Half); +- phylink_set(mask, 100baseT_Full); ++ !phy_interface_mode_is_8023z(state->interface)) + phylink_set(mask, Autoneg); +- } +- +- /* This switch only supports 1G full-duplex. */ +- if (state->interface != PHY_INTERFACE_MODE_MII && +- state->interface != PHY_INTERFACE_MODE_2500BASEX) { +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 1000baseX_Full); +- } +- +- priv->info->mac_port_validate(ds, port, state->interface, mask); +- +- phylink_set(mask, Pause); +- phylink_set(mask, Asym_Pause); + + linkmode_and(supported, supported, mask); + linkmode_and(state->advertising, state->advertising, mask); +@@ -3168,7 +3125,6 @@ static const struct mt753x_info mt753x_t + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, + }, +@@ -3179,7 +3135,6 @@ static const struct mt753x_info mt753x_t + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .mac_port_validate = mt7530_mac_port_validate, + .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, + }, +@@ -3191,7 +3146,6 @@ static const struct mt753x_info mt753x_t + .pad_setup = mt7531_pad_setup, + .cpu_port_config = mt7531_cpu_port_config, + .mac_port_get_caps = mt7531_mac_port_get_caps, +- .mac_port_validate = mt7531_mac_port_validate, + .mac_port_get_state = mt7531_phylink_mac_link_state, + .mac_port_config = mt7531_mac_config, + .mac_pcs_an_restart = mt7531_sgmii_restart_an, +@@ -3253,7 +3207,6 @@ mt7530_probe(struct mdio_device *mdiodev + if (!priv->info->sw_setup || !priv->info->pad_setup || + !priv->info->phy_read || !priv->info->phy_write || + !priv->info->mac_port_get_caps || +- !priv->info->mac_port_validate || + !priv->info->mac_port_get_state || !priv->info->mac_port_config) + return -EINVAL; + diff --git a/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch new file mode 100644 index 00000000000..b9b74833d22 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch @@ -0,0 +1,385 @@ +From fd993fd59d96d5e2d5972ec4ca1f9651025c987b Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:27 +0100 +Subject: [PATCH 07/13] net: dsa: mt7530: partially convert to phylink_pcs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Partially convert the mt7530 driver to use phylink's PCS support. This +is a partial implementation as we don't move anything into the +pcs_config method yet - this driver supports SGMII or 1000BASE-X +without in-band. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 144 +++++++++++++++++++++++---------------- + drivers/net/dsa/mt7530.h | 21 +++--- + 2 files changed, 95 insertions(+), 70 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -24,6 +24,11 @@ + + #include "mt7530.h" + ++static struct mt753x_pcs *pcs_to_mt753x_pcs(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mt753x_pcs, pcs); ++} ++ + /* String, offset, and register size in bytes if different from 4 bytes */ + static const struct mt7530_mib_desc mt7530_mib[] = { + MIB_DESC(1, 0x00, "TxDrop"), +@@ -2544,12 +2549,11 @@ static int mt7531_rgmii_setup(struct mt7 + return 0; + } + +-static void +-mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, +- unsigned int mode, phy_interface_t interface, +- int speed, int duplex) ++static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, int speed, int duplex) + { +- struct mt7530_priv *priv = ds->priv; ++ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; ++ int port = pcs_to_mt753x_pcs(pcs)->port; + unsigned int val; + + /* For adjusting speed and duplex of SGMII force mode. */ +@@ -2575,6 +2579,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw + + /* MT7531 SGMII 1G force mode can only work in full duplex mode, + * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. ++ * ++ * The speed check is unnecessary as the MAC capabilities apply ++ * this restriction. --rmk + */ + if ((speed == SPEED_10 || speed == SPEED_100) && + duplex != DUPLEX_FULL) +@@ -2650,9 +2657,10 @@ static int mt7531_sgmii_setup_mode_an(st + return 0; + } + +-static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port) ++static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) + { +- struct mt7530_priv *priv = ds->priv; ++ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; ++ int port = pcs_to_mt753x_pcs(pcs)->port; + u32 val; + + /* Only restart AN when AN is enabled */ +@@ -2709,6 +2717,24 @@ mt753x_mac_config(struct dsa_switch *ds, + return priv->info->mac_port_config(ds, port, mode, state->interface); + } + ++static struct phylink_pcs * ++mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port, ++ phy_interface_t interface) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_TRGMII: ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return &priv->pcs[port].pcs; ++ ++ default: ++ return NULL; ++ } ++} ++ + static void + mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, + const struct phylink_link_state *state) +@@ -2770,17 +2796,6 @@ unsupported: + mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); + } + +-static void +-mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port) +-{ +- struct mt7530_priv *priv = ds->priv; +- +- if (!priv->info->mac_pcs_an_restart) +- return; +- +- priv->info->mac_pcs_an_restart(ds, port); +-} +- + static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface) +@@ -2790,16 +2805,13 @@ static void mt753x_phylink_mac_link_down + mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); + } + +-static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port, +- unsigned int mode, phy_interface_t interface, +- int speed, int duplex) ++static void mt753x_phylink_pcs_link_up(struct phylink_pcs *pcs, ++ unsigned int mode, ++ phy_interface_t interface, ++ int speed, int duplex) + { +- struct mt7530_priv *priv = ds->priv; +- +- if (!priv->info->mac_pcs_link_up) +- return; +- +- priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex); ++ if (pcs->ops->pcs_link_up) ++ pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex); + } + + static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, +@@ -2812,8 +2824,6 @@ static void mt753x_phylink_mac_link_up(s + struct mt7530_priv *priv = ds->priv; + u32 mcr; + +- mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex); +- + mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; + + /* MT753x MAC works in 1G full duplex mode for all up-clocked +@@ -2891,6 +2901,8 @@ mt7531_cpu_port_config(struct dsa_switch + return ret; + mt7530_write(priv, MT7530_PMCR_P(port), + PMCR_CPU_PORT_SETTING(priv->id)); ++ mt753x_phylink_pcs_link_up(&priv->pcs[port].pcs, MLO_AN_FIXED, ++ interface, speed, DUPLEX_FULL); + mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, + speed, DUPLEX_FULL, true, true); + +@@ -2930,16 +2942,13 @@ mt753x_phylink_validate(struct dsa_switc + linkmode_and(state->advertising, state->advertising, mask); + } + +-static int +-mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port, +- struct phylink_link_state *state) ++static void mt7530_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) + { +- struct mt7530_priv *priv = ds->priv; ++ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; ++ int port = pcs_to_mt753x_pcs(pcs)->port; + u32 pmsr; + +- if (port < 0 || port >= MT7530_NUM_PORTS) +- return -EINVAL; +- + pmsr = mt7530_read(priv, MT7530_PMSR_P(port)); + + state->link = (pmsr & PMSR_LINK); +@@ -2966,8 +2975,6 @@ mt7530_phylink_mac_link_state(struct dsa + state->pause |= MLO_PAUSE_RX; + if (pmsr & PMSR_TX_FC) + state->pause |= MLO_PAUSE_TX; +- +- return 1; + } + + static int +@@ -3009,32 +3016,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 + return 0; + } + +-static int +-mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port, +- struct phylink_link_state *state) ++static void mt7531_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) + { +- struct mt7530_priv *priv = ds->priv; ++ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; ++ int port = pcs_to_mt753x_pcs(pcs)->port; + + if (state->interface == PHY_INTERFACE_MODE_SGMII) +- return mt7531_sgmii_pcs_get_state_an(priv, port, state); +- +- return -EOPNOTSUPP; ++ mt7531_sgmii_pcs_get_state_an(priv, port, state); ++ else ++ state->link = false; + } + +-static int +-mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port, +- struct phylink_link_state *state) ++static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) + { +- struct mt7530_priv *priv = ds->priv; ++ return 0; ++} + +- return priv->info->mac_port_get_state(ds, port, state); ++static void mt7530_pcs_an_restart(struct phylink_pcs *pcs) ++{ + } + ++static const struct phylink_pcs_ops mt7530_pcs_ops = { ++ .pcs_get_state = mt7530_pcs_get_state, ++ .pcs_config = mt753x_pcs_config, ++ .pcs_an_restart = mt7530_pcs_an_restart, ++}; ++ ++static const struct phylink_pcs_ops mt7531_pcs_ops = { ++ .pcs_get_state = mt7531_pcs_get_state, ++ .pcs_config = mt753x_pcs_config, ++ .pcs_an_restart = mt7531_pcs_an_restart, ++ .pcs_link_up = mt7531_pcs_link_up, ++}; ++ + static int + mt753x_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; + int ret = priv->info->sw_setup(ds); ++ int i; + + if (ret) + return ret; +@@ -3047,6 +3071,13 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + ++ /* Initialise the PCS devices */ ++ for (i = 0; i < priv->ds->num_ports; i++) { ++ priv->pcs[i].pcs.ops = priv->info->pcs_ops; ++ priv->pcs[i].priv = priv; ++ priv->pcs[i].port = i; ++ } ++ + return ret; + } + +@@ -3108,9 +3139,8 @@ static const struct dsa_switch_ops mt753 + .port_mirror_del = mt753x_port_mirror_del, + .phylink_get_caps = mt753x_phylink_get_caps, + .phylink_validate = mt753x_phylink_validate, +- .phylink_mac_link_state = mt753x_phylink_mac_link_state, ++ .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs, + .phylink_mac_config = mt753x_phylink_mac_config, +- .phylink_mac_an_restart = mt753x_phylink_mac_an_restart, + .phylink_mac_link_down = mt753x_phylink_mac_link_down, + .phylink_mac_link_up = mt753x_phylink_mac_link_up, + .get_mac_eee = mt753x_get_mac_eee, +@@ -3120,36 +3150,34 @@ static const struct dsa_switch_ops mt753 + static const struct mt753x_info mt753x_table[] = { + [ID_MT7621] = { + .id = ID_MT7621, ++ .pcs_ops = &mt7530_pcs_ops, + .sw_setup = mt7530_setup, + .phy_read = mt7530_phy_read, + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, + }, + [ID_MT7530] = { + .id = ID_MT7530, ++ .pcs_ops = &mt7530_pcs_ops, + .sw_setup = mt7530_setup, + .phy_read = mt7530_phy_read, + .phy_write = mt7530_phy_write, + .pad_setup = mt7530_pad_clk_setup, + .mac_port_get_caps = mt7530_mac_port_get_caps, +- .mac_port_get_state = mt7530_phylink_mac_link_state, + .mac_port_config = mt7530_mac_config, + }, + [ID_MT7531] = { + .id = ID_MT7531, ++ .pcs_ops = &mt7531_pcs_ops, + .sw_setup = mt7531_setup, + .phy_read = mt7531_ind_phy_read, + .phy_write = mt7531_ind_phy_write, + .pad_setup = mt7531_pad_setup, + .cpu_port_config = mt7531_cpu_port_config, + .mac_port_get_caps = mt7531_mac_port_get_caps, +- .mac_port_get_state = mt7531_phylink_mac_link_state, + .mac_port_config = mt7531_mac_config, +- .mac_pcs_an_restart = mt7531_sgmii_restart_an, +- .mac_pcs_link_up = mt7531_sgmii_link_up_force, + }, + }; + +@@ -3207,7 +3235,7 @@ mt7530_probe(struct mdio_device *mdiodev + if (!priv->info->sw_setup || !priv->info->pad_setup || + !priv->info->phy_read || !priv->info->phy_write || + !priv->info->mac_port_get_caps || +- !priv->info->mac_port_get_state || !priv->info->mac_port_config) ++ !priv->info->mac_port_config) + return -EINVAL; + + priv->id = priv->info->id; +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -741,6 +741,12 @@ static const char *p5_intf_modes(unsigne + + struct mt7530_priv; + ++struct mt753x_pcs { ++ struct phylink_pcs pcs; ++ struct mt7530_priv *priv; ++ int port; ++}; ++ + /* struct mt753x_info - This is the main data structure for holding the specific + * part for each supported device + * @sw_setup: Holding the handler to a device initialization +@@ -752,18 +758,14 @@ struct mt7530_priv; + * port + * @mac_port_validate: Holding the way to set addition validate type for a + * certan MAC port +- * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain +- * MAC port + * @mac_port_config: Holding the way setting up the PHY attribute to a + * certain MAC port +- * @mac_pcs_an_restart Holding the way restarting PCS autonegotiation for a +- * certain MAC port +- * @mac_pcs_link_up: Holding the way setting up the PHY attribute to the pcs +- * of the certain MAC port + */ + struct mt753x_info { + enum mt753x_id id; + ++ const struct phylink_pcs_ops *pcs_ops; ++ + int (*sw_setup)(struct dsa_switch *ds); + int (*phy_read)(struct mt7530_priv *priv, int port, int regnum); + int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val); +@@ -774,15 +776,9 @@ struct mt753x_info { + void (*mac_port_validate)(struct dsa_switch *ds, int port, + phy_interface_t interface, + unsigned long *supported); +- int (*mac_port_get_state)(struct dsa_switch *ds, int port, +- struct phylink_link_state *state); + int (*mac_port_config)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface); +- void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port); +- void (*mac_pcs_link_up)(struct dsa_switch *ds, int port, +- unsigned int mode, phy_interface_t interface, +- int speed, int duplex); + }; + + /* struct mt7530_priv - This is the main data structure for holding the state +@@ -824,6 +820,7 @@ struct mt7530_priv { + u8 mirror_tx; + + struct mt7530_port ports[MT7530_NUM_PORTS]; ++ struct mt753x_pcs pcs[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ + struct mutex reg_mutex; + int irq; diff --git a/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch b/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch new file mode 100644 index 00000000000..4aa013aad79 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch @@ -0,0 +1,80 @@ +From 2b0ee6768f3ac09072e5fd60b36580924e1cfa1c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:32 +0100 +Subject: [PATCH 08/13] net: dsa: mt7530: move autoneg handling to PCS + validation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Move the autoneg bit handling to the PCS validation, which allows us to +get rid of mt753x_phylink_validate() and rely on the default +phylink_generic_validate() implementation for the MAC side. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 28 ++++++++++------------------ + 1 file changed, 10 insertions(+), 18 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2921,25 +2921,16 @@ static void mt753x_phylink_get_caps(stru + priv->info->mac_port_get_caps(ds, port, config); + } + +-static void +-mt753x_phylink_validate(struct dsa_switch *ds, int port, +- unsigned long *supported, +- struct phylink_link_state *state) +-{ +- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- u32 caps; +- +- caps = dsa_to_port(ds, port)->pl_config.mac_capabilities; +- +- phylink_set_port_modes(mask); +- phylink_get_linkmodes(mask, state->interface, caps); ++static int mt753x_pcs_validate(struct phylink_pcs *pcs, ++ unsigned long *supported, ++ const struct phylink_link_state *state) ++{ ++ /* Autonegotiation is not supported in TRGMII nor 802.3z modes */ ++ if (state->interface == PHY_INTERFACE_MODE_TRGMII || ++ phy_interface_mode_is_8023z(state->interface)) ++ phylink_clear(supported, Autoneg); + +- if (state->interface != PHY_INTERFACE_MODE_TRGMII && +- !phy_interface_mode_is_8023z(state->interface)) +- phylink_set(mask, Autoneg); +- +- linkmode_and(supported, supported, mask); +- linkmode_and(state->advertising, state->advertising, mask); ++ return 0; + } + + static void mt7530_pcs_get_state(struct phylink_pcs *pcs, +@@ -3041,12 +3032,14 @@ static void mt7530_pcs_an_restart(struct + } + + static const struct phylink_pcs_ops mt7530_pcs_ops = { ++ .pcs_validate = mt753x_pcs_validate, + .pcs_get_state = mt7530_pcs_get_state, + .pcs_config = mt753x_pcs_config, + .pcs_an_restart = mt7530_pcs_an_restart, + }; + + static const struct phylink_pcs_ops mt7531_pcs_ops = { ++ .pcs_validate = mt753x_pcs_validate, + .pcs_get_state = mt7531_pcs_get_state, + .pcs_config = mt753x_pcs_config, + .pcs_an_restart = mt7531_pcs_an_restart, +@@ -3138,7 +3131,6 @@ static const struct dsa_switch_ops mt753 + .port_mirror_add = mt753x_port_mirror_add, + .port_mirror_del = mt753x_port_mirror_del, + .phylink_get_caps = mt753x_phylink_get_caps, +- .phylink_validate = mt753x_phylink_validate, + .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs, + .phylink_mac_config = mt753x_phylink_mac_config, + .phylink_mac_link_down = mt753x_phylink_mac_link_down, diff --git a/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch b/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch new file mode 100644 index 00000000000..d921d78733d --- /dev/null +++ b/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch @@ -0,0 +1,34 @@ +From 5bc26de9bfaa6bb5539c09d4435dced98f429cfc Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 11 Apr 2022 10:46:37 +0100 +Subject: [PATCH 09/13] net: dsa: mt7530: mark as non-legacy +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The mt7530 driver does not make use of the speed, duplex, pause or +advertisement in its phylink_mac_config() implementation, so it can be +marked as a non-legacy driver. + +Tested-by: Marek Behún +Signed-off-by: Russell King (Oracle) +Signed-off-by: Paolo Abeni +--- + drivers/net/dsa/mt7530.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2918,6 +2918,12 @@ static void mt753x_phylink_get_caps(stru + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000FD; + ++ /* This driver does not make use of the speed, duplex, pause or the ++ * advertisement in its mac_config, so it is safe to mark this driver ++ * as non-legacy. ++ */ ++ config->legacy_pre_march2020 = false; ++ + priv->info->mac_port_get_caps(ds, port, config); + } + diff --git a/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch b/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch new file mode 100644 index 00000000000..e797b1ecb42 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch @@ -0,0 +1,116 @@ +From 1f15b5e8733115cee65342bcaafeaf0368809fae Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 25 Apr 2022 22:28:02 +0100 +Subject: [PATCH 10/13] net: dsa: mt753x: fix pcs conversion regression + +Daniel Golle reports that the conversion of mt753x to phylink PCS caused +an oops as below. + +The problem is with the placement of the PCS initialisation, which +occurs after mt7531_setup() has been called. However, burited in this +function is a call to setup the CPU port, which requires the PCS +structure to be already setup. + +Fix this by changing the initialisation order. + +Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 +Mem abort info: + ESR = 0x96000005 + EC = 0x25: DABT (current EL), IL = 32 bits + SET = 0, FnV = 0 + EA = 0, S1PTW = 0 + FSC = 0x05: level 1 translation fault +Data abort info: + ISV = 0, ISS = 0x00000005 + CM = 0, WnR = 0 +user pgtable: 4k pages, 39-bit VAs, pgdp=0000000046057000 +[0000000000000020] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 +Internal error: Oops: 96000005 [#1] SMP +Modules linked in: +CPU: 0 PID: 32 Comm: kworker/u4:1 Tainted: G S 5.18.0-rc3-next-20220422+ #0 +Hardware name: Bananapi BPI-R64 (DT) +Workqueue: events_unbound deferred_probe_work_func +pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +pc : mt7531_cpu_port_config+0xcc/0x1b0 +lr : mt7531_cpu_port_config+0xc0/0x1b0 +sp : ffffffc008d5b980 +x29: ffffffc008d5b990 x28: ffffff80060562c8 x27: 00000000f805633b +x26: ffffff80001a8880 x25: 00000000000009c4 x24: 0000000000000016 +x23: ffffff8005eb6470 x22: 0000000000003600 x21: ffffff8006948080 +x20: 0000000000000000 x19: 0000000000000006 x18: 0000000000000000 +x17: 0000000000000001 x16: 0000000000000001 x15: 02963607fcee069e +x14: 0000000000000000 x13: 0000000000000030 x12: 0101010101010101 +x11: ffffffc037302000 x10: 0000000000000870 x9 : ffffffc008d5b800 +x8 : ffffff800028f950 x7 : 0000000000000001 x6 : 00000000662b3000 +x5 : 00000000000002f0 x4 : 0000000000000000 x3 : ffffff800028f080 +x2 : 0000000000000000 x1 : ffffff800028f080 x0 : 0000000000000000 +Call trace: + mt7531_cpu_port_config+0xcc/0x1b0 + mt753x_cpu_port_enable+0x24/0x1f0 + mt7531_setup+0x49c/0x5c0 + mt753x_setup+0x20/0x31c + dsa_register_switch+0x8bc/0x1020 + mt7530_probe+0x118/0x200 + mdio_probe+0x30/0x64 + really_probe.part.0+0x98/0x280 + __driver_probe_device+0x94/0x140 + driver_probe_device+0x40/0x114 + __device_attach_driver+0xb0/0x10c + bus_for_each_drv+0x64/0xa0 + __device_attach+0xa8/0x16c + device_initial_probe+0x10/0x20 + bus_probe_device+0x94/0x9c + deferred_probe_work_func+0x80/0xb4 + process_one_work+0x200/0x3a0 + worker_thread+0x260/0x4c0 + kthread+0xd4/0xe0 + ret_from_fork+0x10/0x20 +Code: 9409e911 937b7e60 8b0002a0 f9405800 (f9401005) +---[ end trace 0000000000000000 ]--- + +Reported-by: Daniel Golle +Tested-by: Daniel Golle +Fixes: cbd1f243bc41 ("net: dsa: mt7530: partially convert to phylink_pcs") +Signed-off-by: Russell King (Oracle) +Reviewed-by: Florian Fainelli +Link: https://lore.kernel.org/r/E1nj6FW-007WZB-5Y@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -3056,9 +3056,16 @@ static int + mt753x_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; +- int ret = priv->info->sw_setup(ds); +- int i; ++ int i, ret; + ++ /* Initialise the PCS devices */ ++ for (i = 0; i < priv->ds->num_ports; i++) { ++ priv->pcs[i].pcs.ops = priv->info->pcs_ops; ++ priv->pcs[i].priv = priv; ++ priv->pcs[i].port = i; ++ } ++ ++ ret = priv->info->sw_setup(ds); + if (ret) + return ret; + +@@ -3070,13 +3077,6 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + +- /* Initialise the PCS devices */ +- for (i = 0; i < priv->ds->num_ports; i++) { +- priv->pcs[i].pcs.ops = priv->info->pcs_ops; +- priv->pcs[i].priv = priv; +- priv->pcs[i].port = i; +- } +- + return ret; + } + diff --git a/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch b/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch new file mode 100644 index 00000000000..26d207ca6ab --- /dev/null +++ b/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch @@ -0,0 +1,87 @@ +From e26be16262e1fc1e9f1798c12762663bd9c265c6 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 10 Jun 2022 19:05:37 +0200 +Subject: [PATCH 11/13] net: dsa: mt7530: rework mt7530_hw_vlan_{add,del} + +Rework vlan_add/vlan_del functions in preparation for dynamic cpu port. + +Currently BIT(MT7530_CPU_PORT) is added to new_members, even though +mt7530_port_vlan_add() will be called on the CPU port too. + +Let DSA core decide when to call port_vlan_add for the CPU port, rather +than doing it implicitly. + +We can do autonomous forwarding in a certain VLAN, but not add br0 to that +VLAN and avoid flooding the CPU with those packets, if software knows it +doesn't need to process them. + +Suggested-by: Vladimir Oltean +Signed-off-by: Frank Wunderlich +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530.c | 30 ++++++++++++------------------ + 1 file changed, 12 insertions(+), 18 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1536,11 +1536,11 @@ static void + mt7530_hw_vlan_add(struct mt7530_priv *priv, + struct mt7530_hw_vlan_entry *entry) + { ++ struct dsa_port *dp = dsa_to_port(priv->ds, entry->port); + u8 new_members; + u32 val; + +- new_members = entry->old_members | BIT(entry->port) | +- BIT(MT7530_CPU_PORT); ++ new_members = entry->old_members | BIT(entry->port); + + /* Validate the entry with independent learning, create egress tag per + * VLAN and joining the port as one of the port members. +@@ -1551,22 +1551,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *p + + /* Decide whether adding tag or not for those outgoing packets from the + * port inside the VLAN. +- */ +- val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG : +- MT7530_VLAN_EGRESS_TAG; +- mt7530_rmw(priv, MT7530_VAWD2, +- ETAG_CTRL_P_MASK(entry->port), +- ETAG_CTRL_P(entry->port, val)); +- +- /* CPU port is always taken as a tagged port for serving more than one ++ * CPU port is always taken as a tagged port for serving more than one + * VLANs across and also being applied with egress type stack mode for + * that VLAN tags would be appended after hardware special tag used as + * DSA tag. + */ ++ if (dsa_port_is_cpu(dp)) ++ val = MT7530_VLAN_EGRESS_STACK; ++ else if (entry->untagged) ++ val = MT7530_VLAN_EGRESS_UNTAG; ++ else ++ val = MT7530_VLAN_EGRESS_TAG; + mt7530_rmw(priv, MT7530_VAWD2, +- ETAG_CTRL_P_MASK(MT7530_CPU_PORT), +- ETAG_CTRL_P(MT7530_CPU_PORT, +- MT7530_VLAN_EGRESS_STACK)); ++ ETAG_CTRL_P_MASK(entry->port), ++ ETAG_CTRL_P(entry->port, val)); + } + + static void +@@ -1585,11 +1583,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *p + return; + } + +- /* If certain member apart from CPU port is still alive in the VLAN, +- * the entry would be kept valid. Otherwise, the entry is got to be +- * disabled. +- */ +- if (new_members && new_members != BIT(MT7530_CPU_PORT)) { ++ if (new_members) { + val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | + VLAN_VALID; + mt7530_write(priv, MT7530_VAWD1, val); diff --git a/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch b/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch new file mode 100644 index 00000000000..b02705cc701 --- /dev/null +++ b/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch @@ -0,0 +1,75 @@ +From 1f0dfd443eea7fc3e818e96f7c8264913ba41859 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 10 Jun 2022 19:05:38 +0200 +Subject: [PATCH 12/13] net: dsa: mt7530: rework mt753[01]_setup + +Enumerate available cpu-ports instead of using hardcoded constant. + +Suggested-by: Vladimir Oltean +Signed-off-by: Frank Wunderlich +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530.c | 25 +++++++++++++++++++++---- + 1 file changed, 21 insertions(+), 4 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2101,11 +2101,12 @@ static int + mt7530_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; ++ struct device_node *dn = NULL; + struct device_node *phy_node; + struct device_node *mac_np; + struct mt7530_dummy_poll p; + phy_interface_t interface; +- struct device_node *dn; ++ struct dsa_port *cpu_dp; + u32 id, val; + int ret, i; + +@@ -2113,7 +2114,19 @@ mt7530_setup(struct dsa_switch *ds) + * controller also is the container for two GMACs nodes representing + * as two netdev instances. + */ +- dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; ++ dsa_switch_for_each_cpu_port(cpu_dp, ds) { ++ dn = cpu_dp->master->dev.of_node->parent; ++ /* It doesn't matter which CPU port is found first, ++ * their masters should share the same parent OF node ++ */ ++ break; ++ } ++ ++ if (!dn) { ++ dev_err(ds->dev, "parent OF node of DSA master not found"); ++ return -EINVAL; ++ } ++ + ds->assisted_learning_on_cpu_port = true; + ds->mtu_enforcement_ingress = true; + +@@ -2286,6 +2299,7 @@ mt7531_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; + struct mt7530_dummy_poll p; ++ struct dsa_port *cpu_dp; + u32 val, id; + int ret, i; + +@@ -2360,8 +2374,11 @@ mt7531_setup(struct dsa_switch *ds) + CORE_PLL_GROUP4, val); + + /* BPDU to CPU port */ +- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, +- BIT(MT7530_CPU_PORT)); ++ dsa_switch_for_each_cpu_port(cpu_dp, ds) { ++ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, ++ BIT(cpu_dp->index)); ++ break; ++ } + mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, + MT753X_BPDU_CPU_ONLY); + diff --git a/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch b/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch new file mode 100644 index 00000000000..2bfa1ef438e --- /dev/null +++ b/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch @@ -0,0 +1,117 @@ +From ad2606f6fafae3a7d41c4f2af5554c8f6adecbc7 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 10 Jun 2022 19:05:39 +0200 +Subject: [PATCH 13/13] net: dsa: mt7530: get cpu-port via dp->cpu_dp instead + of constant + +Replace last occurences of hardcoded cpu-port by cpu_dp member of +dsa_port struct. + +Now the constant can be dropped. + +Suggested-by: Vladimir Oltean +Signed-off-by: Frank Wunderlich +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530.c | 27 ++++++++++++++++++++------- + drivers/net/dsa/mt7530.h | 1 - + 2 files changed, 20 insertions(+), 8 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1040,6 +1040,7 @@ static int + mt7530_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) + { ++ struct dsa_port *dp = dsa_to_port(ds, port); + struct mt7530_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); +@@ -1048,7 +1049,11 @@ mt7530_port_enable(struct dsa_switch *ds + * restore the port matrix if the port is the member of a certain + * bridge. + */ +- priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ if (dsa_port_is_user(dp)) { ++ struct dsa_port *cpu_dp = dp->cpu_dp; ++ ++ priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index)); ++ } + priv->ports[port].enable = true; + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, + priv->ports[port].pm); +@@ -1196,7 +1201,8 @@ mt7530_port_bridge_join(struct dsa_switc + struct net_device *bridge) + { + struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; +- u32 port_bitmap = BIT(MT7530_CPU_PORT); ++ struct dsa_port *cpu_dp = dp->cpu_dp; ++ u32 port_bitmap = BIT(cpu_dp->index); + struct mt7530_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); +@@ -1273,9 +1279,12 @@ mt7530_port_set_vlan_unaware(struct dsa_ + * the CPU port get out of VLAN filtering mode. + */ + if (all_user_ports_removed) { +- mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT), ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct dsa_port *cpu_dp = dp->cpu_dp; ++ ++ mt7530_write(priv, MT7530_PCR_P(cpu_dp->index), + PCR_MATRIX(dsa_user_ports(priv->ds))); +- mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG ++ mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG + | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); + } + } +@@ -1325,6 +1334,7 @@ mt7530_port_bridge_leave(struct dsa_swit + struct net_device *bridge) + { + struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; ++ struct dsa_port *cpu_dp = dp->cpu_dp; + struct mt7530_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); +@@ -1353,8 +1363,8 @@ mt7530_port_bridge_leave(struct dsa_swit + */ + if (priv->ports[port].enable) + mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, +- PCR_MATRIX(BIT(MT7530_CPU_PORT))); +- priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); ++ PCR_MATRIX(BIT(cpu_dp->index))); ++ priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index)); + + /* When a port is removed from the bridge, the port would be set up + * back to the default as is at initial boot which is a VLAN-unaware +@@ -1517,6 +1527,9 @@ static int + mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack) + { ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct dsa_port *cpu_dp = dp->cpu_dp; ++ + if (vlan_filtering) { + /* The port is being kept as VLAN-unaware port when bridge is + * set up with vlan_filtering not being set, Otherwise, the +@@ -1524,7 +1537,7 @@ mt7530_port_vlan_filtering(struct dsa_sw + * for becoming a VLAN-aware port. + */ + mt7530_port_set_vlan_aware(ds, port); +- mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT); ++ mt7530_port_set_vlan_aware(ds, cpu_dp->index); + } else { + mt7530_port_set_vlan_unaware(ds, port); + } +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -8,7 +8,6 @@ + + #define MT7530_NUM_PORTS 7 + #define MT7530_NUM_PHYS 5 +-#define MT7530_CPU_PORT 6 + #define MT7530_NUM_FDB_RECORDS 2048 + #define MT7530_ALL_MEMBERS 0xff + diff --git a/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch b/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch new file mode 100644 index 00000000000..c5501fb0402 --- /dev/null +++ b/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch @@ -0,0 +1,330 @@ +From 23233e577ef973c2c5d0dd757a0a4605e34ecb57 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:36 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on page_pool for single page + buffers + +Rely on page_pool allocator for single page buffers in order to keep +them dma mapped and add skb recycling support. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/Kconfig | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 185 +++++++++++++++----- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++ + 3 files changed, 156 insertions(+), 40 deletions(-) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -16,6 +16,7 @@ config NET_MEDIATEK_SOC + depends on NET_DSA || !NET_DSA + select PHYLINK + select DIMLIB ++ select PAGE_POOL + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1389,6 +1389,68 @@ static void mtk_update_rx_cpu_idx(struct + } + } + ++static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, ++ struct xdp_rxq_info *xdp_q, ++ int id, int size) ++{ ++ struct page_pool_params pp_params = { ++ .order = 0, ++ .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, ++ .pool_size = size, ++ .nid = NUMA_NO_NODE, ++ .dev = eth->dma_dev, ++ .dma_dir = DMA_FROM_DEVICE, ++ .offset = MTK_PP_HEADROOM, ++ .max_len = MTK_PP_MAX_BUF_SIZE, ++ }; ++ struct page_pool *pp; ++ int err; ++ ++ pp = page_pool_create(&pp_params); ++ if (IS_ERR(pp)) ++ return pp; ++ ++ err = xdp_rxq_info_reg(xdp_q, ð->dummy_dev, id, ++ eth->rx_napi.napi_id); ++ if (err < 0) ++ goto err_free_pp; ++ ++ err = xdp_rxq_info_reg_mem_model(xdp_q, MEM_TYPE_PAGE_POOL, pp); ++ if (err) ++ goto err_unregister_rxq; ++ ++ return pp; ++ ++err_unregister_rxq: ++ xdp_rxq_info_unreg(xdp_q); ++err_free_pp: ++ page_pool_destroy(pp); ++ ++ return ERR_PTR(err); ++} ++ ++static void *mtk_page_pool_get_buff(struct page_pool *pp, dma_addr_t *dma_addr, ++ gfp_t gfp_mask) ++{ ++ struct page *page; ++ ++ page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN); ++ if (!page) ++ return NULL; ++ ++ *dma_addr = page_pool_get_dma_addr(page) + MTK_PP_HEADROOM; ++ return page_address(page); ++} ++ ++static void mtk_rx_put_buff(struct mtk_rx_ring *ring, void *data, bool napi) ++{ ++ if (ring->page_pool) ++ page_pool_put_full_page(ring->page_pool, ++ virt_to_head_page(data), napi); ++ else ++ skb_free_frag(data); ++} ++ + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { +@@ -1402,9 +1464,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; ++ u32 hash, reason, reserve_len; + struct net_device *netdev; + dma_addr_t dma_addr; +- u32 hash, reason; + int mac = 0; + + ring = mtk_get_rx_ring(eth); +@@ -1435,36 +1497,54 @@ static int mtk_poll_rx(struct napi_struc + goto release_desc; + + /* alloc new buffer */ +- if (ring->frag_size <= PAGE_SIZE) +- new_data = napi_alloc_frag(ring->frag_size); +- else +- new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); +- if (unlikely(!new_data)) { +- netdev->stats.rx_dropped++; +- goto release_desc; +- } +- dma_addr = dma_map_single(eth->dma_dev, +- new_data + NET_SKB_PAD + +- eth->ip_align, +- ring->buf_size, +- DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { +- skb_free_frag(new_data); +- netdev->stats.rx_dropped++; +- goto release_desc; +- } ++ if (ring->page_pool) { ++ new_data = mtk_page_pool_get_buff(ring->page_pool, ++ &dma_addr, ++ GFP_ATOMIC); ++ if (unlikely(!new_data)) { ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } ++ } else { ++ if (ring->frag_size <= PAGE_SIZE) ++ new_data = napi_alloc_frag(ring->frag_size); ++ else ++ new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); ++ ++ if (unlikely(!new_data)) { ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } + +- dma_unmap_single(eth->dma_dev, trxd.rxd1, +- ring->buf_size, DMA_FROM_DEVICE); ++ dma_addr = dma_map_single(eth->dma_dev, ++ new_data + NET_SKB_PAD + eth->ip_align, ++ ring->buf_size, DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, ++ dma_addr))) { ++ skb_free_frag(new_data); ++ netdev->stats.rx_dropped++; ++ goto release_desc; ++ } ++ ++ dma_unmap_single(eth->dma_dev, trxd.rxd1, ++ ring->buf_size, DMA_FROM_DEVICE); ++ } + + /* receive data */ + skb = build_skb(data, ring->frag_size); + if (unlikely(!skb)) { +- skb_free_frag(data); ++ mtk_rx_put_buff(ring, data, true); + netdev->stats.rx_dropped++; + goto skip_rx; + } +- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); ++ ++ if (ring->page_pool) { ++ reserve_len = MTK_PP_HEADROOM; ++ skb_mark_for_recycle(skb); ++ } else { ++ reserve_len = NET_SKB_PAD + NET_IP_ALIGN; ++ } ++ skb_reserve(skb, reserve_len); + + pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; +@@ -1518,7 +1598,6 @@ static int mtk_poll_rx(struct napi_struc + skip_rx: + ring->data[idx] = new_data; + rxd->rxd1 = (unsigned int)dma_addr; +- + release_desc: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; +@@ -1526,7 +1605,6 @@ release_desc: + rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); + + ring->calc_idx = idx; +- + done++; + } + +@@ -1890,13 +1968,15 @@ static int mtk_rx_alloc(struct mtk_eth * + if (!ring->data) + return -ENOMEM; + +- for (i = 0; i < rx_dma_size; i++) { +- if (ring->frag_size <= PAGE_SIZE) +- ring->data[i] = netdev_alloc_frag(ring->frag_size); +- else +- ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); +- if (!ring->data[i]) +- return -ENOMEM; ++ if (!eth->hwlro) { ++ struct page_pool *pp; ++ ++ pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, ++ rx_dma_size); ++ if (IS_ERR(pp)) ++ return PTR_ERR(pp); ++ ++ ring->page_pool = pp; + } + + ring->dma = dma_alloc_coherent(eth->dma_dev, +@@ -1907,16 +1987,33 @@ static int mtk_rx_alloc(struct mtk_eth * + + for (i = 0; i < rx_dma_size; i++) { + struct mtk_rx_dma_v2 *rxd; +- +- dma_addr_t dma_addr = dma_map_single(eth->dma_dev, +- ring->data[i] + NET_SKB_PAD + eth->ip_align, +- ring->buf_size, +- DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) +- return -ENOMEM; ++ dma_addr_t dma_addr; ++ void *data; + + rxd = ring->dma + i * eth->soc->txrx.rxd_size; ++ if (ring->page_pool) { ++ data = mtk_page_pool_get_buff(ring->page_pool, ++ &dma_addr, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ } else { ++ if (ring->frag_size <= PAGE_SIZE) ++ data = netdev_alloc_frag(ring->frag_size); ++ else ++ data = mtk_max_lro_buf_alloc(GFP_KERNEL); ++ ++ if (!data) ++ return -ENOMEM; ++ ++ dma_addr = dma_map_single(eth->dma_dev, ++ data + NET_SKB_PAD + eth->ip_align, ++ ring->buf_size, DMA_FROM_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, ++ dma_addr))) ++ return -ENOMEM; ++ } + rxd->rxd1 = (unsigned int)dma_addr; ++ ring->data[i] = data; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + rxd->rxd2 = RX_DMA_LSO; +@@ -1932,6 +2029,7 @@ static int mtk_rx_alloc(struct mtk_eth * + rxd->rxd8 = 0; + } + } ++ + ring->dma_size = rx_dma_size; + ring->calc_idx_update = false; + ring->calc_idx = rx_dma_size - 1; +@@ -1983,7 +2081,7 @@ static void mtk_rx_clean(struct mtk_eth + + dma_unmap_single(eth->dma_dev, rxd->rxd1, + ring->buf_size, DMA_FROM_DEVICE); +- skb_free_frag(ring->data[i]); ++ mtk_rx_put_buff(ring, ring->data[i], false); + } + kfree(ring->data); + ring->data = NULL; +@@ -1995,6 +2093,13 @@ static void mtk_rx_clean(struct mtk_eth + ring->dma, ring->phys); + ring->dma = NULL; + } ++ ++ if (ring->page_pool) { ++ if (xdp_rxq_info_is_reg(&ring->xdp_q)) ++ xdp_rxq_info_unreg(&ring->xdp_q); ++ page_pool_destroy(ring->page_pool); ++ ring->page_pool = NULL; ++ } + } + + static int mtk_hwlro_rx_init(struct mtk_eth *eth) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -18,6 +18,8 @@ + #include + #include + #include ++#include ++#include + #include "mtk_ppe.h" + + #define MTK_QDMA_PAGE_SIZE 2048 +@@ -49,6 +51,11 @@ + #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) + #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) + ++#define MTK_PP_HEADROOM XDP_PACKET_HEADROOM ++#define MTK_PP_PAD (MTK_PP_HEADROOM + \ ++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) ++#define MTK_PP_MAX_BUF_SIZE (PAGE_SIZE - MTK_PP_PAD) ++ + #define MTK_QRX_OFFSET 0x10 + + #define MTK_MAX_RX_RING_NUM 4 +@@ -743,6 +750,9 @@ struct mtk_rx_ring { + bool calc_idx_update; + u16 calc_idx; + u32 crx_idx_reg; ++ /* page_pool */ ++ struct page_pool *page_pool; ++ struct xdp_rxq_info xdp_q; + }; + + enum mkt_eth_capabilities { diff --git a/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch b/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch new file mode 100644 index 00000000000..d94bdabd714 --- /dev/null +++ b/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch @@ -0,0 +1,291 @@ +From 7c26c20da5d420cde55618263be4aa2f6de53056 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:37 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add basic XDP support + +Introduce basic XDP support to mtk_eth_soc driver. +Supported XDP verdicts: +- XDP_PASS +- XDP_DROP +- XDP_REDIRECT + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 162 +++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + + 2 files changed, 145 insertions(+), 19 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1389,6 +1389,11 @@ static void mtk_update_rx_cpu_idx(struct + } + } + ++static bool mtk_page_pool_enabled(struct mtk_eth *eth) ++{ ++ return !eth->hwlro; ++} ++ + static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, + struct xdp_rxq_info *xdp_q, + int id, int size) +@@ -1451,11 +1456,52 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, ++ struct xdp_buff *xdp, struct net_device *dev) ++{ ++ struct bpf_prog *prog; ++ u32 act = XDP_PASS; ++ ++ rcu_read_lock(); ++ ++ prog = rcu_dereference(eth->prog); ++ if (!prog) ++ goto out; ++ ++ act = bpf_prog_run_xdp(prog, xdp); ++ switch (act) { ++ case XDP_PASS: ++ goto out; ++ case XDP_REDIRECT: ++ if (unlikely(xdp_do_redirect(dev, xdp, prog))) { ++ act = XDP_DROP; ++ break; ++ } ++ goto out; ++ default: ++ bpf_warn_invalid_xdp_action(act); ++ fallthrough; ++ case XDP_ABORTED: ++ trace_xdp_exception(dev, prog, act); ++ fallthrough; ++ case XDP_DROP: ++ break; ++ } ++ ++ page_pool_put_full_page(ring->page_pool, ++ virt_to_head_page(xdp->data), true); ++out: ++ rcu_read_unlock(); ++ ++ return act; ++} ++ + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { + struct dim_sample dim_sample = {}; + struct mtk_rx_ring *ring; ++ bool xdp_flush = false; + int idx; + struct sk_buff *skb; + u8 *data, *new_data; +@@ -1464,9 +1510,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; +- u32 hash, reason, reserve_len; + struct net_device *netdev; + dma_addr_t dma_addr; ++ u32 hash, reason; + int mac = 0; + + ring = mtk_get_rx_ring(eth); +@@ -1496,8 +1542,14 @@ static int mtk_poll_rx(struct napi_struc + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto release_desc; + ++ pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); ++ + /* alloc new buffer */ + if (ring->page_pool) { ++ struct page *page = virt_to_head_page(data); ++ struct xdp_buff xdp; ++ u32 ret; ++ + new_data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, + GFP_ATOMIC); +@@ -1505,6 +1557,34 @@ static int mtk_poll_rx(struct napi_struc + netdev->stats.rx_dropped++; + goto release_desc; + } ++ ++ dma_sync_single_for_cpu(eth->dma_dev, ++ page_pool_get_dma_addr(page) + MTK_PP_HEADROOM, ++ pktlen, page_pool_get_dma_dir(ring->page_pool)); ++ ++ xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q); ++ xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen, ++ false); ++ xdp_buff_clear_frags_flag(&xdp); ++ ++ ret = mtk_xdp_run(eth, ring, &xdp, netdev); ++ if (ret == XDP_REDIRECT) ++ xdp_flush = true; ++ ++ if (ret != XDP_PASS) ++ goto skip_rx; ++ ++ skb = build_skb(data, PAGE_SIZE); ++ if (unlikely(!skb)) { ++ page_pool_put_full_page(ring->page_pool, ++ page, true); ++ netdev->stats.rx_dropped++; ++ goto skip_rx; ++ } ++ ++ skb_reserve(skb, xdp.data - xdp.data_hard_start); ++ skb_put(skb, xdp.data_end - xdp.data); ++ skb_mark_for_recycle(skb); + } else { + if (ring->frag_size <= PAGE_SIZE) + new_data = napi_alloc_frag(ring->frag_size); +@@ -1528,27 +1608,20 @@ static int mtk_poll_rx(struct napi_struc + + dma_unmap_single(eth->dma_dev, trxd.rxd1, + ring->buf_size, DMA_FROM_DEVICE); +- } + +- /* receive data */ +- skb = build_skb(data, ring->frag_size); +- if (unlikely(!skb)) { +- mtk_rx_put_buff(ring, data, true); +- netdev->stats.rx_dropped++; +- goto skip_rx; +- } ++ skb = build_skb(data, ring->frag_size); ++ if (unlikely(!skb)) { ++ netdev->stats.rx_dropped++; ++ skb_free_frag(data); ++ goto skip_rx; ++ } + +- if (ring->page_pool) { +- reserve_len = MTK_PP_HEADROOM; +- skb_mark_for_recycle(skb); +- } else { +- reserve_len = NET_SKB_PAD + NET_IP_ALIGN; ++ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); ++ skb_put(skb, pktlen); + } +- skb_reserve(skb, reserve_len); + +- pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; +- skb_put(skb, pktlen); ++ bytes += skb->len; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + rxdcsum = &trxd.rxd3; +@@ -1560,7 +1633,6 @@ static int mtk_poll_rx(struct napi_struc + else + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); +- bytes += pktlen; + + hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; + if (hash != MTK_RXD4_FOE_ENTRY) { +@@ -1623,6 +1695,9 @@ rx_done: + &dim_sample); + net_dim(ð->rx_dim, dim_sample); + ++ if (xdp_flush) ++ xdp_do_flush_map(); ++ + return done; + } + +@@ -1968,7 +2043,7 @@ static int mtk_rx_alloc(struct mtk_eth * + if (!ring->data) + return -ENOMEM; + +- if (!eth->hwlro) { ++ if (mtk_page_pool_enabled(eth)) { + struct page_pool *pp; + + pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, +@@ -2710,6 +2785,48 @@ static int mtk_stop(struct net_device *d + return 0; + } + ++static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog, ++ struct netlink_ext_ack *extack) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ struct bpf_prog *old_prog; ++ bool need_update; ++ ++ if (eth->hwlro) { ++ NL_SET_ERR_MSG_MOD(extack, "XDP not supported with HWLRO"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (dev->mtu > MTK_PP_MAX_BUF_SIZE) { ++ NL_SET_ERR_MSG_MOD(extack, "MTU too large for XDP"); ++ return -EOPNOTSUPP; ++ } ++ ++ need_update = !!eth->prog != !!prog; ++ if (netif_running(dev) && need_update) ++ mtk_stop(dev); ++ ++ old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held()); ++ if (old_prog) ++ bpf_prog_put(old_prog); ++ ++ if (netif_running(dev) && need_update) ++ return mtk_open(dev); ++ ++ return 0; ++} ++ ++static int mtk_xdp(struct net_device *dev, struct netdev_bpf *xdp) ++{ ++ switch (xdp->command) { ++ case XDP_SETUP_PROG: ++ return mtk_xdp_setup(dev, xdp->prog, xdp->extack); ++ default: ++ return -EINVAL; ++ } ++} ++ + static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) + { + regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, +@@ -3005,6 +3122,12 @@ static int mtk_change_mtu(struct net_dev + struct mtk_eth *eth = mac->hw; + u32 mcr_cur, mcr_new; + ++ if (rcu_access_pointer(eth->prog) && ++ length > MTK_PP_MAX_BUF_SIZE) { ++ netdev_err(dev, "Invalid MTU for XDP mode\n"); ++ return -EINVAL; ++ } ++ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; +@@ -3332,6 +3455,7 @@ static const struct net_device_ops mtk_n + .ndo_poll_controller = mtk_poll_controller, + #endif + .ndo_setup_tc = mtk_eth_setup_tc, ++ .ndo_bpf = mtk_xdp, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1086,6 +1086,8 @@ struct mtk_eth { + + struct mtk_ppe *ppe; + struct rhashtable flow_table; ++ ++ struct bpf_prog __rcu *prog; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the diff --git a/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch b/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch new file mode 100644 index 00000000000..cf4d658684b --- /dev/null +++ b/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch @@ -0,0 +1,110 @@ +From 916a6ee836d6b7b8ef1ed5f0515e256ca60e9968 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:38 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp ethtool counters + +Report xdp stats through ethtool + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 26 +++++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 12 ++++++++++ + 2 files changed, 36 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -34,6 +34,10 @@ MODULE_PARM_DESC(msg_level, "Message lev + #define MTK_ETHTOOL_STAT(x) { #x, \ + offsetof(struct mtk_hw_stats, x) / sizeof(u64) } + ++#define MTK_ETHTOOL_XDP_STAT(x) { #x, \ ++ offsetof(struct mtk_hw_stats, xdp_stats.x) / \ ++ sizeof(u64) } ++ + static const struct mtk_reg_map mtk_reg_map = { + .tx_irq_mask = 0x1a1c, + .tx_irq_status = 0x1a18, +@@ -141,6 +145,13 @@ static const struct mtk_ethtool_stats { + MTK_ETHTOOL_STAT(rx_long_errors), + MTK_ETHTOOL_STAT(rx_checksum_errors), + MTK_ETHTOOL_STAT(rx_flow_control_packets), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_redirect), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_pass), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_drop), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx), ++ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx_errors), ++ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit), ++ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit_errors), + }; + + static const char * const mtk_clks_source_name[] = { +@@ -1459,6 +1470,9 @@ static void mtk_rx_put_buff(struct mtk_r + static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, + struct xdp_buff *xdp, struct net_device *dev) + { ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_hw_stats *hw_stats = mac->hw_stats; ++ u64 *count = &hw_stats->xdp_stats.rx_xdp_drop; + struct bpf_prog *prog; + u32 act = XDP_PASS; + +@@ -1471,13 +1485,16 @@ static u32 mtk_xdp_run(struct mtk_eth *e + act = bpf_prog_run_xdp(prog, xdp); + switch (act) { + case XDP_PASS: +- goto out; ++ count = &hw_stats->xdp_stats.rx_xdp_pass; ++ goto update_stats; + case XDP_REDIRECT: + if (unlikely(xdp_do_redirect(dev, xdp, prog))) { + act = XDP_DROP; + break; + } +- goto out; ++ ++ count = &hw_stats->xdp_stats.rx_xdp_redirect; ++ goto update_stats; + default: + bpf_warn_invalid_xdp_action(act); + fallthrough; +@@ -1490,6 +1507,11 @@ static u32 mtk_xdp_run(struct mtk_eth *e + + page_pool_put_full_page(ring->page_pool, + virt_to_head_page(xdp->data), true); ++ ++update_stats: ++ u64_stats_update_begin(&hw_stats->syncp); ++ *count = *count + 1; ++ u64_stats_update_end(&hw_stats->syncp); + out: + rcu_read_unlock(); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -568,6 +568,16 @@ struct mtk_tx_dma_v2 { + struct mtk_eth; + struct mtk_mac; + ++struct mtk_xdp_stats { ++ u64 rx_xdp_redirect; ++ u64 rx_xdp_pass; ++ u64 rx_xdp_drop; ++ u64 rx_xdp_tx; ++ u64 rx_xdp_tx_errors; ++ u64 tx_xdp_xmit; ++ u64 tx_xdp_xmit_errors; ++}; ++ + /* struct mtk_hw_stats - the structure that holds the traffic statistics. + * @stats_lock: make sure that stats operations are atomic + * @reg_offset: the status register offset of the SoC +@@ -591,6 +601,8 @@ struct mtk_hw_stats { + u64 rx_checksum_errors; + u64 rx_flow_control_packets; + ++ struct mtk_xdp_stats xdp_stats; ++ + spinlock_t stats_lock; + u32 reg_offset; + struct u64_stats_sync syncp; diff --git a/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch b/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch new file mode 100644 index 00000000000..58b49f28a25 --- /dev/null +++ b/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch @@ -0,0 +1,340 @@ +From 5886d26fd25bbe26130e3e5f7474b9b3e98a3469 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:39 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add xmit XDP support + +Introduce XDP support for XDP_TX verdict and ndo_xdp_xmit function +pointer. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 192 +++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 +- + 2 files changed, 180 insertions(+), 22 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -988,15 +988,26 @@ static void mtk_tx_unmap(struct mtk_eth + } + } + +- tx_buf->flags = 0; +- if (tx_buf->skb && +- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) { +- if (napi) +- napi_consume_skb(tx_buf->skb, napi); ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ if (tx_buf->data && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; ++ ++ if (napi) ++ napi_consume_skb(skb, napi); ++ else ++ dev_kfree_skb_any(skb); ++ } ++ } else if (tx_buf->data) { ++ struct xdp_frame *xdpf = tx_buf->data; ++ ++ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) ++ xdp_return_frame_rx_napi(xdpf); + else +- dev_kfree_skb_any(tx_buf->skb); ++ xdp_return_frame(xdpf); + } +- tx_buf->skb = NULL; ++ tx_buf->flags = 0; ++ tx_buf->data = NULL; + } + + static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, +@@ -1013,7 +1024,7 @@ static void setup_tx_buf(struct mtk_eth + dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); + dma_unmap_len_set(tx_buf, dma_len1, size); + } else { +- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + txd->txd1 = mapped_addr; + txd->txd2 = TX_DMA_PLEN0(size); + dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); +@@ -1189,7 +1200,7 @@ static int mtk_tx_map(struct sk_buff *sk + soc->txrx.txd_size); + if (new_desc) + memset(tx_buf, 0, sizeof(*tx_buf)); +- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; + tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : + MTK_TX_FLAGS_FPORT1; +@@ -1203,7 +1214,8 @@ static int mtk_tx_map(struct sk_buff *sk + } + + /* store skb to cleanup */ +- itx_buf->skb = skb; ++ itx_buf->type = MTK_TYPE_SKB; ++ itx_buf->data = skb; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + if (k & 0x1) +@@ -1415,13 +1427,14 @@ static struct page_pool *mtk_create_page + .pool_size = size, + .nid = NUMA_NO_NODE, + .dev = eth->dma_dev, +- .dma_dir = DMA_FROM_DEVICE, + .offset = MTK_PP_HEADROOM, + .max_len = MTK_PP_MAX_BUF_SIZE, + }; + struct page_pool *pp; + int err; + ++ pp_params.dma_dir = rcu_access_pointer(eth->prog) ? DMA_BIDIRECTIONAL ++ : DMA_FROM_DEVICE; + pp = page_pool_create(&pp_params); + if (IS_ERR(pp)) + return pp; +@@ -1467,6 +1480,122 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, ++ struct net_device *dev, bool dma_map) ++{ ++ const struct mtk_soc_data *soc = eth->soc; ++ struct mtk_tx_ring *ring = ð->tx_ring; ++ struct mtk_tx_dma_desc_info txd_info = { ++ .size = xdpf->len, ++ .first = true, ++ .last = true, ++ }; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_tx_dma *txd, *txd_pdma; ++ int err = 0, index = 0, n_desc = 1; ++ struct mtk_tx_buf *tx_buf; ++ ++ if (unlikely(test_bit(MTK_RESETTING, ð->state))) ++ return -EBUSY; ++ ++ if (unlikely(atomic_read(&ring->free_count) <= 1)) ++ return -EBUSY; ++ ++ spin_lock(ð->page_lock); ++ ++ txd = ring->next_free; ++ if (txd == ring->last_free) { ++ err = -ENOMEM; ++ goto out; ++ } ++ ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); ++ memset(tx_buf, 0, sizeof(*tx_buf)); ++ ++ if (dma_map) { /* ndo_xdp_xmit */ ++ txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, ++ txd_info.size, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { ++ err = -ENOMEM; ++ goto out; ++ } ++ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; ++ } else { ++ struct page *page = virt_to_head_page(xdpf->data); ++ ++ txd_info.addr = page_pool_get_dma_addr(page) + ++ sizeof(*xdpf) + xdpf->headroom; ++ dma_sync_single_for_device(eth->dma_dev, txd_info.addr, ++ txd_info.size, ++ DMA_BIDIRECTIONAL); ++ } ++ mtk_tx_set_dma_desc(dev, txd, &txd_info); ++ ++ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ ++ txd_pdma = qdma_to_pdma(ring, txd); ++ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, ++ index++); ++ ++ /* store xdpf for cleanup */ ++ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; ++ tx_buf->data = xdpf; ++ ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ if (index & 1) ++ txd_pdma->txd2 |= TX_DMA_LS0; ++ else ++ txd_pdma->txd2 |= TX_DMA_LS1; ++ } ++ ++ ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); ++ atomic_sub(n_desc, &ring->free_count); ++ ++ /* make sure that all changes to the dma ring are flushed before we ++ * continue ++ */ ++ wmb(); ++ ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); ++ } else { ++ int idx; ++ ++ idx = txd_to_idx(ring, txd, soc->txrx.txd_size); ++ mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), ++ MT7628_TX_CTX_IDX0); ++ } ++out: ++ spin_unlock(ð->page_lock); ++ ++ return err; ++} ++ ++static int mtk_xdp_xmit(struct net_device *dev, int num_frame, ++ struct xdp_frame **frames, u32 flags) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_hw_stats *hw_stats = mac->hw_stats; ++ struct mtk_eth *eth = mac->hw; ++ int i, nxmit = 0; ++ ++ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) ++ return -EINVAL; ++ ++ for (i = 0; i < num_frame; i++) { ++ if (mtk_xdp_submit_frame(eth, frames[i], dev, true)) ++ break; ++ nxmit++; ++ } ++ ++ u64_stats_update_begin(&hw_stats->syncp); ++ hw_stats->xdp_stats.tx_xdp_xmit += nxmit; ++ hw_stats->xdp_stats.tx_xdp_xmit_errors += num_frame - nxmit; ++ u64_stats_update_end(&hw_stats->syncp); ++ ++ return nxmit; ++} ++ + static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, + struct xdp_buff *xdp, struct net_device *dev) + { +@@ -1495,6 +1624,18 @@ static u32 mtk_xdp_run(struct mtk_eth *e + + count = &hw_stats->xdp_stats.rx_xdp_redirect; + goto update_stats; ++ case XDP_TX: { ++ struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); ++ ++ if (mtk_xdp_submit_frame(eth, xdpf, dev, false)) { ++ count = &hw_stats->xdp_stats.rx_xdp_tx_errors; ++ act = XDP_DROP; ++ break; ++ } ++ ++ count = &hw_stats->xdp_stats.rx_xdp_tx; ++ goto update_stats; ++ } + default: + bpf_warn_invalid_xdp_action(act); + fallthrough; +@@ -1728,9 +1869,8 @@ static int mtk_poll_tx_qdma(struct mtk_e + { + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct mtk_tx_ring *ring = ð->tx_ring; +- struct mtk_tx_dma *desc; +- struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; ++ struct mtk_tx_dma *desc; + u32 cpu, dma; + + cpu = ring->last_free_ptr; +@@ -1751,15 +1891,21 @@ static int mtk_poll_tx_qdma(struct mtk_e + if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) + mac = 1; + +- skb = tx_buf->skb; +- if (!skb) ++ if (!tx_buf->data) + break; + +- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; ++ + bytes[mac] += skb->len; + done[mac]++; + budget--; ++ } else if (tx_buf->type == MTK_TYPE_XDP_TX || ++ tx_buf->type == MTK_TYPE_XDP_NDO) { ++ budget--; + } ++ + mtk_tx_unmap(eth, tx_buf, true); + + ring->last_free = desc; +@@ -1778,9 +1924,8 @@ static int mtk_poll_tx_pdma(struct mtk_e + unsigned int *done, unsigned int *bytes) + { + struct mtk_tx_ring *ring = ð->tx_ring; +- struct mtk_tx_dma *desc; +- struct sk_buff *skb; + struct mtk_tx_buf *tx_buf; ++ struct mtk_tx_dma *desc; + u32 cpu, dma; + + cpu = ring->cpu_idx; +@@ -1788,14 +1933,18 @@ static int mtk_poll_tx_pdma(struct mtk_e + + while ((cpu != dma) && budget) { + tx_buf = &ring->buf[cpu]; +- skb = tx_buf->skb; +- if (!skb) ++ if (!tx_buf->data) + break; + +- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB && ++ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ struct sk_buff *skb = tx_buf->data; + bytes[0] += skb->len; + done[0]++; + budget--; ++ } else if (tx_buf->type == MTK_TYPE_XDP_TX || ++ tx_buf->type == MTK_TYPE_XDP_NDO) { ++ budget--; + } + + mtk_tx_unmap(eth, tx_buf, true); +@@ -3478,6 +3627,7 @@ static const struct net_device_ops mtk_n + #endif + .ndo_setup_tc = mtk_eth_setup_tc, + .ndo_bpf = mtk_xdp, ++ .ndo_xdp_xmit = mtk_xdp_xmit, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -694,6 +694,12 @@ enum mtk_dev_state { + MTK_RESETTING + }; + ++enum mtk_tx_buf_type { ++ MTK_TYPE_SKB, ++ MTK_TYPE_XDP_TX, ++ MTK_TYPE_XDP_NDO, ++}; ++ + /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at + * by the TX descriptor s + * @skb: The SKB pointer of the packet being sent +@@ -703,7 +709,9 @@ enum mtk_dev_state { + * @dma_len1: The length of the second segment + */ + struct mtk_tx_buf { +- struct sk_buff *skb; ++ enum mtk_tx_buf_type type; ++ void *data; ++ + u32 flags; + DEFINE_DMA_UNMAP_ADDR(dma_addr0); + DEFINE_DMA_UNMAP_LEN(dma_len0); diff --git a/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch b/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch new file mode 100644 index 00000000000..e93e0df544a --- /dev/null +++ b/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch @@ -0,0 +1,95 @@ +From 84b9cd389036d4a262d8cee794d56c04095358a7 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:19:40 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for + page_pool_get_stats + +Introduce support for the page_pool stats API into mtk_eth_soc driver. +Report page_pool stats through ethtool. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/Kconfig | 1 + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++-- + 2 files changed, 35 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -17,6 +17,7 @@ config NET_MEDIATEK_SOC + select PHYLINK + select DIMLIB + select PAGE_POOL ++ select PAGE_POOL_STATS + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3488,11 +3488,18 @@ static void mtk_get_strings(struct net_d + int i; + + switch (stringset) { +- case ETH_SS_STATS: ++ case ETH_SS_STATS: { ++ struct mtk_mac *mac = netdev_priv(dev); ++ + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { + memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } ++ if (mtk_page_pool_enabled(mac->hw)) ++ page_pool_ethtool_stats_get_strings(data); ++ break; ++ } ++ default: + break; + } + } +@@ -3500,13 +3507,35 @@ static void mtk_get_strings(struct net_d + static int mtk_get_sset_count(struct net_device *dev, int sset) + { + switch (sset) { +- case ETH_SS_STATS: +- return ARRAY_SIZE(mtk_ethtool_stats); ++ case ETH_SS_STATS: { ++ int count = ARRAY_SIZE(mtk_ethtool_stats); ++ struct mtk_mac *mac = netdev_priv(dev); ++ ++ if (mtk_page_pool_enabled(mac->hw)) ++ count += page_pool_ethtool_stats_get_count(); ++ return count; ++ } + default: + return -EOPNOTSUPP; + } + } + ++static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) ++{ ++ struct page_pool_stats stats = {}; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(eth->rx_ring); i++) { ++ struct mtk_rx_ring *ring = ð->rx_ring[i]; ++ ++ if (!ring->page_pool) ++ continue; ++ ++ page_pool_get_stats(ring->page_pool, &stats); ++ } ++ page_pool_ethtool_stats_get(data, &stats); ++} ++ + static void mtk_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) + { +@@ -3534,6 +3563,8 @@ static void mtk_get_ethtool_stats(struct + + for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) + *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); ++ if (mtk_page_pool_enabled(mac->hw)) ++ mtk_ethtool_pp_stats(mac->hw, data_dst); + } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); + } + diff --git a/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch b/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch new file mode 100644 index 00000000000..8e6895fe97f --- /dev/null +++ b/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch @@ -0,0 +1,113 @@ +From b16fe6d82b71fa0dd5c957bc22d66a694976d6eb Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 27 Jul 2022 23:20:50 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce mtk_xdp_frame_map + utility routine + +This is a preliminary patch to add xdp multi-frag support to mtk_eth_soc +driver + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 68 +++++++++++++-------- + 1 file changed, 42 insertions(+), 26 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1480,6 +1480,41 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, ++ struct mtk_tx_dma_desc_info *txd_info, ++ struct mtk_tx_dma *txd, struct mtk_tx_buf *tx_buf, ++ void *data, u16 headroom, int index, bool dma_map) ++{ ++ struct mtk_tx_ring *ring = ð->tx_ring; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_tx_dma *txd_pdma; ++ ++ if (dma_map) { /* ndo_xdp_xmit */ ++ txd_info->addr = dma_map_single(eth->dma_dev, data, ++ txd_info->size, DMA_TO_DEVICE); ++ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) ++ return -ENOMEM; ++ ++ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; ++ } else { ++ struct page *page = virt_to_head_page(data); ++ ++ txd_info->addr = page_pool_get_dma_addr(page) + ++ sizeof(struct xdp_frame) + headroom; ++ dma_sync_single_for_device(eth->dma_dev, txd_info->addr, ++ txd_info->size, DMA_BIDIRECTIONAL); ++ } ++ mtk_tx_set_dma_desc(dev, txd, txd_info); ++ ++ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ ++ txd_pdma = qdma_to_pdma(ring, txd); ++ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, ++ index); ++ ++ return 0; ++} ++ + static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + struct net_device *dev, bool dma_map) + { +@@ -1490,9 +1525,8 @@ static int mtk_xdp_submit_frame(struct m + .first = true, + .last = true, + }; +- struct mtk_mac *mac = netdev_priv(dev); +- struct mtk_tx_dma *txd, *txd_pdma; + int err = 0, index = 0, n_desc = 1; ++ struct mtk_tx_dma *txd, *txd_pdma; + struct mtk_tx_buf *tx_buf; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) +@@ -1512,36 +1546,18 @@ static int mtk_xdp_submit_frame(struct m + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); + memset(tx_buf, 0, sizeof(*tx_buf)); + +- if (dma_map) { /* ndo_xdp_xmit */ +- txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, +- txd_info.size, DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { +- err = -ENOMEM; +- goto out; +- } +- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; +- } else { +- struct page *page = virt_to_head_page(xdpf->data); +- +- txd_info.addr = page_pool_get_dma_addr(page) + +- sizeof(*xdpf) + xdpf->headroom; +- dma_sync_single_for_device(eth->dma_dev, txd_info.addr, +- txd_info.size, +- DMA_BIDIRECTIONAL); +- } +- mtk_tx_set_dma_desc(dev, txd, &txd_info); +- +- tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; +- +- txd_pdma = qdma_to_pdma(ring, txd); +- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, +- index++); ++ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, ++ xdpf->data, xdpf->headroom, index, ++ dma_map); ++ if (err < 0) ++ goto out; + + /* store xdpf for cleanup */ + tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; + tx_buf->data = xdpf; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { ++ txd_pdma = qdma_to_pdma(ring, txd); + if (index & 1) + txd_pdma->txd2 |= TX_DMA_LS0; + else diff --git a/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch b/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch new file mode 100644 index 00000000000..23e4a4dfcbf --- /dev/null +++ b/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch @@ -0,0 +1,218 @@ +From 155738a4f319538a09f734ce1f5a2eac3ada1de2 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Wed, 27 Jul 2022 23:20:51 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp multi-frag support + +Add the capability to map non-linear xdp frames in XDP_TX and +ndo_xdp_xmit callback. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 125 +++++++++++++------- + 1 file changed, 82 insertions(+), 43 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -988,23 +988,22 @@ static void mtk_tx_unmap(struct mtk_eth + } + } + +- if (tx_buf->type == MTK_TYPE_SKB) { +- if (tx_buf->data && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { + struct sk_buff *skb = tx_buf->data; + + if (napi) + napi_consume_skb(skb, napi); + else + dev_kfree_skb_any(skb); +- } +- } else if (tx_buf->data) { +- struct xdp_frame *xdpf = tx_buf->data; ++ } else { ++ struct xdp_frame *xdpf = tx_buf->data; + +- if (napi && tx_buf->type == MTK_TYPE_XDP_TX) +- xdp_return_frame_rx_napi(xdpf); +- else +- xdp_return_frame(xdpf); ++ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) ++ xdp_return_frame_rx_napi(xdpf); ++ else ++ xdp_return_frame(xdpf); ++ } + } + tx_buf->flags = 0; + tx_buf->data = NULL; +@@ -1507,6 +1506,8 @@ static int mtk_xdp_frame_map(struct mtk_ + mtk_tx_set_dma_desc(dev, txd, txd_info); + + tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; ++ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; ++ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + + txd_pdma = qdma_to_pdma(ring, txd); + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, +@@ -1518,43 +1519,69 @@ static int mtk_xdp_frame_map(struct mtk_ + static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, + struct net_device *dev, bool dma_map) + { ++ struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_dma_desc_info txd_info = { + .size = xdpf->len, + .first = true, +- .last = true, ++ .last = !xdp_frame_has_frags(xdpf), + }; +- int err = 0, index = 0, n_desc = 1; +- struct mtk_tx_dma *txd, *txd_pdma; +- struct mtk_tx_buf *tx_buf; ++ int err, index = 0, n_desc = 1, nr_frags; ++ struct mtk_tx_dma *htxd, *txd, *txd_pdma; ++ struct mtk_tx_buf *htx_buf, *tx_buf; ++ void *data = xdpf->data; + + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + return -EBUSY; + +- if (unlikely(atomic_read(&ring->free_count) <= 1)) ++ nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0; ++ if (unlikely(atomic_read(&ring->free_count) <= 1 + nr_frags)) + return -EBUSY; + + spin_lock(ð->page_lock); + + txd = ring->next_free; + if (txd == ring->last_free) { +- err = -ENOMEM; +- goto out; ++ spin_unlock(ð->page_lock); ++ return -ENOMEM; + } ++ htxd = txd; + + tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); + memset(tx_buf, 0, sizeof(*tx_buf)); ++ htx_buf = tx_buf; + +- err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, +- xdpf->data, xdpf->headroom, index, +- dma_map); +- if (err < 0) +- goto out; ++ for (;;) { ++ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, ++ data, xdpf->headroom, index, dma_map); ++ if (err < 0) ++ goto unmap; ++ ++ if (txd_info.last) ++ break; + ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (index & 0x1)) { ++ txd = mtk_qdma_phys_to_virt(ring, txd->txd2); ++ txd_pdma = qdma_to_pdma(ring, txd); ++ if (txd == ring->last_free) ++ goto unmap; ++ ++ tx_buf = mtk_desc_to_tx_buf(ring, txd, ++ soc->txrx.txd_size); ++ memset(tx_buf, 0, sizeof(*tx_buf)); ++ n_desc++; ++ } ++ ++ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); ++ txd_info.size = skb_frag_size(&sinfo->frags[index]); ++ txd_info.last = index + 1 == nr_frags; ++ data = skb_frag_address(&sinfo->frags[index]); ++ ++ index++; ++ } + /* store xdpf for cleanup */ +- tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; +- tx_buf->data = xdpf; ++ htx_buf->data = xdpf; + + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { + txd_pdma = qdma_to_pdma(ring, txd); +@@ -1581,7 +1608,24 @@ static int mtk_xdp_submit_frame(struct m + mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), + MT7628_TX_CTX_IDX0); + } +-out: ++ ++ spin_unlock(ð->page_lock); ++ ++ return 0; ++ ++unmap: ++ while (htxd != txd) { ++ txd_pdma = qdma_to_pdma(ring, htxd); ++ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->txrx.txd_size); ++ mtk_tx_unmap(eth, tx_buf, false); ++ ++ htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ++ txd_pdma->txd2 = TX_DMA_DESP2_DEF; ++ ++ htxd = mtk_qdma_phys_to_virt(ring, htxd->txd2); ++ } ++ + spin_unlock(ð->page_lock); + + return err; +@@ -1910,18 +1954,15 @@ static int mtk_poll_tx_qdma(struct mtk_e + if (!tx_buf->data) + break; + +- if (tx_buf->type == MTK_TYPE_SKB && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- struct sk_buff *skb = tx_buf->data; ++ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ struct sk_buff *skb = tx_buf->data; + +- bytes[mac] += skb->len; +- done[mac]++; +- budget--; +- } else if (tx_buf->type == MTK_TYPE_XDP_TX || +- tx_buf->type == MTK_TYPE_XDP_NDO) { ++ bytes[mac] += skb->len; ++ done[mac]++; ++ } + budget--; + } +- + mtk_tx_unmap(eth, tx_buf, true); + + ring->last_free = desc; +@@ -1952,17 +1993,15 @@ static int mtk_poll_tx_pdma(struct mtk_e + if (!tx_buf->data) + break; + +- if (tx_buf->type == MTK_TYPE_SKB && +- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- struct sk_buff *skb = tx_buf->data; +- bytes[0] += skb->len; +- done[0]++; +- budget--; +- } else if (tx_buf->type == MTK_TYPE_XDP_TX || +- tx_buf->type == MTK_TYPE_XDP_NDO) { ++ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { ++ if (tx_buf->type == MTK_TYPE_SKB) { ++ struct sk_buff *skb = tx_buf->data; ++ ++ bytes[0] += skb->len; ++ done[0]++; ++ } + budget--; + } +- + mtk_tx_unmap(eth, tx_buf, true); + + desc = ring->dma + cpu * eth->soc->txrx.txd_size; diff --git a/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch new file mode 100644 index 00000000000..9743a3f2062 --- /dev/null +++ b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch @@ -0,0 +1,394 @@ +From 4765a9722e09765866e131ec31f7b9cf4c1f4854 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:57:50 +0000 +Subject: [PATCH] net: pcs: add driver for MediaTek SGMII PCS + +The SGMII core found in several MediaTek SoCs is identical to what can +also be found in MediaTek's MT7531 Ethernet switch IC. +As this has not always been clear, both drivers developed different +implementations to deal with the PCS. +Recently Alexander Couzens pointed out this fact which lead to the +development of this shared driver. + +Add a dedicated driver, mostly by copying the code now found in the +Ethernet driver. The now redundant code will be removed by a follow-up +commit. + +Suggested-by: Alexander Couzens +Suggested-by: Russell King (Oracle) +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +Reviewed-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + MAINTAINERS | 8 + + drivers/net/pcs/Kconfig | 7 + + drivers/net/pcs/Makefile | 1 + + drivers/net/pcs/pcs-mtk-lynxi.c | 305 ++++++++++++++++++++++++++++++ + include/linux/pcs/pcs-mtk-lynxi.h | 13 ++ + 5 files changed, 334 insertions(+) + create mode 100644 drivers/net/pcs/pcs-mtk-lynxi.c + create mode 100644 include/linux/pcs/pcs-mtk-lynxi.h + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11789,6 +11789,14 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/mediatek/ + ++MEDIATEK ETHERNET PCS DRIVER ++M: Alexander Couzens ++M: Daniel Golle ++L: netdev@vger.kernel.org ++S: Maintained ++F: drivers/net/pcs/pcs-mtk-lynxi.c ++F: include/linux/pcs/pcs-mtk-lynxi.h ++ + MEDIATEK I2C CONTROLLER DRIVER + M: Qii Wang + L: linux-i2c@vger.kernel.org +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -18,4 +18,11 @@ config PCS_LYNX + This module provides helpers to phylink for managing the Lynx PCS + which is part of the Layerscape and QorIQ Ethernet SERDES. + ++config PCS_MTK_LYNXI ++ tristate ++ select REGMAP ++ help ++ This module provides helpers to phylink for managing the LynxI PCS ++ which is part of MediaTek's SoC and Ethernet switch ICs. ++ + endmenu +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -5,3 +5,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs. + + obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o ++obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o +--- /dev/null ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -0,0 +1,305 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2018-2019 MediaTek Inc. ++/* A library for MediaTek SGMII circuit ++ * ++ * Author: Sean Wang ++ * Author: Alexander Couzens ++ * Author: Daniel Golle ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* SGMII subsystem config registers */ ++/* BMCR (low 16) BMSR (high 16) */ ++#define SGMSYS_PCS_CONTROL_1 0x0 ++#define SGMII_BMCR GENMASK(15, 0) ++#define SGMII_BMSR GENMASK(31, 16) ++ ++#define SGMSYS_PCS_DEVICE_ID 0x4 ++#define SGMII_LYNXI_DEV_ID 0x4d544950 ++ ++#define SGMSYS_PCS_ADVERTISE 0x8 ++#define SGMII_ADVERTISE GENMASK(15, 0) ++#define SGMII_LPA GENMASK(31, 16) ++ ++#define SGMSYS_PCS_SCRATCH 0x14 ++#define SGMII_DEV_VERSION GENMASK(31, 16) ++ ++/* Register to programmable link timer, the unit in 2 * 8ns */ ++#define SGMSYS_PCS_LINK_TIMER 0x18 ++#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) ++#define SGMII_LINK_TIMER_VAL(ns) FIELD_PREP(SGMII_LINK_TIMER_MASK, \ ++ ((ns) / 2 / 8)) ++ ++/* Register to control remote fault */ ++#define SGMSYS_SGMII_MODE 0x20 ++#define SGMII_IF_MODE_SGMII BIT(0) ++#define SGMII_SPEED_DUPLEX_AN BIT(1) ++#define SGMII_SPEED_MASK GENMASK(3, 2) ++#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) ++#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) ++#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) ++#define SGMII_DUPLEX_HALF BIT(4) ++#define SGMII_REMOTE_FAULT_DIS BIT(8) ++ ++/* Register to reset SGMII design */ ++#define SGMSYS_RESERVED_0 0x34 ++#define SGMII_SW_RESET BIT(0) ++ ++/* Register to set SGMII speed, ANA RG_ Control Signals III */ ++#define SGMII_PHY_SPEED_MASK GENMASK(3, 2) ++#define SGMII_PHY_SPEED_1_25G FIELD_PREP(SGMII_PHY_SPEED_MASK, 0) ++#define SGMII_PHY_SPEED_3_125G FIELD_PREP(SGMII_PHY_SPEED_MASK, 1) ++ ++/* Register to power up QPHY */ ++#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 ++#define SGMII_PHYA_PWD BIT(4) ++ ++/* Register to QPHY wrapper control */ ++#define SGMSYS_QPHY_WRAP_CTRL 0xec ++#define SGMII_PN_SWAP_MASK GENMASK(1, 0) ++#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) ++ ++/* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated ++ * data ++ * @regmap: The register map pointing at the range used to setup ++ * SGMII modes ++ * @dev: Pointer to device owning the PCS ++ * @ana_rgc3: The offset of register ANA_RGC3 relative to regmap ++ * @interface: Currently configured interface mode ++ * @pcs: Phylink PCS structure ++ * @flags: Flags indicating hardware properties ++ */ ++struct mtk_pcs_lynxi { ++ struct regmap *regmap; ++ u32 ana_rgc3; ++ phy_interface_t interface; ++ struct phylink_pcs pcs; ++ u32 flags; ++}; ++ ++static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs) ++{ ++ return container_of(pcs, struct mtk_pcs_lynxi, pcs); ++} ++ ++static void mtk_pcs_lynxi_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ unsigned int bm, adv; ++ ++ /* Read the BMSR and LPA */ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ ++ phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), ++ FIELD_GET(SGMII_LPA, adv)); ++} ++ ++static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, ++ const unsigned long *advertising, ++ bool permit_pause_to_mac) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ bool mode_changed = false, changed, use_an; ++ unsigned int rgc3, sgm_mode, bmcr; ++ int advertise, link_timer; ++ ++ advertise = phylink_mii_c22_pcs_encode_advertisement(interface, ++ advertising); ++ if (advertise < 0) ++ return advertise; ++ ++ /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and ++ * we assume that fixes it's speed at bitrate = line rate (in ++ * other words, 1000Mbps or 2500Mbps). ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII) { ++ sgm_mode = SGMII_IF_MODE_SGMII; ++ if (phylink_autoneg_inband(mode)) { ++ sgm_mode |= SGMII_REMOTE_FAULT_DIS | ++ SGMII_SPEED_DUPLEX_AN; ++ use_an = true; ++ } else { ++ use_an = false; ++ } ++ } else if (phylink_autoneg_inband(mode)) { ++ /* 1000base-X or 2500base-X autoneg */ ++ sgm_mode = SGMII_REMOTE_FAULT_DIS; ++ use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ advertising); ++ } else { ++ /* 1000base-X or 2500base-X without autoneg */ ++ sgm_mode = 0; ++ use_an = false; ++ } ++ ++ if (use_an) ++ bmcr = BMCR_ANENABLE; ++ else ++ bmcr = 0; ++ ++ if (mpcs->interface != interface) { ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ ++ /* PHYA power down */ ++ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD); ++ ++ /* Reset SGMII PCS state */ ++ regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0, ++ SGMII_SW_RESET); ++ ++ if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_MASK, ++ SGMII_PN_SWAP_TX_RX); ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = SGMII_PHY_SPEED_3_125G; ++ else ++ rgc3 = SGMII_PHY_SPEED_1_25G; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ SGMII_PHY_SPEED_MASK, rgc3); ++ ++ /* Setup the link timer */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, ++ SGMII_LINK_TIMER_VAL(link_timer)); ++ ++ mpcs->interface = interface; ++ mode_changed = true; ++ } ++ ++ /* Update the advertisement, noting whether it has changed */ ++ regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, ++ SGMII_ADVERTISE, advertise, &changed); ++ ++ /* Update the sgmsys mode register */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | ++ SGMII_IF_MODE_SGMII, sgm_mode); ++ ++ /* Update the BMCR */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ BMCR_ANENABLE, bmcr); ++ ++ /* Release PHYA power down state ++ * Only removing bit SGMII_PHYA_PWD isn't enough. ++ * There are cases when the SGMII_PHYA_PWD register contains 0x9 which ++ * prevents SGMII from working. The SGMII still shows link but no traffic ++ * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was ++ * taken from a good working state of the SGMII interface. ++ * Unknown how much the QPHY needs but it is racy without a sleep. ++ * Tested on mt7622 & mt7986. ++ */ ++ usleep_range(50, 100); ++ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); ++ ++ return changed || mode_changed; ++} ++ ++static void mtk_pcs_lynxi_restart_an(struct phylink_pcs *pcs) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ ++ regmap_set_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, BMCR_ANRESTART); ++} ++ ++static void mtk_pcs_lynxi_link_up(struct phylink_pcs *pcs, unsigned int mode, ++ phy_interface_t interface, int speed, ++ int duplex) ++{ ++ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); ++ unsigned int sgm_mode; ++ ++ if (!phylink_autoneg_inband(mode)) { ++ /* Force the speed and duplex setting */ ++ if (speed == SPEED_10) ++ sgm_mode = SGMII_SPEED_10; ++ else if (speed == SPEED_100) ++ sgm_mode = SGMII_SPEED_100; ++ else ++ sgm_mode = SGMII_SPEED_1000; ++ ++ if (duplex != DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_HALF; ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, ++ sgm_mode); ++ } ++} ++ ++static const struct phylink_pcs_ops mtk_pcs_lynxi_ops = { ++ .pcs_get_state = mtk_pcs_lynxi_get_state, ++ .pcs_config = mtk_pcs_lynxi_config, ++ .pcs_an_restart = mtk_pcs_lynxi_restart_an, ++ .pcs_link_up = mtk_pcs_lynxi_link_up, ++}; ++ ++struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ++ struct regmap *regmap, u32 ana_rgc3, ++ u32 flags) ++{ ++ struct mtk_pcs_lynxi *mpcs; ++ u32 id, ver; ++ int ret; ++ ++ ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id); ++ if (ret < 0) ++ return NULL; ++ ++ if (id != SGMII_LYNXI_DEV_ID) { ++ dev_err(dev, "unknown PCS device id %08x\n", id); ++ return NULL; ++ } ++ ++ ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver); ++ if (ret < 0) ++ return NULL; ++ ++ ver = FIELD_GET(SGMII_DEV_VERSION, ver); ++ if (ver != 0x1) { ++ dev_err(dev, "unknown PCS device version %04x\n", ver); ++ return NULL; ++ } ++ ++ dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id, ++ ver); ++ ++ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL); ++ if (!mpcs) ++ return NULL; ++ ++ mpcs->ana_rgc3 = ana_rgc3; ++ mpcs->regmap = regmap; ++ mpcs->flags = flags; ++ mpcs->pcs.ops = &mtk_pcs_lynxi_ops; ++ mpcs->pcs.poll = true; ++ mpcs->interface = PHY_INTERFACE_MODE_NA; ++ ++ return &mpcs->pcs; ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_create); ++ ++void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) ++{ ++ if (!pcs) ++ return; ++ ++ kfree(pcs_to_mtk_pcs_lynxi(pcs)); ++} ++EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/include/linux/pcs/pcs-mtk-lynxi.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __LINUX_PCS_MTK_LYNXI_H ++#define __LINUX_PCS_MTK_LYNXI_H ++ ++#include ++#include ++ ++#define MTK_SGMII_FLAG_PN_SWAP BIT(0) ++struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, ++ struct regmap *regmap, ++ u32 ana_rgc3, u32 flags); ++void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs); ++#endif diff --git a/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch b/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch new file mode 100644 index 00000000000..817b3e10fdf --- /dev/null +++ b/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch @@ -0,0 +1,74 @@ +From 0cf731f9ebb5bf6f252055bebf4463a5c0bd490b Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 23 Aug 2022 14:24:07 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix hw hash reporting for + MTK_NETSYS_V2 + +Properly report hw rx hash for mt7986 chipset accroding to the new dma +descriptor layout. + +Fixes: 197c9e9b17b11 ("net: ethernet: mtk_eth_soc: introduce support for mt7986 chipset") +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/091394ea4e705fbb35f828011d98d0ba33808f69.1661257293.git.lorenzo@kernel.org +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 +++++++++++---------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +++++ + 2 files changed, 17 insertions(+), 10 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1846,10 +1846,19 @@ static int mtk_poll_rx(struct napi_struc + skb->dev = netdev; + bytes += skb->len; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; ++ if (hash != MTK_RXD5_FOE_ENTRY) ++ skb_set_hash(skb, jhash_1word(hash, 0), ++ PKT_HASH_TYPE_L4); + rxdcsum = &trxd.rxd3; +- else ++ } else { ++ hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; ++ if (hash != MTK_RXD4_FOE_ENTRY) ++ skb_set_hash(skb, jhash_1word(hash, 0), ++ PKT_HASH_TYPE_L4); + rxdcsum = &trxd.rxd4; ++ } + + if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) + skb->ip_summed = CHECKSUM_UNNECESSARY; +@@ -1857,16 +1866,9 @@ static int mtk_poll_rx(struct napi_struc + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); + +- hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; +- if (hash != MTK_RXD4_FOE_ENTRY) { +- hash = jhash_1word(hash, 0); +- skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); +- } +- + reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) +- mtk_ppe_check_skb(eth->ppe, skb, +- trxd.rxd4 & MTK_RXD4_FOE_ENTRY); ++ mtk_ppe_check_skb(eth->ppe, skb, hash); + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -314,6 +314,11 @@ + #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ + #define RX_DMA_SPECIAL_TAG BIT(22) + ++/* PDMA descriptor rxd5 */ ++#define MTK_RXD5_FOE_ENTRY GENMASK(14, 0) ++#define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18) ++#define MTK_RXD5_SRC_PORT GENMASK(29, 26) ++ + #define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) + #define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) + diff --git a/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch b/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch new file mode 100644 index 00000000000..0de8ab4376c --- /dev/null +++ b/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch @@ -0,0 +1,31 @@ +From: Tom Rix +Date: Sat, 16 Jul 2022 17:46:54 -0400 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix off by one check of + ARRAY_SIZE + +In mtk_wed_tx_ring_setup(.., int idx, ..), idx is used as an index here + struct mtk_wed_ring *ring = &dev->tx_ring[idx]; + +The bounds of idx are checked here + BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); + +If idx is the size of the array, it will pass this check and overflow. +So change the check to >= . + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Signed-off-by: Tom Rix +Link: https://lore.kernel.org/r/20220716214654.1540240-1-trix@redhat.com +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -651,7 +651,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + * WDMA RX. + */ + +- BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); ++ BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); + + if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) + return -ENOMEM; diff --git a/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch b/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch new file mode 100644 index 00000000000..fc6e2464688 --- /dev/null +++ b/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch @@ -0,0 +1,27 @@ +From: Lorenzo Bianconi +Date: Mon, 18 Jul 2022 11:51:53 +0200 +Subject: [PATCH] net: ethernet: mtk_ppe: fix possible NULL pointer dereference + in mtk_flow_get_wdma_info + +odev pointer can be NULL in mtk_flow_offload_replace routine according +to the flower action rules. Fix possible NULL pointer dereference in +mtk_flow_get_wdma_info. + +Fixes: a333215e10cb5 ("net: ethernet: mtk_eth_soc: implement flow offloading to WED devices") +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/4e1685bc4976e21e364055f6bee86261f8f9ee93.1658137753.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -93,6 +93,9 @@ mtk_flow_get_wdma_info(struct net_device + }; + struct net_device_path path = {}; + ++ if (!ctx.dev) ++ return -ENODEV; ++ + memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); + + if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) diff --git a/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch b/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch new file mode 100644 index 00000000000..c0720152d65 --- /dev/null +++ b/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch @@ -0,0 +1,64 @@ +From: Lorenzo Bianconi +Date: Fri, 22 Jul 2022 09:06:19 +0200 +Subject: [PATCH] net: ethernet: mtk-ppe: fix traffic offload with bridged wlan + +A typical flow offload scenario for OpenWrt users is routed traffic +received by the wan interface that is redirected to a wlan device +belonging to the lan bridge. Current implementation fails to +fill wdma offload info in mtk_flow_get_wdma_info() since odev device is +the local bridge. Fix the issue running dev_fill_forward_path routine in +mtk_flow_get_wdma_info in order to identify the wlan device. + +Tested-by: Paolo Valerio +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -88,32 +88,28 @@ mtk_flow_offload_mangle_eth(const struct + static int + mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info) + { +- struct net_device_path_ctx ctx = { +- .dev = dev, +- }; +- struct net_device_path path = {}; ++ struct net_device_path_stack stack; ++ struct net_device_path *path; ++ int err; + +- if (!ctx.dev) ++ if (!dev) + return -ENODEV; + +- memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); +- + if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) + return -1; + +- if (!dev->netdev_ops->ndo_fill_forward_path) +- return -1; +- +- if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path)) +- return -1; ++ err = dev_fill_forward_path(dev, addr, &stack); ++ if (err) ++ return err; + +- if (path.type != DEV_PATH_MTK_WDMA) ++ path = &stack.path[stack.num_paths - 1]; ++ if (path->type != DEV_PATH_MTK_WDMA) + return -1; + +- info->wdma_idx = path.mtk_wdma.wdma_idx; +- info->queue = path.mtk_wdma.queue; +- info->bss = path.mtk_wdma.bss; +- info->wcid = path.mtk_wdma.wcid; ++ info->wdma_idx = path->mtk_wdma.wdma_idx; ++ info->queue = path->mtk_wdma.queue; ++ info->bss = path->mtk_wdma.bss; ++ info->wcid = path->mtk_wdma.wcid; + + return 0; + } diff --git a/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch b/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch new file mode 100644 index 00000000000..3c28e835518 --- /dev/null +++ b/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch @@ -0,0 +1,33 @@ +From c9daab322313087afde8c46f41df3c628410ae20 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 14:46:01 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: remove mtk_foe_entry_timestamp + +Get rid of mtk_foe_entry_timestamp routine since it is no longer used. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 11 ----------- + 1 file changed, 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -302,17 +302,6 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + __mtk_ppe_check_skb(ppe, skb, hash); + } + +-static inline int +-mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash) +-{ +- u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1); +- +- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) +- return -1; +- +- return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1); +-} +- + int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, + u8 pse_port, u8 *src_mac, u8 *dest_mac); + int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port); diff --git a/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch b/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch new file mode 100644 index 00000000000..f6fc7340794 --- /dev/null +++ b/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch @@ -0,0 +1,35 @@ +From 5e69163d3b9931098922b3fc2f8e786af8c1f37e Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 13 Sep 2022 15:03:05 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: enable XDP support just for + MT7986 SoC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Disable page_pool/XDP support for MT7621 SoC in order fix a regression +introduce adding XDP for MT7986 SoC. There is no a real use case for XDP +on MT7621 since it is a low-end cpu. Moreover this patch reduces the +memory footprint. + +Tested-by: Sergio Paracuellos +Tested-by: Arınç ÜNAL +Fixes: 23233e577ef9 ("net: ethernet: mtk_eth_soc: rely on page_pool for single page buffers") +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/2bf31e27b888c43228b0d84dd2ef5033338269e2.1663074002.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1413,7 +1413,7 @@ static void mtk_update_rx_cpu_idx(struct + + static bool mtk_page_pool_enabled(struct mtk_eth *eth) + { +- return !eth->hwlro; ++ return MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2); + } + + static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, diff --git a/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch b/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch new file mode 100644 index 00000000000..f8bbea6c858 --- /dev/null +++ b/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch @@ -0,0 +1,127 @@ +From patchwork Thu Sep 8 19:33:38 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970556 +X-Patchwork-Delegate: kuba@kernel.org +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 03/12] net: ethernet: mtk_eth_soc: move gdma_to_ppe + and ppe_base definitions in mtk register map +Date: Thu, 8 Sep 2022 21:33:37 +0200 +Message-Id: + <95938fc9cbe0223714be2658a49ca58e9baace00.1662661555.git.lorenzo@kernel.org> +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +This is a preliminary patch to introduce mt7986 hw packet engine. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 15 +++++++++++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 ++- + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 -- + 3 files changed, 13 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -73,6 +73,8 @@ static const struct mtk_reg_map mtk_reg_ + .fq_blen = 0x1b2c, + }, + .gdm1_cnt = 0x2400, ++ .gdma_to_ppe0 = 0x4444, ++ .ppe_base = 0x0c00, + }; + + static const struct mtk_reg_map mt7628_reg_map = { +@@ -126,6 +128,8 @@ static const struct mtk_reg_map mt7986_r + .fq_blen = 0x472c, + }, + .gdm1_cnt = 0x1c00, ++ .gdma_to_ppe0 = 0x3333, ++ .ppe_base = 0x2000, + }; + + /* strings used by ethtool */ +@@ -2925,6 +2929,7 @@ static int mtk_open(struct net_device *d + + /* we run 2 netdevs on the same dma ring so we only bring it up once */ + if (!refcount_read(ð->dma_refcnt)) { ++ const struct mtk_soc_data *soc = eth->soc; + u32 gdm_config = MTK_GDMA_TO_PDMA; + int err; + +@@ -2934,15 +2939,15 @@ static int mtk_open(struct net_device *d + return err; + } + +- if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0) +- gdm_config = MTK_GDMA_TO_PPE; ++ if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) ++ gdm_config = soc->reg_map->gdma_to_ppe0; + + mtk_gdm_config(eth, gdm_config); + + napi_enable(ð->tx_napi); + napi_enable(ð->rx_napi); + mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); +- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); ++ mtk_rx_irq_enable(eth, soc->txrx.rx_irq_done_mask); + refcount_set(ð->dma_refcnt, 1); + } + else +@@ -4048,7 +4053,9 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2); ++ u32 ppe_addr = eth->soc->reg_map->ppe_base; ++ ++ eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); + if (!eth->ppe) { + err = -ENOMEM; + goto err_free_dev; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -105,7 +105,6 @@ + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) + #define MTK_GDMA_TO_PDMA 0x0 +-#define MTK_GDMA_TO_PPE 0x4444 + #define MTK_GDMA_DROP_ALL 0x7777 + + /* Unicast Filter MAC Address Register - Low */ +@@ -953,6 +952,8 @@ struct mtk_reg_map { + u32 fq_blen; /* fq free page buffer length */ + } qdma; + u32 gdm1_cnt; ++ u32 gdma_to_ppe0; ++ u32 ppe_base; + }; + + /* struct mtk_eth_data - This is the structure holding all differences +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -8,8 +8,6 @@ + #include + #include + +-#define MTK_ETH_PPE_BASE 0xc00 +- + #define MTK_PPE_ENTRIES_SHIFT 3 + #define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT) + #define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1) diff --git a/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch b/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch new file mode 100644 index 00000000000..7bed2785c99 --- /dev/null +++ b/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch @@ -0,0 +1,199 @@ +From patchwork Thu Sep 8 19:33:38 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970557 +X-Patchwork-Delegate: kuba@kernel.org +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 04/12] net: ethernet: mtk_eth_soc: move ppe table + hash offset to mtk_soc_data structure +Date: Thu, 8 Sep 2022 21:33:38 +0200 +Message-Id: + +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +This is a preliminary patch to introduce mt7986 hw packet engine. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 24 +++++++++++++++------ + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- + 4 files changed, 25 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4151,6 +4151,7 @@ static const struct mtk_soc_data mt7621_ + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4169,6 +4170,7 @@ static const struct mtk_soc_data mt7622_ + .required_clks = MT7622_CLKS_BITMAP, + .required_pctl = false, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4186,6 +4188,7 @@ static const struct mtk_soc_data mt7623_ + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, + .offload_version = 2, ++ .hash_offset = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4219,6 +4222,7 @@ static const struct mtk_soc_data mt7986_ + .caps = MT7986_CAPS, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, ++ .hash_offset = 4, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -967,6 +967,7 @@ struct mtk_reg_map { + * the target SoC + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. ++ * @hash_offset Flow table hash offset. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. + * @rx_irq_done_mask Rx irq done register mask. +@@ -981,6 +982,7 @@ struct mtk_soc_data { + u32 required_clks; + bool required_pctl; + u8 offload_version; ++ u8 hash_offset; + netdev_features_t hw_features; + struct { + u32 txd_size; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -88,7 +88,7 @@ static void mtk_ppe_cache_enable(struct + enable * MTK_PPE_CACHE_CTL_EN); + } + +-static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e) ++static u32 mtk_ppe_hash_entry(struct mtk_eth *eth, struct mtk_foe_entry *e) + { + u32 hv1, hv2, hv3; + u32 hash; +@@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk + hash = (hash >> 24) | ((hash & 0xffffff) << 8); + hash ^= hv1 ^ hv2 ^ hv3; + hash ^= hash >> 16; +- hash <<= 1; ++ hash <<= (ffs(eth->soc->hash_offset) - 1); + hash &= MTK_PPE_ENTRIES - 1; + + return hash; +@@ -540,15 +540,16 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ const struct mtk_soc_data *soc = ppe->eth->soc; + u32 hash; + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return mtk_foe_entry_commit_l2(ppe, entry); + +- hash = mtk_ppe_hash_entry(&entry->data); ++ hash = mtk_ppe_hash_entry(ppe->eth, &entry->data); + entry->hash = 0xffff; + spin_lock_bh(&ppe_lock); +- hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); ++ hlist_add_head(&entry->list, &ppe->foe_flow[hash / soc->hash_offset]); + spin_unlock_bh(&ppe_lock); + + return 0; +@@ -558,6 +559,7 @@ static void + mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, + u16 hash) + { ++ const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; + struct mtk_foe_entry foe, *hwe; + struct mtk_foe_mac_info *l2; +@@ -572,7 +574,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + flow_info->l2_data.base_flow = entry; + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; + flow_info->hash = hash; +- hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); ++ hlist_add_head(&flow_info->list, ++ &ppe->foe_flow[hash / soc->hash_offset]); + hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); + + hwe = &ppe->foe_table[hash]; +@@ -596,7 +599,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) + { +- struct hlist_head *head = &ppe->foe_flow[hash / 2]; ++ const struct mtk_soc_data *soc = ppe->eth->soc; ++ struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; + struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; +@@ -680,9 +684,11 @@ int mtk_foe_entry_idle_time(struct mtk_p + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, + int version) + { ++ const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; + struct mtk_foe_entry *foe; + struct mtk_ppe *ppe; ++ u32 foe_flow_size; + + ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); + if (!ppe) +@@ -705,6 +711,12 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + + ppe->foe_table = foe; + ++ foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * ++ sizeof(*ppe->foe_flow); ++ ppe->foe_flow = devm_kzalloc(dev, foe_flow_size, GFP_KERNEL); ++ if (!ppe->foe_flow) ++ return NULL; ++ + mtk_ppe_debugfs_init(ppe); + + return ppe; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -270,7 +270,7 @@ struct mtk_ppe { + dma_addr_t foe_phys; + + u16 foe_check_time[MTK_PPE_ENTRIES]; +- struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; ++ struct hlist_head *foe_flow; + + struct rhashtable l2_flows; + diff --git a/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch b/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch new file mode 100644 index 00000000000..93860e41457 --- /dev/null +++ b/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch @@ -0,0 +1,318 @@ +From patchwork Thu Sep 8 19:33:39 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Lorenzo Bianconi +X-Patchwork-Id: 12970559 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +From: Lorenzo Bianconi +To: netdev@vger.kernel.org +Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, + Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, + linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, + Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, + ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, + devicetree@vger.kernel.org, robh@kernel.org +Subject: [PATCH net-next 05/12] net: ethernet: mtk_eth_soc: add the capability + to run multiple ppe +Date: Thu, 8 Sep 2022 21:33:39 +0200 +Message-Id: + +X-Mailer: git-send-email 2.37.3 +In-Reply-To: +References: +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +mt7986 chipset support multiple packet engines for wlan <-> eth +packet forwarding. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 35 ++++++++++++------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + drivers/net/ethernet/mediatek/mtk_ppe.c | 14 +++++--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 9 +++-- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 8 ++--- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 13 +++---- + 6 files changed, 48 insertions(+), 33 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1872,7 +1872,7 @@ static int mtk_poll_rx(struct napi_struc + + reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) +- mtk_ppe_check_skb(eth->ppe, skb, hash); ++ mtk_ppe_check_skb(eth->ppe[0], skb, hash); + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +@@ -2930,7 +2930,8 @@ static int mtk_open(struct net_device *d + /* we run 2 netdevs on the same dma ring so we only bring it up once */ + if (!refcount_read(ð->dma_refcnt)) { + const struct mtk_soc_data *soc = eth->soc; +- u32 gdm_config = MTK_GDMA_TO_PDMA; ++ u32 gdm_config; ++ int i; + int err; + + err = mtk_start_dma(eth); +@@ -2939,8 +2940,11 @@ static int mtk_open(struct net_device *d + return err; + } + +- if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) +- gdm_config = soc->reg_map->gdma_to_ppe0; ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_start(eth->ppe[i]); ++ ++ gdm_config = soc->offload_version ? soc->reg_map->gdma_to_ppe0 ++ : MTK_GDMA_TO_PDMA; + + mtk_gdm_config(eth, gdm_config); + +@@ -2985,6 +2989,7 @@ static int mtk_stop(struct net_device *d + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; ++ int i; + + phylink_stop(mac->phylink); + +@@ -3012,8 +3017,8 @@ static int mtk_stop(struct net_device *d + + mtk_dma_free(eth); + +- if (eth->soc->offload_version) +- mtk_ppe_stop(eth->ppe); ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_stop(eth->ppe[i]); + + return 0; + } +@@ -4053,12 +4058,19 @@ static int mtk_probe(struct platform_dev + } + + if (eth->soc->offload_version) { +- u32 ppe_addr = eth->soc->reg_map->ppe_base; ++ u32 num_ppe; + +- eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); +- if (!eth->ppe) { +- err = -ENOMEM; +- goto err_free_dev; ++ num_ppe = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; ++ num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe); ++ for (i = 0; i < num_ppe; i++) { ++ u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; ++ ++ eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, ++ eth->soc->offload_version, i); ++ if (!eth->ppe[i]) { ++ err = -ENOMEM; ++ goto err_free_dev; ++ } + } + + err = mtk_eth_offload_init(eth); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1112,7 +1112,7 @@ struct mtk_eth { + + int ip_align; + +- struct mtk_ppe *ppe; ++ struct mtk_ppe *ppe[2]; + struct rhashtable flow_table; + + struct bpf_prog __rcu *prog; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -682,7 +682,7 @@ int mtk_foe_entry_idle_time(struct mtk_p + } + + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, +- int version) ++ int version, int index) + { + const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; +@@ -717,7 +717,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + if (!ppe->foe_flow) + return NULL; + +- mtk_ppe_debugfs_init(ppe); ++ mtk_ppe_debugfs_init(ppe, index); + + return ppe; + } +@@ -738,10 +738,13 @@ static void mtk_ppe_init_foe_table(struc + ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; + } + +-int mtk_ppe_start(struct mtk_ppe *ppe) ++void mtk_ppe_start(struct mtk_ppe *ppe) + { + u32 val; + ++ if (!ppe) ++ return; ++ + mtk_ppe_init_foe_table(ppe); + ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys); + +@@ -809,8 +812,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe) + ppe_w32(ppe, MTK_PPE_GLO_CFG, val); + + ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); +- +- return 0; + } + + int mtk_ppe_stop(struct mtk_ppe *ppe) +@@ -818,6 +819,9 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) + u32 val; + int i; + ++ if (!ppe) ++ return 0; ++ + for (i = 0; i < MTK_PPE_ENTRIES; i++) + ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, + MTK_FOE_STATE_INVALID); +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -247,6 +247,7 @@ struct mtk_flow_entry { + }; + u8 type; + s8 wed_index; ++ u8 ppe_index; + u16 hash; + union { + struct mtk_foe_entry data; +@@ -265,6 +266,7 @@ struct mtk_ppe { + struct device *dev; + void __iomem *base; + int version; ++ char dirname[5]; + + struct mtk_foe_entry *foe_table; + dma_addr_t foe_phys; +@@ -277,8 +279,9 @@ struct mtk_ppe { + void *acct_table; + }; + +-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version); +-int mtk_ppe_start(struct mtk_ppe *ppe); ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, ++ int version, int index); ++void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); +@@ -317,6 +320,6 @@ int mtk_foe_entry_set_wdma(struct mtk_fo + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); ++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); + + #endif +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -187,7 +187,7 @@ mtk_ppe_debugfs_foe_open_bind(struct ino + inode->i_private); + } + +-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe) ++int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) + { + static const struct file_operations fops_all = { + .open = mtk_ppe_debugfs_foe_open_all, +@@ -195,17 +195,17 @@ int mtk_ppe_debugfs_init(struct mtk_ppe + .llseek = seq_lseek, + .release = single_release, + }; +- + static const struct file_operations fops_bind = { + .open = mtk_ppe_debugfs_foe_open_bind, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + }; +- + struct dentry *root; + +- root = debugfs_create_dir("mtk_ppe", NULL); ++ snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index); ++ ++ root = debugfs_create_dir(ppe->dirname, NULL); + if (!root) + return -ENOMEM; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -434,7 +434,7 @@ mtk_flow_offload_replace(struct mtk_eth + memcpy(&entry->data, &foe, sizeof(entry->data)); + entry->wed_index = wed_index; + +- err = mtk_foe_entry_commit(eth->ppe, entry); ++ err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry); + if (err < 0) + goto free; + +@@ -446,7 +446,7 @@ mtk_flow_offload_replace(struct mtk_eth + return 0; + + clear: +- mtk_foe_entry_clear(eth->ppe, entry); ++ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); + free: + kfree(entry); + if (wed_index >= 0) +@@ -464,7 +464,7 @@ mtk_flow_offload_destroy(struct mtk_eth + if (!entry) + return -ENOENT; + +- mtk_foe_entry_clear(eth->ppe, entry); ++ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); + rhashtable_remove_fast(ð->flow_table, &entry->node, + mtk_flow_ht_params); + if (entry->wed_index >= 0) +@@ -485,7 +485,7 @@ mtk_flow_offload_stats(struct mtk_eth *e + if (!entry) + return -ENOENT; + +- idle = mtk_foe_entry_idle_time(eth->ppe, entry); ++ idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); + f->stats.lastused = jiffies - idle * HZ; + + return 0; +@@ -537,7 +537,7 @@ mtk_eth_setup_tc_block(struct net_device + struct flow_block_cb *block_cb; + flow_setup_cb_t *cb; + +- if (!eth->ppe || !eth->ppe->foe_table) ++ if (!eth->soc->offload_version) + return -EOPNOTSUPP; + + if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) +@@ -590,8 +590,5 @@ int mtk_eth_setup_tc(struct net_device * + + int mtk_eth_offload_init(struct mtk_eth *eth) + { +- if (!eth->ppe || !eth->ppe->foe_table) +- return 0; +- + return rhashtable_init(ð->flow_table, &mtk_flow_ht_params); + } diff --git a/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch b/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch new file mode 100644 index 00000000000..a4b285632e1 --- /dev/null +++ b/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch @@ -0,0 +1,80 @@ +From 0dcbe607cec32ccae23b02a641b8bd6191a328ae Mon Sep 17 00:00:00 2001 +Message-Id: <0dcbe607cec32ccae23b02a641b8bd6191a328ae.1662243796.git.lorenzo@kernel.org> +In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Tue, 23 Aug 2022 23:09:05 +0200 +Subject: [PATCH net-next 2/4] net: ethernet: mtk_eth_soc: move wdma_base + definitions in mtk register map + +This is a preliminary patch to introduce mt7986 wed support. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++++------ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +--- + 2 files changed, 11 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -75,6 +75,10 @@ static const struct mtk_reg_map mtk_reg_ + .gdm1_cnt = 0x2400, + .gdma_to_ppe0 = 0x4444, + .ppe_base = 0x0c00, ++ .wdma_base = { ++ [0] = 0x2800, ++ [1] = 0x2c00, ++ }, + }; + + static const struct mtk_reg_map mt7628_reg_map = { +@@ -130,6 +134,10 @@ static const struct mtk_reg_map mt7986_r + .gdm1_cnt = 0x1c00, + .gdma_to_ppe0 = 0x3333, + .ppe_base = 0x2000, ++ .wdma_base = { ++ [0] = 0x4800, ++ [1] = 0x4c00, ++ }, + }; + + /* strings used by ethtool */ +@@ -3970,16 +3978,12 @@ static int mtk_probe(struct platform_dev + for (i = 0;; i++) { + struct device_node *np = of_parse_phandle(pdev->dev.of_node, + "mediatek,wed", i); +- static const u32 wdma_regs[] = { +- MTK_WDMA0_BASE, +- MTK_WDMA1_BASE +- }; + void __iomem *wdma; + +- if (!np || i >= ARRAY_SIZE(wdma_regs)) ++ if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) + break; + +- wdma = eth->base + wdma_regs[i]; ++ wdma = eth->base + eth->soc->reg_map->wdma_base[i]; + mtk_wed_add_hw(np, eth, wdma, i); + } + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -268,9 +268,6 @@ + #define TX_DMA_FPORT_MASK_V2 0xf + #define TX_DMA_SWC_V2 BIT(30) + +-#define MTK_WDMA0_BASE 0x2800 +-#define MTK_WDMA1_BASE 0x2c00 +- + /* QDMA descriptor txd4 */ + #define TX_DMA_CHKSUM (0x7 << 29) + #define TX_DMA_TSO BIT(28) +@@ -954,6 +951,7 @@ struct mtk_reg_map { + u32 gdm1_cnt; + u32 gdma_to_ppe0; + u32 ppe_base; ++ u32 wdma_base[2]; + }; + + /* struct mtk_eth_data - This is the structure holding all differences diff --git a/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch b/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch new file mode 100644 index 00000000000..2bce63c4c01 --- /dev/null +++ b/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch @@ -0,0 +1,251 @@ +From e3c27d869fccc1f2b8d0b4cde4763ab223874e8c Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Sun, 21 Aug 2022 17:51:17 +0200 +Subject: [PATCH net-next 3/4] net: ethernet: mtk_eth_soc: add foe_entry_size + to mtk_eth_soc + +Introduce foe_entry_size to mtk_eth_soc data structure since mt7986 +relies on a bigger mtk_foe_entry data structure. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 + + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 55 +++++++++++-------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- + 5 files changed, 48 insertions(+), 24 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4168,6 +4168,7 @@ static const struct mtk_soc_data mt7621_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4187,6 +4188,7 @@ static const struct mtk_soc_data mt7622_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4205,6 +4207,7 @@ static const struct mtk_soc_data mt7623_ + .required_pctl = true, + .offload_version = 2, + .hash_offset = 2, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -966,6 +966,7 @@ struct mtk_reg_map { + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. + * @hash_offset Flow table hash offset. ++ * @foe_entry_size Foe table entry size. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. + * @rx_irq_done_mask Rx irq done register mask. +@@ -981,6 +982,7 @@ struct mtk_soc_data { + bool required_pctl; + u8 offload_version; + u8 hash_offset; ++ u16 foe_entry_size; + netdev_features_t hw_features; + struct { + u32 txd_size; +@@ -1141,6 +1143,14 @@ struct mtk_mac { + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ + extern const struct of_device_id of_mtk_match[]; + ++static inline struct mtk_foe_entry * ++mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) ++{ ++ const struct mtk_soc_data *soc = ppe->eth->soc; ++ ++ return ppe->foe_table + hash * soc->foe_entry_size; ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -410,9 +410,10 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + + hlist_del_init(&entry->list); + if (entry->hash != 0xffff) { +- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; +- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, +- MTK_FOE_STATE_BIND); ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); ++ ++ hwe->ib1 &= ~MTK_FOE_IB1_STATE; ++ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); + dma_wmb(); + } + entry->hash = 0xffff; +@@ -451,7 +452,7 @@ mtk_flow_entry_update_l2(struct mtk_ppe + int cur_idle; + u32 ib1; + +- hwe = &ppe->foe_table[cur->hash]; ++ hwe = mtk_foe_get_entry(ppe, cur->hash); + ib1 = READ_ONCE(hwe->ib1); + + if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { +@@ -473,8 +474,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe + static void + mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { ++ struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; +- struct mtk_foe_entry foe; + + spin_lock_bh(&ppe_lock); + +@@ -486,8 +487,8 @@ mtk_flow_entry_update(struct mtk_ppe *pp + if (entry->hash == 0xffff) + goto out; + +- hwe = &ppe->foe_table[entry->hash]; +- memcpy(&foe, hwe, sizeof(foe)); ++ hwe = mtk_foe_get_entry(ppe, entry->hash); ++ memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); + if (!mtk_flow_entry_match(entry, &foe)) { + entry->hash = 0xffff; + goto out; +@@ -511,8 +512,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; + entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); + +- hwe = &ppe->foe_table[hash]; +- memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); ++ hwe = mtk_foe_get_entry(ppe, hash); ++ memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); + wmb(); + hwe->ib1 = entry->ib1; + +@@ -561,7 +562,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; +- struct mtk_foe_entry foe, *hwe; ++ struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; + u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; + int type; +@@ -578,8 +579,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + &ppe->foe_flow[hash / soc->hash_offset]); + hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); + +- hwe = &ppe->foe_table[hash]; +- memcpy(&foe, hwe, sizeof(foe)); ++ hwe = mtk_foe_get_entry(ppe, hash); ++ memcpy(&foe, hwe, soc->foe_entry_size); + foe.ib1 &= ib1_mask; + foe.ib1 |= entry->data.ib1 & ~ib1_mask; + +@@ -601,7 +602,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; +- struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; + struct hlist_node *n; +@@ -686,9 +687,9 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + { + const struct mtk_soc_data *soc = eth->soc; + struct device *dev = eth->dev; +- struct mtk_foe_entry *foe; + struct mtk_ppe *ppe; + u32 foe_flow_size; ++ void *foe; + + ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); + if (!ppe) +@@ -704,7 +705,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + ppe->dev = dev; + ppe->version = version; + +- foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), ++ foe = dmam_alloc_coherent(ppe->dev, ++ MTK_PPE_ENTRIES * soc->foe_entry_size, + &ppe->foe_phys, GFP_KERNEL); + if (!foe) + return NULL; +@@ -727,15 +729,21 @@ static void mtk_ppe_init_foe_table(struc + static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 }; + int i, k; + +- memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(*ppe->foe_table)); ++ memset(ppe->foe_table, 0, ++ MTK_PPE_ENTRIES * ppe->eth->soc->foe_entry_size); + + if (!IS_ENABLED(CONFIG_SOC_MT7621)) + return; + + /* skip all entries that cross the 1024 byte boundary */ +- for (i = 0; i < MTK_PPE_ENTRIES; i += 128) +- for (k = 0; k < ARRAY_SIZE(skip); k++) +- ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; ++ for (i = 0; i < MTK_PPE_ENTRIES; i += 128) { ++ for (k = 0; k < ARRAY_SIZE(skip); k++) { ++ struct mtk_foe_entry *hwe; ++ ++ hwe = mtk_foe_get_entry(ppe, i + skip[k]); ++ hwe->ib1 |= MTK_FOE_IB1_STATIC; ++ } ++ } + } + + void mtk_ppe_start(struct mtk_ppe *ppe) +@@ -822,9 +830,12 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) + if (!ppe) + return 0; + +- for (i = 0; i < MTK_PPE_ENTRIES; i++) +- ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, +- MTK_FOE_STATE_INVALID); ++ for (i = 0; i < MTK_PPE_ENTRIES; i++) { ++ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, i); ++ ++ hwe->ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, ++ MTK_FOE_STATE_INVALID); ++ } + + mtk_ppe_cache_enable(ppe, false); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -268,7 +268,7 @@ struct mtk_ppe { + int version; + char dirname[5]; + +- struct mtk_foe_entry *foe_table; ++ void *foe_table; + dma_addr_t foe_phys; + + u16 foe_check_time[MTK_PPE_ENTRIES]; +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -79,7 +79,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file + int i; + + for (i = 0; i < MTK_PPE_ENTRIES; i++) { +- struct mtk_foe_entry *entry = &ppe->foe_table[i]; ++ struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); + struct mtk_foe_mac_info *l2; + struct mtk_flow_addr_info ai = {}; + unsigned char h_source[ETH_ALEN]; diff --git a/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch b/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch new file mode 100644 index 00000000000..77daf6c8bfe --- /dev/null +++ b/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch @@ -0,0 +1,27 @@ +From 12ff69304c83c679ca01ef3db963ab0db9de19fb Mon Sep 17 00:00:00 2001 +Message-Id: <12ff69304c83c679ca01ef3db963ab0db9de19fb.1662332102.git.lorenzo@kernel.org> +In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 00:43:43 +0200 +Subject: [PATCH net-next 2/6] net: ethernet: mtk_eth_soc: fix typo in + __mtk_foe_entry_clear + +Set ib1 state to MTK_FOE_STATE_UNBIND in __mtk_foe_entry_clear routine. + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -413,7 +413,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); ++ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_UNBIND); + dma_wmb(); + } + entry->hash = 0xffff; diff --git a/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch b/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch new file mode 100644 index 00000000000..7ab6d486b22 --- /dev/null +++ b/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch @@ -0,0 +1,28 @@ +From 4253e6e2b795a18ab534adcd5c313d3fc4150975 Mon Sep 17 00:00:00 2001 +Message-Id: <4253e6e2b795a18ab534adcd5c313d3fc4150975.1662332102.git.lorenzo@kernel.org> +In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 00:48:52 +0200 +Subject: [PATCH net-next 3/6] net: ethernet: mtk_eth_soc: check max allowed + value in mtk_ppe_check_skb + +Check theoretical OOB accesses in mtk_ppe_check_skb routine + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_ppe.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -294,6 +294,9 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + if (!ppe) + return; + ++ if (hash > MTK_PPE_HASH_MASK) ++ return; ++ + now = (u16)jiffies; + diff = now - ppe->foe_check_time[hash]; + if (diff < HZ / 10) diff --git a/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch b/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch new file mode 100644 index 00000000000..a8c88daf1ff --- /dev/null +++ b/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch @@ -0,0 +1,189 @@ +From e5ecb4f619197b93fa682d722452dc8412864cdb Mon Sep 17 00:00:00 2001 +Message-Id: +From: Lorenzo Bianconi +Date: Fri, 26 Aug 2022 01:12:57 +0200 +Subject: [PATCH net-next 1/5] net: ethernet: mtk_eth_wed: add + mtk_wed_configure_irq and mtk_wed_dma_{enable/disable} + +Introduce mtk_wed_configure_irq, mtk_wed_dma_enable and mtk_wed_dma_disable +utility routines. +This is a preliminary patch to introduce mt7986 wed support. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 87 +++++++++++++------- + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 6 +- + 2 files changed, 64 insertions(+), 29 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -237,9 +237,30 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + } + + static void +-mtk_wed_stop(struct mtk_wed_device *dev) ++mtk_wed_dma_disable(struct mtk_wed_device *dev) + { ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); ++ ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); ++ ++ wed_clr(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_TX_DMA_EN | ++ MTK_WED_GLO_CFG_RX_DMA_EN); ++ + regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); ++ wdma_m32(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_TX_DMA_EN | ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++} ++ ++static void ++mtk_wed_stop(struct mtk_wed_device *dev) ++{ ++ mtk_wed_dma_disable(dev); + mtk_wed_set_ext_int(dev, false); + + wed_clr(dev, MTK_WED_CTRL, +@@ -252,15 +273,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) + wdma_w32(dev, MTK_WDMA_INT_MASK, 0); + wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); + wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); +- +- wed_clr(dev, MTK_WED_GLO_CFG, +- MTK_WED_GLO_CFG_TX_DMA_EN | +- MTK_WED_GLO_CFG_RX_DMA_EN); +- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, +- MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | +- MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); +- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, +- MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); + } + + static void +@@ -313,7 +325,10 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; + wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); + +- wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES); ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); + + offset = dev->hw->index ? 0x04000400 : 0; + wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); +@@ -520,43 +535,38 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_d + } + + static void +-mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) ++mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) + { +- u32 wdma_mask; +- u32 val; +- int i; +- +- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +- if (!dev->tx_wdma[i].desc) +- mtk_wed_wdma_ring_setup(dev, i, 16); +- +- wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); +- +- mtk_wed_hw_init(dev); ++ u32 wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); + ++ /* wed control cr set */ + wed_set(dev, MTK_WED_CTRL, + MTK_WED_CTRL_WDMA_INT_AGENT_EN | + MTK_WED_CTRL_WPDMA_INT_AGENT_EN | + MTK_WED_CTRL_WED_TX_BM_EN | + MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); + +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, ++ MTK_WED_PCIE_INT_TRIGGER_STATUS); + + wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, + MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | + MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); + +- wed_set(dev, MTK_WED_WPDMA_INT_CTRL, +- MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); +- ++ /* initail wdma interrupt agent */ + wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); + wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); + + wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); + wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); +- + wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask); + wed_w32(dev, MTK_WED_INT_MASK, irq_mask); ++} ++ ++static void ++mtk_wed_dma_enable(struct mtk_wed_device *dev) ++{ ++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); + + wed_set(dev, MTK_WED_GLO_CFG, + MTK_WED_GLO_CFG_TX_DMA_EN | +@@ -567,6 +577,26 @@ mtk_wed_start(struct mtk_wed_device *dev + wed_set(dev, MTK_WED_WDMA_GLO_CFG, + MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); + ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_TX_DMA_EN | ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++} ++ ++static void ++mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) ++{ ++ u32 val; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) ++ if (!dev->tx_wdma[i].desc) ++ mtk_wed_wdma_ring_setup(dev, i, 16); ++ ++ mtk_wed_hw_init(dev); ++ mtk_wed_configure_irq(dev, irq_mask); ++ + mtk_wed_set_ext_int(dev, true); + val = dev->wlan.wpdma_phys | + MTK_PCIE_MIRROR_MAP_EN | +@@ -577,6 +607,7 @@ mtk_wed_start(struct mtk_wed_device *dev + val |= BIT(0); + regmap_write(dev->hw->mirror, dev->hw->index * 4, val); + ++ mtk_wed_dma_enable(dev); + dev->running = true; + } + +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -224,7 +224,11 @@ struct mtk_wdma_desc { + #define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) + + #define MTK_WDMA_GLO_CFG 0x204 +-#define MTK_WDMA_GLO_CFG_RX_INFO_PRERES GENMASK(28, 26) ++#define MTK_WDMA_GLO_CFG_TX_DMA_EN BIT(0) ++#define MTK_WDMA_GLO_CFG_RX_DMA_EN BIT(2) ++#define MTK_WDMA_GLO_CFG_RX_INFO3_PRERES BIT(26) ++#define MTK_WDMA_GLO_CFG_RX_INFO2_PRERES BIT(27) ++#define MTK_WDMA_GLO_CFG_RX_INFO1_PRERES BIT(28) + + #define MTK_WDMA_RESET_IDX 0x208 + #define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) diff --git a/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch b/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch new file mode 100644 index 00000000000..bfca7b20e45 --- /dev/null +++ b/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch @@ -0,0 +1,942 @@ +From 463a71af080fbc77339bee2037fb1e081e3824f7 Mon Sep 17 00:00:00 2001 +Message-Id: <463a71af080fbc77339bee2037fb1e081e3824f7.1662886034.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Sat, 27 Aug 2022 16:15:14 +0200 +Subject: [PATCH net-next 2/5] net: ethernet: mtk_eth_wed: add wed support for + mt7986 chipset + +Introduce Wireless Etherne Dispatcher support on transmission side +for mt7986 chipset + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 +- + drivers/net/ethernet/mediatek/mtk_wed.c | 371 ++++++++++++++---- + drivers/net/ethernet/mediatek/mtk_wed.h | 8 +- + .../net/ethernet/mediatek/mtk_wed_debugfs.c | 3 + + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 81 +++- + include/linux/soc/mediatek/mtk_wed.h | 8 + + 6 files changed, 408 insertions(+), 97 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3895,6 +3895,7 @@ void mtk_eth_set_dma_device(struct mtk_e + + static int mtk_probe(struct platform_device *pdev) + { ++ struct resource *res = NULL; + struct device_node *mac_np; + struct mtk_eth *eth; + int err, i; +@@ -3975,16 +3976,31 @@ static int mtk_probe(struct platform_dev + } + } + +- for (i = 0;; i++) { +- struct device_node *np = of_parse_phandle(pdev->dev.of_node, +- "mediatek,wed", i); +- void __iomem *wdma; +- +- if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) +- break; +- +- wdma = eth->base + eth->soc->reg_map->wdma_base[i]; +- mtk_wed_add_hw(np, eth, wdma, i); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ } ++ ++ if (eth->soc->offload_version) { ++ for (i = 0;; i++) { ++ struct device_node *np; ++ phys_addr_t wdma_phy; ++ u32 wdma_base; ++ ++ if (i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) ++ break; ++ ++ np = of_parse_phandle(pdev->dev.of_node, ++ "mediatek,wed", i); ++ if (!np) ++ break; ++ ++ wdma_base = eth->soc->reg_map->wdma_base[i]; ++ wdma_phy = res ? res->start + wdma_base : 0; ++ mtk_wed_add_hw(np, eth, eth->base + wdma_base, ++ wdma_phy, i); ++ } + } + + for (i = 0; i < 3; i++) { +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -25,6 +25,11 @@ + + #define MTK_WED_TX_RING_SIZE 2048 + #define MTK_WED_WDMA_RING_SIZE 1024 ++#define MTK_WED_MAX_GROUP_SIZE 0x100 ++#define MTK_WED_VLD_GROUP_SIZE 0x40 ++#define MTK_WED_PER_GROUP_PKT 128 ++ ++#define MTK_WED_FBUF_SIZE 128 + + static struct mtk_wed_hw *hw_list[2]; + static DEFINE_MUTEX(hw_lock); +@@ -150,10 +155,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi + + desc->buf0 = cpu_to_le32(buf_phys); + desc->buf1 = cpu_to_le32(buf_phys + txd_size); +- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | +- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, +- MTK_WED_BUF_SIZE - txd_size) | +- MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ ++ if (dev->hw->version == 1) ++ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG1; ++ else ++ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | ++ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2, ++ MTK_WED_BUF_SIZE - txd_size) | ++ MTK_WDMA_DESC_CTRL_LAST_SEG0; + desc->ctrl = cpu_to_le32(ctrl); + desc->info = 0; + desc++; +@@ -209,7 +221,7 @@ mtk_wed_free_ring(struct mtk_wed_device + if (!ring->desc) + return; + +- dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc), ++ dma_free_coherent(dev->hw->dev, ring->size * ring->desc_size, + ring->desc, ring->desc_phys); + } + +@@ -229,6 +241,14 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + { + u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; + ++ if (dev->hw->version == 1) ++ mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; ++ else ++ mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | ++ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | ++ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | ++ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; ++ + if (!dev->hw->num_flows) + mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; + +@@ -237,6 +257,20 @@ mtk_wed_set_ext_int(struct mtk_wed_devic + } + + static void ++mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable) ++{ ++ if (enable) { ++ wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); ++ wed_w32(dev, MTK_WED_TXP_DW1, ++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103)); ++ } else { ++ wed_w32(dev, MTK_WED_TXP_DW1, ++ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100)); ++ wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); ++ } ++} ++ ++static void + mtk_wed_dma_disable(struct mtk_wed_device *dev) + { + wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, +@@ -249,12 +283,22 @@ mtk_wed_dma_disable(struct mtk_wed_devic + MTK_WED_GLO_CFG_TX_DMA_EN | + MTK_WED_GLO_CFG_RX_DMA_EN); + +- regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); + wdma_m32(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_TX_DMA_EN | + MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0); ++ ++ if (dev->hw->version == 1) { ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); ++ wdma_m32(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++ } else { ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); ++ ++ mtk_wed_set_512_support(dev, false); ++ } + } + + static void +@@ -293,7 +337,7 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_free_buffer(dev); + mtk_wed_free_tx_rings(dev); + +- if (of_dma_is_coherent(wlan_node)) ++ if (of_dma_is_coherent(wlan_node) && hw->hifsys) + regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, + BIT(hw->index), BIT(hw->index)); + +@@ -308,14 +352,69 @@ mtk_wed_detach(struct mtk_wed_device *de + mutex_unlock(&hw_lock); + } + ++#define PCIE_BASE_ADDR0 0x11280000 ++static void ++mtk_wed_bus_init(struct mtk_wed_device *dev) ++{ ++ struct device_node *np = dev->hw->eth->dev->of_node; ++ struct regmap *regs; ++ u32 val; ++ ++ regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); ++ if (IS_ERR(regs)) ++ return; ++ ++ regmap_update_bits(regs, 0, BIT(0), BIT(0)); ++ ++ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); ++ ++ /* pcie interrupt control: pola/source selection */ ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); ++ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ ++ /* pcie interrupt status trigger register */ ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); ++ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); ++ ++ /* pola setting */ ++ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++} ++ ++static void ++mtk_wed_set_wpdma(struct mtk_wed_device *dev) ++{ ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); ++ } else { ++ mtk_wed_bus_init(dev); ++ ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree); ++ } ++} ++ + static void + mtk_wed_hw_init_early(struct mtk_wed_device *dev) + { + u32 mask, set; +- u32 offset; + + mtk_wed_stop(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ mtk_wed_set_wpdma(dev); + + mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE | + MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE | +@@ -325,17 +424,33 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; + wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); + +- wdma_set(dev, MTK_WDMA_GLO_CFG, +- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); +- +- offset = dev->hw->index ? 0x04000400 : 0; +- wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); +- wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); ++ if (dev->hw->version == 1) { ++ u32 offset = dev->hw->index ? 0x04000400 : 0; + +- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index)); +- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ ++ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); ++ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, ++ MTK_PCIE_BASE(dev->hw->index)); ++ } else { ++ wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy); ++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT); ++ wed_w32(dev, MTK_WED_WDMA_OFFSET0, ++ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_INTS, ++ MTK_WDMA_INT_STATUS) | ++ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_CFG, ++ MTK_WDMA_GLO_CFG)); ++ ++ wed_w32(dev, MTK_WED_WDMA_OFFSET1, ++ FIELD_PREP(MTK_WED_WDMA_OFST1_TX_CTRL, ++ MTK_WDMA_RING_TX(0)) | ++ FIELD_PREP(MTK_WED_WDMA_OFST1_RX_CTRL, ++ MTK_WDMA_RING_RX(0))); ++ } + } + + static void +@@ -355,37 +470,65 @@ mtk_wed_hw_init(struct mtk_wed_device *d + + wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); + +- wed_w32(dev, MTK_WED_TX_BM_TKID, +- FIELD_PREP(MTK_WED_TX_BM_TKID_START, +- dev->wlan.token_start) | +- FIELD_PREP(MTK_WED_TX_BM_TKID_END, +- dev->wlan.token_start + dev->wlan.nbuf - 1)); +- + wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); + +- wed_w32(dev, MTK_WED_TX_BM_DYN_THR, +- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | +- MTK_WED_TX_BM_DYN_THR_HI); ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_TX_BM_TKID, ++ FIELD_PREP(MTK_WED_TX_BM_TKID_START, ++ dev->wlan.token_start) | ++ FIELD_PREP(MTK_WED_TX_BM_TKID_END, ++ dev->wlan.token_start + ++ dev->wlan.nbuf - 1)); ++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | ++ MTK_WED_TX_BM_DYN_THR_HI); ++ } else { ++ wed_w32(dev, MTK_WED_TX_BM_TKID_V2, ++ FIELD_PREP(MTK_WED_TX_BM_TKID_START, ++ dev->wlan.token_start) | ++ FIELD_PREP(MTK_WED_TX_BM_TKID_END, ++ dev->wlan.token_start + ++ dev->wlan.nbuf - 1)); ++ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) | ++ MTK_WED_TX_BM_DYN_THR_HI_V2); ++ wed_w32(dev, MTK_WED_TX_TKID_CTRL, ++ MTK_WED_TX_TKID_CTRL_PAUSE | ++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM, ++ dev->buf_ring.size / 128) | ++ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM, ++ dev->buf_ring.size / 128)); ++ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR, ++ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) | ++ MTK_WED_TX_TKID_DYN_THR_HI); ++ } + + mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); + +- wed_set(dev, MTK_WED_CTRL, +- MTK_WED_CTRL_WED_TX_BM_EN | +- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ if (dev->hw->version == 1) ++ wed_set(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ else ++ wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE); + + wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); + } + + static void +-mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size) ++mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size) + { ++ void *head = (void *)ring->desc; + int i; + + for (i = 0; i < size; i++) { +- desc[i].buf0 = 0; +- desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); +- desc[i].buf1 = 0; +- desc[i].info = 0; ++ struct mtk_wdma_desc *desc; ++ ++ desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size); ++ desc->buf0 = 0; ++ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); ++ desc->buf1 = 0; ++ desc->info = 0; + } + } + +@@ -436,12 +579,10 @@ mtk_wed_reset_dma(struct mtk_wed_device + int i; + + for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) { +- struct mtk_wdma_desc *desc = dev->tx_ring[i].desc; +- +- if (!desc) ++ if (!dev->tx_ring[i].desc) + continue; + +- mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE); ++ mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE); + } + + if (mtk_wed_poll_busy(dev)) +@@ -498,16 +639,16 @@ mtk_wed_reset_dma(struct mtk_wed_device + + static int + mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, +- int size) ++ int size, u32 desc_size) + { +- ring->desc = dma_alloc_coherent(dev->hw->dev, +- size * sizeof(*ring->desc), ++ ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size, + &ring->desc_phys, GFP_KERNEL); + if (!ring->desc) + return -ENOMEM; + ++ ring->desc_size = desc_size; + ring->size = size; +- mtk_wed_ring_reset(ring->desc, size); ++ mtk_wed_ring_reset(ring, size); + + return 0; + } +@@ -515,9 +656,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device + static int + mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) + { ++ u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; + struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; + +- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE)) ++ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) + return -ENOMEM; + + wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, +@@ -546,16 +688,41 @@ mtk_wed_configure_irq(struct mtk_wed_dev + MTK_WED_CTRL_WED_TX_BM_EN | + MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); + +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, +- MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ if (dev->hw->version == 1) { ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, ++ MTK_WED_PCIE_INT_TRIGGER_STATUS); ++ ++ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, ++ MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | ++ MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); + +- wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, +- MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | +- MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); ++ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); ++ } else { ++ /* initail tx interrupt trigger */ ++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, ++ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR | ++ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG, ++ dev->wlan.tx_tbit[0]) | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG, ++ dev->wlan.tx_tbit[1])); ++ ++ /* initail txfree interrupt trigger */ ++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE, ++ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN | ++ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG, ++ dev->wlan.txfree_tbit)); ++ ++ wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask); ++ wed_set(dev, MTK_WED_WDMA_INT_CTRL, ++ FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL, ++ dev->wdma_idx)); ++ } + +- /* initail wdma interrupt agent */ + wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); +- wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); + + wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); + wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); +@@ -580,14 +747,28 @@ mtk_wed_dma_enable(struct mtk_wed_device + wdma_set(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_TX_DMA_EN | + MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES); ++ ++ if (dev->hw->version == 1) { ++ wdma_set(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); ++ } else { ++ wed_set(dev, MTK_WED_WPDMA_CTRL, ++ MTK_WED_WPDMA_CTRL_SDL1_FIXED); ++ ++ wed_set(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); ++ ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP | ++ MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV); ++ } + } + + static void + mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) + { +- u32 val; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +@@ -598,14 +779,17 @@ mtk_wed_start(struct mtk_wed_device *dev + mtk_wed_configure_irq(dev, irq_mask); + + mtk_wed_set_ext_int(dev, true); +- val = dev->wlan.wpdma_phys | +- MTK_PCIE_MIRROR_MAP_EN | +- FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index); +- +- if (dev->hw->index) +- val |= BIT(1); +- val |= BIT(0); +- regmap_write(dev->hw->mirror, dev->hw->index * 4, val); ++ ++ if (dev->hw->version == 1) { ++ u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN | ++ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, ++ dev->hw->index); ++ ++ val |= BIT(0) | (BIT(1) * !!dev->hw->index); ++ regmap_write(dev->hw->mirror, dev->hw->index * 4, val); ++ } else { ++ mtk_wed_set_512_support(dev, true); ++ } + + mtk_wed_dma_enable(dev); + dev->running = true; +@@ -639,7 +823,9 @@ mtk_wed_attach(struct mtk_wed_device *de + goto out; + } + +- dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index); ++ dev_info(&dev->wlan.pci_dev->dev, ++ "attaching wed device %d version %d\n", ++ hw->index, hw->version); + + dev->hw = hw; + dev->dev = hw->dev; +@@ -657,7 +843,9 @@ mtk_wed_attach(struct mtk_wed_device *de + } + + mtk_wed_hw_init_early(dev); +- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0); ++ if (hw->hifsys) ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, ++ BIT(hw->index), 0); + + out: + mutex_unlock(&hw_lock); +@@ -684,7 +872,8 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + + BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); + +- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) ++ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, ++ sizeof(*ring->desc))) + return -ENOMEM; + + if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) +@@ -711,21 +900,21 @@ static int + mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs) + { + struct mtk_wed_ring *ring = &dev->txfree_ring; +- int i; ++ int i, index = dev->hw->version == 1; + + /* + * For txfree event handling, the same DMA ring is shared between WED + * and WLAN. The WLAN driver accesses the ring index registers through + * WED + */ +- ring->reg_base = MTK_WED_RING_RX(1); ++ ring->reg_base = MTK_WED_RING_RX(index); + ring->wpdma = regs; + + for (i = 0; i < 12; i += 4) { + u32 val = readl(regs + i); + +- wed_w32(dev, MTK_WED_RING_RX(1) + i, val); +- wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val); ++ wed_w32(dev, MTK_WED_RING_RX(index) + i, val); ++ wed_w32(dev, MTK_WED_WPDMA_RING_RX(index) + i, val); + } + + return 0; +@@ -734,11 +923,19 @@ mtk_wed_txfree_ring_setup(struct mtk_wed + static u32 + mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) + { +- u32 val; ++ u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ ++ if (dev->hw->version == 1) ++ ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; ++ else ++ ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | ++ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | ++ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | ++ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; + + val = wed_r32(dev, MTK_WED_EXT_INT_STATUS); + wed_w32(dev, MTK_WED_EXT_INT_STATUS, val); +- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK; ++ val &= ext_mask; + if (!dev->hw->num_flows) + val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; + if (val && net_ratelimit()) +@@ -813,7 +1010,8 @@ out: + } + + void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index) ++ void __iomem *wdma, phys_addr_t wdma_phy, ++ int index) + { + static const struct mtk_wed_ops wed_ops = { + .attach = mtk_wed_attach, +@@ -860,26 +1058,33 @@ void mtk_wed_add_hw(struct device_node * + hw = kzalloc(sizeof(*hw), GFP_KERNEL); + if (!hw) + goto unlock; ++ + hw->node = np; + hw->regs = regs; + hw->eth = eth; + hw->dev = &pdev->dev; ++ hw->wdma_phy = wdma_phy; + hw->wdma = wdma; + hw->index = index; + hw->irq = irq; +- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, +- "mediatek,pcie-mirror"); +- hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, +- "mediatek,hifsys"); +- if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { +- kfree(hw); +- goto unlock; +- } ++ hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; + +- if (!index) { +- regmap_write(hw->mirror, 0, 0); +- regmap_write(hw->mirror, 4, 0); ++ if (hw->version == 1) { ++ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,pcie-mirror"); ++ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, ++ "mediatek,hifsys"); ++ if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { ++ kfree(hw); ++ goto unlock; ++ } ++ ++ if (!index) { ++ regmap_write(hw->mirror, 0, 0); ++ regmap_write(hw->mirror, 4, 0); ++ } + } ++ + mtk_wed_hw_add_debugfs(hw); + + hw_list[index] = hw; +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -18,11 +18,13 @@ struct mtk_wed_hw { + struct regmap *hifsys; + struct device *dev; + void __iomem *wdma; ++ phys_addr_t wdma_phy; + struct regmap *mirror; + struct dentry *debugfs_dir; + struct mtk_wed_device *wed_dev; + u32 debugfs_reg; + u32 num_flows; ++ u8 version; + char dirname[5]; + int irq; + int index; +@@ -101,14 +103,16 @@ wpdma_txfree_w32(struct mtk_wed_device * + } + + void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index); ++ void __iomem *wdma, phys_addr_t wdma_phy, ++ int index); + void mtk_wed_exit(void); + int mtk_wed_flow_add(int index); + void mtk_wed_flow_remove(int index); + #else + static inline void + mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +- void __iomem *wdma, int index) ++ void __iomem *wdma, phys_addr_t wdma_phy, ++ int index) + { + } + static inline void +--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c +@@ -116,6 +116,9 @@ wed_txinfo_show(struct seq_file *s, void + DUMP_WDMA(WDMA_GLO_CFG), + DUMP_WDMA_RING(WDMA_RING_RX(0)), + DUMP_WDMA_RING(WDMA_RING_RX(1)), ++ ++ DUMP_STR("TX FREE"), ++ DUMP_WED(WED_RX_MIB(0)), + }; + struct mtk_wed_hw *hw = s->private; + struct mtk_wed_device *dev = hw->wed_dev; +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -5,6 +5,7 @@ + #define __MTK_WED_REGS_H + + #define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0) ++#define MTK_WDMA_DESC_CTRL_LEN1_V2 GENMASK(13, 0) + #define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15) + #define MTK_WDMA_DESC_CTRL_BURST BIT(16) + #define MTK_WDMA_DESC_CTRL_LEN0 GENMASK(29, 16) +@@ -41,6 +42,7 @@ struct mtk_wdma_desc { + #define MTK_WED_CTRL_RESERVE_EN BIT(12) + #define MTK_WED_CTRL_RESERVE_BUSY BIT(13) + #define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24) ++#define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25) + #define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28) + + #define MTK_WED_EXT_INT_STATUS 0x020 +@@ -57,7 +59,8 @@ struct mtk_wdma_desc { + #define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19) + #define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20) + #define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21) +-#define MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR BIT(22) ++#define MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR BIT(22) ++#define MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR BIT(23) + #define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24) + #define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ + MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ +@@ -65,8 +68,7 @@ struct mtk_wdma_desc { + MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \ + MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \ + MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \ +- MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR | \ +- MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR) ++ MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR) + + #define MTK_WED_EXT_INT_MASK 0x028 + +@@ -81,6 +83,7 @@ struct mtk_wdma_desc { + #define MTK_WED_TX_BM_BASE 0x084 + + #define MTK_WED_TX_BM_TKID 0x088 ++#define MTK_WED_TX_BM_TKID_V2 0x0c8 + #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0) + #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16) + +@@ -94,7 +97,25 @@ struct mtk_wdma_desc { + + #define MTK_WED_TX_BM_DYN_THR 0x0a0 + #define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0) ++#define MTK_WED_TX_BM_DYN_THR_LO_V2 GENMASK(8, 0) + #define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16) ++#define MTK_WED_TX_BM_DYN_THR_HI_V2 GENMASK(24, 16) ++ ++#define MTK_WED_TX_TKID_CTRL 0x0c0 ++#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM GENMASK(6, 0) ++#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16) ++#define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28) ++ ++#define MTK_WED_TX_TKID_DYN_THR 0x0e0 ++#define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0) ++#define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16) ++ ++#define MTK_WED_TXP_DW0 0x120 ++#define MTK_WED_TXP_DW1 0x124 ++#define MTK_WED_WPDMA_WRITE_TXP GENMASK(31, 16) ++#define MTK_WED_TXDP_CTRL 0x130 ++#define MTK_WED_TXDP_DW9_OVERWR BIT(9) ++#define MTK_WED_RX_BM_TKID_MIB 0x1cc + + #define MTK_WED_INT_STATUS 0x200 + #define MTK_WED_INT_MASK 0x204 +@@ -125,6 +146,7 @@ struct mtk_wdma_desc { + #define MTK_WED_RESET_IDX_RX GENMASK(17, 16) + + #define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4) ++#define MTK_WED_RX_MIB(_n) (0x2e0 + (_n) * 4) + + #define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10) + +@@ -155,21 +177,62 @@ struct mtk_wdma_desc { + #define MTK_WED_WPDMA_GLO_CFG_BYTE_SWAP BIT(29) + #define MTK_WED_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) + ++/* CONFIG_MEDIATEK_NETSYS_V2 */ ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC BIT(4) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC BIT(5) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC BIT(6) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC BIT(7) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(18, 16) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20) ++#define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR BIT(21) ++#define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP BIT(24) ++#define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV BIT(28) ++ + #define MTK_WED_WPDMA_RESET_IDX 0x50c + #define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0) + #define MTK_WED_WPDMA_RESET_IDX_RX GENMASK(17, 16) + ++#define MTK_WED_WPDMA_CTRL 0x518 ++#define MTK_WED_WPDMA_CTRL_SDL1_FIXED BIT(31) ++ + #define MTK_WED_WPDMA_INT_CTRL 0x520 + #define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) + + #define MTK_WED_WPDMA_INT_MASK 0x524 + ++#define MTK_WED_WPDMA_INT_CTRL_TX 0x530 ++#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN BIT(0) ++#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR BIT(1) ++#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG GENMASK(6, 2) ++#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN BIT(8) ++#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR BIT(9) ++#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG GENMASK(14, 10) ++ ++#define MTK_WED_WPDMA_INT_CTRL_RX 0x534 ++ ++#define MTK_WED_WPDMA_INT_CTRL_TX_FREE 0x538 ++#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN BIT(0) ++#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR BIT(1) ++#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG GENMASK(6, 2) ++ + #define MTK_WED_PCIE_CFG_BASE 0x560 + ++#define MTK_WED_PCIE_CFG_BASE 0x560 ++#define MTK_WED_PCIE_CFG_INTM 0x564 ++#define MTK_WED_PCIE_CFG_MSIS 0x568 + #define MTK_WED_PCIE_INT_TRIGGER 0x570 + #define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16) + ++#define MTK_WED_PCIE_INT_CTRL 0x57c ++#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20) ++#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16) ++#define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12) ++ + #define MTK_WED_WPDMA_CFG_BASE 0x580 ++#define MTK_WED_WPDMA_CFG_INT_MASK 0x584 ++#define MTK_WED_WPDMA_CFG_TX 0x588 ++#define MTK_WED_WPDMA_CFG_TX_FREE 0x58c + + #define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4) + #define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4) +@@ -203,15 +266,24 @@ struct mtk_wdma_desc { + #define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16) + #define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24) + ++#define MTK_WED_WDMA_INT_CLR 0xa24 ++#define MTK_WED_WDMA_INT_CLR_RX_DONE GENMASK(17, 16) ++ + #define MTK_WED_WDMA_INT_TRIGGER 0xa28 + #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16) + + #define MTK_WED_WDMA_INT_CTRL 0xa2c + #define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16) + ++#define MTK_WED_WDMA_CFG_BASE 0xaa0 + #define MTK_WED_WDMA_OFFSET0 0xaa4 + #define MTK_WED_WDMA_OFFSET1 0xaa8 + ++#define MTK_WED_WDMA_OFST0_GLO_INTS GENMASK(15, 0) ++#define MTK_WED_WDMA_OFST0_GLO_CFG GENMASK(31, 16) ++#define MTK_WED_WDMA_OFST1_TX_CTRL GENMASK(15, 0) ++#define MTK_WED_WDMA_OFST1_RX_CTRL GENMASK(31, 16) ++ + #define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4) + #define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4) + #define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4) +@@ -221,6 +293,7 @@ struct mtk_wdma_desc { + #define MTK_WED_RING_OFS_CPU_IDX 0x08 + #define MTK_WED_RING_OFS_DMA_IDX 0x0c + ++#define MTK_WDMA_RING_TX(_n) (0x000 + (_n) * 0x10) + #define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) + + #define MTK_WDMA_GLO_CFG 0x204 +@@ -234,6 +307,8 @@ struct mtk_wdma_desc { + #define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) + #define MTK_WDMA_RESET_IDX_RX GENMASK(17, 16) + ++#define MTK_WDMA_INT_STATUS 0x220 ++ + #define MTK_WDMA_INT_MASK 0x228 + #define MTK_WDMA_INT_MASK_TX_DONE GENMASK(3, 0) + #define MTK_WDMA_INT_MASK_RX_DONE GENMASK(17, 16) +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -14,6 +14,7 @@ struct mtk_wdma_desc; + struct mtk_wed_ring { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; ++ u32 desc_size; + int size; + + u32 reg_base; +@@ -45,10 +46,17 @@ struct mtk_wed_device { + struct pci_dev *pci_dev; + + u32 wpdma_phys; ++ u32 wpdma_int; ++ u32 wpdma_mask; ++ u32 wpdma_tx; ++ u32 wpdma_txfree; + + u16 token_start; + unsigned int nbuf; + ++ u8 tx_tbit[MTK_WED_TX_QUEUES]; ++ u8 txfree_tbit; ++ + u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); + int (*offload_enable)(struct mtk_wed_device *wed); + void (*offload_disable)(struct mtk_wed_device *wed); diff --git a/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch b/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch new file mode 100644 index 00000000000..70b7bad31f2 --- /dev/null +++ b/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch @@ -0,0 +1,237 @@ +From 6e1df49f330dce7c58a39d6772f1385b6887bb03 Mon Sep 17 00:00:00 2001 +Message-Id: <6e1df49f330dce7c58a39d6772f1385b6887bb03.1662990860.git.lorenzo@kernel.org> +From: Lorenzo Bianconi +Date: Thu, 8 Sep 2022 11:26:10 +0200 +Subject: [PATCH net-next] net: ethernet: mtk_eth_wed: add axi bus support + +Other than pcie bus, introduce support for axi bus to mtk wed driver. +Axi bus is used to connect mt7986-wmac soc chip available on mt7986 +device. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 116 +++++++++++++------ + drivers/net/ethernet/mediatek/mtk_wed_regs.h | 2 + + include/linux/soc/mediatek/mtk_wed.h | 11 +- + 3 files changed, 91 insertions(+), 38 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -85,11 +85,31 @@ static struct mtk_wed_hw * + mtk_wed_assign(struct mtk_wed_device *dev) + { + struct mtk_wed_hw *hw; ++ int i; ++ ++ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { ++ hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; ++ if (!hw) ++ return NULL; ++ ++ if (!hw->wed_dev) ++ goto out; ++ ++ if (hw->version == 1) ++ return NULL; ++ ++ /* MT7986 WED devices do not have any pcie slot restrictions */ ++ } ++ /* MT7986 PCIE or AXI */ ++ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { ++ hw = hw_list[i]; ++ if (hw && !hw->wed_dev) ++ goto out; ++ } + +- hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; +- if (!hw || hw->wed_dev) +- return NULL; ++ return NULL; + ++out: + hw->wed_dev = dev; + return hw; + } +@@ -322,7 +342,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) + static void + mtk_wed_detach(struct mtk_wed_device *dev) + { +- struct device_node *wlan_node = dev->wlan.pci_dev->dev.of_node; + struct mtk_wed_hw *hw = dev->hw; + + mutex_lock(&hw_lock); +@@ -337,9 +356,14 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_free_buffer(dev); + mtk_wed_free_tx_rings(dev); + +- if (of_dma_is_coherent(wlan_node) && hw->hifsys) +- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, +- BIT(hw->index), BIT(hw->index)); ++ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { ++ struct device_node *wlan_node; ++ ++ wlan_node = dev->wlan.pci_dev->dev.of_node; ++ if (of_dma_is_coherent(wlan_node) && hw->hifsys) ++ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, ++ BIT(hw->index), BIT(hw->index)); ++ } + + if (!hw_list[!hw->index]->wed_dev && + hw->eth->dma_dev != hw->eth->dev) +@@ -356,40 +380,54 @@ mtk_wed_detach(struct mtk_wed_device *de + static void + mtk_wed_bus_init(struct mtk_wed_device *dev) + { +- struct device_node *np = dev->hw->eth->dev->of_node; +- struct regmap *regs; +- u32 val; +- +- regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); +- if (IS_ERR(regs)) +- return; ++ switch (dev->wlan.bus_type) { ++ case MTK_WED_BUS_PCIE: { ++ struct device_node *np = dev->hw->eth->dev->of_node; ++ struct regmap *regs; ++ u32 val; ++ ++ regs = syscon_regmap_lookup_by_phandle(np, ++ "mediatek,wed-pcie"); ++ if (IS_ERR(regs)) ++ break; + +- regmap_update_bits(regs, 0, BIT(0), BIT(0)); ++ regmap_update_bits(regs, 0, BIT(0), BIT(0)); + +- wed_w32(dev, MTK_WED_PCIE_INT_CTRL, +- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); ++ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); + +- /* pcie interrupt control: pola/source selection */ +- wed_set(dev, MTK_WED_PCIE_INT_CTRL, +- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | +- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); +- wed_r32(dev, MTK_WED_PCIE_INT_CTRL); +- +- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); +- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); +- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); +- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); +- +- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); +- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); +- +- /* pcie interrupt status trigger register */ +- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); +- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); +- +- /* pola setting */ +- val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); +- wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++ /* pcie interrupt control: pola/source selection */ ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | ++ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); ++ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); ++ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); ++ ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); ++ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); ++ ++ /* pcie interrupt status trigger register */ ++ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); ++ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); ++ ++ /* pola setting */ ++ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); ++ wed_set(dev, MTK_WED_PCIE_INT_CTRL, ++ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); ++ break; ++ } ++ case MTK_WED_BUS_AXI: ++ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, ++ MTK_WED_WPDMA_INT_CTRL_SIG_SRC | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0)); ++ break; ++ default: ++ break; ++ } + } + + static void +@@ -800,12 +838,14 @@ mtk_wed_attach(struct mtk_wed_device *de + __releases(RCU) + { + struct mtk_wed_hw *hw; ++ struct device *device; + int ret = 0; + + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "mtk_wed_attach without holding the RCU read lock"); + +- if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 || ++ if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE && ++ pci_domain_nr(dev->wlan.pci_dev->bus) > 1) || + !try_module_get(THIS_MODULE)) + ret = -ENODEV; + +@@ -823,8 +863,10 @@ mtk_wed_attach(struct mtk_wed_device *de + goto out; + } + +- dev_info(&dev->wlan.pci_dev->dev, +- "attaching wed device %d version %d\n", ++ device = dev->wlan.bus_type == MTK_WED_BUS_PCIE ++ ? &dev->wlan.pci_dev->dev ++ : &dev->wlan.platform_dev->dev; ++ dev_info(device, "attaching wed device %d version %d\n", + hw->index, hw->version); + + dev->hw = hw; +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -198,6 +198,8 @@ struct mtk_wdma_desc { + + #define MTK_WED_WPDMA_INT_CTRL 0x520 + #define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) ++#define MTK_WED_WPDMA_INT_CTRL_SIG_SRC BIT(22) ++#define MTK_WED_WPDMA_INT_CTRL_SRC_SEL GENMASK(17, 16) + + #define MTK_WED_WPDMA_INT_MASK 0x524 + +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -11,6 +11,11 @@ + struct mtk_wed_hw; + struct mtk_wdma_desc; + ++enum mtk_wed_bus_tye { ++ MTK_WED_BUS_PCIE, ++ MTK_WED_BUS_AXI, ++}; ++ + struct mtk_wed_ring { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; +@@ -43,7 +48,11 @@ struct mtk_wed_device { + + /* filled by driver: */ + struct { +- struct pci_dev *pci_dev; ++ union { ++ struct platform_device *platform_dev; ++ struct pci_dev *pci_dev; ++ }; ++ enum mtk_wed_bus_tye bus_type; + + u32 wpdma_phys; + u32 wpdma_int; diff --git a/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch b/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch new file mode 100644 index 00000000000..fedcb6ccd89 --- /dev/null +++ b/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch @@ -0,0 +1,882 @@ +From 93408c858e5dc01d97c55efa721268f63fde2ae5 Mon Sep 17 00:00:00 2001 +Message-Id: <93408c858e5dc01d97c55efa721268f63fde2ae5.1662886034.git.lorenzo@kernel.org> +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Sat, 3 Sep 2022 18:34:09 +0200 +Subject: [PATCH net-next 4/5] net: ethernet: mtk_eth_soc: introduce flow + offloading support for mt7986 + +Introduce hw flow offload support for mt7986 chipset. PPE is not enabled +yet in mt7986 since mt76 support is not available yet. + +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 72 ++++++ + drivers/net/ethernet/mediatek/mtk_ppe.c | 213 +++++++++++------- + drivers/net/ethernet/mediatek/mtk_ppe.h | 52 ++++- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 49 ++-- + drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 8 + + 6 files changed, 289 insertions(+), 116 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1859,12 +1859,14 @@ static int mtk_poll_rx(struct napi_struc + bytes += skb->len; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5); + hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; + if (hash != MTK_RXD5_FOE_ENTRY) + skb_set_hash(skb, jhash_1word(hash, 0), + PKT_HASH_TYPE_L4); + rxdcsum = &trxd.rxd3; + } else { ++ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; + if (hash != MTK_RXD4_FOE_ENTRY) + skb_set_hash(skb, jhash_1word(hash, 0), +@@ -1878,7 +1880,6 @@ static int mtk_poll_rx(struct napi_struc + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); + +- reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); + if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) + mtk_ppe_check_skb(eth->ppe[0], skb, hash); + +@@ -4184,7 +4185,7 @@ static const struct mtk_soc_data mt7621_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4204,7 +4205,7 @@ static const struct mtk_soc_data mt7622_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4223,7 +4224,7 @@ static const struct mtk_soc_data mt7623_ + .required_pctl = true, + .offload_version = 2, + .hash_offset = 2, +- .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4255,9 +4256,11 @@ static const struct mtk_soc_data mt7986_ + .reg_map = &mt7986_reg_map, + .ana_rgc3 = 0x128, + .caps = MT7986_CAPS, ++ .hw_features = MTK_HW_FEATURES, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, + .hash_offset = 4, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1151,6 +1151,78 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u + return ppe->foe_table + hash * soc->foe_entry_size; + } + ++static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_TIMESTAMP_V2; ++ ++ return MTK_FOE_IB1_BIND_TIMESTAMP; ++} ++ ++static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_PPPOE_V2; ++ ++ return MTK_FOE_IB1_BIND_PPPOE; ++} ++ ++static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_VLAN_TAG_V2; ++ ++ return MTK_FOE_IB1_BIND_VLAN_TAG; ++} ++ ++static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_BIND_VLAN_LAYER_V2; ++ ++ return MTK_FOE_IB1_BIND_VLAN_LAYER; ++} ++ ++static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); ++ ++ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, val); ++} ++ ++static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); ++ ++ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, val); ++} ++ ++static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB1_PACKET_TYPE_V2; ++ ++ return MTK_FOE_IB1_PACKET_TYPE; ++} ++ ++static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE_V2, val); ++ ++ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, val); ++} ++ ++static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) ++{ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return MTK_FOE_IB2_MULTICAST_V2; ++ ++ return MTK_FOE_IB2_MULTICAST; ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -56,7 +56,7 @@ static u32 ppe_clear(struct mtk_ppe *ppe + + static u32 mtk_eth_timestamp(struct mtk_eth *eth) + { +- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; ++ return mtk_r32(eth, 0x0010) & mtk_get_ib1_ts_mask(eth); + } + + static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) +@@ -93,7 +93,7 @@ static u32 mtk_ppe_hash_entry(struct mtk + u32 hv1, hv2, hv3; + u32 hash; + +- switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { ++ switch (mtk_get_ib1_pkt_type(eth, e->ib1)) { + case MTK_PPE_PKT_TYPE_IPV4_ROUTE: + case MTK_PPE_PKT_TYPE_IPV4_HNAPT: + hv1 = e->ipv4.orig.ports; +@@ -129,9 +129,9 @@ static u32 mtk_ppe_hash_entry(struct mtk + } + + static inline struct mtk_foe_mac_info * +-mtk_foe_entry_l2(struct mtk_foe_entry *entry) ++mtk_foe_entry_l2(struct mtk_eth *eth, struct mtk_foe_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return &entry->bridge.l2; +@@ -143,9 +143,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e + } + + static inline u32 * +-mtk_foe_entry_ib2(struct mtk_foe_entry *entry) ++mtk_foe_entry_ib2(struct mtk_eth *eth, struct mtk_foe_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) + return &entry->bridge.ib2; +@@ -156,27 +156,38 @@ mtk_foe_entry_ib2(struct mtk_foe_entry * + return &entry->ipv4.ib2; + } + +-int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, +- u8 pse_port, u8 *src_mac, u8 *dest_mac) ++int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int type, int l4proto, u8 pse_port, u8 *src_mac, ++ u8 *dest_mac) + { + struct mtk_foe_mac_info *l2; + u32 ports_pad, val; + + memset(entry, 0, sizeof(*entry)); + +- val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | +- FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | +- FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | +- MTK_FOE_IB1_BIND_TTL | +- MTK_FOE_IB1_BIND_CACHE; +- entry->ib1 = val; +- +- val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | +- FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) | +- FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | ++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE_V2, type) | ++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | ++ MTK_FOE_IB1_BIND_CACHE_V2 | MTK_FOE_IB1_BIND_TTL_V2; ++ entry->ib1 = val; ++ ++ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf); ++ } else { ++ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | ++ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | ++ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | ++ MTK_FOE_IB1_BIND_CACHE | MTK_FOE_IB1_BIND_TTL; ++ entry->ib1 = val; ++ ++ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f); ++ } + + if (is_multicast_ether_addr(dest_mac)) +- val |= MTK_FOE_IB2_MULTICAST; ++ val |= mtk_get_ib2_multicast_mask(eth); + + ports_pad = 0xa5a5a500 | (l4proto & 0xff); + if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) +@@ -210,24 +221,30 @@ int mtk_foe_entry_prepare(struct mtk_foe + return 0; + } + +-int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port) ++int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, u8 port) + { +- u32 *ib2 = mtk_foe_entry_ib2(entry); +- u32 val; ++ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); ++ u32 val = *ib2; + +- val = *ib2; +- val &= ~MTK_FOE_IB2_DEST_PORT; +- val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ val &= ~MTK_FOE_IB2_DEST_PORT_V2; ++ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, port); ++ } else { ++ val &= ~MTK_FOE_IB2_DEST_PORT; ++ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); ++ } + *ib2 = val; + + return 0; + } + +-int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress, ++int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, bool egress, + __be32 src_addr, __be16 src_port, + __be32 dest_addr, __be16 dest_port) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + struct mtk_ipv4_tuple *t; + + switch (type) { +@@ -262,11 +279,12 @@ int mtk_foe_entry_set_ipv4_tuple(struct + return 0; + } + +-int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, ++int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, + __be32 *src_addr, __be16 src_port, + __be32 *dest_addr, __be16 dest_port) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); + u32 *src, *dest; + int i; + +@@ -297,39 +315,41 @@ int mtk_foe_entry_set_ipv6_tuple(struct + return 0; + } + +-int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port) ++int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int port) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + + l2->etype = BIT(port); + +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER)) +- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth))) ++ entry->ib1 |= mtk_prep_ib1_vlan_layer(eth, 1); + else + l2->etype |= BIT(8); + +- entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG; ++ entry->ib1 &= ~mtk_get_ib1_vlan_tag_mask(eth); + + return 0; + } + +-int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid) ++int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int vid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + +- switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) { ++ switch (mtk_prep_ib1_vlan_layer(eth, entry->ib1)) { + case 0: +- entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG | +- FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | ++ mtk_prep_ib1_vlan_layer(eth, 1); + l2->vlan1 = vid; + return 0; + case 1: +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) { ++ if (!(entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) { + l2->vlan1 = vid; + l2->etype |= BIT(8); + } else { + l2->vlan2 = vid; +- entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); ++ entry->ib1 += mtk_prep_ib1_vlan_layer(eth, 1); + } + return 0; + default: +@@ -337,34 +357,42 @@ int mtk_foe_entry_set_vlan(struct mtk_fo + } + } + +-int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid) ++int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int sid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + +- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) || +- (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) ++ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth)) || ++ (entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) + l2->etype = ETH_P_PPP_SES; + +- entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE; ++ entry->ib1 |= mtk_get_ib1_ppoe_mask(eth); + l2->pppoe_id = sid; + + return 0; + } + +-int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, +- int bss, int wcid) ++int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int wdma_idx, int txq, int bss, int wcid) + { +- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); +- u32 *ib2 = mtk_foe_entry_ib2(entry); ++ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); ++ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); + +- *ib2 &= ~MTK_FOE_IB2_PORT_MG; +- *ib2 |= MTK_FOE_IB2_WDMA_WINFO; +- if (wdma_idx) +- *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; +- +- l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | +- FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | +- FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2; ++ *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) | ++ MTK_FOE_IB2_WDMA_WINFO_V2; ++ l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) | ++ FIELD_PREP(MTK_FOE_WINFO_BSS, bss); ++ } else { ++ *ib2 &= ~MTK_FOE_IB2_PORT_MG; ++ *ib2 |= MTK_FOE_IB2_WDMA_WINFO; ++ if (wdma_idx) ++ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; ++ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | ++ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); ++ } + + return 0; + } +@@ -376,14 +404,15 @@ static inline bool mtk_foe_entry_usable( + } + + static bool +-mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data) ++mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, ++ struct mtk_foe_entry *data) + { + int type, len; + + if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) + return false; + +- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); ++ type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); + if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) + len = offsetof(struct mtk_foe_entry, ipv6._rsv); + else +@@ -427,14 +456,12 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + + static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) + { +- u16 timestamp; +- u16 now; +- +- now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; +- timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); ++ u16 now = mtk_eth_timestamp(ppe->eth); ++ u16 timestamp = ib1 & ib1_ts_mask; + + if (timestamp > now) +- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; ++ return ib1_ts_mask + 1 - timestamp + now; + else + return now - timestamp; + } +@@ -442,6 +469,7 @@ static int __mtk_foe_entry_idle_time(str + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { ++ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + struct mtk_flow_entry *cur; + struct mtk_foe_entry *hwe; + struct hlist_node *tmp; +@@ -466,8 +494,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe + continue; + + idle = cur_idle; +- entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->data.ib1 &= ~ib1_ts_mask; ++ entry->data.ib1 |= hwe->ib1 & ib1_ts_mask; + } + } + +@@ -489,7 +517,7 @@ mtk_flow_entry_update(struct mtk_ppe *pp + + hwe = mtk_foe_get_entry(ppe, entry->hash); + memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); +- if (!mtk_flow_entry_match(entry, &foe)) { ++ if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { + entry->hash = 0xffff; + goto out; + } +@@ -504,16 +532,22 @@ static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) + { ++ struct mtk_eth *eth = ppe->eth; ++ u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; +- u16 timestamp; + +- timestamp = mtk_eth_timestamp(ppe->eth); +- timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; +- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP_V2, ++ timestamp); ++ } else { ++ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; ++ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, ++ timestamp); ++ } + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); ++ memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size); + wmb(); + hwe->ib1 = entry->ib1; + +@@ -540,8 +574,8 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * + + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); + const struct mtk_soc_data *soc = ppe->eth->soc; ++ int type = mtk_get_ib1_pkt_type(ppe->eth, entry->data.ib1); + u32 hash; + + if (type == MTK_PPE_PKT_TYPE_BRIDGE) +@@ -564,7 +598,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ + struct mtk_flow_entry *flow_info; + struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; +- u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; ++ u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + + flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), +@@ -584,16 +618,16 @@ mtk_foe_entry_commit_subflow(struct mtk_ + foe.ib1 &= ib1_mask; + foe.ib1 |= entry->data.ib1 & ~ib1_mask; + +- l2 = mtk_foe_entry_l2(&foe); ++ l2 = mtk_foe_entry_l2(ppe->eth, &foe); + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); + +- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); ++ type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) + memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) + l2->etype = ETH_P_IPV6; + +- *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; ++ *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; + + __mtk_foe_entry_commit(ppe, &foe, hash); + } +@@ -626,7 +660,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe + continue; + } + +- if (found || !mtk_flow_entry_match(entry, hwe)) { ++ if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { + if (entry->hash != 0xffff) + entry->hash = 0xffff; + continue; +@@ -771,6 +805,8 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | + FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, + MTK_PPE_ENTRIES_SHIFT); ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_PPE_TB_CFG_INFO_SEL; + ppe_w32(ppe, MTK_PPE_TB_CFG, val); + + ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK, +@@ -778,15 +814,21 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + + mtk_ppe_cache_enable(ppe, true); + +- val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | +- MTK_PPE_FLOW_CFG_IP4_UDP_FRAG | +- MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | ++ val = MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | + MTK_PPE_FLOW_CFG_IP6_5T_ROUTE | + MTK_PPE_FLOW_CFG_IP6_6RD | + MTK_PPE_FLOW_CFG_IP4_NAT | + MTK_PPE_FLOW_CFG_IP4_NAPT | + MTK_PPE_FLOW_CFG_IP4_DSLITE | + MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_PPE_MD_TOAP_BYP_CRSN0 | ++ MTK_PPE_MD_TOAP_BYP_CRSN1 | ++ MTK_PPE_MD_TOAP_BYP_CRSN2 | ++ MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY; ++ else ++ val |= MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | ++ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG; + ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); + + val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) | +@@ -820,6 +862,11 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + ppe_w32(ppe, MTK_PPE_GLO_CFG, val); + + ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); ++ ++ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) { ++ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); ++ ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); ++ } + } + + int mtk_ppe_stop(struct mtk_ppe *ppe) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -32,6 +32,15 @@ + #define MTK_FOE_IB1_UDP BIT(30) + #define MTK_FOE_IB1_STATIC BIT(31) + ++/* CONFIG_MEDIATEK_NETSYS_V2 */ ++#define MTK_FOE_IB1_BIND_TIMESTAMP_V2 GENMASK(7, 0) ++#define MTK_FOE_IB1_BIND_VLAN_LAYER_V2 GENMASK(16, 14) ++#define MTK_FOE_IB1_BIND_PPPOE_V2 BIT(17) ++#define MTK_FOE_IB1_BIND_VLAN_TAG_V2 BIT(18) ++#define MTK_FOE_IB1_BIND_CACHE_V2 BIT(20) ++#define MTK_FOE_IB1_BIND_TTL_V2 BIT(22) ++#define MTK_FOE_IB1_PACKET_TYPE_V2 GENMASK(27, 23) ++ + enum { + MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0, + MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1, +@@ -53,14 +62,25 @@ enum { + + #define MTK_FOE_IB2_PORT_MG GENMASK(17, 12) + ++#define MTK_FOE_IB2_RX_IDX GENMASK(18, 17) + #define MTK_FOE_IB2_PORT_AG GENMASK(23, 18) + + #define MTK_FOE_IB2_DSCP GENMASK(31, 24) + ++/* CONFIG_MEDIATEK_NETSYS_V2 */ ++#define MTK_FOE_IB2_PORT_MG_V2 BIT(7) ++#define MTK_FOE_IB2_DEST_PORT_V2 GENMASK(12, 9) ++#define MTK_FOE_IB2_MULTICAST_V2 BIT(13) ++#define MTK_FOE_IB2_WDMA_WINFO_V2 BIT(19) ++#define MTK_FOE_IB2_PORT_AG_V2 GENMASK(23, 20) ++ + #define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0) + #define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6) + #define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14) + ++#define MTK_FOE_WINFO_BSS GENMASK(5, 0) ++#define MTK_FOE_WINFO_WCID GENMASK(15, 6) ++ + enum { + MTK_FOE_STATE_INVALID, + MTK_FOE_STATE_UNBIND, +@@ -81,6 +101,9 @@ struct mtk_foe_mac_info { + + u16 pppoe_id; + u16 src_mac_lo; ++ ++ u16 minfo; ++ u16 winfo; + }; + + /* software-only entry type */ +@@ -198,7 +221,7 @@ struct mtk_foe_entry { + struct mtk_foe_ipv4_dslite dslite; + struct mtk_foe_ipv6 ipv6; + struct mtk_foe_ipv6_6rd ipv6_6rd; +- u32 data[19]; ++ u32 data[23]; + }; + }; + +@@ -306,20 +329,27 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s + __mtk_ppe_check_skb(ppe, skb, hash); + } + +-int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, +- u8 pse_port, u8 *src_mac, u8 *dest_mac); +-int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port); +-int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig, ++int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int type, int l4proto, u8 pse_port, u8 *src_mac, ++ u8 *dest_mac); ++int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, u8 port); ++int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, bool orig, + __be32 src_addr, __be16 src_port, + __be32 dest_addr, __be16 dest_port); +-int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, ++int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth, ++ struct mtk_foe_entry *entry, + __be32 *src_addr, __be16 src_port, + __be32 *dest_addr, __be16 dest_port); +-int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port); +-int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); +-int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); +-int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, +- int bss, int wcid); ++int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int port); ++int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int vid); ++int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int sid); ++int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ int wdma_idx, int txq, int bss, int wcid); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -52,18 +52,19 @@ static const struct rhashtable_params mt + }; + + static int +-mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data, +- bool egress) ++mtk_flow_set_ipv4_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe, ++ struct mtk_flow_data *data, bool egress) + { +- return mtk_foe_entry_set_ipv4_tuple(foe, egress, ++ return mtk_foe_entry_set_ipv4_tuple(eth, foe, egress, + data->v4.src_addr, data->src_port, + data->v4.dst_addr, data->dst_port); + } + + static int +-mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data) ++mtk_flow_set_ipv6_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe, ++ struct mtk_flow_data *data) + { +- return mtk_foe_entry_set_ipv6_tuple(foe, ++ return mtk_foe_entry_set_ipv6_tuple(eth, foe, + data->v6.src_addr.s6_addr32, data->src_port, + data->v6.dst_addr.s6_addr32, data->dst_port); + } +@@ -190,16 +191,29 @@ mtk_flow_set_output_device(struct mtk_et + int pse_port, dsa_port; + + if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { +- mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss, +- info.wcid); +- pse_port = 3; ++ mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue, ++ info.bss, info.wcid); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ switch (info.wdma_idx) { ++ case 0: ++ pse_port = 8; ++ break; ++ case 1: ++ pse_port = 9; ++ break; ++ default: ++ return -EINVAL; ++ } ++ } else { ++ pse_port = 3; ++ } + *wed_index = info.wdma_idx; + goto out; + } + + dsa_port = mtk_flow_get_dsa_port(&dev); + if (dsa_port >= 0) +- mtk_foe_entry_set_dsa(foe, dsa_port); ++ mtk_foe_entry_set_dsa(eth, foe, dsa_port); + + if (dev == eth->netdev[0]) + pse_port = 1; +@@ -209,7 +223,7 @@ mtk_flow_set_output_device(struct mtk_et + return -EOPNOTSUPP; + + out: +- mtk_foe_entry_set_pse_port(foe, pse_port); ++ mtk_foe_entry_set_pse_port(eth, foe, pse_port); + + return 0; + } +@@ -333,9 +347,8 @@ mtk_flow_offload_replace(struct mtk_eth + !is_valid_ether_addr(data.eth.h_dest)) + return -EINVAL; + +- err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0, +- data.eth.h_source, +- data.eth.h_dest); ++ err = mtk_foe_entry_prepare(eth, &foe, offload_type, l4proto, 0, ++ data.eth.h_source, data.eth.h_dest); + if (err) + return err; + +@@ -360,7 +373,7 @@ mtk_flow_offload_replace(struct mtk_eth + data.v4.src_addr = addrs.key->src; + data.v4.dst_addr = addrs.key->dst; + +- mtk_flow_set_ipv4_addr(&foe, &data, false); ++ mtk_flow_set_ipv4_addr(eth, &foe, &data, false); + } + + if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { +@@ -371,7 +384,7 @@ mtk_flow_offload_replace(struct mtk_eth + data.v6.src_addr = addrs.key->src; + data.v6.dst_addr = addrs.key->dst; + +- mtk_flow_set_ipv6_addr(&foe, &data); ++ mtk_flow_set_ipv6_addr(eth, &foe, &data); + } + + flow_action_for_each(i, act, &rule->action) { +@@ -401,7 +414,7 @@ mtk_flow_offload_replace(struct mtk_eth + } + + if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { +- err = mtk_flow_set_ipv4_addr(&foe, &data, true); ++ err = mtk_flow_set_ipv4_addr(eth, &foe, &data, true); + if (err) + return err; + } +@@ -413,10 +426,10 @@ mtk_flow_offload_replace(struct mtk_eth + if (data.vlan.proto != htons(ETH_P_8021Q)) + return -EOPNOTSUPP; + +- mtk_foe_entry_set_vlan(&foe, data.vlan.id); ++ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id); + } + if (data.pppoe.num == 1) +- mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); ++ mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid); + + err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest, + &wed_index); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h +@@ -21,6 +21,9 @@ + #define MTK_PPE_GLO_CFG_BUSY BIT(31) + + #define MTK_PPE_FLOW_CFG 0x204 ++#define MTK_PPE_MD_TOAP_BYP_CRSN0 BIT(1) ++#define MTK_PPE_MD_TOAP_BYP_CRSN1 BIT(2) ++#define MTK_PPE_MD_TOAP_BYP_CRSN2 BIT(3) + #define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6) + #define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7) + #define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8) +@@ -54,6 +57,7 @@ + #define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14) + #define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16) + #define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18) ++#define MTK_PPE_TB_CFG_INFO_SEL BIT(20) + + enum { + MTK_PPE_SCAN_MODE_DISABLED, +@@ -112,6 +116,8 @@ enum { + #define MTK_PPE_DEFAULT_CPU_PORT 0x248 + #define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4)) + ++#define MTK_PPE_DEFAULT_CPU_PORT1 0x24c ++ + #define MTK_PPE_MTU_DROP 0x308 + + #define MTK_PPE_VLAN_MTU0 0x30c +@@ -141,4 +147,6 @@ enum { + #define MTK_PPE_MIB_CACHE_CTL_EN BIT(0) + #define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2) + ++#define MTK_PPE_SBW_CTRL 0x374 ++ + #endif diff --git a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch new file mode 100644 index 00000000000..e8bb85ac940 --- /dev/null +++ b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch @@ -0,0 +1,26 @@ +From b94b02a270471337bef73c44fa3493a521e31a61 Mon Sep 17 00:00:00 2001 +Message-Id: +In-Reply-To: +References: +From: Lorenzo Bianconi +Date: Mon, 5 Sep 2022 13:56:13 +0200 +Subject: [PATCH net-next 5/5] net: ethernet: mtk_eth_soc: enable flow + offloading support for mt7986 + +Enable hw packet engine and wireless packet dispatcher for mt7986 + +Signed-off-by: Lorenzo Bianconi +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4259,6 +4259,7 @@ static const struct mtk_soc_data mt7986_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7986_CLKS_BITMAP, + .required_pctl = false, ++ .offload_version = 2, + .hash_offset = 4, + .foe_entry_size = sizeof(struct mtk_foe_entry), + .txrx = { diff --git a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch new file mode 100644 index 00000000000..c4bd29365c7 --- /dev/null +++ b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch @@ -0,0 +1,46 @@ +From 40350ce3ae8701146aafd79c5f7b5582d9955e58 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 25 Sep 2022 15:12:35 +0100 +Subject: [PATCH 1/2] net: ethernet: mtk_eth_soc: fix wrong use of new helper + function +To: linux-mediatek@lists.infradead.org, + netdev@vger.kernel.org, + Lorenzo Bianconi +Cc: Sujuan Chen , + Bo Jiao , + Felix Fietkau , + John Crispin , + Sean Wang , + Mark Lee , + David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + Matthias Brugger , + Chen Minqiang + +In function mtk_foe_entry_set_vlan() the call to field accessor macro +FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1) +has been wrongly replaced by +mtk_prep_ib1_vlan_layer(eth, entry->ib1) + +Use correct helper function mtk_get_ib1_vlan_layer instead. + +Reported-by: Chen Minqiang +Fixes: 03a3180e5c09e1 ("net: ethernet: mtk_eth_soc: introduce flow offloading support for mt7986") +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -337,7 +337,7 @@ int mtk_foe_entry_set_vlan(struct mtk_et + { + struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); + +- switch (mtk_prep_ib1_vlan_layer(eth, entry->ib1)) { ++ switch (mtk_get_ib1_vlan_layer(eth, entry->ib1)) { + case 0: + entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | + mtk_prep_ib1_vlan_layer(eth, 1); diff --git a/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch b/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch new file mode 100644 index 00000000000..bb02f401a2d --- /dev/null +++ b/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch @@ -0,0 +1,49 @@ +From fcf14c2c5deae8f8c3d25530bab10856f63f8a63 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 25 Sep 2022 15:18:54 +0100 +Subject: [PATCH 2/2] net: ethernet: mtk_eth_soc: fix usage of foe_entry_size +To: linux-mediatek@lists.infradead.org, + netdev@vger.kernel.org, + Lorenzo Bianconi +Cc: Sujuan Chen , + Bo Jiao , + Felix Fietkau , + John Crispin , + Sean Wang , + Mark Lee , + David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + Matthias Brugger , + Chen Minqiang + +As sizeof(hwe->data) can now longer be used as the actual size depends +on foe_entry_size, in commit 9d8cb4c096ab02 +("net: ethernet: mtk_eth_soc: add foe_entry_size to mtk_eth_soc") the +use of sizeof(hwe->data) is hence replaced. +However, replacing it with ppe->eth->soc->foe_entry_size is wrong as +foe_entry_size represents the size of the whole descriptor and not just +the 'data' field. +Fix this by subtracing the size of the only other field in the struct +'ib1', so we actually end up with the correct size to be copied to the +data field. + +Reported-by: Chen Minqiang +Fixes: 9d8cb4c096ab02 ("net: ethernet: mtk_eth_soc: add foe_entry_size to mtk_eth_soc") +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -547,7 +547,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + } + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size); ++ memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size - sizeof(hwe->ib1)); + wmb(); + hwe->ib1 = entry->ib1; + diff --git a/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch b/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch new file mode 100644 index 00000000000..27c719b6635 --- /dev/null +++ b/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch @@ -0,0 +1,32 @@ +From c9da02bfb1112461e048d3b736afb1873f6f4ccf Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 27 Sep 2022 16:30:02 +0100 +Subject: [PATCH 1/1] net: ethernet: mtk_eth_soc: fix mask of + RX_DMA_GET_SPORT{,_V2} + +The bitmasks applied in RX_DMA_GET_SPORT and RX_DMA_GET_SPORT_V2 macros +were swapped. Fix that. + +Reported-by: Chen Minqiang +Fixes: 160d3a9b192985 ("net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support") +Acked-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +Link: https://lore.kernel.org/r/YzMW+mg9UsaCdKRQ@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -315,8 +315,8 @@ + #define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18) + #define MTK_RXD5_SRC_PORT GENMASK(29, 26) + +-#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) +-#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) ++#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0x7) ++#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0xf) + + /* PDMA V2 descriptor rxd3 */ + #define RX_DMA_VTAG_V2 BIT(0) diff --git a/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch b/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch new file mode 100644 index 00000000000..11465c1c5b7 --- /dev/null +++ b/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch @@ -0,0 +1,37 @@ +From ae3ed15da5889263de372ff9df2e83e16acca4cb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 30 Sep 2022 01:56:53 +0100 +Subject: [PATCH 1/1] net: ethernet: mtk_eth_soc: fix state in + __mtk_foe_entry_clear + +Setting ib1 state to MTK_FOE_STATE_UNBIND in __mtk_foe_entry_clear +routine as done by commit 0e80707d94e4c8 ("net: ethernet: mtk_eth_soc: +fix typo in __mtk_foe_entry_clear") breaks flow offloading, at least +on older MTK_NETSYS_V1 SoCs, OpenWrt users have confirmed the bug on +MT7622 and MT7621 systems. +Felix Fietkau suggested to use MTK_FOE_STATE_INVALID instead which +works well on both, MTK_NETSYS_V1 and MTK_NETSYS_V2. + +Tested on MT7622 (Linksys E8450) and MT7986 (BananaPi BPI-R3). + +Suggested-by: Felix Fietkau +Fixes: 0e80707d94e4c8 ("net: ethernet: mtk_eth_soc: fix typo in __mtk_foe_entry_clear") +Fixes: 33fc42de33278b ("net: ethernet: mtk_eth_soc: support creating mac address based offload entries") +Signed-off-by: Daniel Golle +Link: https://lore.kernel.org/r/YzY+1Yg0FBXcnrtc@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -442,7 +442,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_UNBIND); ++ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); + } + entry->hash = 0xffff; diff --git a/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch b/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch new file mode 100644 index 00000000000..b41318afd76 --- /dev/null +++ b/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch @@ -0,0 +1,73 @@ +From b3d0d98179d62f9d55635a600679c4fa362baf8d Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Mon, 17 Oct 2022 11:51:54 +0800 +Subject: [PATCH 1/3] net: ethernet: mtk_eth_soc: fix possible memory leak in + mtk_probe() + +If mtk_wed_add_hw() has been called, mtk_wed_exit() needs be called +in error path or removing module to free the memory allocated in +mtk_wed_add_hw(). + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Signed-off-by: Yang Yingliang +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4011,19 +4011,23 @@ static int mtk_probe(struct platform_dev + eth->irq[i] = platform_get_irq(pdev, i); + if (eth->irq[i] < 0) { + dev_err(&pdev->dev, "no IRQ%d resource found\n", i); +- return -ENXIO; ++ err = -ENXIO; ++ goto err_wed_exit; + } + } + for (i = 0; i < ARRAY_SIZE(eth->clks); i++) { + eth->clks[i] = devm_clk_get(eth->dev, + mtk_clks_source_name[i]); + if (IS_ERR(eth->clks[i])) { +- if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) +- return -EPROBE_DEFER; ++ if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) { ++ err = -EPROBE_DEFER; ++ goto err_wed_exit; ++ } + if (eth->soc->required_clks & BIT(i)) { + dev_err(&pdev->dev, "clock %s not found\n", + mtk_clks_source_name[i]); +- return -EINVAL; ++ err = -EINVAL; ++ goto err_wed_exit; + } + eth->clks[i] = NULL; + } +@@ -4034,7 +4038,7 @@ static int mtk_probe(struct platform_dev + + err = mtk_hw_init(eth); + if (err) +- return err; ++ goto err_wed_exit; + + eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO); + +@@ -4132,6 +4136,8 @@ err_free_dev: + mtk_free_dev(eth); + err_deinit_hw: + mtk_hw_deinit(eth); ++err_wed_exit: ++ mtk_wed_exit(); + + return err; + } +@@ -4151,6 +4157,7 @@ static int mtk_remove(struct platform_de + phylink_disconnect_phy(mac->phylink); + } + ++ mtk_wed_exit(); + mtk_hw_deinit(eth); + + netif_napi_del(ð->tx_napi); diff --git a/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch b/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch new file mode 100644 index 00000000000..ef5374dcc57 --- /dev/null +++ b/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch @@ -0,0 +1,47 @@ +From 9d4f20a476ca57e4c9246eb1fa2a61bea2354720 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Mon, 17 Oct 2022 11:51:55 +0800 +Subject: [PATCH 2/3] net: ethernet: mtk_eth_wed: add missing put_device() in + mtk_wed_add_hw() + +After calling get_device() in mtk_wed_add_hw(), in error path, put_device() +needs be called. + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Signed-off-by: Yang Yingliang +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -1084,11 +1084,11 @@ void mtk_wed_add_hw(struct device_node * + get_device(&pdev->dev); + irq = platform_get_irq(pdev, 0); + if (irq < 0) +- return; ++ goto err_put_device; + + regs = syscon_regmap_lookup_by_phandle(np, NULL); + if (IS_ERR(regs)) +- return; ++ goto err_put_device; + + rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); + +@@ -1131,8 +1131,14 @@ void mtk_wed_add_hw(struct device_node * + + hw_list[index] = hw; + ++ mutex_unlock(&hw_lock); ++ ++ return; ++ + unlock: + mutex_unlock(&hw_lock); ++err_put_device: ++ put_device(&pdev->dev); + } + + void mtk_wed_exit(void) diff --git a/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch b/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch new file mode 100644 index 00000000000..0a452d4a7d4 --- /dev/null +++ b/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch @@ -0,0 +1,43 @@ +From e0bb4659e235770e6f53b3692e958591f49448f5 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Mon, 17 Oct 2022 11:51:56 +0800 +Subject: [PATCH 3/3] net: ethernet: mtk_eth_wed: add missing of_node_put() + +The device_node pointer returned by of_parse_phandle() with refcount +incremented, when finish using it, the refcount need be decreased. + +Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") +Signed-off-by: Yang Yingliang +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -1079,7 +1079,7 @@ void mtk_wed_add_hw(struct device_node * + + pdev = of_find_device_by_node(np); + if (!pdev) +- return; ++ goto err_of_node_put; + + get_device(&pdev->dev); + irq = platform_get_irq(pdev, 0); +@@ -1139,6 +1139,8 @@ unlock: + mutex_unlock(&hw_lock); + err_put_device: + put_device(&pdev->dev); ++err_of_node_put: ++ of_node_put(np); + } + + void mtk_wed_exit(void) +@@ -1159,6 +1161,7 @@ void mtk_wed_exit(void) + hw_list[i] = NULL; + debugfs_remove(hw->debugfs_dir); + put_device(hw->dev); ++ of_node_put(hw->node); + kfree(hw); + } + } diff --git a/target/linux/generic/backport-6.1/729-01-v6.1-net-ethernet-mtk_wed-introduce-wed-mcu-support.patch b/target/linux/generic/backport-6.1/729-01-v6.1-net-ethernet-mtk_wed-introduce-wed-mcu-support.patch new file mode 100644 index 00000000000..c48613929d1 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-01-v6.1-net-ethernet-mtk_wed-introduce-wed-mcu-support.patch @@ -0,0 +1,591 @@ +From: Sujuan Chen +Date: Sat, 5 Nov 2022 23:36:18 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: introduce wed mcu support + +Introduce WED mcu support used to configure WED WO chip. +This is a preliminary patch in order to add RX Wireless +Ethernet Dispatch available on MT7986 SoC. + +Tested-by: Daniel Golle +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Sujuan Chen +Signed-off-by: David S. Miller +--- + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_mcu.c + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.h + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -5,7 +5,7 @@ + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o + mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o +-mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o ++mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o + ifdef CONFIG_DEBUG_FS + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o + endif +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -0,0 +1,359 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2022 MediaTek Inc. ++ * ++ * Author: Lorenzo Bianconi ++ * Sujuan Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk_wed_regs.h" ++#include "mtk_wed_wo.h" ++#include "mtk_wed.h" ++ ++static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg) ++{ ++ return readl(wo->boot.addr + reg); ++} ++ ++static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val) ++{ ++ writel(val, wo->boot.addr + reg); ++} ++ ++static struct sk_buff * ++mtk_wed_mcu_msg_alloc(const void *data, int data_len) ++{ ++ int length = sizeof(struct mtk_wed_mcu_hdr) + data_len; ++ struct sk_buff *skb; ++ ++ skb = alloc_skb(length, GFP_KERNEL); ++ if (!skb) ++ return NULL; ++ ++ memset(skb->head, 0, length); ++ skb_reserve(skb, sizeof(struct mtk_wed_mcu_hdr)); ++ if (data && data_len) ++ skb_put_data(skb, data, data_len); ++ ++ return skb; ++} ++ ++static struct sk_buff * ++mtk_wed_mcu_get_response(struct mtk_wed_wo *wo, unsigned long expires) ++{ ++ if (!time_is_after_jiffies(expires)) ++ return NULL; ++ ++ wait_event_timeout(wo->mcu.wait, !skb_queue_empty(&wo->mcu.res_q), ++ expires - jiffies); ++ return skb_dequeue(&wo->mcu.res_q); ++} ++ ++void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb) ++{ ++ skb_queue_tail(&wo->mcu.res_q, skb); ++ wake_up(&wo->mcu.wait); ++} ++ ++void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo, ++ struct sk_buff *skb) ++{ ++ struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data; ++ ++ switch (hdr->cmd) { ++ case MTK_WED_WO_EVT_LOG_DUMP: { ++ const char *msg = (const char *)(skb->data + sizeof(*hdr)); ++ ++ dev_notice(wo->hw->dev, "%s\n", msg); ++ break; ++ } ++ case MTK_WED_WO_EVT_PROFILING: { ++ struct mtk_wed_wo_log_info *info; ++ u32 count = (skb->len - sizeof(*hdr)) / sizeof(*info); ++ int i; ++ ++ info = (struct mtk_wed_wo_log_info *)(skb->data + sizeof(*hdr)); ++ for (i = 0 ; i < count ; i++) ++ dev_notice(wo->hw->dev, ++ "SN:%u latency: total=%u, rro:%u, mod:%u\n", ++ le32_to_cpu(info[i].sn), ++ le32_to_cpu(info[i].total), ++ le32_to_cpu(info[i].rro), ++ le32_to_cpu(info[i].mod)); ++ break; ++ } ++ case MTK_WED_WO_EVT_RXCNT_INFO: ++ break; ++ default: ++ break; ++ } ++ ++ dev_kfree_skb(skb); ++} ++ ++static int ++mtk_wed_mcu_skb_send_msg(struct mtk_wed_wo *wo, struct sk_buff *skb, ++ int id, int cmd, u16 *wait_seq, bool wait_resp) ++{ ++ struct mtk_wed_mcu_hdr *hdr; ++ ++ /* TODO: make it dynamic based on cmd */ ++ wo->mcu.timeout = 20 * HZ; ++ ++ hdr = (struct mtk_wed_mcu_hdr *)skb_push(skb, sizeof(*hdr)); ++ hdr->cmd = cmd; ++ hdr->length = cpu_to_le16(skb->len); ++ ++ if (wait_resp && wait_seq) { ++ u16 seq = ++wo->mcu.seq; ++ ++ if (!seq) ++ seq = ++wo->mcu.seq; ++ *wait_seq = seq; ++ ++ hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_NEED_RSP); ++ hdr->seq = cpu_to_le16(seq); ++ } ++ if (id == MTK_WED_MODULE_ID_WO) ++ hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_FROM_TO_WO); ++ ++ dev_kfree_skb(skb); ++ return 0; ++} ++ ++static int ++mtk_wed_mcu_parse_response(struct mtk_wed_wo *wo, struct sk_buff *skb, ++ int cmd, int seq) ++{ ++ struct mtk_wed_mcu_hdr *hdr; ++ ++ if (!skb) { ++ dev_err(wo->hw->dev, "Message %08x (seq %d) timeout\n", ++ cmd, seq); ++ return -ETIMEDOUT; ++ } ++ ++ hdr = (struct mtk_wed_mcu_hdr *)skb->data; ++ if (le16_to_cpu(hdr->seq) != seq) ++ return -EAGAIN; ++ ++ skb_pull(skb, sizeof(*hdr)); ++ switch (cmd) { ++ case MTK_WED_WO_CMD_RXCNT_INFO: ++ default: ++ break; ++ } ++ ++ return 0; ++} ++ ++int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd, ++ const void *data, int len, bool wait_resp) ++{ ++ unsigned long expires; ++ struct sk_buff *skb; ++ u16 seq; ++ int ret; ++ ++ skb = mtk_wed_mcu_msg_alloc(data, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&wo->mcu.mutex); ++ ++ ret = mtk_wed_mcu_skb_send_msg(wo, skb, id, cmd, &seq, wait_resp); ++ if (ret || !wait_resp) ++ goto unlock; ++ ++ expires = jiffies + wo->mcu.timeout; ++ do { ++ skb = mtk_wed_mcu_get_response(wo, expires); ++ ret = mtk_wed_mcu_parse_response(wo, skb, cmd, seq); ++ dev_kfree_skb(skb); ++ } while (ret == -EAGAIN); ++ ++unlock: ++ mutex_unlock(&wo->mcu.mutex); ++ ++ return ret; ++} ++ ++static int ++mtk_wed_get_memory_region(struct mtk_wed_wo *wo, ++ struct mtk_wed_wo_memory_region *region) ++{ ++ struct reserved_mem *rmem; ++ struct device_node *np; ++ int index; ++ ++ index = of_property_match_string(wo->hw->node, "memory-region-names", ++ region->name); ++ if (index < 0) ++ return index; ++ ++ np = of_parse_phandle(wo->hw->node, "memory-region", index); ++ if (!np) ++ return -ENODEV; ++ ++ rmem = of_reserved_mem_lookup(np); ++ of_node_put(np); ++ ++ if (!rmem) ++ return -ENODEV; ++ ++ region->phy_addr = rmem->base; ++ region->size = rmem->size; ++ region->addr = devm_ioremap(wo->hw->dev, region->phy_addr, region->size); ++ ++ return !region->addr ? -EINVAL : 0; ++} ++ ++static int ++mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw, ++ struct mtk_wed_wo_memory_region *region) ++{ ++ const u8 *first_region_ptr, *region_ptr, *trailer_ptr, *ptr = fw->data; ++ const struct mtk_wed_fw_trailer *trailer; ++ const struct mtk_wed_fw_region *fw_region; ++ ++ trailer_ptr = fw->data + fw->size - sizeof(*trailer); ++ trailer = (const struct mtk_wed_fw_trailer *)trailer_ptr; ++ region_ptr = trailer_ptr - trailer->num_region * sizeof(*fw_region); ++ first_region_ptr = region_ptr; ++ ++ while (region_ptr < trailer_ptr) { ++ u32 length; ++ ++ fw_region = (const struct mtk_wed_fw_region *)region_ptr; ++ length = le32_to_cpu(fw_region->len); ++ ++ if (region->phy_addr != le32_to_cpu(fw_region->addr)) ++ goto next; ++ ++ if (region->size < length) ++ goto next; ++ ++ if (first_region_ptr < ptr + length) ++ goto next; ++ ++ if (region->shared && region->consumed) ++ return 0; ++ ++ if (!region->shared || !region->consumed) { ++ memcpy_toio(region->addr, ptr, length); ++ region->consumed = true; ++ return 0; ++ } ++next: ++ region_ptr += sizeof(*fw_region); ++ ptr += length; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ++mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo) ++{ ++ static struct mtk_wed_wo_memory_region mem_region[] = { ++ [MTK_WED_WO_REGION_EMI] = { ++ .name = "wo-emi", ++ }, ++ [MTK_WED_WO_REGION_ILM] = { ++ .name = "wo-ilm", ++ }, ++ [MTK_WED_WO_REGION_DATA] = { ++ .name = "wo-data", ++ .shared = true, ++ }, ++ }; ++ const struct mtk_wed_fw_trailer *trailer; ++ const struct firmware *fw; ++ const char *fw_name; ++ u32 val, boot_cr; ++ int ret, i; ++ ++ /* load firmware region metadata */ ++ for (i = 0; i < ARRAY_SIZE(mem_region); i++) { ++ ret = mtk_wed_get_memory_region(wo, &mem_region[i]); ++ if (ret) ++ return ret; ++ } ++ ++ wo->boot.name = "wo-boot"; ++ ret = mtk_wed_get_memory_region(wo, &wo->boot); ++ if (ret) ++ return ret; ++ ++ /* set dummy cr */ ++ wed_w32(wo->hw->wed_dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL, ++ wo->hw->index + 1); ++ ++ /* load firmware */ ++ fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1 : MT7986_FIRMWARE_WO0; ++ ret = request_firmware(&fw, fw_name, wo->hw->dev); ++ if (ret) ++ return ret; ++ ++ trailer = (void *)(fw->data + fw->size - ++ sizeof(struct mtk_wed_fw_trailer)); ++ dev_info(wo->hw->dev, ++ "MTK WED WO Firmware Version: %.10s, Build Time: %.15s\n", ++ trailer->fw_ver, trailer->build_date); ++ dev_info(wo->hw->dev, "MTK WED WO Chip ID %02x Region %d\n", ++ trailer->chip_id, trailer->num_region); ++ ++ for (i = 0; i < ARRAY_SIZE(mem_region); i++) { ++ ret = mtk_wed_mcu_run_firmware(wo, fw, &mem_region[i]); ++ if (ret) ++ goto out; ++ } ++ ++ /* set the start address */ ++ boot_cr = wo->hw->index ? MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR ++ : MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR; ++ wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16); ++ /* wo firmware reset */ ++ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00); ++ ++ val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR); ++ val |= wo->hw->index ? MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK ++ : MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK; ++ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val); ++out: ++ release_firmware(fw); ++ ++ return ret; ++} ++ ++static u32 ++mtk_wed_mcu_read_fw_dl(struct mtk_wed_wo *wo) ++{ ++ return wed_r32(wo->hw->wed_dev, ++ MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL); ++} ++ ++int mtk_wed_mcu_init(struct mtk_wed_wo *wo) ++{ ++ u32 val; ++ int ret; ++ ++ skb_queue_head_init(&wo->mcu.res_q); ++ init_waitqueue_head(&wo->mcu.wait); ++ mutex_init(&wo->mcu.mutex); ++ ++ ret = mtk_wed_mcu_load_firmware(wo); ++ if (ret) ++ return ret; ++ ++ return readx_poll_timeout(mtk_wed_mcu_read_fw_dl, wo, val, !val, ++ 100, MTK_FW_DL_TIMEOUT); ++} ++ ++MODULE_FIRMWARE(MT7986_FIRMWARE_WO0); ++MODULE_FIRMWARE(MT7986_FIRMWARE_WO1); +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -152,6 +152,7 @@ struct mtk_wdma_desc { + + #define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10) + ++#define MTK_WED_SCR0 0x3c0 + #define MTK_WED_WPDMA_INT_TRIGGER 0x504 + #define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1) + #define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4) +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -0,0 +1,150 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* Copyright (C) 2022 Lorenzo Bianconi */ ++ ++#ifndef __MTK_WED_WO_H ++#define __MTK_WED_WO_H ++ ++#include ++#include ++ ++struct mtk_wed_hw; ++ ++struct mtk_wed_mcu_hdr { ++ /* DW0 */ ++ u8 version; ++ u8 cmd; ++ __le16 length; ++ ++ /* DW1 */ ++ __le16 seq; ++ __le16 flag; ++ ++ /* DW2 */ ++ __le32 status; ++ ++ /* DW3 */ ++ u8 rsv[20]; ++}; ++ ++struct mtk_wed_wo_log_info { ++ __le32 sn; ++ __le32 total; ++ __le32 rro; ++ __le32 mod; ++}; ++ ++enum mtk_wed_wo_event { ++ MTK_WED_WO_EVT_LOG_DUMP = 0x1, ++ MTK_WED_WO_EVT_PROFILING = 0x2, ++ MTK_WED_WO_EVT_RXCNT_INFO = 0x3, ++}; ++ ++#define MTK_WED_MODULE_ID_WO 1 ++#define MTK_FW_DL_TIMEOUT 4000000 /* us */ ++#define MTK_WOCPU_TIMEOUT 2000000 /* us */ ++ ++enum { ++ MTK_WED_WARP_CMD_FLAG_RSP = BIT(0), ++ MTK_WED_WARP_CMD_FLAG_NEED_RSP = BIT(1), ++ MTK_WED_WARP_CMD_FLAG_FROM_TO_WO = BIT(2), ++}; ++ ++enum { ++ MTK_WED_WO_REGION_EMI, ++ MTK_WED_WO_REGION_ILM, ++ MTK_WED_WO_REGION_DATA, ++ MTK_WED_WO_REGION_BOOT, ++ __MTK_WED_WO_REGION_MAX, ++}; ++ ++enum mtk_wed_dummy_cr_idx { ++ MTK_WED_DUMMY_CR_FWDL, ++ MTK_WED_DUMMY_CR_WO_STATUS, ++}; ++ ++#define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin" ++#define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin" ++ ++#define MTK_WO_MCU_CFG_LS_BASE 0 ++#define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000) ++#define MTK_WO_MCU_CFG_LS_FW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x004) ++#define MTK_WO_MCU_CFG_LS_CFG_DBG1_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x00c) ++#define MTK_WO_MCU_CFG_LS_CFG_DBG2_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x010) ++#define MTK_WO_MCU_CFG_LS_WF_MCCR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x014) ++#define MTK_WO_MCU_CFG_LS_WF_MCCR_SET_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x018) ++#define MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x01c) ++#define MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x050) ++#define MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x060) ++#define MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x064) ++ ++#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK BIT(5) ++#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK BIT(0) ++ ++struct mtk_wed_wo_memory_region { ++ const char *name; ++ void __iomem *addr; ++ phys_addr_t phy_addr; ++ u32 size; ++ bool shared:1; ++ bool consumed:1; ++}; ++ ++struct mtk_wed_fw_region { ++ __le32 decomp_crc; ++ __le32 decomp_len; ++ __le32 decomp_blk_sz; ++ u8 rsv0[4]; ++ __le32 addr; ++ __le32 len; ++ u8 feature_set; ++ u8 rsv1[15]; ++} __packed; ++ ++struct mtk_wed_fw_trailer { ++ u8 chip_id; ++ u8 eco_code; ++ u8 num_region; ++ u8 format_ver; ++ u8 format_flag; ++ u8 rsv[2]; ++ char fw_ver[10]; ++ char build_date[15]; ++ u32 crc; ++}; ++ ++struct mtk_wed_wo { ++ struct mtk_wed_hw *hw; ++ struct mtk_wed_wo_memory_region boot; ++ ++ struct { ++ struct mutex mutex; ++ int timeout; ++ u16 seq; ++ ++ struct sk_buff_head res_q; ++ wait_queue_head_t wait; ++ } mcu; ++}; ++ ++static inline int ++mtk_wed_mcu_check_msg(struct mtk_wed_wo *wo, struct sk_buff *skb) ++{ ++ struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data; ++ ++ if (hdr->version) ++ return -EINVAL; ++ ++ if (skb->len < sizeof(*hdr) || skb->len != le16_to_cpu(hdr->length)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb); ++void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo, ++ struct sk_buff *skb); ++int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd, ++ const void *data, int len, bool wait_resp); ++int mtk_wed_mcu_init(struct mtk_wed_wo *wo); ++ ++#endif /* __MTK_WED_WO_H */ +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -11,6 +11,35 @@ + struct mtk_wed_hw; + struct mtk_wdma_desc; + ++enum mtk_wed_wo_cmd { ++ MTK_WED_WO_CMD_WED_CFG, ++ MTK_WED_WO_CMD_WED_RX_STAT, ++ MTK_WED_WO_CMD_RRO_SER, ++ MTK_WED_WO_CMD_DBG_INFO, ++ MTK_WED_WO_CMD_DEV_INFO, ++ MTK_WED_WO_CMD_BSS_INFO, ++ MTK_WED_WO_CMD_STA_REC, ++ MTK_WED_WO_CMD_DEV_INFO_DUMP, ++ MTK_WED_WO_CMD_BSS_INFO_DUMP, ++ MTK_WED_WO_CMD_STA_REC_DUMP, ++ MTK_WED_WO_CMD_BA_INFO_DUMP, ++ MTK_WED_WO_CMD_FBCMD_Q_DUMP, ++ MTK_WED_WO_CMD_FW_LOG_CTRL, ++ MTK_WED_WO_CMD_LOG_FLUSH, ++ MTK_WED_WO_CMD_CHANGE_STATE, ++ MTK_WED_WO_CMD_CPU_STATS_ENABLE, ++ MTK_WED_WO_CMD_CPU_STATS_DUMP, ++ MTK_WED_WO_CMD_EXCEPTION_INIT, ++ MTK_WED_WO_CMD_PROF_CTRL, ++ MTK_WED_WO_CMD_STA_BA_DUMP, ++ MTK_WED_WO_CMD_BA_CTRL_DUMP, ++ MTK_WED_WO_CMD_RXCNT_CTRL, ++ MTK_WED_WO_CMD_RXCNT_INFO, ++ MTK_WED_WO_CMD_SET_CAP, ++ MTK_WED_WO_CMD_CCIF_RING_DUMP, ++ MTK_WED_WO_CMD_WED_END ++}; ++ + enum mtk_wed_bus_tye { + MTK_WED_BUS_PCIE, + MTK_WED_BUS_AXI, diff --git a/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch b/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch new file mode 100644 index 00000000000..dbd7e30fbb8 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch @@ -0,0 +1,737 @@ +From: Lorenzo Bianconi +Date: Sat, 5 Nov 2022 23:36:19 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: introduce wed wo support + +Introduce WO chip support to mtk wed driver. MTK WED WO is used to +implement RX Wireless Ethernet Dispatch and offload traffic received by +wlan nic to the wired interface. + +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.c + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -5,7 +5,7 @@ + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o + mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o +-mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o ++mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o + ifdef CONFIG_DEBUG_FS + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o + endif +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -16,6 +16,7 @@ + #include "mtk_wed_regs.h" + #include "mtk_wed.h" + #include "mtk_ppe.h" ++#include "mtk_wed_wo.h" + + #define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000) + +@@ -355,6 +356,8 @@ mtk_wed_detach(struct mtk_wed_device *de + + mtk_wed_free_buffer(dev); + mtk_wed_free_tx_rings(dev); ++ if (hw->version != 1) ++ mtk_wed_wo_deinit(hw); + + if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { + struct device_node *wlan_node; +@@ -885,9 +888,11 @@ mtk_wed_attach(struct mtk_wed_device *de + } + + mtk_wed_hw_init_early(dev); +- if (hw->hifsys) ++ if (hw->version == 1) + regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, + BIT(hw->index), 0); ++ else ++ ret = mtk_wed_wo_init(hw); + + out: + mutex_unlock(&hw_lock); +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -10,6 +10,7 @@ + #include + + struct mtk_eth; ++struct mtk_wed_wo; + + struct mtk_wed_hw { + struct device_node *node; +@@ -22,6 +23,7 @@ struct mtk_wed_hw { + struct regmap *mirror; + struct dentry *debugfs_dir; + struct mtk_wed_device *wed_dev; ++ struct mtk_wed_wo *wed_wo; + u32 debugfs_reg; + u32 num_flows; + u8 version; +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -122,8 +122,7 @@ mtk_wed_mcu_skb_send_msg(struct mtk_wed_ + if (id == MTK_WED_MODULE_ID_WO) + hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_FROM_TO_WO); + +- dev_kfree_skb(skb); +- return 0; ++ return mtk_wed_wo_queue_tx_skb(wo, &wo->q_tx, skb); + } + + static int +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c +@@ -0,0 +1,508 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* Copyright (C) 2022 MediaTek Inc. ++ * ++ * Author: Lorenzo Bianconi ++ * Sujuan Chen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mtk_wed.h" ++#include "mtk_wed_regs.h" ++#include "mtk_wed_wo.h" ++ ++static u32 ++mtk_wed_mmio_r32(struct mtk_wed_wo *wo, u32 reg) ++{ ++ u32 val; ++ ++ if (regmap_read(wo->mmio.regs, reg, &val)) ++ val = ~0; ++ ++ return val; ++} ++ ++static void ++mtk_wed_mmio_w32(struct mtk_wed_wo *wo, u32 reg, u32 val) ++{ ++ regmap_write(wo->mmio.regs, reg, val); ++} ++ ++static u32 ++mtk_wed_wo_get_isr(struct mtk_wed_wo *wo) ++{ ++ u32 val = mtk_wed_mmio_r32(wo, MTK_WED_WO_CCIF_RCHNUM); ++ ++ return val & MTK_WED_WO_CCIF_RCHNUM_MASK; ++} ++ ++static void ++mtk_wed_wo_set_isr(struct mtk_wed_wo *wo, u32 mask) ++{ ++ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_IRQ0_MASK, mask); ++} ++ ++static void ++mtk_wed_wo_set_ack(struct mtk_wed_wo *wo, u32 mask) ++{ ++ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_ACK, mask); ++} ++ ++static void ++mtk_wed_wo_set_isr_mask(struct mtk_wed_wo *wo, u32 mask, u32 val, bool set) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wo->mmio.lock, flags); ++ wo->mmio.irq_mask &= ~mask; ++ wo->mmio.irq_mask |= val; ++ if (set) ++ mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask); ++ spin_unlock_irqrestore(&wo->mmio.lock, flags); ++} ++ ++static void ++mtk_wed_wo_irq_enable(struct mtk_wed_wo *wo, u32 mask) ++{ ++ mtk_wed_wo_set_isr_mask(wo, 0, mask, false); ++ tasklet_schedule(&wo->mmio.irq_tasklet); ++} ++ ++static void ++mtk_wed_wo_irq_disable(struct mtk_wed_wo *wo, u32 mask) ++{ ++ mtk_wed_wo_set_isr_mask(wo, mask, 0, true); ++} ++ ++static void ++mtk_wed_wo_kickout(struct mtk_wed_wo *wo) ++{ ++ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_BUSY, 1 << MTK_WED_WO_TXCH_NUM); ++ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_TCHNUM, MTK_WED_WO_TXCH_NUM); ++} ++ ++static void ++mtk_wed_wo_queue_kick(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, ++ u32 val) ++{ ++ wmb(); ++ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, val); ++} ++ ++static void * ++mtk_wed_wo_dequeue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, u32 *len, ++ bool flush) ++{ ++ int buf_len = SKB_WITH_OVERHEAD(q->buf_size); ++ int index = (q->tail + 1) % q->n_desc; ++ struct mtk_wed_wo_queue_entry *entry; ++ struct mtk_wed_wo_queue_desc *desc; ++ void *buf; ++ ++ if (!q->queued) ++ return NULL; ++ ++ if (flush) ++ q->desc[index].ctrl |= cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE); ++ else if (!(q->desc[index].ctrl & cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE))) ++ return NULL; ++ ++ q->tail = index; ++ q->queued--; ++ ++ desc = &q->desc[index]; ++ entry = &q->entry[index]; ++ buf = entry->buf; ++ if (len) ++ *len = FIELD_GET(MTK_WED_WO_CTL_SD_LEN0, ++ le32_to_cpu(READ_ONCE(desc->ctrl))); ++ if (buf) ++ dma_unmap_single(wo->hw->dev, entry->addr, buf_len, ++ DMA_FROM_DEVICE); ++ entry->buf = NULL; ++ ++ return buf; ++} ++ ++static int ++mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, ++ gfp_t gfp, bool rx) ++{ ++ enum dma_data_direction dir = rx ? DMA_FROM_DEVICE : DMA_TO_DEVICE; ++ int n_buf = 0; ++ ++ spin_lock_bh(&q->lock); ++ while (q->queued < q->n_desc) { ++ void *buf = page_frag_alloc(&q->cache, q->buf_size, gfp); ++ struct mtk_wed_wo_queue_entry *entry; ++ dma_addr_t addr; ++ ++ if (!buf) ++ break; ++ ++ addr = dma_map_single(wo->hw->dev, buf, q->buf_size, dir); ++ if (unlikely(dma_mapping_error(wo->hw->dev, addr))) { ++ skb_free_frag(buf); ++ break; ++ } ++ ++ q->head = (q->head + 1) % q->n_desc; ++ entry = &q->entry[q->head]; ++ entry->addr = addr; ++ entry->len = q->buf_size; ++ q->entry[q->head].buf = buf; ++ ++ if (rx) { ++ struct mtk_wed_wo_queue_desc *desc = &q->desc[q->head]; ++ u32 ctrl = MTK_WED_WO_CTL_LAST_SEC0 | ++ FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0, ++ entry->len); ++ ++ WRITE_ONCE(desc->buf0, cpu_to_le32(addr)); ++ WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); ++ } ++ q->queued++; ++ n_buf++; ++ } ++ spin_unlock_bh(&q->lock); ++ ++ return n_buf; ++} ++ ++static void ++mtk_wed_wo_rx_complete(struct mtk_wed_wo *wo) ++{ ++ mtk_wed_wo_set_ack(wo, MTK_WED_WO_RXCH_INT_MASK); ++ mtk_wed_wo_irq_enable(wo, MTK_WED_WO_RXCH_INT_MASK); ++} ++ ++static void ++mtk_wed_wo_rx_run_queue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) ++{ ++ for (;;) { ++ struct mtk_wed_mcu_hdr *hdr; ++ struct sk_buff *skb; ++ void *data; ++ u32 len; ++ ++ data = mtk_wed_wo_dequeue(wo, q, &len, false); ++ if (!data) ++ break; ++ ++ skb = build_skb(data, q->buf_size); ++ if (!skb) { ++ skb_free_frag(data); ++ continue; ++ } ++ ++ __skb_put(skb, len); ++ if (mtk_wed_mcu_check_msg(wo, skb)) { ++ dev_kfree_skb(skb); ++ continue; ++ } ++ ++ hdr = (struct mtk_wed_mcu_hdr *)skb->data; ++ if (hdr->flag & cpu_to_le16(MTK_WED_WARP_CMD_FLAG_RSP)) ++ mtk_wed_mcu_rx_event(wo, skb); ++ else ++ mtk_wed_mcu_rx_unsolicited_event(wo, skb); ++ } ++ ++ if (mtk_wed_wo_queue_refill(wo, q, GFP_ATOMIC, true)) { ++ u32 index = (q->head - 1) % q->n_desc; ++ ++ mtk_wed_wo_queue_kick(wo, q, index); ++ } ++} ++ ++static irqreturn_t ++mtk_wed_wo_irq_handler(int irq, void *data) ++{ ++ struct mtk_wed_wo *wo = data; ++ ++ mtk_wed_wo_set_isr(wo, 0); ++ tasklet_schedule(&wo->mmio.irq_tasklet); ++ ++ return IRQ_HANDLED; ++} ++ ++static void mtk_wed_wo_irq_tasklet(struct tasklet_struct *t) ++{ ++ struct mtk_wed_wo *wo = from_tasklet(wo, t, mmio.irq_tasklet); ++ u32 intr, mask; ++ ++ /* disable interrupts */ ++ mtk_wed_wo_set_isr(wo, 0); ++ ++ intr = mtk_wed_wo_get_isr(wo); ++ intr &= wo->mmio.irq_mask; ++ mask = intr & (MTK_WED_WO_RXCH_INT_MASK | MTK_WED_WO_EXCEPTION_INT_MASK); ++ mtk_wed_wo_irq_disable(wo, mask); ++ ++ if (intr & MTK_WED_WO_RXCH_INT_MASK) { ++ mtk_wed_wo_rx_run_queue(wo, &wo->q_rx); ++ mtk_wed_wo_rx_complete(wo); ++ } ++} ++ ++/* mtk wed wo hw queues */ ++ ++static int ++mtk_wed_wo_queue_alloc(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, ++ int n_desc, int buf_size, int index, ++ struct mtk_wed_wo_queue_regs *regs) ++{ ++ spin_lock_init(&q->lock); ++ q->regs = *regs; ++ q->n_desc = n_desc; ++ q->buf_size = buf_size; ++ ++ q->desc = dmam_alloc_coherent(wo->hw->dev, n_desc * sizeof(*q->desc), ++ &q->desc_dma, GFP_KERNEL); ++ if (!q->desc) ++ return -ENOMEM; ++ ++ q->entry = devm_kzalloc(wo->hw->dev, n_desc * sizeof(*q->entry), ++ GFP_KERNEL); ++ if (!q->entry) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void ++mtk_wed_wo_queue_free(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) ++{ ++ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0); ++ dma_free_coherent(wo->hw->dev, q->n_desc * sizeof(*q->desc), q->desc, ++ q->desc_dma); ++} ++ ++static void ++mtk_wed_wo_queue_tx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) ++{ ++ struct page *page; ++ int i; ++ ++ spin_lock_bh(&q->lock); ++ for (i = 0; i < q->n_desc; i++) { ++ struct mtk_wed_wo_queue_entry *entry = &q->entry[i]; ++ ++ dma_unmap_single(wo->hw->dev, entry->addr, entry->len, ++ DMA_TO_DEVICE); ++ skb_free_frag(entry->buf); ++ entry->buf = NULL; ++ } ++ spin_unlock_bh(&q->lock); ++ ++ if (!q->cache.va) ++ return; ++ ++ page = virt_to_page(q->cache.va); ++ __page_frag_cache_drain(page, q->cache.pagecnt_bias); ++ memset(&q->cache, 0, sizeof(q->cache)); ++} ++ ++static void ++mtk_wed_wo_queue_rx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) ++{ ++ struct page *page; ++ ++ spin_lock_bh(&q->lock); ++ for (;;) { ++ void *buf = mtk_wed_wo_dequeue(wo, q, NULL, true); ++ ++ if (!buf) ++ break; ++ ++ skb_free_frag(buf); ++ } ++ spin_unlock_bh(&q->lock); ++ ++ if (!q->cache.va) ++ return; ++ ++ page = virt_to_page(q->cache.va); ++ __page_frag_cache_drain(page, q->cache.pagecnt_bias); ++ memset(&q->cache, 0, sizeof(q->cache)); ++} ++ ++static void ++mtk_wed_wo_queue_reset(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q) ++{ ++ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0); ++ mtk_wed_mmio_w32(wo, q->regs.desc_base, q->desc_dma); ++ mtk_wed_mmio_w32(wo, q->regs.ring_size, q->n_desc); ++} ++ ++int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, ++ struct sk_buff *skb) ++{ ++ struct mtk_wed_wo_queue_entry *entry; ++ struct mtk_wed_wo_queue_desc *desc; ++ int ret = 0, index; ++ u32 ctrl; ++ ++ spin_lock_bh(&q->lock); ++ ++ q->tail = mtk_wed_mmio_r32(wo, q->regs.dma_idx); ++ index = (q->head + 1) % q->n_desc; ++ if (q->tail == index) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ entry = &q->entry[index]; ++ if (skb->len > entry->len) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ desc = &q->desc[index]; ++ q->head = index; ++ ++ dma_sync_single_for_cpu(wo->hw->dev, entry->addr, skb->len, ++ DMA_TO_DEVICE); ++ memcpy(entry->buf, skb->data, skb->len); ++ dma_sync_single_for_device(wo->hw->dev, entry->addr, skb->len, ++ DMA_TO_DEVICE); ++ ++ ctrl = FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0, skb->len) | ++ MTK_WED_WO_CTL_LAST_SEC0 | MTK_WED_WO_CTL_DMA_DONE; ++ WRITE_ONCE(desc->buf0, cpu_to_le32(entry->addr)); ++ WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); ++ ++ mtk_wed_wo_queue_kick(wo, q, q->head); ++ mtk_wed_wo_kickout(wo); ++out: ++ spin_unlock_bh(&q->lock); ++ ++ dev_kfree_skb(skb); ++ ++ return ret; ++} ++ ++static int ++mtk_wed_wo_exception_init(struct mtk_wed_wo *wo) ++{ ++ return 0; ++} ++ ++static int ++mtk_wed_wo_hardware_init(struct mtk_wed_wo *wo) ++{ ++ struct mtk_wed_wo_queue_regs regs; ++ struct device_node *np; ++ int ret; ++ ++ np = of_parse_phandle(wo->hw->node, "mediatek,wo-ccif", 0); ++ if (!np) ++ return -ENODEV; ++ ++ wo->mmio.regs = syscon_regmap_lookup_by_phandle(np, NULL); ++ if (IS_ERR_OR_NULL(wo->mmio.regs)) ++ return PTR_ERR(wo->mmio.regs); ++ ++ wo->mmio.irq = irq_of_parse_and_map(np, 0); ++ wo->mmio.irq_mask = MTK_WED_WO_ALL_INT_MASK; ++ spin_lock_init(&wo->mmio.lock); ++ tasklet_setup(&wo->mmio.irq_tasklet, mtk_wed_wo_irq_tasklet); ++ ++ ret = devm_request_irq(wo->hw->dev, wo->mmio.irq, ++ mtk_wed_wo_irq_handler, IRQF_TRIGGER_HIGH, ++ KBUILD_MODNAME, wo); ++ if (ret) ++ goto error; ++ ++ regs.desc_base = MTK_WED_WO_CCIF_DUMMY1; ++ regs.ring_size = MTK_WED_WO_CCIF_DUMMY2; ++ regs.dma_idx = MTK_WED_WO_CCIF_SHADOW4; ++ regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY3; ++ ++ ret = mtk_wed_wo_queue_alloc(wo, &wo->q_tx, MTK_WED_WO_RING_SIZE, ++ MTK_WED_WO_CMD_LEN, MTK_WED_WO_TXCH_NUM, ++ ®s); ++ if (ret) ++ goto error; ++ ++ mtk_wed_wo_queue_refill(wo, &wo->q_tx, GFP_KERNEL, false); ++ mtk_wed_wo_queue_reset(wo, &wo->q_tx); ++ ++ regs.desc_base = MTK_WED_WO_CCIF_DUMMY5; ++ regs.ring_size = MTK_WED_WO_CCIF_DUMMY6; ++ regs.dma_idx = MTK_WED_WO_CCIF_SHADOW8; ++ regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY7; ++ ++ ret = mtk_wed_wo_queue_alloc(wo, &wo->q_rx, MTK_WED_WO_RING_SIZE, ++ MTK_WED_WO_CMD_LEN, MTK_WED_WO_RXCH_NUM, ++ ®s); ++ if (ret) ++ goto error; ++ ++ mtk_wed_wo_queue_refill(wo, &wo->q_rx, GFP_KERNEL, true); ++ mtk_wed_wo_queue_reset(wo, &wo->q_rx); ++ ++ /* rx queue irqmask */ ++ mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask); ++ ++ return 0; ++ ++error: ++ devm_free_irq(wo->hw->dev, wo->mmio.irq, wo); ++ ++ return ret; ++} ++ ++static void ++mtk_wed_wo_hw_deinit(struct mtk_wed_wo *wo) ++{ ++ /* disable interrupts */ ++ mtk_wed_wo_set_isr(wo, 0); ++ ++ tasklet_disable(&wo->mmio.irq_tasklet); ++ ++ disable_irq(wo->mmio.irq); ++ devm_free_irq(wo->hw->dev, wo->mmio.irq, wo); ++ ++ mtk_wed_wo_queue_tx_clean(wo, &wo->q_tx); ++ mtk_wed_wo_queue_rx_clean(wo, &wo->q_rx); ++ mtk_wed_wo_queue_free(wo, &wo->q_tx); ++ mtk_wed_wo_queue_free(wo, &wo->q_rx); ++} ++ ++int mtk_wed_wo_init(struct mtk_wed_hw *hw) ++{ ++ struct mtk_wed_wo *wo; ++ int ret; ++ ++ wo = devm_kzalloc(hw->dev, sizeof(*wo), GFP_KERNEL); ++ if (!wo) ++ return -ENOMEM; ++ ++ hw->wed_wo = wo; ++ wo->hw = hw; ++ ++ ret = mtk_wed_wo_hardware_init(wo); ++ if (ret) ++ return ret; ++ ++ ret = mtk_wed_mcu_init(wo); ++ if (ret) ++ return ret; ++ ++ return mtk_wed_wo_exception_init(wo); ++} ++ ++void mtk_wed_wo_deinit(struct mtk_wed_hw *hw) ++{ ++ struct mtk_wed_wo *wo = hw->wed_wo; ++ ++ mtk_wed_wo_hw_deinit(wo); ++} +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -80,6 +80,54 @@ enum mtk_wed_dummy_cr_idx { + #define MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK BIT(5) + #define MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK BIT(0) + ++#define MTK_WED_WO_RING_SIZE 256 ++#define MTK_WED_WO_CMD_LEN 1504 ++ ++#define MTK_WED_WO_TXCH_NUM 0 ++#define MTK_WED_WO_RXCH_NUM 1 ++#define MTK_WED_WO_RXCH_WO_EXCEPTION 7 ++ ++#define MTK_WED_WO_TXCH_INT_MASK BIT(0) ++#define MTK_WED_WO_RXCH_INT_MASK BIT(1) ++#define MTK_WED_WO_EXCEPTION_INT_MASK BIT(7) ++#define MTK_WED_WO_ALL_INT_MASK (MTK_WED_WO_RXCH_INT_MASK | \ ++ MTK_WED_WO_EXCEPTION_INT_MASK) ++ ++#define MTK_WED_WO_CCIF_BUSY 0x004 ++#define MTK_WED_WO_CCIF_START 0x008 ++#define MTK_WED_WO_CCIF_TCHNUM 0x00c ++#define MTK_WED_WO_CCIF_RCHNUM 0x010 ++#define MTK_WED_WO_CCIF_RCHNUM_MASK GENMASK(7, 0) ++ ++#define MTK_WED_WO_CCIF_ACK 0x014 ++#define MTK_WED_WO_CCIF_IRQ0_MASK 0x018 ++#define MTK_WED_WO_CCIF_IRQ1_MASK 0x01c ++#define MTK_WED_WO_CCIF_DUMMY1 0x020 ++#define MTK_WED_WO_CCIF_DUMMY2 0x024 ++#define MTK_WED_WO_CCIF_DUMMY3 0x028 ++#define MTK_WED_WO_CCIF_DUMMY4 0x02c ++#define MTK_WED_WO_CCIF_SHADOW1 0x030 ++#define MTK_WED_WO_CCIF_SHADOW2 0x034 ++#define MTK_WED_WO_CCIF_SHADOW3 0x038 ++#define MTK_WED_WO_CCIF_SHADOW4 0x03c ++#define MTK_WED_WO_CCIF_DUMMY5 0x050 ++#define MTK_WED_WO_CCIF_DUMMY6 0x054 ++#define MTK_WED_WO_CCIF_DUMMY7 0x058 ++#define MTK_WED_WO_CCIF_DUMMY8 0x05c ++#define MTK_WED_WO_CCIF_SHADOW5 0x060 ++#define MTK_WED_WO_CCIF_SHADOW6 0x064 ++#define MTK_WED_WO_CCIF_SHADOW7 0x068 ++#define MTK_WED_WO_CCIF_SHADOW8 0x06c ++ ++#define MTK_WED_WO_CTL_SD_LEN1 GENMASK(13, 0) ++#define MTK_WED_WO_CTL_LAST_SEC1 BIT(14) ++#define MTK_WED_WO_CTL_BURST BIT(15) ++#define MTK_WED_WO_CTL_SD_LEN0_SHIFT 16 ++#define MTK_WED_WO_CTL_SD_LEN0 GENMASK(29, 16) ++#define MTK_WED_WO_CTL_LAST_SEC0 BIT(30) ++#define MTK_WED_WO_CTL_DMA_DONE BIT(31) ++#define MTK_WED_WO_INFO_WINFO GENMASK(15, 0) ++ + struct mtk_wed_wo_memory_region { + const char *name; + void __iomem *addr; +@@ -112,10 +160,53 @@ struct mtk_wed_fw_trailer { + u32 crc; + }; + ++struct mtk_wed_wo_queue_regs { ++ u32 desc_base; ++ u32 ring_size; ++ u32 cpu_idx; ++ u32 dma_idx; ++}; ++ ++struct mtk_wed_wo_queue_desc { ++ __le32 buf0; ++ __le32 ctrl; ++ __le32 buf1; ++ __le32 info; ++ __le32 reserved[4]; ++} __packed __aligned(32); ++ ++struct mtk_wed_wo_queue_entry { ++ dma_addr_t addr; ++ void *buf; ++ u32 len; ++}; ++ ++struct mtk_wed_wo_queue { ++ struct mtk_wed_wo_queue_regs regs; ++ ++ struct page_frag_cache cache; ++ spinlock_t lock; ++ ++ struct mtk_wed_wo_queue_desc *desc; ++ dma_addr_t desc_dma; ++ ++ struct mtk_wed_wo_queue_entry *entry; ++ ++ u16 head; ++ u16 tail; ++ int n_desc; ++ int queued; ++ int buf_size; ++ ++}; ++ + struct mtk_wed_wo { + struct mtk_wed_hw *hw; + struct mtk_wed_wo_memory_region boot; + ++ struct mtk_wed_wo_queue q_tx; ++ struct mtk_wed_wo_queue q_rx; ++ + struct { + struct mutex mutex; + int timeout; +@@ -124,6 +215,15 @@ struct mtk_wed_wo { + struct sk_buff_head res_q; + wait_queue_head_t wait; + } mcu; ++ ++ struct { ++ struct regmap *regs; ++ ++ spinlock_t lock; ++ struct tasklet_struct irq_tasklet; ++ int irq; ++ u32 irq_mask; ++ } mmio; + }; + + static inline int +@@ -146,5 +246,9 @@ void mtk_wed_mcu_rx_unsolicited_event(st + int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd, + const void *data, int len, bool wait_resp); + int mtk_wed_mcu_init(struct mtk_wed_wo *wo); ++int mtk_wed_wo_init(struct mtk_wed_hw *hw); ++void mtk_wed_wo_deinit(struct mtk_wed_hw *hw); ++int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *dev, struct mtk_wed_wo_queue *q, ++ struct sk_buff *skb); + + #endif /* __MTK_WED_WO_H */ diff --git a/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch b/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch new file mode 100644 index 00000000000..ffd6bc3589d --- /dev/null +++ b/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch @@ -0,0 +1,79 @@ +From: Lorenzo Bianconi +Date: Sat, 5 Nov 2022 23:36:20 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: rename tx_wdma array in rx_wdma + +Rename tx_wdma queue array in rx_wdma since this is rx side of wdma soc. +Moreover rename mtk_wed_wdma_ring_setup routine in +mtk_wed_wdma_rx_ring_setup() + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -253,8 +253,8 @@ mtk_wed_free_tx_rings(struct mtk_wed_dev + + for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) + mtk_wed_free_ring(dev, &dev->tx_ring[i]); +- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +- mtk_wed_free_ring(dev, &dev->tx_wdma[i]); ++ for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) ++ mtk_wed_free_ring(dev, &dev->rx_wdma[i]); + } + + static void +@@ -695,10 +695,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device + } + + static int +-mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) ++mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size) + { + u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; +- struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; ++ struct mtk_wed_ring *wdma = &dev->rx_wdma[idx]; + + if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) + return -ENOMEM; +@@ -812,9 +812,9 @@ mtk_wed_start(struct mtk_wed_device *dev + { + int i; + +- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) +- if (!dev->tx_wdma[i].desc) +- mtk_wed_wdma_ring_setup(dev, i, 16); ++ for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) ++ if (!dev->rx_wdma[i].desc) ++ mtk_wed_wdma_rx_ring_setup(dev, i, 16); + + mtk_wed_hw_init(dev); + mtk_wed_configure_irq(dev, irq_mask); +@@ -923,7 +923,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + sizeof(*ring->desc))) + return -ENOMEM; + +- if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) ++ if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) + return -ENOMEM; + + ring->reg_base = MTK_WED_RING_TX(idx); +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -7,6 +7,7 @@ + #include + + #define MTK_WED_TX_QUEUES 2 ++#define MTK_WED_RX_QUEUES 2 + + struct mtk_wed_hw; + struct mtk_wdma_desc; +@@ -66,7 +67,7 @@ struct mtk_wed_device { + + struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES]; + struct mtk_wed_ring txfree_ring; +- struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES]; ++ struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES]; + + struct { + int size; diff --git a/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch b/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch new file mode 100644 index 00000000000..4c34d0cb33b --- /dev/null +++ b/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch @@ -0,0 +1,1521 @@ +From: Lorenzo Bianconi +Date: Sat, 5 Nov 2022 23:36:21 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add configure wed wo support + +Enable RX Wireless Ethernet Dispatch available on MT7986 Soc. + +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -23,6 +24,7 @@ + #define MTK_WED_PKT_SIZE 1900 + #define MTK_WED_BUF_SIZE 2048 + #define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048) ++#define MTK_WED_RX_RING_SIZE 1536 + + #define MTK_WED_TX_RING_SIZE 2048 + #define MTK_WED_WDMA_RING_SIZE 1024 +@@ -31,6 +33,10 @@ + #define MTK_WED_PER_GROUP_PKT 128 + + #define MTK_WED_FBUF_SIZE 128 ++#define MTK_WED_MIOD_CNT 16 ++#define MTK_WED_FB_CMD_CNT 1024 ++#define MTK_WED_RRO_QUE_CNT 8192 ++#define MTK_WED_MIOD_ENTRY_CNT 128 + + static struct mtk_wed_hw *hw_list[2]; + static DEFINE_MUTEX(hw_lock); +@@ -65,12 +71,76 @@ wdma_set(struct mtk_wed_device *dev, u32 + wdma_m32(dev, reg, 0, mask); + } + ++static void ++wdma_clr(struct mtk_wed_device *dev, u32 reg, u32 mask) ++{ ++ wdma_m32(dev, reg, mask, 0); ++} ++ ++static u32 ++wifi_r32(struct mtk_wed_device *dev, u32 reg) ++{ ++ return readl(dev->wlan.base + reg); ++} ++ ++static void ++wifi_w32(struct mtk_wed_device *dev, u32 reg, u32 val) ++{ ++ writel(val, dev->wlan.base + reg); ++} ++ + static u32 + mtk_wed_read_reset(struct mtk_wed_device *dev) + { + return wed_r32(dev, MTK_WED_RESET); + } + ++static u32 ++mtk_wdma_read_reset(struct mtk_wed_device *dev) ++{ ++ return wdma_r32(dev, MTK_WDMA_GLO_CFG); ++} ++ ++static void ++mtk_wdma_rx_reset(struct mtk_wed_device *dev) ++{ ++ u32 status, mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY; ++ int i; ++ ++ wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN); ++ if (readx_poll_timeout(mtk_wdma_read_reset, dev, status, ++ !(status & mask), 0, 1000)) ++ dev_err(dev->hw->dev, "rx reset failed\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) { ++ if (dev->rx_wdma[i].desc) ++ continue; ++ ++ wdma_w32(dev, ++ MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0); ++ } ++} ++ ++static void ++mtk_wdma_tx_reset(struct mtk_wed_device *dev) ++{ ++ u32 status, mask = MTK_WDMA_GLO_CFG_TX_DMA_BUSY; ++ int i; ++ ++ wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN); ++ if (readx_poll_timeout(mtk_wdma_read_reset, dev, status, ++ !(status & mask), 0, 1000)) ++ dev_err(dev->hw->dev, "tx reset failed\n"); ++ ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) { ++ if (dev->tx_wdma[i].desc) ++ continue; ++ ++ wdma_w32(dev, ++ MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0); ++ } ++} ++ + static void + mtk_wed_reset(struct mtk_wed_device *dev, u32 mask) + { +@@ -82,6 +152,54 @@ mtk_wed_reset(struct mtk_wed_device *dev + WARN_ON_ONCE(1); + } + ++static u32 ++mtk_wed_wo_read_status(struct mtk_wed_device *dev) ++{ ++ return wed_r32(dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_WO_STATUS); ++} ++ ++static void ++mtk_wed_wo_reset(struct mtk_wed_device *dev) ++{ ++ struct mtk_wed_wo *wo = dev->hw->wed_wo; ++ u8 state = MTK_WED_WO_STATE_DISABLE; ++ void __iomem *reg; ++ u32 val; ++ ++ mtk_wdma_tx_reset(dev); ++ mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ ++ mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, ++ MTK_WED_WO_CMD_CHANGE_STATE, &state, ++ sizeof(state), false); ++ ++ if (readx_poll_timeout(mtk_wed_wo_read_status, dev, val, ++ val == MTK_WED_WOIF_DISABLE_DONE, ++ 100, MTK_WOCPU_TIMEOUT)) ++ dev_err(dev->hw->dev, "failed to disable wed-wo\n"); ++ ++ reg = ioremap(MTK_WED_WO_CPU_MCUSYS_RESET_ADDR, 4); ++ ++ val = readl(reg); ++ switch (dev->hw->index) { ++ case 0: ++ val |= MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK; ++ writel(val, reg); ++ val &= ~MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK; ++ writel(val, reg); ++ break; ++ case 1: ++ val |= MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK; ++ writel(val, reg); ++ val &= ~MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK; ++ writel(val, reg); ++ break; ++ default: ++ break; ++ } ++ iounmap(reg); ++} ++ + static struct mtk_wed_hw * + mtk_wed_assign(struct mtk_wed_device *dev) + { +@@ -116,7 +234,7 @@ out: + } + + static int +-mtk_wed_buffer_alloc(struct mtk_wed_device *dev) ++mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) + { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; +@@ -133,16 +251,16 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi + if (!page_list) + return -ENOMEM; + +- dev->buf_ring.size = ring_size; +- dev->buf_ring.pages = page_list; ++ dev->tx_buf_ring.size = ring_size; ++ dev->tx_buf_ring.pages = page_list; + + desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc), + &desc_phys, GFP_KERNEL); + if (!desc) + return -ENOMEM; + +- dev->buf_ring.desc = desc; +- dev->buf_ring.desc_phys = desc_phys; ++ dev->tx_buf_ring.desc = desc; ++ dev->tx_buf_ring.desc_phys = desc_phys; + + for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) { + dma_addr_t page_phys, buf_phys; +@@ -203,10 +321,10 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi + } + + static void +-mtk_wed_free_buffer(struct mtk_wed_device *dev) ++mtk_wed_free_tx_buffer(struct mtk_wed_device *dev) + { +- struct mtk_wdma_desc *desc = dev->buf_ring.desc; +- void **page_list = dev->buf_ring.pages; ++ struct mtk_wdma_desc *desc = dev->tx_buf_ring.desc; ++ void **page_list = dev->tx_buf_ring.pages; + int page_idx; + int i; + +@@ -216,7 +334,8 @@ mtk_wed_free_buffer(struct mtk_wed_devic + if (!desc) + goto free_pagelist; + +- for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) { ++ for (i = 0, page_idx = 0; i < dev->tx_buf_ring.size; ++ i += MTK_WED_BUF_PER_PAGE) { + void *page = page_list[page_idx++]; + dma_addr_t buf_addr; + +@@ -229,13 +348,59 @@ mtk_wed_free_buffer(struct mtk_wed_devic + __free_page(page); + } + +- dma_free_coherent(dev->hw->dev, dev->buf_ring.size * sizeof(*desc), +- desc, dev->buf_ring.desc_phys); ++ dma_free_coherent(dev->hw->dev, dev->tx_buf_ring.size * sizeof(*desc), ++ desc, dev->tx_buf_ring.desc_phys); + + free_pagelist: + kfree(page_list); + } + ++static int ++mtk_wed_rx_buffer_alloc(struct mtk_wed_device *dev) ++{ ++ struct mtk_rxbm_desc *desc; ++ dma_addr_t desc_phys; ++ ++ dev->rx_buf_ring.size = dev->wlan.rx_nbuf; ++ desc = dma_alloc_coherent(dev->hw->dev, ++ dev->wlan.rx_nbuf * sizeof(*desc), ++ &desc_phys, GFP_KERNEL); ++ if (!desc) ++ return -ENOMEM; ++ ++ dev->rx_buf_ring.desc = desc; ++ dev->rx_buf_ring.desc_phys = desc_phys; ++ dev->wlan.init_rx_buf(dev, dev->wlan.rx_npkt); ++ ++ return 0; ++} ++ ++static void ++mtk_wed_free_rx_buffer(struct mtk_wed_device *dev) ++{ ++ struct mtk_rxbm_desc *desc = dev->rx_buf_ring.desc; ++ ++ if (!desc) ++ return; ++ ++ dev->wlan.release_rx_buf(dev); ++ dma_free_coherent(dev->hw->dev, dev->rx_buf_ring.size * sizeof(*desc), ++ desc, dev->rx_buf_ring.desc_phys); ++} ++ ++static void ++mtk_wed_rx_buffer_hw_init(struct mtk_wed_device *dev) ++{ ++ wed_w32(dev, MTK_WED_RX_BM_RX_DMAD, ++ FIELD_PREP(MTK_WED_RX_BM_RX_DMAD_SDL0, dev->wlan.rx_size)); ++ wed_w32(dev, MTK_WED_RX_BM_BASE, dev->rx_buf_ring.desc_phys); ++ wed_w32(dev, MTK_WED_RX_BM_INIT_PTR, MTK_WED_RX_BM_INIT_SW_TAIL | ++ FIELD_PREP(MTK_WED_RX_BM_SW_TAIL, dev->wlan.rx_npkt)); ++ wed_w32(dev, MTK_WED_RX_BM_DYN_ALLOC_TH, ++ FIELD_PREP(MTK_WED_RX_BM_DYN_ALLOC_TH_H, 0xffff)); ++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN); ++} ++ + static void + mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring) + { +@@ -247,6 +412,13 @@ mtk_wed_free_ring(struct mtk_wed_device + } + + static void ++mtk_wed_free_rx_rings(struct mtk_wed_device *dev) ++{ ++ mtk_wed_free_rx_buffer(dev); ++ mtk_wed_free_ring(dev, &dev->rro.ring); ++} ++ ++static void + mtk_wed_free_tx_rings(struct mtk_wed_device *dev) + { + int i; +@@ -291,6 +463,38 @@ mtk_wed_set_512_support(struct mtk_wed_d + } + } + ++#define MTK_WFMDA_RX_DMA_EN BIT(2) ++static void ++mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx) ++{ ++ u32 val; ++ int i; ++ ++ if (!(dev->rx_ring[idx].flags & MTK_WED_RING_CONFIGURED)) ++ return; /* queue is not configured by mt76 */ ++ ++ for (i = 0; i < 3; i++) { ++ u32 cur_idx; ++ ++ cur_idx = wed_r32(dev, ++ MTK_WED_WPDMA_RING_RX_DATA(idx) + ++ MTK_WED_RING_OFS_CPU_IDX); ++ if (cur_idx == MTK_WED_RX_RING_SIZE - 1) ++ break; ++ ++ usleep_range(100000, 200000); ++ } ++ ++ if (i == 3) { ++ dev_err(dev->hw->dev, "rx dma enable failed\n"); ++ return; ++ } ++ ++ val = wifi_r32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base) | ++ MTK_WFMDA_RX_DMA_EN; ++ wifi_w32(dev, dev->wlan.wpdma_rx_glo - dev->wlan.phy_base, val); ++} ++ + static void + mtk_wed_dma_disable(struct mtk_wed_device *dev) + { +@@ -304,20 +508,25 @@ mtk_wed_dma_disable(struct mtk_wed_devic + MTK_WED_GLO_CFG_TX_DMA_EN | + MTK_WED_GLO_CFG_RX_DMA_EN); + +- wdma_m32(dev, MTK_WDMA_GLO_CFG, ++ wdma_clr(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_TX_DMA_EN | + MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | +- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0); ++ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES); + + if (dev->hw->version == 1) { + regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); +- wdma_m32(dev, MTK_WDMA_GLO_CFG, +- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); ++ wdma_clr(dev, MTK_WDMA_GLO_CFG, ++ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); + } else { + wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, + MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | + MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); + ++ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, ++ MTK_WED_WPDMA_RX_D_RX_DRV_EN); ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK); ++ + mtk_wed_set_512_support(dev, false); + } + } +@@ -338,6 +547,13 @@ mtk_wed_stop(struct mtk_wed_device *dev) + wdma_w32(dev, MTK_WDMA_INT_MASK, 0); + wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); + wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); ++ ++ if (dev->hw->version == 1) ++ return; ++ ++ wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0); ++ wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0); ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN); + } + + static void +@@ -353,11 +569,21 @@ mtk_wed_detach(struct mtk_wed_device *de + wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); + + mtk_wed_reset(dev, MTK_WED_RESET_WED); ++ if (mtk_wed_get_rx_capa(dev)) { ++ wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); ++ } + +- mtk_wed_free_buffer(dev); ++ mtk_wed_free_tx_buffer(dev); + mtk_wed_free_tx_rings(dev); +- if (hw->version != 1) ++ ++ if (mtk_wed_get_rx_capa(dev)) { ++ mtk_wed_wo_reset(dev); ++ mtk_wed_free_rx_rings(dev); + mtk_wed_wo_deinit(hw); ++ mtk_wdma_rx_reset(dev); ++ } + + if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { + struct device_node *wlan_node; +@@ -441,10 +667,12 @@ mtk_wed_set_wpdma(struct mtk_wed_device + } else { + mtk_wed_bus_init(dev); + +- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int); +- wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask); +- wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx); +- wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx); ++ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree); ++ wed_w32(dev, MTK_WED_WPDMA_RX_GLO_CFG, dev->wlan.wpdma_rx_glo); ++ wed_w32(dev, MTK_WED_WPDMA_RX_RING, dev->wlan.wpdma_rx); + } + } + +@@ -494,6 +722,132 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + } + } + ++static int ++mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, ++ int size) ++{ ++ ring->desc = dma_alloc_coherent(dev->hw->dev, ++ size * sizeof(*ring->desc), ++ &ring->desc_phys, GFP_KERNEL); ++ if (!ring->desc) ++ return -ENOMEM; ++ ++ ring->desc_size = sizeof(*ring->desc); ++ ring->size = size; ++ memset(ring->desc, 0, size); ++ ++ return 0; ++} ++ ++#define MTK_WED_MIOD_COUNT (MTK_WED_MIOD_ENTRY_CNT * MTK_WED_MIOD_CNT) ++static int ++mtk_wed_rro_alloc(struct mtk_wed_device *dev) ++{ ++ struct reserved_mem *rmem; ++ struct device_node *np; ++ int index; ++ ++ index = of_property_match_string(dev->hw->node, "memory-region-names", ++ "wo-dlm"); ++ if (index < 0) ++ return index; ++ ++ np = of_parse_phandle(dev->hw->node, "memory-region", index); ++ if (!np) ++ return -ENODEV; ++ ++ rmem = of_reserved_mem_lookup(np); ++ of_node_put(np); ++ ++ if (!rmem) ++ return -ENODEV; ++ ++ dev->rro.miod_phys = rmem->base; ++ dev->rro.fdbk_phys = MTK_WED_MIOD_COUNT + dev->rro.miod_phys; ++ ++ return mtk_wed_rro_ring_alloc(dev, &dev->rro.ring, ++ MTK_WED_RRO_QUE_CNT); ++} ++ ++static int ++mtk_wed_rro_cfg(struct mtk_wed_device *dev) ++{ ++ struct mtk_wed_wo *wo = dev->hw->wed_wo; ++ struct { ++ struct { ++ __le32 base; ++ __le32 cnt; ++ __le32 unit; ++ } ring[2]; ++ __le32 wed; ++ u8 version; ++ } req = { ++ .ring[0] = { ++ .base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE), ++ .cnt = cpu_to_le32(MTK_WED_MIOD_CNT), ++ .unit = cpu_to_le32(MTK_WED_MIOD_ENTRY_CNT), ++ }, ++ .ring[1] = { ++ .base = cpu_to_le32(MTK_WED_WOCPU_VIEW_MIOD_BASE + ++ MTK_WED_MIOD_COUNT), ++ .cnt = cpu_to_le32(MTK_WED_FB_CMD_CNT), ++ .unit = cpu_to_le32(4), ++ }, ++ }; ++ ++ return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, ++ MTK_WED_WO_CMD_WED_CFG, ++ &req, sizeof(req), true); ++} ++ ++static void ++mtk_wed_rro_hw_init(struct mtk_wed_device *dev) ++{ ++ wed_w32(dev, MTK_WED_RROQM_MIOD_CFG, ++ FIELD_PREP(MTK_WED_RROQM_MIOD_MID_DW, 0x70 >> 2) | ++ FIELD_PREP(MTK_WED_RROQM_MIOD_MOD_DW, 0x10 >> 2) | ++ FIELD_PREP(MTK_WED_RROQM_MIOD_ENTRY_DW, ++ MTK_WED_MIOD_ENTRY_CNT >> 2)); ++ ++ wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL0, dev->rro.miod_phys); ++ wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL1, ++ FIELD_PREP(MTK_WED_RROQM_MIOD_CNT, MTK_WED_MIOD_CNT)); ++ wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL0, dev->rro.fdbk_phys); ++ wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL1, ++ FIELD_PREP(MTK_WED_RROQM_FDBK_CNT, MTK_WED_FB_CMD_CNT)); ++ wed_w32(dev, MTK_WED_RROQM_FDBK_CTRL2, 0); ++ wed_w32(dev, MTK_WED_RROQ_BASE_L, dev->rro.ring.desc_phys); ++ ++ wed_set(dev, MTK_WED_RROQM_RST_IDX, ++ MTK_WED_RROQM_RST_IDX_MIOD | ++ MTK_WED_RROQM_RST_IDX_FDBK); ++ ++ wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0); ++ wed_w32(dev, MTK_WED_RROQM_MIOD_CTRL2, MTK_WED_MIOD_CNT - 1); ++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN); ++} ++ ++static void ++mtk_wed_route_qm_hw_init(struct mtk_wed_device *dev) ++{ ++ wed_w32(dev, MTK_WED_RESET, MTK_WED_RESET_RX_ROUTE_QM); ++ ++ for (;;) { ++ usleep_range(100, 200); ++ if (!(wed_r32(dev, MTK_WED_RESET) & MTK_WED_RESET_RX_ROUTE_QM)) ++ break; ++ } ++ ++ /* configure RX_ROUTE_QM */ ++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST); ++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_TXDMAD_FPORT); ++ wed_set(dev, MTK_WED_RTQM_GLO_CFG, ++ FIELD_PREP(MTK_WED_RTQM_TXDMAD_FPORT, 0x3 + dev->hw->index)); ++ wed_clr(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST); ++ /* enable RX_ROUTE_QM */ ++ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN); ++} ++ + static void + mtk_wed_hw_init(struct mtk_wed_device *dev) + { +@@ -505,11 +859,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d + wed_w32(dev, MTK_WED_TX_BM_CTRL, + MTK_WED_TX_BM_CTRL_PAUSE | + FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, +- dev->buf_ring.size / 128) | ++ dev->tx_buf_ring.size / 128) | + FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, + MTK_WED_TX_RING_SIZE / 256)); + +- wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); ++ wed_w32(dev, MTK_WED_TX_BM_BASE, dev->tx_buf_ring.desc_phys); + + wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); + +@@ -536,9 +890,9 @@ mtk_wed_hw_init(struct mtk_wed_device *d + wed_w32(dev, MTK_WED_TX_TKID_CTRL, + MTK_WED_TX_TKID_CTRL_PAUSE | + FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM, +- dev->buf_ring.size / 128) | ++ dev->tx_buf_ring.size / 128) | + FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM, +- dev->buf_ring.size / 128)); ++ dev->tx_buf_ring.size / 128)); + wed_w32(dev, MTK_WED_TX_TKID_DYN_THR, + FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) | + MTK_WED_TX_TKID_DYN_THR_HI); +@@ -546,18 +900,28 @@ mtk_wed_hw_init(struct mtk_wed_device *d + + mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); + +- if (dev->hw->version == 1) ++ if (dev->hw->version == 1) { + wed_set(dev, MTK_WED_CTRL, + MTK_WED_CTRL_WED_TX_BM_EN | + MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); +- else ++ } else { + wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE); ++ /* rx hw init */ ++ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, ++ MTK_WED_WPDMA_RX_D_RST_CRX_IDX | ++ MTK_WED_WPDMA_RX_D_RST_DRV_IDX); ++ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0); ++ ++ mtk_wed_rx_buffer_hw_init(dev); ++ mtk_wed_rro_hw_init(dev); ++ mtk_wed_route_qm_hw_init(dev); ++ } + + wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); + } + + static void +-mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size) ++mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx) + { + void *head = (void *)ring->desc; + int i; +@@ -567,7 +931,10 @@ mtk_wed_ring_reset(struct mtk_wed_ring * + + desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size); + desc->buf0 = 0; +- desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); ++ if (tx) ++ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); ++ else ++ desc->ctrl = cpu_to_le32(MTK_WFDMA_DESC_CTRL_TO_HOST); + desc->buf1 = 0; + desc->info = 0; + } +@@ -623,7 +990,8 @@ mtk_wed_reset_dma(struct mtk_wed_device + if (!dev->tx_ring[i].desc) + continue; + +- mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE); ++ mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE, ++ true); + } + + if (mtk_wed_poll_busy(dev)) +@@ -641,6 +1009,9 @@ mtk_wed_reset_dma(struct mtk_wed_device + wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); + wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); + ++ if (mtk_wed_get_rx_capa(dev)) ++ mtk_wdma_rx_reset(dev); ++ + if (busy) { + mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); + mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV); +@@ -675,12 +1046,11 @@ mtk_wed_reset_dma(struct mtk_wed_device + MTK_WED_WPDMA_RESET_IDX_RX); + wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); + } +- + } + + static int + mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, +- int size, u32 desc_size) ++ int size, u32 desc_size, bool tx) + { + ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size, + &ring->desc_phys, GFP_KERNEL); +@@ -689,7 +1059,7 @@ mtk_wed_ring_alloc(struct mtk_wed_device + + ring->desc_size = desc_size; + ring->size = size; +- mtk_wed_ring_reset(ring, size); ++ mtk_wed_ring_reset(ring, size, tx); + + return 0; + } +@@ -698,9 +1068,14 @@ static int + mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size) + { + u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; +- struct mtk_wed_ring *wdma = &dev->rx_wdma[idx]; ++ struct mtk_wed_ring *wdma; + +- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) ++ if (idx >= ARRAY_SIZE(dev->rx_wdma)) ++ return -EINVAL; ++ ++ wdma = &dev->rx_wdma[idx]; ++ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size, ++ true)) + return -ENOMEM; + + wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, +@@ -717,6 +1092,60 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we + return 0; + } + ++static int ++mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size) ++{ ++ u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; ++ struct mtk_wed_ring *wdma; ++ ++ if (idx >= ARRAY_SIZE(dev->tx_wdma)) ++ return -EINVAL; ++ ++ wdma = &dev->tx_wdma[idx]; ++ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size, ++ true)) ++ return -ENOMEM; ++ ++ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE, ++ wdma->desc_phys); ++ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT, ++ size); ++ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); ++ wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0); ++ ++ if (!idx) { ++ wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE, ++ wdma->desc_phys); ++ wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_COUNT, ++ size); ++ wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_CPU_IDX, ++ 0); ++ wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_DMA_IDX, ++ 0); ++ } ++ ++ return 0; ++} ++ ++static void ++mtk_wed_ppe_check(struct mtk_wed_device *dev, struct sk_buff *skb, ++ u32 reason, u32 hash) ++{ ++ struct mtk_eth *eth = dev->hw->eth; ++ struct ethhdr *eh; ++ ++ if (!skb) ++ return; ++ ++ if (reason != MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) ++ return; ++ ++ skb_set_mac_header(skb, 0); ++ eh = eth_hdr(skb); ++ skb->protocol = eh->h_proto; ++ mtk_ppe_check_skb(eth->ppe[dev->hw->index], skb, hash); ++} ++ + static void + mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) + { +@@ -739,6 +1168,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev + + wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); + } else { ++ wdma_mask |= FIELD_PREP(MTK_WDMA_INT_MASK_TX_DONE, ++ GENMASK(1, 0)); + /* initail tx interrupt trigger */ + wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, + MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | +@@ -757,6 +1188,16 @@ mtk_wed_configure_irq(struct mtk_wed_dev + FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG, + dev->wlan.txfree_tbit)); + ++ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_RX, ++ MTK_WED_WPDMA_INT_CTRL_RX0_EN | ++ MTK_WED_WPDMA_INT_CTRL_RX0_CLR | ++ MTK_WED_WPDMA_INT_CTRL_RX1_EN | ++ MTK_WED_WPDMA_INT_CTRL_RX1_CLR | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG, ++ dev->wlan.rx_tbit[0]) | ++ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG, ++ dev->wlan.rx_tbit[1])); ++ + wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask); + wed_set(dev, MTK_WED_WDMA_INT_CTRL, + FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL, +@@ -794,9 +1235,15 @@ mtk_wed_dma_enable(struct mtk_wed_device + wdma_set(dev, MTK_WDMA_GLO_CFG, + MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); + } else { ++ int i; ++ + wed_set(dev, MTK_WED_WPDMA_CTRL, + MTK_WED_WPDMA_CTRL_SDL1_FIXED); + ++ wed_set(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK); ++ + wed_set(dev, MTK_WED_WPDMA_GLO_CFG, + MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | + MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); +@@ -804,6 +1251,15 @@ mtk_wed_dma_enable(struct mtk_wed_device + wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, + MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP | + MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV); ++ ++ wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, ++ MTK_WED_WPDMA_RX_D_RX_DRV_EN | ++ FIELD_PREP(MTK_WED_WPDMA_RX_D_RXD_READ_LEN, 0x18) | ++ FIELD_PREP(MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL, ++ 0x2)); ++ ++ for (i = 0; i < MTK_WED_RX_QUEUES; i++) ++ mtk_wed_check_wfdma_rx_fill(dev, i); + } + } + +@@ -829,7 +1285,19 @@ mtk_wed_start(struct mtk_wed_device *dev + val |= BIT(0) | (BIT(1) * !!dev->hw->index); + regmap_write(dev->hw->mirror, dev->hw->index * 4, val); + } else { +- mtk_wed_set_512_support(dev, true); ++ /* driver set mid ready and only once */ ++ wed_w32(dev, MTK_WED_EXT_INT_MASK1, ++ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY); ++ wed_w32(dev, MTK_WED_EXT_INT_MASK2, ++ MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY); ++ ++ wed_r32(dev, MTK_WED_EXT_INT_MASK1); ++ wed_r32(dev, MTK_WED_EXT_INT_MASK2); ++ ++ if (mtk_wed_rro_cfg(dev)) ++ return; ++ ++ mtk_wed_set_512_support(dev, dev->wlan.wcid_512); + } + + mtk_wed_dma_enable(dev); +@@ -863,7 +1331,7 @@ mtk_wed_attach(struct mtk_wed_device *de + if (!hw) { + module_put(THIS_MODULE); + ret = -ENODEV; +- goto out; ++ goto unlock; + } + + device = dev->wlan.bus_type == MTK_WED_BUS_PCIE +@@ -876,15 +1344,24 @@ mtk_wed_attach(struct mtk_wed_device *de + dev->dev = hw->dev; + dev->irq = hw->irq; + dev->wdma_idx = hw->index; ++ dev->version = hw->version; + + if (hw->eth->dma_dev == hw->eth->dev && + of_dma_is_coherent(hw->eth->dev->of_node)) + mtk_eth_set_dma_device(hw->eth, hw->dev); + +- ret = mtk_wed_buffer_alloc(dev); +- if (ret) { +- mtk_wed_detach(dev); ++ ret = mtk_wed_tx_buffer_alloc(dev); ++ if (ret) + goto out; ++ ++ if (mtk_wed_get_rx_capa(dev)) { ++ ret = mtk_wed_rx_buffer_alloc(dev); ++ if (ret) ++ goto out; ++ ++ ret = mtk_wed_rro_alloc(dev); ++ if (ret) ++ goto out; + } + + mtk_wed_hw_init_early(dev); +@@ -893,8 +1370,10 @@ mtk_wed_attach(struct mtk_wed_device *de + BIT(hw->index), 0); + else + ret = mtk_wed_wo_init(hw); +- + out: ++ if (ret) ++ mtk_wed_detach(dev); ++unlock: + mutex_unlock(&hw_lock); + + return ret; +@@ -917,10 +1396,11 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + * WDMA RX. + */ + +- BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); ++ if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring))) ++ return -EINVAL; + + if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, +- sizeof(*ring->desc))) ++ sizeof(*ring->desc), true)) + return -ENOMEM; + + if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) +@@ -967,6 +1447,37 @@ mtk_wed_txfree_ring_setup(struct mtk_wed + return 0; + } + ++static int ++mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs) ++{ ++ struct mtk_wed_ring *ring = &dev->rx_ring[idx]; ++ ++ if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring))) ++ return -EINVAL; ++ ++ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE, ++ sizeof(*ring->desc), false)) ++ return -ENOMEM; ++ ++ if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) ++ return -ENOMEM; ++ ++ ring->reg_base = MTK_WED_RING_RX_DATA(idx); ++ ring->wpdma = regs; ++ ring->flags |= MTK_WED_RING_CONFIGURED; ++ ++ /* WPDMA -> WED */ ++ wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys); ++ wpdma_rx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_RX_RING_SIZE); ++ ++ wed_w32(dev, MTK_WED_WPDMA_RING_RX_DATA(idx) + MTK_WED_RING_OFS_BASE, ++ ring->desc_phys); ++ wed_w32(dev, MTK_WED_WPDMA_RING_RX_DATA(idx) + MTK_WED_RING_OFS_COUNT, ++ MTK_WED_RX_RING_SIZE); ++ ++ return 0; ++} ++ + static u32 + mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) + { +@@ -1063,7 +1574,9 @@ void mtk_wed_add_hw(struct device_node * + static const struct mtk_wed_ops wed_ops = { + .attach = mtk_wed_attach, + .tx_ring_setup = mtk_wed_tx_ring_setup, ++ .rx_ring_setup = mtk_wed_rx_ring_setup, + .txfree_ring_setup = mtk_wed_txfree_ring_setup, ++ .msg_update = mtk_wed_mcu_msg_update, + .start = mtk_wed_start, + .stop = mtk_wed_stop, + .reset_dma = mtk_wed_reset_dma, +@@ -1072,6 +1585,7 @@ void mtk_wed_add_hw(struct device_node * + .irq_get = mtk_wed_irq_get, + .irq_set_mask = mtk_wed_irq_set_mask, + .detach = mtk_wed_detach, ++ .ppe_check = mtk_wed_ppe_check, + }; + struct device_node *eth_np = eth->dev->of_node; + struct platform_device *pdev; +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -87,6 +87,24 @@ wpdma_tx_w32(struct mtk_wed_device *dev, + } + + static inline u32 ++wpdma_rx_r32(struct mtk_wed_device *dev, int ring, u32 reg) ++{ ++ if (!dev->rx_ring[ring].wpdma) ++ return 0; ++ ++ return readl(dev->rx_ring[ring].wpdma + reg); ++} ++ ++static inline void ++wpdma_rx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val) ++{ ++ if (!dev->rx_ring[ring].wpdma) ++ return; ++ ++ writel(val, dev->rx_ring[ring].wpdma + reg); ++} ++ ++static inline u32 + wpdma_txfree_r32(struct mtk_wed_device *dev, u32 reg) + { + if (!dev->txfree_ring.wpdma) +@@ -128,6 +146,7 @@ static inline int mtk_wed_flow_add(int i + static inline void mtk_wed_flow_remove(int index) + { + } ++ + #endif + + #ifdef CONFIG_DEBUG_FS +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #include "mtk_wed_regs.h" + #include "mtk_wed_wo.h" +@@ -60,24 +61,37 @@ void mtk_wed_mcu_rx_event(struct mtk_wed + wake_up(&wo->mcu.wait); + } + ++static void ++mtk_wed_update_rx_stats(struct mtk_wed_device *wed, struct sk_buff *skb) ++{ ++ u32 count = get_unaligned_le32(skb->data); ++ struct mtk_wed_wo_rx_stats *stats; ++ int i; ++ ++ if (count * sizeof(*stats) > skb->len - sizeof(u32)) ++ return; ++ ++ stats = (struct mtk_wed_wo_rx_stats *)(skb->data + sizeof(u32)); ++ for (i = 0 ; i < count ; i++) ++ wed->wlan.update_wo_rx_stats(wed, &stats[i]); ++} ++ + void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo, + struct sk_buff *skb) + { + struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data; + +- switch (hdr->cmd) { +- case MTK_WED_WO_EVT_LOG_DUMP: { +- const char *msg = (const char *)(skb->data + sizeof(*hdr)); ++ skb_pull(skb, sizeof(*hdr)); + +- dev_notice(wo->hw->dev, "%s\n", msg); ++ switch (hdr->cmd) { ++ case MTK_WED_WO_EVT_LOG_DUMP: ++ dev_notice(wo->hw->dev, "%s\n", skb->data); + break; +- } + case MTK_WED_WO_EVT_PROFILING: { +- struct mtk_wed_wo_log_info *info; +- u32 count = (skb->len - sizeof(*hdr)) / sizeof(*info); ++ struct mtk_wed_wo_log_info *info = (void *)skb->data; ++ u32 count = skb->len / sizeof(*info); + int i; + +- info = (struct mtk_wed_wo_log_info *)(skb->data + sizeof(*hdr)); + for (i = 0 ; i < count ; i++) + dev_notice(wo->hw->dev, + "SN:%u latency: total=%u, rro:%u, mod:%u\n", +@@ -88,6 +102,7 @@ void mtk_wed_mcu_rx_unsolicited_event(st + break; + } + case MTK_WED_WO_EVT_RXCNT_INFO: ++ mtk_wed_update_rx_stats(wo->hw->wed_dev, skb); + break; + default: + break; +@@ -144,6 +159,8 @@ mtk_wed_mcu_parse_response(struct mtk_we + skb_pull(skb, sizeof(*hdr)); + switch (cmd) { + case MTK_WED_WO_CMD_RXCNT_INFO: ++ mtk_wed_update_rx_stats(wo->hw->wed_dev, skb); ++ break; + default: + break; + } +@@ -182,6 +199,18 @@ unlock: + return ret; + } + ++int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, ++ int len) ++{ ++ struct mtk_wed_wo *wo = dev->hw->wed_wo; ++ ++ if (dev->hw->version == 1) ++ return 0; ++ ++ return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, id, data, len, ++ true); ++} ++ + static int + mtk_wed_get_memory_region(struct mtk_wed_wo *wo, + struct mtk_wed_wo_memory_region *region) +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -4,6 +4,7 @@ + #ifndef __MTK_WED_REGS_H + #define __MTK_WED_REGS_H + ++#define MTK_WFDMA_DESC_CTRL_TO_HOST BIT(8) + #define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0) + #define MTK_WDMA_DESC_CTRL_LEN1_V2 GENMASK(13, 0) + #define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15) +@@ -28,6 +29,8 @@ struct mtk_wdma_desc { + #define MTK_WED_RESET_WED_TX_DMA BIT(12) + #define MTK_WED_RESET_WDMA_RX_DRV BIT(17) + #define MTK_WED_RESET_WDMA_INT_AGENT BIT(19) ++#define MTK_WED_RESET_RX_RRO_QM BIT(20) ++#define MTK_WED_RESET_RX_ROUTE_QM BIT(21) + #define MTK_WED_RESET_WED BIT(31) + + #define MTK_WED_CTRL 0x00c +@@ -39,8 +42,12 @@ struct mtk_wdma_desc { + #define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9) + #define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10) + #define MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY BIT(11) +-#define MTK_WED_CTRL_RESERVE_EN BIT(12) +-#define MTK_WED_CTRL_RESERVE_BUSY BIT(13) ++#define MTK_WED_CTRL_WED_RX_BM_EN BIT(12) ++#define MTK_WED_CTRL_WED_RX_BM_BUSY BIT(13) ++#define MTK_WED_CTRL_RX_RRO_QM_EN BIT(14) ++#define MTK_WED_CTRL_RX_RRO_QM_BUSY BIT(15) ++#define MTK_WED_CTRL_RX_ROUTE_QM_EN BIT(16) ++#define MTK_WED_CTRL_RX_ROUTE_QM_BUSY BIT(17) + #define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24) + #define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25) + #define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28) +@@ -62,6 +69,9 @@ struct mtk_wdma_desc { + #define MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR BIT(22) + #define MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR BIT(23) + #define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24) ++#define MTK_WED_EXT_INT_STATUS_RX_DRV_GET_BM_DMAD_SKIP BIT(25) ++#define MTK_WED_EXT_INT_STATUS_WPDMA_RX_D_DRV_ERR BIT(26) ++#define MTK_WED_EXT_INT_STATUS_WPDMA_MID_RDY BIT(27) + #define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ + MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ + MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \ +@@ -71,6 +81,8 @@ struct mtk_wdma_desc { + MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR) + + #define MTK_WED_EXT_INT_MASK 0x028 ++#define MTK_WED_EXT_INT_MASK1 0x02c ++#define MTK_WED_EXT_INT_MASK2 0x030 + + #define MTK_WED_STATUS 0x060 + #define MTK_WED_STATUS_TX GENMASK(15, 8) +@@ -151,6 +163,7 @@ struct mtk_wdma_desc { + #define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10) + + #define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10) ++#define MTK_WED_RING_RX_DATA(_n) (0x420 + (_n) * 0x10) + + #define MTK_WED_SCR0 0x3c0 + #define MTK_WED_WPDMA_INT_TRIGGER 0x504 +@@ -213,6 +226,12 @@ struct mtk_wdma_desc { + #define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG GENMASK(14, 10) + + #define MTK_WED_WPDMA_INT_CTRL_RX 0x534 ++#define MTK_WED_WPDMA_INT_CTRL_RX0_EN BIT(0) ++#define MTK_WED_WPDMA_INT_CTRL_RX0_CLR BIT(1) ++#define MTK_WED_WPDMA_INT_CTRL_RX0_DONE_TRIG GENMASK(6, 2) ++#define MTK_WED_WPDMA_INT_CTRL_RX1_EN BIT(8) ++#define MTK_WED_WPDMA_INT_CTRL_RX1_CLR BIT(9) ++#define MTK_WED_WPDMA_INT_CTRL_RX1_DONE_TRIG GENMASK(14, 10) + + #define MTK_WED_WPDMA_INT_CTRL_TX_FREE 0x538 + #define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN BIT(0) +@@ -242,11 +261,34 @@ struct mtk_wdma_desc { + + #define MTK_WED_WPDMA_RING_TX(_n) (0x600 + (_n) * 0x10) + #define MTK_WED_WPDMA_RING_RX(_n) (0x700 + (_n) * 0x10) ++#define MTK_WED_WPDMA_RING_RX_DATA(_n) (0x730 + (_n) * 0x10) ++ ++#define MTK_WED_WPDMA_RX_D_GLO_CFG 0x75c ++#define MTK_WED_WPDMA_RX_D_RX_DRV_EN BIT(0) ++#define MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL GENMASK(11, 7) ++#define MTK_WED_WPDMA_RX_D_RXD_READ_LEN GENMASK(31, 24) ++ ++#define MTK_WED_WPDMA_RX_D_RST_IDX 0x760 ++#define MTK_WED_WPDMA_RX_D_RST_CRX_IDX GENMASK(17, 16) ++#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24) ++ ++#define MTK_WED_WPDMA_RX_GLO_CFG 0x76c ++#define MTK_WED_WPDMA_RX_RING 0x770 ++ ++#define MTK_WED_WPDMA_RX_D_MIB(_n) (0x774 + (_n) * 4) ++#define MTK_WED_WPDMA_RX_D_PROCESSED_MIB(_n) (0x784 + (_n) * 4) ++#define MTK_WED_WPDMA_RX_D_COHERENT_MIB 0x78c ++ ++#define MTK_WED_WDMA_RING_TX 0x800 ++ ++#define MTK_WED_WDMA_TX_MIB 0x810 ++ + #define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10) + #define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4) + + #define MTK_WED_WDMA_GLO_CFG 0xa04 + #define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0) ++#define MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK BIT(1) + #define MTK_WED_WDMA_GLO_CFG_RX_DRV_EN BIT(2) + #define MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY BIT(3) + #define MTK_WED_WDMA_GLO_CFG_BT_SIZE GENMASK(5, 4) +@@ -291,6 +333,20 @@ struct mtk_wdma_desc { + #define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4) + #define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4) + ++#define MTK_WED_RX_BM_RX_DMAD 0xd80 ++#define MTK_WED_RX_BM_RX_DMAD_SDL0 GENMASK(13, 0) ++ ++#define MTK_WED_RX_BM_BASE 0xd84 ++#define MTK_WED_RX_BM_INIT_PTR 0xd88 ++#define MTK_WED_RX_BM_SW_TAIL GENMASK(15, 0) ++#define MTK_WED_RX_BM_INIT_SW_TAIL BIT(16) ++ ++#define MTK_WED_RX_PTR 0xd8c ++ ++#define MTK_WED_RX_BM_DYN_ALLOC_TH 0xdb4 ++#define MTK_WED_RX_BM_DYN_ALLOC_TH_H GENMASK(31, 16) ++#define MTK_WED_RX_BM_DYN_ALLOC_TH_L GENMASK(15, 0) ++ + #define MTK_WED_RING_OFS_BASE 0x00 + #define MTK_WED_RING_OFS_COUNT 0x04 + #define MTK_WED_RING_OFS_CPU_IDX 0x08 +@@ -301,7 +357,9 @@ struct mtk_wdma_desc { + + #define MTK_WDMA_GLO_CFG 0x204 + #define MTK_WDMA_GLO_CFG_TX_DMA_EN BIT(0) ++#define MTK_WDMA_GLO_CFG_TX_DMA_BUSY BIT(1) + #define MTK_WDMA_GLO_CFG_RX_DMA_EN BIT(2) ++#define MTK_WDMA_GLO_CFG_RX_DMA_BUSY BIT(3) + #define MTK_WDMA_GLO_CFG_RX_INFO3_PRERES BIT(26) + #define MTK_WDMA_GLO_CFG_RX_INFO2_PRERES BIT(27) + #define MTK_WDMA_GLO_CFG_RX_INFO1_PRERES BIT(28) +@@ -330,4 +388,70 @@ struct mtk_wdma_desc { + /* DMA channel mapping */ + #define HIFSYS_DMA_AG_MAP 0x008 + ++#define MTK_WED_RTQM_GLO_CFG 0xb00 ++#define MTK_WED_RTQM_BUSY BIT(1) ++#define MTK_WED_RTQM_Q_RST BIT(2) ++#define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5) ++#define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20) ++ ++#define MTK_WED_RTQM_R2H_MIB(_n) (0xb70 + (_n) * 0x4) ++#define MTK_WED_RTQM_R2Q_MIB(_n) (0xb78 + (_n) * 0x4) ++#define MTK_WED_RTQM_Q2N_MIB 0xb80 ++#define MTK_WED_RTQM_Q2H_MIB(_n) (0xb84 + (_n) * 0x4) ++ ++#define MTK_WED_RTQM_Q2B_MIB 0xb8c ++#define MTK_WED_RTQM_PFDBK_MIB 0xb90 ++ ++#define MTK_WED_RROQM_GLO_CFG 0xc04 ++#define MTK_WED_RROQM_RST_IDX 0xc08 ++#define MTK_WED_RROQM_RST_IDX_MIOD BIT(0) ++#define MTK_WED_RROQM_RST_IDX_FDBK BIT(4) ++ ++#define MTK_WED_RROQM_MIOD_CTRL0 0xc40 ++#define MTK_WED_RROQM_MIOD_CTRL1 0xc44 ++#define MTK_WED_RROQM_MIOD_CNT GENMASK(11, 0) ++ ++#define MTK_WED_RROQM_MIOD_CTRL2 0xc48 ++#define MTK_WED_RROQM_MIOD_CTRL3 0xc4c ++ ++#define MTK_WED_RROQM_FDBK_CTRL0 0xc50 ++#define MTK_WED_RROQM_FDBK_CTRL1 0xc54 ++#define MTK_WED_RROQM_FDBK_CNT GENMASK(11, 0) ++ ++#define MTK_WED_RROQM_FDBK_CTRL2 0xc58 ++ ++#define MTK_WED_RROQ_BASE_L 0xc80 ++#define MTK_WED_RROQ_BASE_H 0xc84 ++ ++#define MTK_WED_RROQM_MIOD_CFG 0xc8c ++#define MTK_WED_RROQM_MIOD_MID_DW GENMASK(5, 0) ++#define MTK_WED_RROQM_MIOD_MOD_DW GENMASK(13, 8) ++#define MTK_WED_RROQM_MIOD_ENTRY_DW GENMASK(22, 16) ++ ++#define MTK_WED_RROQM_MID_MIB 0xcc0 ++#define MTK_WED_RROQM_MOD_MIB 0xcc4 ++#define MTK_WED_RROQM_MOD_COHERENT_MIB 0xcc8 ++#define MTK_WED_RROQM_FDBK_MIB 0xcd0 ++#define MTK_WED_RROQM_FDBK_COHERENT_MIB 0xcd4 ++#define MTK_WED_RROQM_FDBK_IND_MIB 0xce0 ++#define MTK_WED_RROQM_FDBK_ENQ_MIB 0xce4 ++#define MTK_WED_RROQM_FDBK_ANC_MIB 0xce8 ++#define MTK_WED_RROQM_FDBK_ANC2H_MIB 0xcec ++ ++#define MTK_WED_RX_BM_RX_DMAD 0xd80 ++#define MTK_WED_RX_BM_BASE 0xd84 ++#define MTK_WED_RX_BM_INIT_PTR 0xd88 ++#define MTK_WED_RX_BM_PTR 0xd8c ++#define MTK_WED_RX_BM_PTR_HEAD GENMASK(32, 16) ++#define MTK_WED_RX_BM_PTR_TAIL GENMASK(15, 0) ++ ++#define MTK_WED_RX_BM_BLEN 0xd90 ++#define MTK_WED_RX_BM_STS 0xd94 ++#define MTK_WED_RX_BM_INTF2 0xd98 ++#define MTK_WED_RX_BM_INTF 0xd9c ++#define MTK_WED_RX_BM_ERR_STS 0xda8 ++ ++#define MTK_WED_WOCPU_VIEW_MIOD_BASE 0x8000 ++#define MTK_WED_PCIE_INT_MASK 0x0 ++ + #endif +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -49,6 +49,10 @@ enum { + MTK_WED_WARP_CMD_FLAG_FROM_TO_WO = BIT(2), + }; + ++#define MTK_WED_WO_CPU_MCUSYS_RESET_ADDR 0x15194050 ++#define MTK_WED_WO_CPU_WO0_MCUSYS_RESET_MASK 0x20 ++#define MTK_WED_WO_CPU_WO1_MCUSYS_RESET_MASK 0x1 ++ + enum { + MTK_WED_WO_REGION_EMI, + MTK_WED_WO_REGION_ILM, +@@ -57,6 +61,28 @@ enum { + __MTK_WED_WO_REGION_MAX, + }; + ++enum mtk_wed_wo_state { ++ MTK_WED_WO_STATE_UNDEFINED, ++ MTK_WED_WO_STATE_INIT, ++ MTK_WED_WO_STATE_ENABLE, ++ MTK_WED_WO_STATE_DISABLE, ++ MTK_WED_WO_STATE_HALT, ++ MTK_WED_WO_STATE_GATING, ++ MTK_WED_WO_STATE_SER_RESET, ++ MTK_WED_WO_STATE_WF_RESET, ++}; ++ ++enum mtk_wed_wo_done_state { ++ MTK_WED_WOIF_UNDEFINED, ++ MTK_WED_WOIF_DISABLE_DONE, ++ MTK_WED_WOIF_TRIGGER_ENABLE, ++ MTK_WED_WOIF_ENABLE_DONE, ++ MTK_WED_WOIF_TRIGGER_GATING, ++ MTK_WED_WOIF_GATING_DONE, ++ MTK_WED_WOIF_TRIGGER_HALT, ++ MTK_WED_WOIF_HALT_DONE, ++}; ++ + enum mtk_wed_dummy_cr_idx { + MTK_WED_DUMMY_CR_FWDL, + MTK_WED_DUMMY_CR_WO_STATUS, +@@ -245,6 +271,8 @@ void mtk_wed_mcu_rx_unsolicited_event(st + struct sk_buff *skb); + int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd, + const void *data, int len, bool wait_resp); ++int mtk_wed_mcu_msg_update(struct mtk_wed_device *dev, int id, void *data, ++ int len); + int mtk_wed_mcu_init(struct mtk_wed_wo *wo); + int mtk_wed_wo_init(struct mtk_wed_hw *hw); + void mtk_wed_wo_deinit(struct mtk_wed_hw *hw); +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -5,10 +5,13 @@ + #include + #include + #include ++#include + + #define MTK_WED_TX_QUEUES 2 + #define MTK_WED_RX_QUEUES 2 + ++#define WED_WO_STA_REC 0x6 ++ + struct mtk_wed_hw; + struct mtk_wdma_desc; + +@@ -41,21 +44,37 @@ enum mtk_wed_wo_cmd { + MTK_WED_WO_CMD_WED_END + }; + ++struct mtk_rxbm_desc { ++ __le32 buf0; ++ __le32 token; ++} __packed __aligned(4); ++ + enum mtk_wed_bus_tye { + MTK_WED_BUS_PCIE, + MTK_WED_BUS_AXI, + }; + ++#define MTK_WED_RING_CONFIGURED BIT(0) + struct mtk_wed_ring { + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; + u32 desc_size; + int size; ++ u32 flags; + + u32 reg_base; + void __iomem *wpdma; + }; + ++struct mtk_wed_wo_rx_stats { ++ __le16 wlan_idx; ++ __le16 tid; ++ __le32 rx_pkt_cnt; ++ __le32 rx_byte_cnt; ++ __le32 rx_err_cnt; ++ __le32 rx_drop_cnt; ++}; ++ + struct mtk_wed_device { + #ifdef CONFIG_NET_MEDIATEK_SOC_WED + const struct mtk_wed_ops *ops; +@@ -64,9 +83,12 @@ struct mtk_wed_device { + bool init_done, running; + int wdma_idx; + int irq; ++ u8 version; + + struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES]; ++ struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES]; + struct mtk_wed_ring txfree_ring; ++ struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES]; + struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES]; + + struct { +@@ -74,7 +96,20 @@ struct mtk_wed_device { + void **pages; + struct mtk_wdma_desc *desc; + dma_addr_t desc_phys; +- } buf_ring; ++ } tx_buf_ring; ++ ++ struct { ++ int size; ++ struct page_frag_cache rx_page; ++ struct mtk_rxbm_desc *desc; ++ dma_addr_t desc_phys; ++ } rx_buf_ring; ++ ++ struct { ++ struct mtk_wed_ring ring; ++ dma_addr_t miod_phys; ++ dma_addr_t fdbk_phys; ++ } rro; + + /* filled by driver: */ + struct { +@@ -83,22 +118,36 @@ struct mtk_wed_device { + struct pci_dev *pci_dev; + }; + enum mtk_wed_bus_tye bus_type; ++ void __iomem *base; ++ u32 phy_base; + + u32 wpdma_phys; + u32 wpdma_int; + u32 wpdma_mask; + u32 wpdma_tx; + u32 wpdma_txfree; ++ u32 wpdma_rx_glo; ++ u32 wpdma_rx; ++ ++ bool wcid_512; + + u16 token_start; + unsigned int nbuf; ++ unsigned int rx_nbuf; ++ unsigned int rx_npkt; ++ unsigned int rx_size; + + u8 tx_tbit[MTK_WED_TX_QUEUES]; ++ u8 rx_tbit[MTK_WED_RX_QUEUES]; + u8 txfree_tbit; + + u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); + int (*offload_enable)(struct mtk_wed_device *wed); + void (*offload_disable)(struct mtk_wed_device *wed); ++ u32 (*init_rx_buf)(struct mtk_wed_device *wed, int size); ++ void (*release_rx_buf)(struct mtk_wed_device *wed); ++ void (*update_wo_rx_stats)(struct mtk_wed_device *wed, ++ struct mtk_wed_wo_rx_stats *stats); + } wlan; + #endif + }; +@@ -107,9 +156,15 @@ struct mtk_wed_ops { + int (*attach)(struct mtk_wed_device *dev); + int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring, + void __iomem *regs); ++ int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring, ++ void __iomem *regs); + int (*txfree_ring_setup)(struct mtk_wed_device *dev, + void __iomem *regs); ++ int (*msg_update)(struct mtk_wed_device *dev, int cmd_id, ++ void *data, int len); + void (*detach)(struct mtk_wed_device *dev); ++ void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb, ++ u32 reason, u32 hash); + + void (*stop)(struct mtk_wed_device *dev); + void (*start)(struct mtk_wed_device *dev, u32 irq_mask); +@@ -144,6 +199,16 @@ mtk_wed_device_attach(struct mtk_wed_dev + return ret; + } + ++static inline bool ++mtk_wed_get_rx_capa(struct mtk_wed_device *dev) ++{ ++#ifdef CONFIG_NET_MEDIATEK_SOC_WED ++ return dev->version != 1; ++#else ++ return false; ++#endif ++} ++ + #ifdef CONFIG_NET_MEDIATEK_SOC_WED + #define mtk_wed_device_active(_dev) !!(_dev)->ops + #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev) +@@ -160,6 +225,12 @@ mtk_wed_device_attach(struct mtk_wed_dev + (_dev)->ops->irq_get(_dev, _mask) + #define mtk_wed_device_irq_set_mask(_dev, _mask) \ + (_dev)->ops->irq_set_mask(_dev, _mask) ++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \ ++ (_dev)->ops->rx_ring_setup(_dev, _ring, _regs) ++#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \ ++ (_dev)->ops->ppe_check(_dev, _skb, _reason, _hash) ++#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \ ++ (_dev)->ops->msg_update(_dev, _id, _msg, _len) + #else + static inline bool mtk_wed_device_active(struct mtk_wed_device *dev) + { +@@ -173,6 +244,9 @@ static inline bool mtk_wed_device_active + #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0) + #define mtk_wed_device_irq_get(_dev, _mask) 0 + #define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0) ++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV ++#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) do {} while (0) ++#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV + #endif + + #endif diff --git a/target/linux/generic/backport-6.1/729-05-v6.1-net-ethernet-mtk_wed-add-rx-mib-counters.patch b/target/linux/generic/backport-6.1/729-05-v6.1-net-ethernet-mtk_wed-add-rx-mib-counters.patch new file mode 100644 index 00000000000..bb1066decea --- /dev/null +++ b/target/linux/generic/backport-6.1/729-05-v6.1-net-ethernet-mtk_wed-add-rx-mib-counters.patch @@ -0,0 +1,149 @@ +From: Lorenzo Bianconi +Date: Sat, 5 Nov 2022 23:36:22 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add rx mib counters + +Introduce WED RX MIB counters support available on MT7986a SoC. + +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c +@@ -2,6 +2,7 @@ + /* Copyright (C) 2021 Felix Fietkau */ + + #include ++#include + #include "mtk_wed.h" + #include "mtk_wed_regs.h" + +@@ -18,6 +19,8 @@ enum { + DUMP_TYPE_WDMA, + DUMP_TYPE_WPDMA_TX, + DUMP_TYPE_WPDMA_TXFREE, ++ DUMP_TYPE_WPDMA_RX, ++ DUMP_TYPE_WED_RRO, + }; + + #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING } +@@ -36,6 +39,9 @@ enum { + + #define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n) + #define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE) ++#define DUMP_WPDMA_RX_RING(_n) DUMP_RING("WPDMA_RX" #_n, 0, DUMP_TYPE_WPDMA_RX, _n) ++#define DUMP_WED_RRO_RING(_base)DUMP_RING("WED_RRO_MIOD", MTK_##_base, DUMP_TYPE_WED_RRO) ++#define DUMP_WED_RRO_FDBK(_base)DUMP_RING("WED_RRO_FDBK", MTK_##_base, DUMP_TYPE_WED_RRO) + + static void + print_reg_val(struct seq_file *s, const char *name, u32 val) +@@ -57,6 +63,7 @@ dump_wed_regs(struct seq_file *s, struct + cur > regs ? "\n" : "", + cur->name); + continue; ++ case DUMP_TYPE_WED_RRO: + case DUMP_TYPE_WED: + val = wed_r32(dev, cur->offset); + break; +@@ -69,6 +76,9 @@ dump_wed_regs(struct seq_file *s, struct + case DUMP_TYPE_WPDMA_TXFREE: + val = wpdma_txfree_r32(dev, cur->offset); + break; ++ case DUMP_TYPE_WPDMA_RX: ++ val = wpdma_rx_r32(dev, cur->base, cur->offset); ++ break; + } + print_reg_val(s, cur->name, val); + } +@@ -132,6 +142,80 @@ wed_txinfo_show(struct seq_file *s, void + } + DEFINE_SHOW_ATTRIBUTE(wed_txinfo); + ++static int ++wed_rxinfo_show(struct seq_file *s, void *data) ++{ ++ static const struct reg_dump regs[] = { ++ DUMP_STR("WPDMA RX"), ++ DUMP_WPDMA_RX_RING(0), ++ DUMP_WPDMA_RX_RING(1), ++ ++ DUMP_STR("WPDMA RX"), ++ DUMP_WED(WED_WPDMA_RX_D_MIB(0)), ++ DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(0)), ++ DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(0)), ++ DUMP_WED(WED_WPDMA_RX_D_MIB(1)), ++ DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(1)), ++ DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(1)), ++ DUMP_WED(WED_WPDMA_RX_D_COHERENT_MIB), ++ ++ DUMP_STR("WED RX"), ++ DUMP_WED_RING(WED_RING_RX_DATA(0)), ++ DUMP_WED_RING(WED_RING_RX_DATA(1)), ++ ++ DUMP_STR("WED RRO"), ++ DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0), ++ DUMP_WED(WED_RROQM_MID_MIB), ++ DUMP_WED(WED_RROQM_MOD_MIB), ++ DUMP_WED(WED_RROQM_MOD_COHERENT_MIB), ++ DUMP_WED_RRO_FDBK(WED_RROQM_FDBK_CTRL0), ++ DUMP_WED(WED_RROQM_FDBK_IND_MIB), ++ DUMP_WED(WED_RROQM_FDBK_ENQ_MIB), ++ DUMP_WED(WED_RROQM_FDBK_ANC_MIB), ++ DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB), ++ ++ DUMP_STR("WED Route QM"), ++ DUMP_WED(WED_RTQM_R2H_MIB(0)), ++ DUMP_WED(WED_RTQM_R2Q_MIB(0)), ++ DUMP_WED(WED_RTQM_Q2H_MIB(0)), ++ DUMP_WED(WED_RTQM_R2H_MIB(1)), ++ DUMP_WED(WED_RTQM_R2Q_MIB(1)), ++ DUMP_WED(WED_RTQM_Q2H_MIB(1)), ++ DUMP_WED(WED_RTQM_Q2N_MIB), ++ DUMP_WED(WED_RTQM_Q2B_MIB), ++ DUMP_WED(WED_RTQM_PFDBK_MIB), ++ ++ DUMP_STR("WED WDMA TX"), ++ DUMP_WED(WED_WDMA_TX_MIB), ++ DUMP_WED_RING(WED_WDMA_RING_TX), ++ ++ DUMP_STR("WDMA TX"), ++ DUMP_WDMA(WDMA_GLO_CFG), ++ DUMP_WDMA_RING(WDMA_RING_TX(0)), ++ DUMP_WDMA_RING(WDMA_RING_TX(1)), ++ ++ DUMP_STR("WED RX BM"), ++ DUMP_WED(WED_RX_BM_BASE), ++ DUMP_WED(WED_RX_BM_RX_DMAD), ++ DUMP_WED(WED_RX_BM_PTR), ++ DUMP_WED(WED_RX_BM_TKID_MIB), ++ DUMP_WED(WED_RX_BM_BLEN), ++ DUMP_WED(WED_RX_BM_STS), ++ DUMP_WED(WED_RX_BM_INTF2), ++ DUMP_WED(WED_RX_BM_INTF), ++ DUMP_WED(WED_RX_BM_ERR_STS), ++ }; ++ struct mtk_wed_hw *hw = s->private; ++ struct mtk_wed_device *dev = hw->wed_dev; ++ ++ if (!dev) ++ return 0; ++ ++ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs)); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(wed_rxinfo); + + static int + mtk_wed_reg_set(void *data, u64 val) +@@ -175,4 +259,7 @@ void mtk_wed_hw_add_debugfs(struct mtk_w + debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg); + debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval); + debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops); ++ if (hw->version != 1) ++ debugfs_create_file_unsafe("rxinfo", 0400, dir, hw, ++ &wed_rxinfo_fops); + } diff --git a/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch b/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch new file mode 100644 index 00000000000..003ca9bae69 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch @@ -0,0 +1,98 @@ +From: Lorenzo Bianconi +Date: Thu, 17 Nov 2022 00:35:04 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: do not overwrite mtu + configuration running reset routine + +Restore user configured MTU running mtk_hw_init() during tx timeout routine +since it will be overwritten after a hw reset. + +Reported-by: Felix Fietkau +Fixes: 9ea4d311509f ("net: ethernet: mediatek: add the whole ethernet reset into the reset process") +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3176,6 +3176,30 @@ static void mtk_dim_tx(struct work_struc + dim->state = DIM_START_MEASURE; + } + ++static void mtk_set_mcr_max_rx(struct mtk_mac *mac, u32 val) ++{ ++ struct mtk_eth *eth = mac->hw; ++ u32 mcr_cur, mcr_new; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ return; ++ ++ mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); ++ mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; ++ ++ if (val <= 1518) ++ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1518); ++ else if (val <= 1536) ++ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1536); ++ else if (val <= 1552) ++ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1552); ++ else ++ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_2048); ++ ++ if (mcr_new != mcr_cur) ++ mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); ++} ++ + static int mtk_hw_init(struct mtk_eth *eth) + { + u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | +@@ -3250,8 +3274,16 @@ static int mtk_hw_init(struct mtk_eth *e + * up with the more appropriate value when mtk_mac_config call is being + * invoked. + */ +- for (i = 0; i < MTK_MAC_COUNT; i++) ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ struct net_device *dev = eth->netdev[i]; ++ + mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i)); ++ if (dev) { ++ struct mtk_mac *mac = netdev_priv(dev); ++ ++ mtk_set_mcr_max_rx(mac, dev->mtu + MTK_RX_ETH_HLEN); ++ } ++ } + + /* Indicates CDM to parse the MTK special tag from CPU + * which also is working out for untag packets. +@@ -3367,7 +3399,6 @@ static int mtk_change_mtu(struct net_dev + int length = new_mtu + MTK_RX_ETH_HLEN; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; +- u32 mcr_cur, mcr_new; + + if (rcu_access_pointer(eth->prog) && + length > MTK_PP_MAX_BUF_SIZE) { +@@ -3375,23 +3406,7 @@ static int mtk_change_mtu(struct net_dev + return -EINVAL; + } + +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { +- mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); +- mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; +- +- if (length <= 1518) +- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1518); +- else if (length <= 1536) +- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1536); +- else if (length <= 1552) +- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1552); +- else +- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_2048); +- +- if (mcr_new != mcr_cur) +- mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); +- } +- ++ mtk_set_mcr_max_rx(mac, length); + dev->mtu = new_mtu; + + return 0; diff --git a/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch b/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch new file mode 100644 index 00000000000..342ffb99d2f --- /dev/null +++ b/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch @@ -0,0 +1,36 @@ +From: Lorenzo Bianconi +Date: Thu, 17 Nov 2022 00:58:46 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: remove cpu_relax in + mtk_pending_work + +Get rid of cpu_relax in mtk_pending_work routine since MTK_RESETTING is +set only in mtk_pending_work() and it runs holding rtnl lock + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3437,11 +3437,8 @@ static void mtk_pending_work(struct work + rtnl_lock(); + + dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); ++ set_bit(MTK_RESETTING, ð->state); + +- while (test_and_set_bit_lock(MTK_RESETTING, ð->state)) +- cpu_relax(); +- +- dev_dbg(eth->dev, "[%s][%d] mtk_stop starts\n", __func__, __LINE__); + /* stop all devices to make sure that dma is properly shut down */ + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->netdev[i]) +@@ -3475,7 +3472,7 @@ static void mtk_pending_work(struct work + + dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); + +- clear_bit_unlock(MTK_RESETTING, ð->state); ++ clear_bit(MTK_RESETTING, ð->state); + + rtnl_unlock(); + } diff --git a/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch b/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch new file mode 100644 index 00000000000..12aa3ebf6a7 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch @@ -0,0 +1,63 @@ +From: Lorenzo Bianconi +Date: Thu, 17 Nov 2022 15:29:53 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions + +Fix RSTCTRL_PPE0 and RSTCTRL_PPE1 register mask definitions for +MTK_NETSYS_V2. +Remove duplicated definitions. + +Fixes: 160d3a9b1929 ("net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support") +Signed-off-by: Lorenzo Bianconi +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3239,16 +3239,17 @@ static int mtk_hw_init(struct mtk_eth *e + return 0; + } + +- val = RSTCTRL_FE | RSTCTRL_PPE; + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); +- +- val |= RSTCTRL_ETH; +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) +- val |= RSTCTRL_PPE1; ++ val = RSTCTRL_PPE0_V2; ++ } else { ++ val = RSTCTRL_PPE0; + } + +- ethsys_reset(eth, val); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ val |= RSTCTRL_PPE1; ++ ++ ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val); + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -445,18 +445,14 @@ + /* ethernet reset control register */ + #define ETHSYS_RSTCTRL 0x34 + #define RSTCTRL_FE BIT(6) +-#define RSTCTRL_PPE BIT(31) +-#define RSTCTRL_PPE1 BIT(30) ++#define RSTCTRL_PPE0 BIT(31) ++#define RSTCTRL_PPE0_V2 BIT(30) ++#define RSTCTRL_PPE1 BIT(31) + #define RSTCTRL_ETH BIT(23) + + /* ethernet reset check idle register */ + #define ETHSYS_FE_RST_CHK_IDLE_EN 0x28 + +-/* ethernet reset control register */ +-#define ETHSYS_RSTCTRL 0x34 +-#define RSTCTRL_FE BIT(6) +-#define RSTCTRL_PPE BIT(31) +- + /* ethernet dma channel agent map */ + #define ETHSYS_DMA_AG_MAP 0x408 + #define ETHSYS_DMA_AG_MAP_PDMA BIT(0) diff --git a/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch b/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch new file mode 100644 index 00000000000..d91d8299111 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch @@ -0,0 +1,80 @@ +From: Sujuan Chen +Date: Thu, 24 Nov 2022 11:18:14 +0800 +Subject: [PATCH] net: ethernet: mtk_wed: add wcid overwritten support for wed + v1 + +All wed versions should enable the wcid overwritten feature, +since the wcid size is controlled by the wlan driver. + +Tested-by: Sujuan Chen +Co-developed-by: Bo Jiao +Signed-off-by: Bo Jiao +Signed-off-by: Sujuan Chen +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -526,9 +526,9 @@ mtk_wed_dma_disable(struct mtk_wed_devic + MTK_WED_WPDMA_RX_D_RX_DRV_EN); + wed_clr(dev, MTK_WED_WDMA_GLO_CFG, + MTK_WED_WDMA_GLO_CFG_TX_DDONE_CHK); +- +- mtk_wed_set_512_support(dev, false); + } ++ ++ mtk_wed_set_512_support(dev, false); + } + + static void +@@ -1297,9 +1297,10 @@ mtk_wed_start(struct mtk_wed_device *dev + if (mtk_wed_rro_cfg(dev)) + return; + +- mtk_wed_set_512_support(dev, dev->wlan.wcid_512); + } + ++ mtk_wed_set_512_support(dev, dev->wlan.wcid_512); ++ + mtk_wed_dma_enable(dev); + dev->running = true; + } +@@ -1365,11 +1366,13 @@ mtk_wed_attach(struct mtk_wed_device *de + } + + mtk_wed_hw_init_early(dev); +- if (hw->version == 1) ++ if (hw->version == 1) { + regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, + BIT(hw->index), 0); +- else ++ } else { ++ dev->rev_id = wed_r32(dev, MTK_WED_REV_ID); + ret = mtk_wed_wo_init(hw); ++ } + out: + if (ret) + mtk_wed_detach(dev); +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -20,6 +20,8 @@ struct mtk_wdma_desc { + __le32 info; + } __packed __aligned(4); + ++#define MTK_WED_REV_ID 0x004 ++ + #define MTK_WED_RESET 0x008 + #define MTK_WED_RESET_TX_BM BIT(0) + #define MTK_WED_RESET_TX_FREE_AGENT BIT(4) +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -85,6 +85,9 @@ struct mtk_wed_device { + int irq; + u8 version; + ++ /* used by wlan driver */ ++ u32 rev_id; ++ + struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES]; + struct mtk_wed_ring rx_ring[MTK_WED_RX_QUEUES]; + struct mtk_wed_ring txfree_ring; diff --git a/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch b/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch new file mode 100644 index 00000000000..d97bb715e0f --- /dev/null +++ b/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch @@ -0,0 +1,85 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Nov 2022 16:22:51 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: return status value in + mtk_wdma_rx_reset + +Move MTK_WDMA_RESET_IDX configuration in mtk_wdma_rx_reset routine. +Increase poll timeout to 10ms in order to be aligned with vendor sdk. +This is a preliminary patch to add Wireless Ethernet Dispatcher reset +support. + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -101,17 +101,21 @@ mtk_wdma_read_reset(struct mtk_wed_devic + return wdma_r32(dev, MTK_WDMA_GLO_CFG); + } + +-static void ++static int + mtk_wdma_rx_reset(struct mtk_wed_device *dev) + { + u32 status, mask = MTK_WDMA_GLO_CFG_RX_DMA_BUSY; +- int i; ++ int i, ret; + + wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN); +- if (readx_poll_timeout(mtk_wdma_read_reset, dev, status, +- !(status & mask), 0, 1000)) ++ ret = readx_poll_timeout(mtk_wdma_read_reset, dev, status, ++ !(status & mask), 0, 10000); ++ if (ret) + dev_err(dev->hw->dev, "rx reset failed\n"); + ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); ++ + for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) { + if (dev->rx_wdma[i].desc) + continue; +@@ -119,6 +123,8 @@ mtk_wdma_rx_reset(struct mtk_wed_device + wdma_w32(dev, + MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0); + } ++ ++ return ret; + } + + static void +@@ -565,9 +571,7 @@ mtk_wed_detach(struct mtk_wed_device *de + + mtk_wed_stop(dev); + +- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); +- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); +- ++ mtk_wdma_rx_reset(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); + if (mtk_wed_get_rx_capa(dev)) { + wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN); +@@ -582,7 +586,6 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_wo_reset(dev); + mtk_wed_free_rx_rings(dev); + mtk_wed_wo_deinit(hw); +- mtk_wdma_rx_reset(dev); + } + + if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { +@@ -1006,11 +1009,7 @@ mtk_wed_reset_dma(struct mtk_wed_device + wed_w32(dev, MTK_WED_RESET_IDX, 0); + } + +- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); +- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); +- +- if (mtk_wed_get_rx_capa(dev)) +- mtk_wdma_rx_reset(dev); ++ mtk_wdma_rx_reset(dev); + + if (busy) { + mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); diff --git a/target/linux/generic/backport-6.1/729-11-v6.2-net-ethernet-mtk_wed-move-MTK_WDMA_RESET_IDX_TX-conf.patch b/target/linux/generic/backport-6.1/729-11-v6.2-net-ethernet-mtk_wed-move-MTK_WDMA_RESET_IDX_TX-conf.patch new file mode 100644 index 00000000000..10c1732c969 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-11-v6.2-net-ethernet-mtk_wed-move-MTK_WDMA_RESET_IDX_TX-conf.patch @@ -0,0 +1,52 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Nov 2022 16:22:52 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: move MTK_WDMA_RESET_IDX_TX + configuration in mtk_wdma_tx_reset + +Remove duplicated code. Increase poll timeout to 10ms in order to be +aligned with vendor sdk. +This is a preliminary patch to add Wireless Ethernet Dispatcher reset +support. + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -135,16 +135,15 @@ mtk_wdma_tx_reset(struct mtk_wed_device + + wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN); + if (readx_poll_timeout(mtk_wdma_read_reset, dev, status, +- !(status & mask), 0, 1000)) ++ !(status & mask), 0, 10000)) + dev_err(dev->hw->dev, "tx reset failed\n"); + +- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) { +- if (dev->tx_wdma[i].desc) +- continue; ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX); ++ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); + ++ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) + wdma_w32(dev, + MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0); +- } + } + + static void +@@ -573,12 +572,6 @@ mtk_wed_detach(struct mtk_wed_device *de + + mtk_wdma_rx_reset(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); +- if (mtk_wed_get_rx_capa(dev)) { +- wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN); +- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX); +- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); +- } +- + mtk_wed_free_tx_buffer(dev); + mtk_wed_free_tx_rings(dev); + diff --git a/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch b/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch new file mode 100644 index 00000000000..dfc0f8c3f38 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch @@ -0,0 +1,98 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Nov 2022 16:22:53 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: update mtk_wed_stop + +Update mtk_wed_stop routine and rename old mtk_wed_stop() to +mtk_wed_deinit(). This is a preliminary patch to add Wireless Ethernet +Dispatcher reset support. + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -539,14 +539,8 @@ mtk_wed_dma_disable(struct mtk_wed_devic + static void + mtk_wed_stop(struct mtk_wed_device *dev) + { +- mtk_wed_dma_disable(dev); + mtk_wed_set_ext_int(dev, false); + +- wed_clr(dev, MTK_WED_CTRL, +- MTK_WED_CTRL_WDMA_INT_AGENT_EN | +- MTK_WED_CTRL_WPDMA_INT_AGENT_EN | +- MTK_WED_CTRL_WED_TX_BM_EN | +- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); + wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0); + wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0); + wdma_w32(dev, MTK_WDMA_INT_MASK, 0); +@@ -558,7 +552,27 @@ mtk_wed_stop(struct mtk_wed_device *dev) + + wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0); + wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0); +- wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN); ++} ++ ++static void ++mtk_wed_deinit(struct mtk_wed_device *dev) ++{ ++ mtk_wed_stop(dev); ++ mtk_wed_dma_disable(dev); ++ ++ wed_clr(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WPDMA_INT_AGENT_EN | ++ MTK_WED_CTRL_WED_TX_BM_EN | ++ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ ++ if (dev->hw->version == 1) ++ return; ++ ++ wed_clr(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_RX_ROUTE_QM_EN | ++ MTK_WED_CTRL_WED_RX_BM_EN | ++ MTK_WED_CTRL_RX_RRO_QM_EN); + } + + static void +@@ -568,7 +582,7 @@ mtk_wed_detach(struct mtk_wed_device *de + + mutex_lock(&hw_lock); + +- mtk_wed_stop(dev); ++ mtk_wed_deinit(dev); + + mtk_wdma_rx_reset(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); +@@ -677,7 +691,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev + { + u32 mask, set; + +- mtk_wed_stop(dev); ++ mtk_wed_deinit(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); + mtk_wed_set_wpdma(dev); + +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -234,6 +234,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic + (_dev)->ops->ppe_check(_dev, _skb, _reason, _hash) + #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \ + (_dev)->ops->msg_update(_dev, _id, _msg, _len) ++#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev) ++#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev) + #else + static inline bool mtk_wed_device_active(struct mtk_wed_device *dev) + { +@@ -250,6 +252,8 @@ static inline bool mtk_wed_device_active + #define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV + #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) do {} while (0) + #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV ++#define mtk_wed_device_stop(_dev) do {} while (0) ++#define mtk_wed_device_dma_reset(_dev) do {} while (0) + #endif + + #endif diff --git a/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch b/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch new file mode 100644 index 00000000000..2205fea513d --- /dev/null +++ b/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch @@ -0,0 +1,309 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Nov 2022 16:22:54 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add mtk_wed_rx_reset routine + +Introduce mtk_wed_rx_reset routine in order to reset rx DMA for Wireless +Ethernet Dispatcher available on MT7986 SoC. + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -951,42 +951,130 @@ mtk_wed_ring_reset(struct mtk_wed_ring * + } + + static u32 +-mtk_wed_check_busy(struct mtk_wed_device *dev) ++mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) + { +- if (wed_r32(dev, MTK_WED_GLO_CFG) & MTK_WED_GLO_CFG_TX_DMA_BUSY) +- return true; +- +- if (wed_r32(dev, MTK_WED_WPDMA_GLO_CFG) & +- MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY) +- return true; +- +- if (wed_r32(dev, MTK_WED_CTRL) & MTK_WED_CTRL_WDMA_INT_AGENT_BUSY) +- return true; +- +- if (wed_r32(dev, MTK_WED_WDMA_GLO_CFG) & +- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) +- return true; +- +- if (wdma_r32(dev, MTK_WDMA_GLO_CFG) & +- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) +- return true; +- +- if (wed_r32(dev, MTK_WED_CTRL) & +- (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY)) +- return true; +- +- return false; ++ return !!(wed_r32(dev, reg) & mask); + } + + static int +-mtk_wed_poll_busy(struct mtk_wed_device *dev) ++mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) + { + int sleep = 15000; + int timeout = 100 * sleep; + u32 val; + + return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep, +- timeout, false, dev); ++ timeout, false, dev, reg, mask); ++} ++ ++static int ++mtk_wed_rx_reset(struct mtk_wed_device *dev) ++{ ++ struct mtk_wed_wo *wo = dev->hw->wed_wo; ++ u8 val = MTK_WED_WO_STATE_SER_RESET; ++ int i, ret; ++ ++ ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, ++ MTK_WED_WO_CMD_CHANGE_STATE, &val, ++ sizeof(val), true); ++ if (ret) ++ return ret; ++ ++ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN); ++ ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, ++ MTK_WED_WPDMA_RX_D_RX_DRV_BUSY); ++ if (ret) { ++ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT); ++ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV); ++ } else { ++ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, ++ MTK_WED_WPDMA_RX_D_RST_CRX_IDX | ++ MTK_WED_WPDMA_RX_D_RST_DRV_IDX); ++ ++ wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, ++ MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE | ++ MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE); ++ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, ++ MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE | ++ MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE); ++ ++ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0); ++ } ++ ++ /* reset rro qm */ ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN); ++ ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_RX_RRO_QM_BUSY); ++ if (ret) { ++ mtk_wed_reset(dev, MTK_WED_RESET_RX_RRO_QM); ++ } else { ++ wed_set(dev, MTK_WED_RROQM_RST_IDX, ++ MTK_WED_RROQM_RST_IDX_MIOD | ++ MTK_WED_RROQM_RST_IDX_FDBK); ++ wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0); ++ } ++ ++ /* reset route qm */ ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN); ++ ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_RX_ROUTE_QM_BUSY); ++ if (ret) ++ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM); ++ else ++ wed_set(dev, MTK_WED_RTQM_GLO_CFG, ++ MTK_WED_RTQM_Q_RST); ++ ++ /* reset tx wdma */ ++ mtk_wdma_tx_reset(dev); ++ ++ /* reset tx wdma drv */ ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN); ++ mtk_wed_poll_busy(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WDMA_INT_AGENT_BUSY); ++ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV); ++ ++ /* reset wed rx dma */ ++ ret = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_RX_DMA_BUSY); ++ wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_RX_DMA_EN); ++ if (ret) { ++ mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA); ++ } else { ++ struct mtk_eth *eth = dev->hw->eth; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ wed_set(dev, MTK_WED_RESET_IDX, ++ MTK_WED_RESET_IDX_RX_V2); ++ else ++ wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX); ++ wed_w32(dev, MTK_WED_RESET_IDX, 0); ++ } ++ ++ /* reset rx bm */ ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN); ++ mtk_wed_poll_busy(dev, MTK_WED_CTRL, ++ MTK_WED_CTRL_WED_RX_BM_BUSY); ++ mtk_wed_reset(dev, MTK_WED_RESET_RX_BM); ++ ++ /* wo change to enable state */ ++ val = MTK_WED_WO_STATE_ENABLE; ++ ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, ++ MTK_WED_WO_CMD_CHANGE_STATE, &val, ++ sizeof(val), true); ++ if (ret) ++ return ret; ++ ++ /* wed_rx_ring_reset */ ++ for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++) { ++ if (!dev->rx_ring[i].desc) ++ continue; ++ ++ mtk_wed_ring_reset(&dev->rx_ring[i], MTK_WED_RX_RING_SIZE, ++ false); ++ } ++ mtk_wed_free_rx_buffer(dev); ++ ++ return 0; + } + + static void +@@ -1004,19 +1092,23 @@ mtk_wed_reset_dma(struct mtk_wed_device + true); + } + +- if (mtk_wed_poll_busy(dev)) +- busy = mtk_wed_check_busy(dev); +- ++ /* 1. reset WED tx DMA */ ++ wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_EN); ++ busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG, ++ MTK_WED_GLO_CFG_TX_DMA_BUSY); + if (busy) { + mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA); + } else { +- wed_w32(dev, MTK_WED_RESET_IDX, +- MTK_WED_RESET_IDX_TX | +- MTK_WED_RESET_IDX_RX); ++ wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX); + wed_w32(dev, MTK_WED_RESET_IDX, 0); + } + +- mtk_wdma_rx_reset(dev); ++ /* 2. reset WDMA rx DMA */ ++ busy = !!mtk_wdma_rx_reset(dev); ++ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); ++ if (!busy) ++ busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG, ++ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY); + + if (busy) { + mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); +@@ -1033,6 +1125,9 @@ mtk_wed_reset_dma(struct mtk_wed_device + MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); + } + ++ /* 3. reset WED WPDMA tx */ ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); ++ + for (i = 0; i < 100; i++) { + val = wed_r32(dev, MTK_WED_TX_BM_INTF); + if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40) +@@ -1040,8 +1135,19 @@ mtk_wed_reset_dma(struct mtk_wed_device + } + + mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT); ++ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_BM_EN); + mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); + ++ /* 4. reset WED WPDMA tx */ ++ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY); ++ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); ++ if (!busy) ++ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG, ++ MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY); ++ + if (busy) { + mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT); + mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV); +@@ -1052,6 +1158,17 @@ mtk_wed_reset_dma(struct mtk_wed_device + MTK_WED_WPDMA_RESET_IDX_RX); + wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); + } ++ ++ dev->init_done = false; ++ if (dev->hw->version == 1) ++ return; ++ ++ if (!busy) { ++ wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_WPDMA_IDX_RX); ++ wed_w32(dev, MTK_WED_RESET_IDX, 0); ++ } ++ ++ mtk_wed_rx_reset(dev); + } + + static int +@@ -1274,6 +1391,9 @@ mtk_wed_start(struct mtk_wed_device *dev + { + int i; + ++ if (mtk_wed_get_rx_capa(dev) && mtk_wed_rx_buffer_alloc(dev)) ++ return; ++ + for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) + if (!dev->rx_wdma[i].desc) + mtk_wed_wdma_rx_ring_setup(dev, i, 16); +@@ -1362,10 +1482,6 @@ mtk_wed_attach(struct mtk_wed_device *de + goto out; + + if (mtk_wed_get_rx_capa(dev)) { +- ret = mtk_wed_rx_buffer_alloc(dev); +- if (ret) +- goto out; +- + ret = mtk_wed_rro_alloc(dev); + if (ret) + goto out; +--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h +@@ -24,11 +24,15 @@ struct mtk_wdma_desc { + + #define MTK_WED_RESET 0x008 + #define MTK_WED_RESET_TX_BM BIT(0) ++#define MTK_WED_RESET_RX_BM BIT(1) + #define MTK_WED_RESET_TX_FREE_AGENT BIT(4) + #define MTK_WED_RESET_WPDMA_TX_DRV BIT(8) + #define MTK_WED_RESET_WPDMA_RX_DRV BIT(9) ++#define MTK_WED_RESET_WPDMA_RX_D_DRV BIT(10) + #define MTK_WED_RESET_WPDMA_INT_AGENT BIT(11) + #define MTK_WED_RESET_WED_TX_DMA BIT(12) ++#define MTK_WED_RESET_WED_RX_DMA BIT(13) ++#define MTK_WED_RESET_WDMA_TX_DRV BIT(16) + #define MTK_WED_RESET_WDMA_RX_DRV BIT(17) + #define MTK_WED_RESET_WDMA_INT_AGENT BIT(19) + #define MTK_WED_RESET_RX_RRO_QM BIT(20) +@@ -158,6 +162,8 @@ struct mtk_wdma_desc { + #define MTK_WED_RESET_IDX 0x20c + #define MTK_WED_RESET_IDX_TX GENMASK(3, 0) + #define MTK_WED_RESET_IDX_RX GENMASK(17, 16) ++#define MTK_WED_RESET_IDX_RX_V2 GENMASK(7, 6) ++#define MTK_WED_RESET_WPDMA_IDX_RX GENMASK(31, 30) + + #define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4) + #define MTK_WED_RX_MIB(_n) (0x2e0 + (_n) * 4) +@@ -267,6 +273,9 @@ struct mtk_wdma_desc { + + #define MTK_WED_WPDMA_RX_D_GLO_CFG 0x75c + #define MTK_WED_WPDMA_RX_D_RX_DRV_EN BIT(0) ++#define MTK_WED_WPDMA_RX_D_RX_DRV_BUSY BIT(1) ++#define MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE BIT(3) ++#define MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE BIT(4) + #define MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL GENMASK(11, 7) + #define MTK_WED_WPDMA_RX_D_RXD_READ_LEN GENMASK(31, 24) + diff --git a/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch b/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch new file mode 100644 index 00000000000..602483bcb8d --- /dev/null +++ b/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch @@ -0,0 +1,103 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Nov 2022 16:22:55 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add reset to tx_ring_setup callback + +Introduce reset parameter to mtk_wed_tx_ring_setup signature. +This is a preliminary patch to add Wireless Ethernet Dispatcher reset +support. + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -1188,7 +1188,8 @@ mtk_wed_ring_alloc(struct mtk_wed_device + } + + static int +-mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size) ++mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size, ++ bool reset) + { + u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; + struct mtk_wed_ring *wdma; +@@ -1197,8 +1198,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we + return -EINVAL; + + wdma = &dev->rx_wdma[idx]; +- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size, +- true)) ++ if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, ++ desc_size, true)) + return -ENOMEM; + + wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, +@@ -1396,7 +1397,7 @@ mtk_wed_start(struct mtk_wed_device *dev + + for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) + if (!dev->rx_wdma[i].desc) +- mtk_wed_wdma_rx_ring_setup(dev, i, 16); ++ mtk_wed_wdma_rx_ring_setup(dev, i, 16, false); + + mtk_wed_hw_init(dev); + mtk_wed_configure_irq(dev, irq_mask); +@@ -1505,7 +1506,8 @@ unlock: + } + + static int +-mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs) ++mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs, ++ bool reset) + { + struct mtk_wed_ring *ring = &dev->tx_ring[idx]; + +@@ -1524,11 +1526,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev + if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring))) + return -EINVAL; + +- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, +- sizeof(*ring->desc), true)) ++ if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, ++ sizeof(*ring->desc), true)) + return -ENOMEM; + +- if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) ++ if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, ++ reset)) + return -ENOMEM; + + ring->reg_base = MTK_WED_RING_TX(idx); +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -158,7 +158,7 @@ struct mtk_wed_device { + struct mtk_wed_ops { + int (*attach)(struct mtk_wed_device *dev); + int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring, +- void __iomem *regs); ++ void __iomem *regs, bool reset); + int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring, + void __iomem *regs); + int (*txfree_ring_setup)(struct mtk_wed_device *dev, +@@ -216,8 +216,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic + #define mtk_wed_device_active(_dev) !!(_dev)->ops + #define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev) + #define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask) +-#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) \ +- (_dev)->ops->tx_ring_setup(_dev, _ring, _regs) ++#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) \ ++ (_dev)->ops->tx_ring_setup(_dev, _ring, _regs, _reset) + #define mtk_wed_device_txfree_ring_setup(_dev, _regs) \ + (_dev)->ops->txfree_ring_setup(_dev, _regs) + #define mtk_wed_device_reg_read(_dev, _reg) \ +@@ -243,7 +243,7 @@ static inline bool mtk_wed_device_active + } + #define mtk_wed_device_detach(_dev) do {} while (0) + #define mtk_wed_device_start(_dev, _mask) do {} while (0) +-#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV ++#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV + #define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV + #define mtk_wed_device_reg_read(_dev, _reg) 0 + #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0) diff --git a/target/linux/generic/backport-6.1/729-15-v6.2-net-ethernet-mtk_wed-fix-sleep-while-atomic-in-mtk_w.patch b/target/linux/generic/backport-6.1/729-15-v6.2-net-ethernet-mtk_wed-fix-sleep-while-atomic-in-mtk_w.patch new file mode 100644 index 00000000000..f9b11326b1c --- /dev/null +++ b/target/linux/generic/backport-6.1/729-15-v6.2-net-ethernet-mtk_wed-fix-sleep-while-atomic-in-mtk_w.patch @@ -0,0 +1,103 @@ +From: Lorenzo Bianconi +Date: Thu, 1 Dec 2022 16:26:53 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: fix sleep while atomic in + mtk_wed_wo_queue_refill + +In order to fix the following sleep while atomic bug always alloc pages +with GFP_ATOMIC in mtk_wed_wo_queue_refill since page_frag_alloc runs in +spin_lock critical section. + +[ 9.049719] Hardware name: MediaTek MT7986a RFB (DT) +[ 9.054665] Call trace: +[ 9.057096] dump_backtrace+0x0/0x154 +[ 9.060751] show_stack+0x14/0x1c +[ 9.064052] dump_stack_lvl+0x64/0x7c +[ 9.067702] dump_stack+0x14/0x2c +[ 9.071001] ___might_sleep+0xec/0x120 +[ 9.074736] __might_sleep+0x4c/0x9c +[ 9.078296] __alloc_pages+0x184/0x2e4 +[ 9.082030] page_frag_alloc_align+0x98/0x1ac +[ 9.086369] mtk_wed_wo_queue_refill+0x134/0x234 +[ 9.090974] mtk_wed_wo_init+0x174/0x2c0 +[ 9.094881] mtk_wed_attach+0x7c8/0x7e0 +[ 9.098701] mt7915_mmio_wed_init+0x1f0/0x3a0 [mt7915e] +[ 9.103940] mt7915_pci_probe+0xec/0x3bc [mt7915e] +[ 9.108727] pci_device_probe+0xac/0x13c +[ 9.112638] really_probe.part.0+0x98/0x2f4 +[ 9.116807] __driver_probe_device+0x94/0x13c +[ 9.121147] driver_probe_device+0x40/0x114 +[ 9.125314] __driver_attach+0x7c/0x180 +[ 9.129133] bus_for_each_dev+0x5c/0x90 +[ 9.132953] driver_attach+0x20/0x2c +[ 9.136513] bus_add_driver+0x104/0x1fc +[ 9.140333] driver_register+0x74/0x120 +[ 9.144153] __pci_register_driver+0x40/0x50 +[ 9.148407] mt7915_init+0x5c/0x1000 [mt7915e] +[ 9.152848] do_one_initcall+0x40/0x25c +[ 9.156669] do_init_module+0x44/0x230 +[ 9.160403] load_module+0x1f30/0x2750 +[ 9.164135] __do_sys_init_module+0x150/0x200 +[ 9.168475] __arm64_sys_init_module+0x18/0x20 +[ 9.172901] invoke_syscall.constprop.0+0x4c/0xe0 +[ 9.177589] do_el0_svc+0x48/0xe0 +[ 9.180889] el0_svc+0x14/0x50 +[ 9.183929] el0t_64_sync_handler+0x9c/0x120 +[ 9.188183] el0t_64_sync+0x158/0x15c + +Fixes: 799684448e3e ("net: ethernet: mtk_wed: introduce wed wo support") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Pavan Chebbi +Link: https://lore.kernel.org/r/67ca94bdd3d9eaeb86e52b3050fbca0bcf7bb02f.1669908312.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c +@@ -133,17 +133,18 @@ mtk_wed_wo_dequeue(struct mtk_wed_wo *wo + + static int + mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, +- gfp_t gfp, bool rx) ++ bool rx) + { + enum dma_data_direction dir = rx ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + int n_buf = 0; + + spin_lock_bh(&q->lock); + while (q->queued < q->n_desc) { +- void *buf = page_frag_alloc(&q->cache, q->buf_size, gfp); + struct mtk_wed_wo_queue_entry *entry; + dma_addr_t addr; ++ void *buf; + ++ buf = page_frag_alloc(&q->cache, q->buf_size, GFP_ATOMIC); + if (!buf) + break; + +@@ -215,7 +216,7 @@ mtk_wed_wo_rx_run_queue(struct mtk_wed_w + mtk_wed_mcu_rx_unsolicited_event(wo, skb); + } + +- if (mtk_wed_wo_queue_refill(wo, q, GFP_ATOMIC, true)) { ++ if (mtk_wed_wo_queue_refill(wo, q, true)) { + u32 index = (q->head - 1) % q->n_desc; + + mtk_wed_wo_queue_kick(wo, q, index); +@@ -432,7 +433,7 @@ mtk_wed_wo_hardware_init(struct mtk_wed_ + if (ret) + goto error; + +- mtk_wed_wo_queue_refill(wo, &wo->q_tx, GFP_KERNEL, false); ++ mtk_wed_wo_queue_refill(wo, &wo->q_tx, false); + mtk_wed_wo_queue_reset(wo, &wo->q_tx); + + regs.desc_base = MTK_WED_WO_CCIF_DUMMY5; +@@ -446,7 +447,7 @@ mtk_wed_wo_hardware_init(struct mtk_wed_ + if (ret) + goto error; + +- mtk_wed_wo_queue_refill(wo, &wo->q_rx, GFP_KERNEL, true); ++ mtk_wed_wo_queue_refill(wo, &wo->q_rx, true); + mtk_wed_wo_queue_reset(wo, &wo->q_rx); + + /* rx queue irqmask */ diff --git a/target/linux/generic/backport-6.1/729-16-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-rx-qu.patch b/target/linux/generic/backport-6.1/729-16-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-rx-qu.patch new file mode 100644 index 00000000000..fa6f56dbe72 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-16-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-rx-qu.patch @@ -0,0 +1,52 @@ +From: Lorenzo Bianconi +Date: Tue, 10 Jan 2023 10:31:26 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: get rid of queue lock for rx queue + +Queue spinlock is currently held in mtk_wed_wo_queue_rx_clean and +mtk_wed_wo_queue_refill routines for MTK Wireless Ethernet Dispatcher +MCU rx queue. mtk_wed_wo_queue_refill() is running during initialization +and in rx tasklet while mtk_wed_wo_queue_rx_clean() is running in +mtk_wed_wo_hw_deinit() during hw de-init phase after rx tasklet has been +disabled. Since mtk_wed_wo_queue_rx_clean and mtk_wed_wo_queue_refill +routines can't run concurrently get rid of spinlock for mcu rx queue. + +Reviewed-by: Alexander Duyck +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/36ec3b729542ea60898471d890796f745479ba32.1673342990.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c +@@ -138,7 +138,6 @@ mtk_wed_wo_queue_refill(struct mtk_wed_w + enum dma_data_direction dir = rx ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + int n_buf = 0; + +- spin_lock_bh(&q->lock); + while (q->queued < q->n_desc) { + struct mtk_wed_wo_queue_entry *entry; + dma_addr_t addr; +@@ -172,7 +171,6 @@ mtk_wed_wo_queue_refill(struct mtk_wed_w + q->queued++; + n_buf++; + } +- spin_unlock_bh(&q->lock); + + return n_buf; + } +@@ -316,7 +314,6 @@ mtk_wed_wo_queue_rx_clean(struct mtk_wed + { + struct page *page; + +- spin_lock_bh(&q->lock); + for (;;) { + void *buf = mtk_wed_wo_dequeue(wo, q, NULL, true); + +@@ -325,7 +322,6 @@ mtk_wed_wo_queue_rx_clean(struct mtk_wed + + skb_free_frag(buf); + } +- spin_unlock_bh(&q->lock); + + if (!q->cache.va) + return; diff --git a/target/linux/generic/backport-6.1/729-17-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-tx-qu.patch b/target/linux/generic/backport-6.1/729-17-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-tx-qu.patch new file mode 100644 index 00000000000..9b1e4c32507 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-17-v6.3-net-ethernet-mtk_wed-get-rid-of-queue-lock-for-tx-qu.patch @@ -0,0 +1,75 @@ +From: Lorenzo Bianconi +Date: Thu, 12 Jan 2023 10:21:29 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: get rid of queue lock for tx queue + +Similar to MTK Wireless Ethernet Dispatcher (WED) MCU rx queue, +we do not need to protect WED MCU tx queue with a spin lock since +the tx queue is accessed in the two following routines: +- mtk_wed_wo_queue_tx_skb(): + it is run at initialization and during mt7915 normal operation. + Moreover MCU messages are serialized through MCU mutex. +- mtk_wed_wo_queue_tx_clean(): + it runs just at mt7915 driver module unload when no more messages + are sent to the MCU. + +Remove tx queue spinlock. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/7bd0337b2a13ab1a63673b7c03fd35206b3b284e.1673515140.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c +@@ -258,7 +258,6 @@ mtk_wed_wo_queue_alloc(struct mtk_wed_wo + int n_desc, int buf_size, int index, + struct mtk_wed_wo_queue_regs *regs) + { +- spin_lock_init(&q->lock); + q->regs = *regs; + q->n_desc = n_desc; + q->buf_size = buf_size; +@@ -290,7 +289,6 @@ mtk_wed_wo_queue_tx_clean(struct mtk_wed + struct page *page; + int i; + +- spin_lock_bh(&q->lock); + for (i = 0; i < q->n_desc; i++) { + struct mtk_wed_wo_queue_entry *entry = &q->entry[i]; + +@@ -299,7 +297,6 @@ mtk_wed_wo_queue_tx_clean(struct mtk_wed + skb_free_frag(entry->buf); + entry->buf = NULL; + } +- spin_unlock_bh(&q->lock); + + if (!q->cache.va) + return; +@@ -347,8 +344,6 @@ int mtk_wed_wo_queue_tx_skb(struct mtk_w + int ret = 0, index; + u32 ctrl; + +- spin_lock_bh(&q->lock); +- + q->tail = mtk_wed_mmio_r32(wo, q->regs.dma_idx); + index = (q->head + 1) % q->n_desc; + if (q->tail == index) { +@@ -379,8 +374,6 @@ int mtk_wed_wo_queue_tx_skb(struct mtk_w + mtk_wed_wo_queue_kick(wo, q, q->head); + mtk_wed_wo_kickout(wo); + out: +- spin_unlock_bh(&q->lock); +- + dev_kfree_skb(skb); + + return ret; +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -211,7 +211,6 @@ struct mtk_wed_wo_queue { + struct mtk_wed_wo_queue_regs regs; + + struct page_frag_cache cache; +- spinlock_t lock; + + struct mtk_wed_wo_queue_desc *desc; + dma_addr_t desc_dma; diff --git a/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch b/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch new file mode 100644 index 00000000000..45b85c06cb5 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch @@ -0,0 +1,70 @@ +From: Lorenzo Bianconi +Date: Sat, 14 Jan 2023 18:01:28 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce mtk_hw_reset utility + routine + +This is a preliminary patch to add Wireless Ethernet Dispatcher reset +support. + +Reviewed-by: Leon Romanovsky +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3200,6 +3200,27 @@ static void mtk_set_mcr_max_rx(struct mt + mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_hw_reset(struct mtk_eth *eth) ++{ ++ u32 val; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); ++ val = RSTCTRL_PPE0_V2; ++ } else { ++ val = RSTCTRL_PPE0; ++ } ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ val |= RSTCTRL_PPE1; ++ ++ ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, ++ 0x3ffffff); ++} ++ + static int mtk_hw_init(struct mtk_eth *eth) + { + u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | +@@ -3239,22 +3260,9 @@ static int mtk_hw_init(struct mtk_eth *e + return 0; + } + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +- regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); +- val = RSTCTRL_PPE0_V2; +- } else { +- val = RSTCTRL_PPE0; +- } +- +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) +- val |= RSTCTRL_PPE1; +- +- ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val); ++ mtk_hw_reset(eth); + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +- regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, +- 0x3ffffff); +- + /* Set FE to PDMAv2 if necessary */ + val = mtk_r32(eth, MTK_FE_GLO_MISC); + mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC); diff --git a/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch b/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch new file mode 100644 index 00000000000..c34e30c773e --- /dev/null +++ b/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch @@ -0,0 +1,107 @@ +From: Lorenzo Bianconi +Date: Sat, 14 Jan 2023 18:01:29 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce mtk_hw_warm_reset + support + +Introduce mtk_hw_warm_reset utility routine. This is a preliminary patch +to align reset procedure to vendor sdk and avoid to power down the chip +during hw reset. + +Reviewed-by: Leon Romanovsky +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3221,7 +3221,54 @@ static void mtk_hw_reset(struct mtk_eth + 0x3ffffff); + } + +-static int mtk_hw_init(struct mtk_eth *eth) ++static u32 mtk_hw_reset_read(struct mtk_eth *eth) ++{ ++ u32 val; ++ ++ regmap_read(eth->ethsys, ETHSYS_RSTCTRL, &val); ++ return val; ++} ++ ++static void mtk_hw_warm_reset(struct mtk_eth *eth) ++{ ++ u32 rst_mask, val; ++ ++ regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, RSTCTRL_FE, ++ RSTCTRL_FE); ++ if (readx_poll_timeout_atomic(mtk_hw_reset_read, eth, val, ++ val & RSTCTRL_FE, 1, 1000)) { ++ dev_err(eth->dev, "warm reset failed\n"); ++ mtk_hw_reset(eth); ++ return; ++ } ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0_V2; ++ else ++ rst_mask = RSTCTRL_ETH | RSTCTRL_PPE0; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ rst_mask |= RSTCTRL_PPE1; ++ ++ regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, rst_mask, rst_mask); ++ ++ udelay(1); ++ val = mtk_hw_reset_read(eth); ++ if (!(val & rst_mask)) ++ dev_err(eth->dev, "warm reset stage0 failed %08x (%08x)\n", ++ val, rst_mask); ++ ++ rst_mask |= RSTCTRL_FE; ++ regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, rst_mask, ~rst_mask); ++ ++ udelay(1); ++ val = mtk_hw_reset_read(eth); ++ if (val & rst_mask) ++ dev_err(eth->dev, "warm reset stage1 failed %08x (%08x)\n", ++ val, rst_mask); ++} ++ ++static int mtk_hw_init(struct mtk_eth *eth, bool reset) + { + u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | + ETHSYS_DMA_AG_MAP_PPE; +@@ -3260,7 +3307,12 @@ static int mtk_hw_init(struct mtk_eth *e + return 0; + } + +- mtk_hw_reset(eth); ++ msleep(100); ++ ++ if (reset) ++ mtk_hw_warm_reset(eth); ++ else ++ mtk_hw_reset(eth); + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + /* Set FE to PDMAv2 if necessary */ +@@ -3465,7 +3517,7 @@ static void mtk_pending_work(struct work + if (eth->dev->pins) + pinctrl_select_state(eth->dev->pins->p, + eth->dev->pins->default_state); +- mtk_hw_init(eth); ++ mtk_hw_init(eth, true); + + /* restart DMA and enable IRQs */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +@@ -4057,7 +4109,7 @@ static int mtk_probe(struct platform_dev + eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); + INIT_WORK(ð->pending_work, mtk_pending_work); + +- err = mtk_hw_init(eth); ++ err = mtk_hw_init(eth, false); + if (err) + goto err_wed_exit; + diff --git a/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch b/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch new file mode 100644 index 00000000000..29a5b627390 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch @@ -0,0 +1,262 @@ +From: Lorenzo Bianconi +Date: Sat, 14 Jan 2023 18:01:30 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: align reset procedure to vendor + sdk + +Avoid to power-down the ethernet chip during hw reset and align reset +procedure to vendor sdk. + +Reviewed-by: Leon Romanovsky +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2786,14 +2786,29 @@ static void mtk_dma_free(struct mtk_eth + kfree(eth->scratch_head); + } + ++static bool mtk_hw_reset_check(struct mtk_eth *eth) ++{ ++ u32 val = mtk_r32(eth, MTK_INT_STATUS2); ++ ++ return (val & MTK_FE_INT_FQ_EMPTY) || (val & MTK_FE_INT_RFIFO_UF) || ++ (val & MTK_FE_INT_RFIFO_OV) || (val & MTK_FE_INT_TSO_FAIL) || ++ (val & MTK_FE_INT_TSO_ALIGN) || (val & MTK_FE_INT_TSO_ILLEGAL); ++} ++ + static void mtk_tx_timeout(struct net_device *dev, unsigned int txqueue) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + ++ if (test_bit(MTK_RESETTING, ð->state)) ++ return; ++ ++ if (!mtk_hw_reset_check(eth)) ++ return; ++ + eth->netdev[mac->id]->stats.tx_errors++; +- netif_err(eth, tx_err, dev, +- "transmit timed out\n"); ++ netif_err(eth, tx_err, dev, "transmit timed out\n"); ++ + schedule_work(ð->pending_work); + } + +@@ -3275,15 +3290,17 @@ static int mtk_hw_init(struct mtk_eth *e + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + int i, val, ret; + +- if (test_and_set_bit(MTK_HW_INIT, ð->state)) ++ if (!reset && test_and_set_bit(MTK_HW_INIT, ð->state)) + return 0; + +- pm_runtime_enable(eth->dev); +- pm_runtime_get_sync(eth->dev); ++ if (!reset) { ++ pm_runtime_enable(eth->dev); ++ pm_runtime_get_sync(eth->dev); + +- ret = mtk_clk_enable(eth); +- if (ret) +- goto err_disable_pm; ++ ret = mtk_clk_enable(eth); ++ if (ret) ++ goto err_disable_pm; ++ } + + if (eth->ethsys) + regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask, +@@ -3409,8 +3426,10 @@ static int mtk_hw_init(struct mtk_eth *e + return 0; + + err_disable_pm: +- pm_runtime_put_sync(eth->dev); +- pm_runtime_disable(eth->dev); ++ if (!reset) { ++ pm_runtime_put_sync(eth->dev); ++ pm_runtime_disable(eth->dev); ++ } + + return ret; + } +@@ -3489,30 +3508,53 @@ static int mtk_do_ioctl(struct net_devic + return -EOPNOTSUPP; + } + ++static void mtk_prepare_for_reset(struct mtk_eth *eth) ++{ ++ u32 val; ++ int i; ++ ++ /* disabe FE P3 and P4 */ ++ val = mtk_r32(eth, MTK_FE_GLO_CFG) | MTK_FE_LINK_DOWN_P3; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ val |= MTK_FE_LINK_DOWN_P4; ++ mtk_w32(eth, val, MTK_FE_GLO_CFG); ++ ++ /* adjust PPE configurations to prepare for reset */ ++ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) ++ mtk_ppe_prepare_reset(eth->ppe[i]); ++ ++ /* disable NETSYS interrupts */ ++ mtk_w32(eth, 0, MTK_FE_INT_ENABLE); ++ ++ /* force link down GMAC */ ++ for (i = 0; i < 2; i++) { ++ val = mtk_r32(eth, MTK_MAC_MCR(i)) & ~MAC_MCR_FORCE_LINK; ++ mtk_w32(eth, val, MTK_MAC_MCR(i)); ++ } ++} ++ + static void mtk_pending_work(struct work_struct *work) + { + struct mtk_eth *eth = container_of(work, struct mtk_eth, pending_work); +- int err, i; + unsigned long restart = 0; ++ u32 val; ++ int i; + + rtnl_lock(); +- +- dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); + set_bit(MTK_RESETTING, ð->state); + ++ mtk_prepare_for_reset(eth); ++ + /* stop all devices to make sure that dma is properly shut down */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i]) ++ if (!eth->netdev[i] || !netif_running(eth->netdev[i])) + continue; ++ + mtk_stop(eth->netdev[i]); + __set_bit(i, &restart); + } +- dev_dbg(eth->dev, "[%s][%d] mtk_stop ends\n", __func__, __LINE__); + +- /* restart underlying hardware such as power, clock, pin mux +- * and the connected phy +- */ +- mtk_hw_deinit(eth); ++ usleep_range(15000, 16000); + + if (eth->dev->pins) + pinctrl_select_state(eth->dev->pins->p, +@@ -3523,15 +3565,19 @@ static void mtk_pending_work(struct work + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!test_bit(i, &restart)) + continue; +- err = mtk_open(eth->netdev[i]); +- if (err) { ++ ++ if (mtk_open(eth->netdev[i])) { + netif_alert(eth, ifup, eth->netdev[i], +- "Driver up/down cycle failed, closing device.\n"); ++ "Driver up/down cycle failed\n"); + dev_close(eth->netdev[i]); + } + } + +- dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); ++ /* enabe FE P3 and P4 */ ++ val = mtk_r32(eth, MTK_FE_GLO_CFG) & ~MTK_FE_LINK_DOWN_P3; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) ++ val &= ~MTK_FE_LINK_DOWN_P4; ++ mtk_w32(eth, val, MTK_FE_GLO_CFG); + + clear_bit(MTK_RESETTING, ð->state); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -72,12 +72,24 @@ + #define MTK_HW_LRO_REPLACE_DELTA 1000 + #define MTK_HW_LRO_SDL_REMAIN_ROOM 1522 + ++/* Frame Engine Global Configuration */ ++#define MTK_FE_GLO_CFG 0x00 ++#define MTK_FE_LINK_DOWN_P3 BIT(11) ++#define MTK_FE_LINK_DOWN_P4 BIT(12) ++ + /* Frame Engine Global Reset Register */ + #define MTK_RST_GL 0x04 + #define RST_GL_PSE BIT(0) + + /* Frame Engine Interrupt Status Register */ + #define MTK_INT_STATUS2 0x08 ++#define MTK_FE_INT_ENABLE 0x0c ++#define MTK_FE_INT_FQ_EMPTY BIT(8) ++#define MTK_FE_INT_TSO_FAIL BIT(12) ++#define MTK_FE_INT_TSO_ILLEGAL BIT(13) ++#define MTK_FE_INT_TSO_ALIGN BIT(14) ++#define MTK_FE_INT_RFIFO_OV BIT(18) ++#define MTK_FE_INT_RFIFO_UF BIT(19) + #define MTK_GDM1_AF BIT(28) + #define MTK_GDM2_AF BIT(29) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -716,6 +716,33 @@ int mtk_foe_entry_idle_time(struct mtk_p + return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); + } + ++int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) ++{ ++ if (!ppe) ++ return -EINVAL; ++ ++ /* disable KA */ ++ ppe_clear(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_KEEPALIVE); ++ ppe_clear(ppe, MTK_PPE_BIND_LMT1, MTK_PPE_NTU_KEEPALIVE); ++ ppe_w32(ppe, MTK_PPE_KEEPALIVE, 0); ++ usleep_range(10000, 11000); ++ ++ /* set KA timer to maximum */ ++ ppe_set(ppe, MTK_PPE_BIND_LMT1, MTK_PPE_NTU_KEEPALIVE); ++ ppe_w32(ppe, MTK_PPE_KEEPALIVE, 0xffffffff); ++ ++ /* set KA tick select */ ++ ppe_set(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_TICK_SEL); ++ ppe_set(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_KEEPALIVE); ++ usleep_range(10000, 11000); ++ ++ /* disable scan mode */ ++ ppe_clear(ppe, MTK_PPE_TB_CFG, MTK_PPE_TB_CFG_SCAN_MODE); ++ usleep_range(10000, 11000); ++ ++ return mtk_ppe_wait_busy(ppe); ++} ++ + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, + int version, int index) + { +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -306,6 +306,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + int version, int index); + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); ++int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h +@@ -58,6 +58,12 @@ + #define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16) + #define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18) + #define MTK_PPE_TB_CFG_INFO_SEL BIT(20) ++#define MTK_PPE_TB_TICK_SEL BIT(24) ++ ++#define MTK_PPE_BIND_LMT1 0x230 ++#define MTK_PPE_NTU_KEEPALIVE GENMASK(23, 16) ++ ++#define MTK_PPE_KEEPALIVE 0x234 + + enum { + MTK_PPE_SCAN_MODE_DISABLED, diff --git a/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch b/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch new file mode 100644 index 00000000000..cebb750bf64 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch @@ -0,0 +1,249 @@ +From: Lorenzo Bianconi +Date: Sat, 14 Jan 2023 18:01:31 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add dma checks to + mtk_hw_reset_check + +Introduce mtk_hw_check_dma_hang routine to monitor possible dma hangs. + +Reviewed-by: Leon Romanovsky +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -50,6 +50,7 @@ static const struct mtk_reg_map mtk_reg_ + .delay_irq = 0x0a0c, + .irq_status = 0x0a20, + .irq_mask = 0x0a28, ++ .adma_rx_dbg0 = 0x0a38, + .int_grp = 0x0a50, + }, + .qdma = { +@@ -79,6 +80,8 @@ static const struct mtk_reg_map mtk_reg_ + [0] = 0x2800, + [1] = 0x2c00, + }, ++ .pse_iq_sta = 0x0110, ++ .pse_oq_sta = 0x0118, + }; + + static const struct mtk_reg_map mt7628_reg_map = { +@@ -109,6 +112,7 @@ static const struct mtk_reg_map mt7986_r + .delay_irq = 0x620c, + .irq_status = 0x6220, + .irq_mask = 0x6228, ++ .adma_rx_dbg0 = 0x6238, + .int_grp = 0x6250, + }, + .qdma = { +@@ -138,6 +142,8 @@ static const struct mtk_reg_map mt7986_r + [0] = 0x4800, + [1] = 0x4c00, + }, ++ .pse_iq_sta = 0x0180, ++ .pse_oq_sta = 0x01a0, + }; + + /* strings used by ethtool */ +@@ -3283,6 +3289,102 @@ static void mtk_hw_warm_reset(struct mtk + val, rst_mask); + } + ++static bool mtk_hw_check_dma_hang(struct mtk_eth *eth) ++{ ++ const struct mtk_reg_map *reg_map = eth->soc->reg_map; ++ bool gmac1_tx, gmac2_tx, gdm1_tx, gdm2_tx; ++ bool oq_hang, cdm1_busy, adma_busy; ++ bool wtx_busy, cdm_full, oq_free; ++ u32 wdidx, val, gdm1_fc, gdm2_fc; ++ bool qfsm_hang, qfwd_hang; ++ bool ret = false; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) ++ return false; ++ ++ /* WDMA sanity checks */ ++ wdidx = mtk_r32(eth, reg_map->wdma_base[0] + 0xc); ++ ++ val = mtk_r32(eth, reg_map->wdma_base[0] + 0x204); ++ wtx_busy = FIELD_GET(MTK_TX_DMA_BUSY, val); ++ ++ val = mtk_r32(eth, reg_map->wdma_base[0] + 0x230); ++ cdm_full = !FIELD_GET(MTK_CDM_TXFIFO_RDY, val); ++ ++ oq_free = (!(mtk_r32(eth, reg_map->pse_oq_sta) & GENMASK(24, 16)) && ++ !(mtk_r32(eth, reg_map->pse_oq_sta + 0x4) & GENMASK(8, 0)) && ++ !(mtk_r32(eth, reg_map->pse_oq_sta + 0x10) & GENMASK(24, 16))); ++ ++ if (wdidx == eth->reset.wdidx && wtx_busy && cdm_full && oq_free) { ++ if (++eth->reset.wdma_hang_count > 2) { ++ eth->reset.wdma_hang_count = 0; ++ ret = true; ++ } ++ goto out; ++ } ++ ++ /* QDMA sanity checks */ ++ qfsm_hang = !!mtk_r32(eth, reg_map->qdma.qtx_cfg + 0x234); ++ qfwd_hang = !mtk_r32(eth, reg_map->qdma.qtx_cfg + 0x308); ++ ++ gdm1_tx = FIELD_GET(GENMASK(31, 16), mtk_r32(eth, MTK_FE_GDM1_FSM)) > 0; ++ gdm2_tx = FIELD_GET(GENMASK(31, 16), mtk_r32(eth, MTK_FE_GDM2_FSM)) > 0; ++ gmac1_tx = FIELD_GET(GENMASK(31, 24), mtk_r32(eth, MTK_MAC_FSM(0))) != 1; ++ gmac2_tx = FIELD_GET(GENMASK(31, 24), mtk_r32(eth, MTK_MAC_FSM(1))) != 1; ++ gdm1_fc = mtk_r32(eth, reg_map->gdm1_cnt + 0x24); ++ gdm2_fc = mtk_r32(eth, reg_map->gdm1_cnt + 0x64); ++ ++ if (qfsm_hang && qfwd_hang && ++ ((gdm1_tx && gmac1_tx && gdm1_fc < 1) || ++ (gdm2_tx && gmac2_tx && gdm2_fc < 1))) { ++ if (++eth->reset.qdma_hang_count > 2) { ++ eth->reset.qdma_hang_count = 0; ++ ret = true; ++ } ++ goto out; ++ } ++ ++ /* ADMA sanity checks */ ++ oq_hang = !!(mtk_r32(eth, reg_map->pse_oq_sta) & GENMASK(8, 0)); ++ cdm1_busy = !!(mtk_r32(eth, MTK_FE_CDM1_FSM) & GENMASK(31, 16)); ++ adma_busy = !(mtk_r32(eth, reg_map->pdma.adma_rx_dbg0) & GENMASK(4, 0)) && ++ !(mtk_r32(eth, reg_map->pdma.adma_rx_dbg0) & BIT(6)); ++ ++ if (oq_hang && cdm1_busy && adma_busy) { ++ if (++eth->reset.adma_hang_count > 2) { ++ eth->reset.adma_hang_count = 0; ++ ret = true; ++ } ++ goto out; ++ } ++ ++ eth->reset.wdma_hang_count = 0; ++ eth->reset.qdma_hang_count = 0; ++ eth->reset.adma_hang_count = 0; ++out: ++ eth->reset.wdidx = wdidx; ++ ++ return ret; ++} ++ ++static void mtk_hw_reset_monitor_work(struct work_struct *work) ++{ ++ struct delayed_work *del_work = to_delayed_work(work); ++ struct mtk_eth *eth = container_of(del_work, struct mtk_eth, ++ reset.monitor_work); ++ ++ if (test_bit(MTK_RESETTING, ð->state)) ++ goto out; ++ ++ /* DMA stuck checks */ ++ if (mtk_hw_check_dma_hang(eth)) ++ schedule_work(ð->pending_work); ++ ++out: ++ schedule_delayed_work(ð->reset.monitor_work, ++ MTK_DMA_MONITOR_TIMEOUT); ++} ++ + static int mtk_hw_init(struct mtk_eth *eth, bool reset) + { + u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | +@@ -3615,6 +3717,7 @@ static int mtk_cleanup(struct mtk_eth *e + mtk_unreg_dev(eth); + mtk_free_dev(eth); + cancel_work_sync(ð->pending_work); ++ cancel_delayed_work_sync(ð->reset.monitor_work); + + return 0; + } +@@ -4042,6 +4145,7 @@ static int mtk_probe(struct platform_dev + + eth->rx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; + INIT_WORK(ð->rx_dim.work, mtk_dim_rx); ++ INIT_DELAYED_WORK(ð->reset.monitor_work, mtk_hw_reset_monitor_work); + + eth->tx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; + INIT_WORK(ð->tx_dim.work, mtk_dim_tx); +@@ -4246,6 +4350,8 @@ static int mtk_probe(struct platform_dev + NAPI_POLL_WEIGHT); + + platform_set_drvdata(pdev, eth); ++ schedule_delayed_work(ð->reset.monitor_work, ++ MTK_DMA_MONITOR_TIMEOUT); + + return 0; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -256,6 +256,8 @@ + + #define MTK_RX_DONE_INT_V2 BIT(14) + ++#define MTK_CDM_TXFIFO_RDY BIT(7) ++ + /* QDMA Interrupt grouping registers */ + #define MTK_RLS_DONE_INT BIT(0) + +@@ -538,6 +540,17 @@ + #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c) + #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110) + ++#define MTK_FE_CDM1_FSM 0x220 ++#define MTK_FE_CDM2_FSM 0x224 ++#define MTK_FE_CDM3_FSM 0x238 ++#define MTK_FE_CDM4_FSM 0x298 ++#define MTK_FE_CDM5_FSM 0x318 ++#define MTK_FE_CDM6_FSM 0x328 ++#define MTK_FE_GDM1_FSM 0x228 ++#define MTK_FE_GDM2_FSM 0x22C ++ ++#define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100)) ++ + struct mtk_rx_dma { + unsigned int rxd1; + unsigned int rxd2; +@@ -934,6 +947,7 @@ struct mtk_reg_map { + u32 delay_irq; /* delay interrupt */ + u32 irq_status; /* interrupt status */ + u32 irq_mask; /* interrupt mask */ ++ u32 adma_rx_dbg0; + u32 int_grp; + } pdma; + struct { +@@ -960,6 +974,8 @@ struct mtk_reg_map { + u32 gdma_to_ppe0; + u32 ppe_base; + u32 wdma_base[2]; ++ u32 pse_iq_sta; ++ u32 pse_oq_sta; + }; + + /* struct mtk_eth_data - This is the structure holding all differences +@@ -1002,6 +1018,8 @@ struct mtk_soc_data { + } txrx; + }; + ++#define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000) ++ + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + +@@ -1124,6 +1142,14 @@ struct mtk_eth { + struct rhashtable flow_table; + + struct bpf_prog __rcu *prog; ++ ++ struct { ++ struct delayed_work monitor_work; ++ u32 wdidx; ++ u8 wdma_hang_count; ++ u8 qdma_hang_count; ++ u8 adma_hang_count; ++ } reset; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the diff --git a/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch b/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch new file mode 100644 index 00000000000..2eca2686708 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch @@ -0,0 +1,124 @@ +From: Lorenzo Bianconi +Date: Sat, 14 Jan 2023 18:01:32 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add reset/reset_complete callbacks + +Introduce reset and reset_complete wlan callback to schedule WLAN driver +reset when ethernet/wed driver is resetting. + +Tested-by: Daniel Golle +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Paolo Abeni +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3646,6 +3646,11 @@ static void mtk_pending_work(struct work + set_bit(MTK_RESETTING, ð->state); + + mtk_prepare_for_reset(eth); ++ mtk_wed_fe_reset(); ++ /* Run again reset preliminary configuration in order to avoid any ++ * possible race during FE reset since it can run releasing RTNL lock. ++ */ ++ mtk_prepare_for_reset(eth); + + /* stop all devices to make sure that dma is properly shut down */ + for (i = 0; i < MTK_MAC_COUNT; i++) { +@@ -3683,6 +3688,8 @@ static void mtk_pending_work(struct work + + clear_bit(MTK_RESETTING, ð->state); + ++ mtk_wed_fe_reset_complete(); ++ + rtnl_unlock(); + } + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -205,6 +205,48 @@ mtk_wed_wo_reset(struct mtk_wed_device * + iounmap(reg); + } + ++void mtk_wed_fe_reset(void) ++{ ++ int i; ++ ++ mutex_lock(&hw_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { ++ struct mtk_wed_hw *hw = hw_list[i]; ++ struct mtk_wed_device *dev = hw->wed_dev; ++ int err; ++ ++ if (!dev || !dev->wlan.reset) ++ continue; ++ ++ /* reset callback blocks until WLAN reset is completed */ ++ err = dev->wlan.reset(dev); ++ if (err) ++ dev_err(dev->dev, "wlan reset failed: %d\n", err); ++ } ++ ++ mutex_unlock(&hw_lock); ++} ++ ++void mtk_wed_fe_reset_complete(void) ++{ ++ int i; ++ ++ mutex_lock(&hw_lock); ++ ++ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { ++ struct mtk_wed_hw *hw = hw_list[i]; ++ struct mtk_wed_device *dev = hw->wed_dev; ++ ++ if (!dev || !dev->wlan.reset_complete) ++ continue; ++ ++ dev->wlan.reset_complete(dev); ++ } ++ ++ mutex_unlock(&hw_lock); ++} ++ + static struct mtk_wed_hw * + mtk_wed_assign(struct mtk_wed_device *dev) + { +--- a/drivers/net/ethernet/mediatek/mtk_wed.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed.h +@@ -128,6 +128,8 @@ void mtk_wed_add_hw(struct device_node * + void mtk_wed_exit(void); + int mtk_wed_flow_add(int index); + void mtk_wed_flow_remove(int index); ++void mtk_wed_fe_reset(void); ++void mtk_wed_fe_reset_complete(void); + #else + static inline void + mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, +@@ -147,6 +149,13 @@ static inline void mtk_wed_flow_remove(i + { + } + ++static inline void mtk_wed_fe_reset(void) ++{ ++} ++ ++static inline void mtk_wed_fe_reset_complete(void) ++{ ++} + #endif + + #ifdef CONFIG_DEBUG_FS +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -151,6 +151,8 @@ struct mtk_wed_device { + void (*release_rx_buf)(struct mtk_wed_device *wed); + void (*update_wo_rx_stats)(struct mtk_wed_device *wed, + struct mtk_wed_wo_rx_stats *stats); ++ int (*reset)(struct mtk_wed_device *wed); ++ void (*reset_complete)(struct mtk_wed_device *wed); + } wlan; + #endif + }; diff --git a/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch b/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch new file mode 100644 index 00000000000..cf81acf4919 --- /dev/null +++ b/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch @@ -0,0 +1,106 @@ +From: Lorenzo Bianconi +Date: Mon, 5 Dec 2022 12:34:42 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: add reset to rx_ring_setup callback + +This patch adds reset parameter to mtk_wed_rx_ring_setup signature +in order to align rx_ring_setup callback to tx_ring_setup one introduced +in 'commit 23dca7a90017 ("net: ethernet: mtk_wed: add reset to +tx_ring_setup callback")' + +Co-developed-by: Sujuan Chen +Signed-off-by: Sujuan Chen +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Leon Romanovsky +Link: https://lore.kernel.org/r/29c6e7a5469e784406cf3e2920351d1207713d05.1670239984.git.lorenzo@kernel.org +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -1259,7 +1259,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we + } + + static int +-mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size) ++mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size, ++ bool reset) + { + u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; + struct mtk_wed_ring *wdma; +@@ -1268,8 +1269,8 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we + return -EINVAL; + + wdma = &dev->tx_wdma[idx]; +- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size, +- true)) ++ if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, ++ desc_size, true)) + return -ENOMEM; + + wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE, +@@ -1279,6 +1280,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we + wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); + wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0); + ++ if (reset) ++ mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true); ++ + if (!idx) { + wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE, + wdma->desc_phys); +@@ -1618,18 +1622,20 @@ mtk_wed_txfree_ring_setup(struct mtk_wed + } + + static int +-mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs) ++mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs, ++ bool reset) + { + struct mtk_wed_ring *ring = &dev->rx_ring[idx]; + + if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring))) + return -EINVAL; + +- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE, +- sizeof(*ring->desc), false)) ++ if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE, ++ sizeof(*ring->desc), false)) + return -ENOMEM; + +- if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) ++ if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE, ++ reset)) + return -ENOMEM; + + ring->reg_base = MTK_WED_RING_RX_DATA(idx); +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -162,7 +162,7 @@ struct mtk_wed_ops { + int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring, + void __iomem *regs, bool reset); + int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring, +- void __iomem *regs); ++ void __iomem *regs, bool reset); + int (*txfree_ring_setup)(struct mtk_wed_device *dev, + void __iomem *regs); + int (*msg_update)(struct mtk_wed_device *dev, int cmd_id, +@@ -230,8 +230,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic + (_dev)->ops->irq_get(_dev, _mask) + #define mtk_wed_device_irq_set_mask(_dev, _mask) \ + (_dev)->ops->irq_set_mask(_dev, _mask) +-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \ +- (_dev)->ops->rx_ring_setup(_dev, _ring, _regs) ++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \ ++ (_dev)->ops->rx_ring_setup(_dev, _ring, _regs, _reset) + #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \ + (_dev)->ops->ppe_check(_dev, _skb, _reason, _hash) + #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \ +@@ -251,7 +251,7 @@ static inline bool mtk_wed_device_active + #define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0) + #define mtk_wed_device_irq_get(_dev, _mask) 0 + #define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0) +-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV ++#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV + #define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) do {} while (0) + #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV + #define mtk_wed_device_stop(_dev) do {} while (0) diff --git a/target/linux/generic/backport-6.1/730-01-v6.3-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch b/target/linux/generic/backport-6.1/730-01-v6.3-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch new file mode 100644 index 00000000000..45af898cf00 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-01-v6.3-net-ethernet-mtk_eth_soc-account-for-vlan-in-rx-head.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Date: Thu, 27 Oct 2022 19:50:31 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: account for vlan in rx + header length + +The network stack assumes that devices can handle an extra VLAN tag without +increasing the MTU + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -29,7 +29,7 @@ + #define MTK_TX_DMA_BUF_LEN_V2 0xffff + #define MTK_DMA_SIZE 512 + #define MTK_MAC_COUNT 2 +-#define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN) ++#define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + ETH_FCS_LEN) + #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) + #define MTK_DMA_DUMMY_DESC 0xffffffff + #define MTK_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \ diff --git a/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch new file mode 100644 index 00000000000..b3412df9e0c --- /dev/null +++ b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch @@ -0,0 +1,143 @@ +From: Felix Fietkau +Date: Thu, 27 Oct 2022 19:53:57 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: increase tx ring side for + QDMA devices + +In order to use the hardware traffic shaper feature, a larger tx ring is +needed, especially for the scratch ring, which the hardware shaper uses to +reorder packets. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -901,7 +901,7 @@ static int mtk_init_fq_dma(struct mtk_et + { + const struct mtk_soc_data *soc = eth->soc; + dma_addr_t phy_ring_tail; +- int cnt = MTK_DMA_SIZE; ++ int cnt = MTK_QDMA_RING_SIZE; + dma_addr_t dma_addr; + int i; + +@@ -2155,19 +2155,25 @@ static int mtk_tx_alloc(struct mtk_eth * + struct mtk_tx_ring *ring = ð->tx_ring; + int i, sz = soc->txrx.txd_size; + struct mtk_tx_dma_v2 *txd; ++ int ring_size; + +- ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), ++ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ++ ring_size = MTK_QDMA_RING_SIZE; ++ else ++ ring_size = MTK_DMA_SIZE; ++ ++ ring->buf = kcalloc(ring_size, sizeof(*ring->buf), + GFP_KERNEL); + if (!ring->buf) + goto no_tx_mem; + +- ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, ++ ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz, + &ring->phys, GFP_KERNEL); + if (!ring->dma) + goto no_tx_mem; + +- for (i = 0; i < MTK_DMA_SIZE; i++) { +- int next = (i + 1) % MTK_DMA_SIZE; ++ for (i = 0; i < ring_size; i++) { ++ int next = (i + 1) % ring_size; + u32 next_ptr = ring->phys + next * sz; + + txd = ring->dma + i * sz; +@@ -2187,22 +2193,22 @@ static int mtk_tx_alloc(struct mtk_eth * + * descriptors in ring->dma_pdma. + */ + if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { +- ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, ++ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz, + &ring->phys_pdma, GFP_KERNEL); + if (!ring->dma_pdma) + goto no_tx_mem; + +- for (i = 0; i < MTK_DMA_SIZE; i++) { ++ for (i = 0; i < ring_size; i++) { + ring->dma_pdma[i].txd2 = TX_DMA_DESP2_DEF; + ring->dma_pdma[i].txd4 = 0; + } + } + +- ring->dma_size = MTK_DMA_SIZE; +- atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); ++ ring->dma_size = ring_size; ++ atomic_set(&ring->free_count, ring_size - 2); + ring->next_free = ring->dma; + ring->last_free = (void *)txd; +- ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); ++ ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz)); + ring->thresh = MAX_SKB_FRAGS; + + /* make sure that all changes to the dma ring are flushed before we +@@ -2214,14 +2220,14 @@ static int mtk_tx_alloc(struct mtk_eth * + mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); + mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); + mtk_w32(eth, +- ring->phys + ((MTK_DMA_SIZE - 1) * sz), ++ ring->phys + ((ring_size - 1) * sz), + soc->reg_map->qdma.crx_ptr); + mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); + mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, + soc->reg_map->qdma.qtx_cfg); + } else { + mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); +- mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0); ++ mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0); + mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); + mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx); + } +@@ -2239,7 +2245,7 @@ static void mtk_tx_clean(struct mtk_eth + int i; + + if (ring->buf) { +- for (i = 0; i < MTK_DMA_SIZE; i++) ++ for (i = 0; i < ring->dma_size; i++) + mtk_tx_unmap(eth, &ring->buf[i], false); + kfree(ring->buf); + ring->buf = NULL; +@@ -2247,14 +2253,14 @@ static void mtk_tx_clean(struct mtk_eth + + if (ring->dma) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * soc->txrx.txd_size, ++ ring->dma_size * soc->txrx.txd_size, + ring->dma, ring->phys); + ring->dma = NULL; + } + + if (ring->dma_pdma) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * soc->txrx.txd_size, ++ ring->dma_size * soc->txrx.txd_size, + ring->dma_pdma, ring->phys_pdma); + ring->dma_pdma = NULL; + } +@@ -2774,7 +2780,7 @@ static void mtk_dma_free(struct mtk_eth + netdev_reset_queue(eth->netdev[i]); + if (eth->scratch_ring) { + dma_free_coherent(eth->dma_dev, +- MTK_DMA_SIZE * soc->txrx.txd_size, ++ MTK_QDMA_RING_SIZE * soc->txrx.txd_size, + eth->scratch_ring, eth->phy_scratch_ring); + eth->scratch_ring = NULL; + eth->phy_scratch_ring = 0; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -27,6 +27,7 @@ + #define MTK_MAX_RX_LENGTH_2K 2048 + #define MTK_TX_DMA_BUF_LEN 0x3fff + #define MTK_TX_DMA_BUF_LEN_V2 0xffff ++#define MTK_QDMA_RING_SIZE 2048 + #define MTK_DMA_SIZE 512 + #define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + ETH_FCS_LEN) diff --git a/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch b/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch new file mode 100644 index 00000000000..32dc5c37832 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch @@ -0,0 +1,52 @@ +From: Felix Fietkau +Date: Fri, 4 Nov 2022 19:49:08 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: avoid port_mg assignment on + MT7622 and newer + +On newer chips, this field is unused and contains some bits related to queue +assignment. Initialize it to 0 in those cases. +Fix offload_version on MT7621 and MT7623, which still need the previous value. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4428,7 +4428,7 @@ static const struct mtk_soc_data mt7621_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7621_CLKS_BITMAP, + .required_pctl = false, +- .offload_version = 2, ++ .offload_version = 1, + .hash_offset = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { +@@ -4467,7 +4467,7 @@ static const struct mtk_soc_data mt7623_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, +- .offload_version = 2, ++ .offload_version = 1, + .hash_offset = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -175,6 +175,8 @@ int mtk_foe_entry_prepare(struct mtk_eth + val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) | + FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf); + } else { ++ int port_mg = eth->soc->offload_version > 1 ? 0 : 0x3f; ++ + val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | + FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | + FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | +@@ -182,7 +184,7 @@ int mtk_foe_entry_prepare(struct mtk_eth + entry->ib1 = val; + + val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) | +- FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | ++ FIELD_PREP(MTK_FOE_IB2_PORT_MG, port_mg) | + FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f); + } + diff --git a/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch b/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch new file mode 100644 index 00000000000..cfbd510c8f2 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch @@ -0,0 +1,654 @@ +From: Felix Fietkau +Date: Thu, 27 Oct 2022 20:17:27 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: implement multi-queue + support for per-port queues + +When sending traffic to multiple ports with different link speeds, queued +packets to one port can drown out tx to other ports. +In order to better handle transmission to multiple ports, use the hardware +shaper feature to implement weighted fair queueing between ports. +Weight and maximum rate are automatically adjusted based on the link speed +of the port. +The first 3 queues are unrestricted and reserved for non-DSA direct tx on +GMAC ports. The following queues are automatically assigned by the MTK DSA +tag driver based on the target port number. +The PPE offload code configures the queues for offloaded traffic in the same +way. +This feature is only supported on devices supporting QDMA. All queues still +share the same DMA ring and descriptor pool. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -55,6 +55,7 @@ static const struct mtk_reg_map mtk_reg_ + }, + .qdma = { + .qtx_cfg = 0x1800, ++ .qtx_sch = 0x1804, + .rx_ptr = 0x1900, + .rx_cnt_cfg = 0x1904, + .qcrx_ptr = 0x1908, +@@ -62,6 +63,7 @@ static const struct mtk_reg_map mtk_reg_ + .rst_idx = 0x1a08, + .delay_irq = 0x1a0c, + .fc_th = 0x1a10, ++ .tx_sch_rate = 0x1a14, + .int_grp = 0x1a20, + .hred = 0x1a44, + .ctx_ptr = 0x1b00, +@@ -117,6 +119,7 @@ static const struct mtk_reg_map mt7986_r + }, + .qdma = { + .qtx_cfg = 0x4400, ++ .qtx_sch = 0x4404, + .rx_ptr = 0x4500, + .rx_cnt_cfg = 0x4504, + .qcrx_ptr = 0x4508, +@@ -134,6 +137,7 @@ static const struct mtk_reg_map mt7986_r + .fq_tail = 0x4724, + .fq_count = 0x4728, + .fq_blen = 0x472c, ++ .tx_sch_rate = 0x4798, + }, + .gdm1_cnt = 0x1c00, + .gdma_to_ppe0 = 0x3333, +@@ -577,6 +581,75 @@ static void mtk_mac_link_down(struct phy + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, ++ int speed) ++{ ++ const struct mtk_soc_data *soc = eth->soc; ++ u32 ofs, val; ++ ++ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ++ return; ++ ++ val = MTK_QTX_SCH_MIN_RATE_EN | ++ /* minimum: 10 Mbps */ ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | ++ MTK_QTX_SCH_LEAKY_BUCKET_SIZE; ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; ++ ++ if (IS_ENABLED(CONFIG_SOC_MT7621)) { ++ switch (speed) { ++ case SPEED_10: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 2) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); ++ break; ++ case SPEED_100: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3); ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); ++ break; ++ case SPEED_1000: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 105) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10); ++ break; ++ default: ++ break; ++ } ++ } else { ++ switch (speed) { ++ case SPEED_10: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); ++ break; ++ case SPEED_100: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5); ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1); ++ break; ++ case SPEED_1000: ++ val |= MTK_QTX_SCH_MAX_RATE_EN | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 10) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ ofs = MTK_QTX_OFFSET * idx; ++ mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); ++} ++ + static void mtk_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, +@@ -602,6 +675,8 @@ static void mtk_mac_link_up(struct phyli + break; + } + ++ mtk_set_queue_speed(mac->hw, mac->id, speed); ++ + /* Configure duplex */ + if (duplex == DUPLEX_FULL) + mcr |= MAC_MCR_FORCE_DPX; +@@ -1060,7 +1135,8 @@ static void mtk_tx_set_dma_desc_v1(struc + + WRITE_ONCE(desc->txd1, info->addr); + +- data = TX_DMA_SWC | TX_DMA_PLEN0(info->size); ++ data = TX_DMA_SWC | TX_DMA_PLEN0(info->size) | ++ FIELD_PREP(TX_DMA_PQID, info->qid); + if (info->last) + data |= TX_DMA_LS0; + WRITE_ONCE(desc->txd3, data); +@@ -1094,9 +1170,6 @@ static void mtk_tx_set_dma_desc_v2(struc + data |= TX_DMA_LS0; + WRITE_ONCE(desc->txd3, data); + +- if (!info->qid && mac->id) +- info->qid = MTK_QDMA_GMAC2_QID; +- + data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ + data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); + WRITE_ONCE(desc->txd4, data); +@@ -1140,11 +1213,12 @@ static int mtk_tx_map(struct sk_buff *sk + .gso = gso, + .csum = skb->ip_summed == CHECKSUM_PARTIAL, + .vlan = skb_vlan_tag_present(skb), +- .qid = skb->mark & MTK_QDMA_TX_MASK, ++ .qid = skb_get_queue_mapping(skb), + .vlan_tci = skb_vlan_tag_get(skb), + .first = true, + .last = !skb_is_nonlinear(skb), + }; ++ struct netdev_queue *txq; + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + const struct mtk_soc_data *soc = eth->soc; +@@ -1152,8 +1226,10 @@ static int mtk_tx_map(struct sk_buff *sk + struct mtk_tx_dma *itxd_pdma, *txd_pdma; + struct mtk_tx_buf *itx_buf, *tx_buf; + int i, n_desc = 1; ++ int queue = skb_get_queue_mapping(skb); + int k = 0; + ++ txq = netdev_get_tx_queue(dev, queue); + itxd = ring->next_free; + itxd_pdma = qdma_to_pdma(ring, itxd); + if (itxd == ring->last_free) +@@ -1202,7 +1278,7 @@ static int mtk_tx_map(struct sk_buff *sk + memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); + txd_info.size = min_t(unsigned int, frag_size, + soc->txrx.dma_max_len); +- txd_info.qid = skb->mark & MTK_QDMA_TX_MASK; ++ txd_info.qid = queue; + txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && + !(frag_size - txd_info.size); + txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, +@@ -1241,7 +1317,7 @@ static int mtk_tx_map(struct sk_buff *sk + txd_pdma->txd2 |= TX_DMA_LS1; + } + +- netdev_sent_queue(dev, skb->len); ++ netdev_tx_sent_queue(txq, skb->len); + skb_tx_timestamp(skb); + + ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); +@@ -1253,8 +1329,7 @@ static int mtk_tx_map(struct sk_buff *sk + wmb(); + + if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { +- if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || +- !netdev_xmit_more()) ++ if (netif_xmit_stopped(txq) || !netdev_xmit_more()) + mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); + } else { + int next_idx; +@@ -1323,7 +1398,7 @@ static void mtk_wake_queue(struct mtk_et + for (i = 0; i < MTK_MAC_COUNT; i++) { + if (!eth->netdev[i]) + continue; +- netif_wake_queue(eth->netdev[i]); ++ netif_tx_wake_all_queues(eth->netdev[i]); + } + } + +@@ -1347,7 +1422,7 @@ static netdev_tx_t mtk_start_xmit(struct + + tx_num = mtk_cal_txd_req(eth, skb); + if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { +- netif_stop_queue(dev); ++ netif_tx_stop_all_queues(dev); + netif_err(eth, tx_queued, dev, + "Tx Ring full when queue awake!\n"); + spin_unlock(ð->page_lock); +@@ -1373,7 +1448,7 @@ static netdev_tx_t mtk_start_xmit(struct + goto drop; + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) +- netif_stop_queue(dev); ++ netif_tx_stop_all_queues(dev); + + spin_unlock(ð->page_lock); + +@@ -1540,10 +1615,12 @@ static int mtk_xdp_submit_frame(struct m + struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); + const struct mtk_soc_data *soc = eth->soc; + struct mtk_tx_ring *ring = ð->tx_ring; ++ struct mtk_mac *mac = netdev_priv(dev); + struct mtk_tx_dma_desc_info txd_info = { + .size = xdpf->len, + .first = true, + .last = !xdp_frame_has_frags(xdpf), ++ .qid = mac->id, + }; + int err, index = 0, n_desc = 1, nr_frags; + struct mtk_tx_dma *htxd, *txd, *txd_pdma; +@@ -1594,6 +1671,7 @@ static int mtk_xdp_submit_frame(struct m + memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); + txd_info.size = skb_frag_size(&sinfo->frags[index]); + txd_info.last = index + 1 == nr_frags; ++ txd_info.qid = mac->id; + data = skb_frag_address(&sinfo->frags[index]); + + index++; +@@ -1945,8 +2023,46 @@ rx_done: + return done; + } + ++struct mtk_poll_state { ++ struct netdev_queue *txq; ++ unsigned int total; ++ unsigned int done; ++ unsigned int bytes; ++}; ++ ++static void ++mtk_poll_tx_done(struct mtk_eth *eth, struct mtk_poll_state *state, u8 mac, ++ struct sk_buff *skb) ++{ ++ struct netdev_queue *txq; ++ struct net_device *dev; ++ unsigned int bytes = skb->len; ++ ++ state->total++; ++ eth->tx_packets++; ++ eth->tx_bytes += bytes; ++ ++ dev = eth->netdev[mac]; ++ if (!dev) ++ return; ++ ++ txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); ++ if (state->txq == txq) { ++ state->done++; ++ state->bytes += bytes; ++ return; ++ } ++ ++ if (state->txq) ++ netdev_tx_completed_queue(state->txq, state->done, state->bytes); ++ ++ state->txq = txq; ++ state->done = 1; ++ state->bytes = bytes; ++} ++ + static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, +- unsigned int *done, unsigned int *bytes) ++ struct mtk_poll_state *state) + { + const struct mtk_reg_map *reg_map = eth->soc->reg_map; + struct mtk_tx_ring *ring = ð->tx_ring; +@@ -1976,12 +2092,9 @@ static int mtk_poll_tx_qdma(struct mtk_e + break; + + if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- if (tx_buf->type == MTK_TYPE_SKB) { +- struct sk_buff *skb = tx_buf->data; ++ if (tx_buf->type == MTK_TYPE_SKB) ++ mtk_poll_tx_done(eth, state, mac, tx_buf->data); + +- bytes[mac] += skb->len; +- done[mac]++; +- } + budget--; + } + mtk_tx_unmap(eth, tx_buf, true); +@@ -1999,7 +2112,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + } + + static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, +- unsigned int *done, unsigned int *bytes) ++ struct mtk_poll_state *state) + { + struct mtk_tx_ring *ring = ð->tx_ring; + struct mtk_tx_buf *tx_buf; +@@ -2015,12 +2128,8 @@ static int mtk_poll_tx_pdma(struct mtk_e + break; + + if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { +- if (tx_buf->type == MTK_TYPE_SKB) { +- struct sk_buff *skb = tx_buf->data; +- +- bytes[0] += skb->len; +- done[0]++; +- } ++ if (tx_buf->type == MTK_TYPE_SKB) ++ mtk_poll_tx_done(eth, state, 0, tx_buf->data); + budget--; + } + mtk_tx_unmap(eth, tx_buf, true); +@@ -2041,26 +2150,15 @@ static int mtk_poll_tx(struct mtk_eth *e + { + struct mtk_tx_ring *ring = ð->tx_ring; + struct dim_sample dim_sample = {}; +- unsigned int done[MTK_MAX_DEVS]; +- unsigned int bytes[MTK_MAX_DEVS]; +- int total = 0, i; +- +- memset(done, 0, sizeof(done)); +- memset(bytes, 0, sizeof(bytes)); ++ struct mtk_poll_state state = {}; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) +- budget = mtk_poll_tx_qdma(eth, budget, done, bytes); ++ budget = mtk_poll_tx_qdma(eth, budget, &state); + else +- budget = mtk_poll_tx_pdma(eth, budget, done, bytes); ++ budget = mtk_poll_tx_pdma(eth, budget, &state); + +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i] || !done[i]) +- continue; +- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]); +- total += done[i]; +- eth->tx_packets += done[i]; +- eth->tx_bytes += bytes[i]; +- } ++ if (state.txq) ++ netdev_tx_completed_queue(state.txq, state.done, state.bytes); + + dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes, + &dim_sample); +@@ -2070,7 +2168,7 @@ static int mtk_poll_tx(struct mtk_eth *e + (atomic_read(&ring->free_count) > ring->thresh)) + mtk_wake_queue(eth); + +- return total; ++ return state.total; + } + + static void mtk_handle_status_irq(struct mtk_eth *eth) +@@ -2156,6 +2254,7 @@ static int mtk_tx_alloc(struct mtk_eth * + int i, sz = soc->txrx.txd_size; + struct mtk_tx_dma_v2 *txd; + int ring_size; ++ u32 ofs, val; + + if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) + ring_size = MTK_QDMA_RING_SIZE; +@@ -2223,8 +2322,25 @@ static int mtk_tx_alloc(struct mtk_eth * + ring->phys + ((ring_size - 1) * sz), + soc->reg_map->qdma.crx_ptr); + mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); +- mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, +- soc->reg_map->qdma.qtx_cfg); ++ ++ for (i = 0, ofs = 0; i < MTK_QDMA_NUM_QUEUES; i++) { ++ val = (QDMA_RES_THRES << 8) | QDMA_RES_THRES; ++ mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs); ++ ++ val = MTK_QTX_SCH_MIN_RATE_EN | ++ /* minimum: 10 Mbps */ ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | ++ MTK_QTX_SCH_LEAKY_BUCKET_SIZE; ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; ++ mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); ++ ofs += MTK_QTX_OFFSET; ++ } ++ val = MTK_QDMA_TX_SCH_MAX_WFQ | (MTK_QDMA_TX_SCH_MAX_WFQ << 16); ++ mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4); + } else { + mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); + mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0); +@@ -2904,7 +3020,7 @@ static int mtk_start_dma(struct mtk_eth + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + val |= MTK_MUTLI_CNT | MTK_RESV_BUF | + MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | +- MTK_CHK_DDONE_EN; ++ MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN; + else + val |= MTK_RX_BT_32DWORDS; + mtk_w32(eth, val, reg_map->qdma.glo_cfg); +@@ -2950,6 +3066,45 @@ static void mtk_gdm_config(struct mtk_et + mtk_w32(eth, 0, MTK_RST_GL); + } + ++static int mtk_device_event(struct notifier_block *n, unsigned long event, void *ptr) ++{ ++ struct mtk_mac *mac = container_of(n, struct mtk_mac, device_notifier); ++ struct mtk_eth *eth = mac->hw; ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ struct ethtool_link_ksettings s; ++ struct net_device *ldev; ++ struct list_head *iter; ++ struct dsa_port *dp; ++ ++ if (event != NETDEV_CHANGE) ++ return NOTIFY_DONE; ++ ++ netdev_for_each_lower_dev(dev, ldev, iter) { ++ if (netdev_priv(ldev) == mac) ++ goto found; ++ } ++ ++ return NOTIFY_DONE; ++ ++found: ++ if (!dsa_slave_dev_check(dev)) ++ return NOTIFY_DONE; ++ ++ if (__ethtool_get_link_ksettings(dev, &s)) ++ return NOTIFY_DONE; ++ ++ if (s.base.speed == 0 || s.base.speed == ((__u32)-1)) ++ return NOTIFY_DONE; ++ ++ dp = dsa_port_from_netdev(dev); ++ if (dp->index >= MTK_QDMA_NUM_QUEUES) ++ return NOTIFY_DONE; ++ ++ mtk_set_queue_speed(eth, dp->index + 3, s.base.speed); ++ ++ return NOTIFY_DONE; ++} ++ + static int mtk_open(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); +@@ -2994,7 +3149,8 @@ static int mtk_open(struct net_device *d + refcount_inc(ð->dma_refcnt); + + phylink_start(mac->phylink); +- netif_start_queue(dev); ++ netif_tx_start_all_queues(dev); ++ + return 0; + } + +@@ -3717,8 +3873,12 @@ static int mtk_unreg_dev(struct mtk_eth + int i; + + for (i = 0; i < MTK_MAC_COUNT; i++) { ++ struct mtk_mac *mac; + if (!eth->netdev[i]) + continue; ++ mac = netdev_priv(eth->netdev[i]); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) ++ unregister_netdevice_notifier(&mac->device_notifier); + unregister_netdev(eth->netdev[i]); + } + +@@ -3935,6 +4095,23 @@ static int mtk_set_rxnfc(struct net_devi + return ret; + } + ++static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb, ++ struct net_device *sb_dev) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ unsigned int queue = 0; ++ ++ if (netdev_uses_dsa(dev)) ++ queue = skb_get_queue_mapping(skb) + 3; ++ else ++ queue = mac->id; ++ ++ if (queue >= dev->num_tx_queues) ++ queue = 0; ++ ++ return queue; ++} ++ + static const struct ethtool_ops mtk_ethtool_ops = { + .get_link_ksettings = mtk_get_link_ksettings, + .set_link_ksettings = mtk_set_link_ksettings, +@@ -3970,6 +4147,7 @@ static const struct net_device_ops mtk_n + .ndo_setup_tc = mtk_eth_setup_tc, + .ndo_bpf = mtk_xdp, + .ndo_xdp_xmit = mtk_xdp_xmit, ++ .ndo_select_queue = mtk_select_queue, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +@@ -3979,6 +4157,7 @@ static int mtk_add_mac(struct mtk_eth *e + struct phylink *phylink; + struct mtk_mac *mac; + int id, err; ++ int txqs = 1; + + if (!_id) { + dev_err(eth->dev, "missing mac id\n"); +@@ -3996,7 +4175,10 @@ static int mtk_add_mac(struct mtk_eth *e + return -EINVAL; + } + +- eth->netdev[id] = alloc_etherdev(sizeof(*mac)); ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) ++ txqs = MTK_QDMA_NUM_QUEUES; ++ ++ eth->netdev[id] = alloc_etherdev_mqs(sizeof(*mac), txqs, 1); + if (!eth->netdev[id]) { + dev_err(eth->dev, "alloc_etherdev failed\n"); + return -ENOMEM; +@@ -4093,6 +4275,11 @@ static int mtk_add_mac(struct mtk_eth *e + else + eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN; + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { ++ mac->device_notifier.notifier_call = mtk_device_event; ++ register_netdevice_notifier(&mac->device_notifier); ++ } ++ + return 0; + + free_netdev: +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -22,6 +22,7 @@ + #include + #include "mtk_ppe.h" + ++#define MTK_QDMA_NUM_QUEUES 16 + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 + #define MTK_MAX_RX_LENGTH_2K 2048 +@@ -215,8 +216,26 @@ + #define MTK_RING_MAX_AGG_CNT_H ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3) + + /* QDMA TX Queue Configuration Registers */ ++#define MTK_QTX_OFFSET 0x10 + #define QDMA_RES_THRES 4 + ++/* QDMA Tx Queue Scheduler Configuration Registers */ ++#define MTK_QTX_SCH_TX_SEL BIT(31) ++#define MTK_QTX_SCH_TX_SEL_V2 GENMASK(31, 30) ++ ++#define MTK_QTX_SCH_LEAKY_BUCKET_EN BIT(30) ++#define MTK_QTX_SCH_LEAKY_BUCKET_SIZE GENMASK(29, 28) ++#define MTK_QTX_SCH_MIN_RATE_EN BIT(27) ++#define MTK_QTX_SCH_MIN_RATE_MAN GENMASK(26, 20) ++#define MTK_QTX_SCH_MIN_RATE_EXP GENMASK(19, 16) ++#define MTK_QTX_SCH_MAX_RATE_WEIGHT GENMASK(15, 12) ++#define MTK_QTX_SCH_MAX_RATE_EN BIT(11) ++#define MTK_QTX_SCH_MAX_RATE_MAN GENMASK(10, 4) ++#define MTK_QTX_SCH_MAX_RATE_EXP GENMASK(3, 0) ++ ++/* QDMA TX Scheduler Rate Control Register */ ++#define MTK_QDMA_TX_SCH_MAX_WFQ BIT(15) ++ + /* QDMA Global Configuration Register */ + #define MTK_RX_2B_OFFSET BIT(31) + #define MTK_RX_BT_32DWORDS (3 << 11) +@@ -235,6 +254,7 @@ + #define MTK_WCOMP_EN BIT(24) + #define MTK_RESV_BUF (0x40 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) ++#define MTK_LEAKY_BUCKET_EN BIT(11) + + /* QDMA Flow Control Register */ + #define FC_THRES_DROP_MODE BIT(20) +@@ -265,8 +285,6 @@ + #define MTK_STAT_OFFSET 0x40 + + /* QDMA TX NUM */ +-#define MTK_QDMA_TX_NUM 16 +-#define MTK_QDMA_TX_MASK (MTK_QDMA_TX_NUM - 1) + #define QID_BITS_V2(x) (((x) & 0x3f) << 16) + #define MTK_QDMA_GMAC2_QID 8 + +@@ -296,6 +314,7 @@ + #define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) + #define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len) + #define TX_DMA_SWC BIT(14) ++#define TX_DMA_PQID GENMASK(3, 0) + + /* PDMA on MT7628 */ + #define TX_DMA_DONE BIT(31) +@@ -953,6 +972,7 @@ struct mtk_reg_map { + } pdma; + struct { + u32 qtx_cfg; /* tx queue configuration */ ++ u32 qtx_sch; /* tx queue scheduler configuration */ + u32 rx_ptr; /* rx base pointer */ + u32 rx_cnt_cfg; /* rx max count configuration */ + u32 qcrx_ptr; /* rx cpu pointer */ +@@ -970,6 +990,7 @@ struct mtk_reg_map { + u32 fq_tail; /* fq tail pointer */ + u32 fq_count; /* fq free page count */ + u32 fq_blen; /* fq free page buffer length */ ++ u32 tx_sch_rate; /* tx scheduler rate control registers */ + } qdma; + u32 gdm1_cnt; + u32 gdma_to_ppe0; +@@ -1173,6 +1194,7 @@ struct mtk_mac { + __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; + int hwlro_ip_cnt; + unsigned int syscfg0; ++ struct notifier_block device_notifier; + }; + + /* the struct describing the SoC. these are declared in the soc_xyz.c files */ diff --git a/target/linux/generic/backport-6.1/730-05-v6.3-net-dsa-tag_mtk-assign-per-port-queues.patch b/target/linux/generic/backport-6.1/730-05-v6.3-net-dsa-tag_mtk-assign-per-port-queues.patch new file mode 100644 index 00000000000..186df4bdc92 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-05-v6.3-net-dsa-tag_mtk-assign-per-port-queues.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau +Date: Fri, 28 Oct 2022 18:16:03 +0200 +Subject: [PATCH] net: dsa: tag_mtk: assign per-port queues + +Keeps traffic sent to the switch within link speed limits + +Signed-off-by: Felix Fietkau +--- + +--- a/net/dsa/tag_mtk.c ++++ b/net/dsa/tag_mtk.c +@@ -25,6 +25,8 @@ static struct sk_buff *mtk_tag_xmit(stru + u8 xmit_tpid; + u8 *mtk_tag; + ++ skb_set_queue_mapping(skb, dp->index); ++ + /* Build the special tag after the MAC Source Address. If VLAN header + * is present, it's required that VLAN header and special tag is + * being combined. Only in this way we can allow the switch can parse diff --git a/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch b/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch new file mode 100644 index 00000000000..8935eb673ae --- /dev/null +++ b/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch @@ -0,0 +1,93 @@ +From: Felix Fietkau +Date: Thu, 3 Nov 2022 17:49:44 +0100 +Subject: [PATCH] net: ethernet: mediatek: ppe: assign per-port queues + for offloaded traffic + +Keeps traffic sent to the switch within link speed limits + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -405,6 +405,24 @@ static inline bool mtk_foe_entry_usable( + FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; + } + ++int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ unsigned int queue) ++{ ++ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ *ib2 &= ~MTK_FOE_IB2_QID_V2; ++ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID_V2, queue); ++ *ib2 |= MTK_FOE_IB2_PSE_QOS_V2; ++ } else { ++ *ib2 &= ~MTK_FOE_IB2_QID; ++ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, queue); ++ *ib2 |= MTK_FOE_IB2_PSE_QOS; ++ } ++ ++ return 0; ++} ++ + static bool + mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, + struct mtk_foe_entry *data) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -68,7 +68,9 @@ enum { + #define MTK_FOE_IB2_DSCP GENMASK(31, 24) + + /* CONFIG_MEDIATEK_NETSYS_V2 */ ++#define MTK_FOE_IB2_QID_V2 GENMASK(6, 0) + #define MTK_FOE_IB2_PORT_MG_V2 BIT(7) ++#define MTK_FOE_IB2_PSE_QOS_V2 BIT(8) + #define MTK_FOE_IB2_DEST_PORT_V2 GENMASK(12, 9) + #define MTK_FOE_IB2_MULTICAST_V2 BIT(13) + #define MTK_FOE_IB2_WDMA_WINFO_V2 BIT(19) +@@ -351,6 +353,8 @@ int mtk_foe_entry_set_pppoe(struct mtk_e + int sid); + int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, + int wdma_idx, int txq, int bss, int wcid); ++int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, ++ unsigned int queue); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -188,7 +188,7 @@ mtk_flow_set_output_device(struct mtk_et + int *wed_index) + { + struct mtk_wdma_info info = {}; +- int pse_port, dsa_port; ++ int pse_port, dsa_port, queue; + + if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { + mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue, +@@ -212,8 +212,6 @@ mtk_flow_set_output_device(struct mtk_et + } + + dsa_port = mtk_flow_get_dsa_port(&dev); +- if (dsa_port >= 0) +- mtk_foe_entry_set_dsa(eth, foe, dsa_port); + + if (dev == eth->netdev[0]) + pse_port = 1; +@@ -222,6 +220,14 @@ mtk_flow_set_output_device(struct mtk_et + else + return -EOPNOTSUPP; + ++ if (dsa_port >= 0) { ++ mtk_foe_entry_set_dsa(eth, foe, dsa_port); ++ queue = 3 + dsa_port; ++ } else { ++ queue = pse_port - 1; ++ } ++ mtk_foe_entry_set_queue(eth, foe, queue); ++ + out: + mtk_foe_entry_set_pse_port(eth, foe, pse_port); + diff --git a/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch b/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch new file mode 100644 index 00000000000..44af9128b75 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau +Date: Thu, 27 Oct 2022 23:39:52 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: compile out netsys v2 code + on mt7621 + +Avoid some branches in the hot path on low-end devices with limited CPU power, +and reduce code size + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -917,7 +917,13 @@ enum mkt_eth_capabilities { + #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) + +-#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x)) ++#ifdef CONFIG_SOC_MT7621 ++#define MTK_CAP_MASK MTK_NETSYS_V2 ++#else ++#define MTK_CAP_MASK 0 ++#endif ++ ++#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x) & ~(MTK_CAP_MASK)) == (_x)) + + #define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ + MTK_GMAC2_RGMII | MTK_SHARED_INT | \ diff --git a/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch new file mode 100644 index 00000000000..0478cb528e2 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch @@ -0,0 +1,72 @@ +From: Felix Fietkau +Date: Tue, 8 Nov 2022 15:03:15 +0100 +Subject: [PATCH] net: dsa: add support for DSA rx offloading via + metadata dst + +If a metadata dst is present with the type METADATA_HW_PORT_MUX on a dsa cpu +port netdev, assume that it carries the port number and that there is no DSA +tag present in the skb data. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -940,12 +940,14 @@ bool __skb_flow_dissect(const struct net + #if IS_ENABLED(CONFIG_NET_DSA) + if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) && + proto == htons(ETH_P_XDSA))) { ++ struct metadata_dst *md_dst = skb_metadata_dst(skb); + const struct dsa_device_ops *ops; + int offset = 0; + + ops = skb->dev->dsa_ptr->tag_ops; + /* Only DSA header taggers break flow dissection */ +- if (ops->needed_headroom) { ++ if (ops->needed_headroom && ++ (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)) { + if (ops->flow_dissect) + ops->flow_dissect(skb, &proto, &offset); + else +--- a/net/dsa/dsa.c ++++ b/net/dsa/dsa.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "dsa_priv.h" + +@@ -225,6 +226,7 @@ static bool dsa_skb_defer_rx_timestamp(s + static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *unused) + { ++ struct metadata_dst *md_dst = skb_metadata_dst(skb); + struct dsa_port *cpu_dp = dev->dsa_ptr; + struct sk_buff *nskb = NULL; + struct dsa_slave_priv *p; +@@ -238,7 +240,22 @@ static int dsa_switch_rcv(struct sk_buff + if (!skb) + return 0; + +- nskb = cpu_dp->rcv(skb, dev); ++ if (md_dst && md_dst->type == METADATA_HW_PORT_MUX) { ++ unsigned int port = md_dst->u.port_info.port_id; ++ ++ skb_dst_drop(skb); ++ if (!skb_has_extensions(skb)) ++ skb->slow_gro = 0; ++ ++ skb->dev = dsa_master_find_slave(dev, 0, port); ++ if (likely(skb->dev)) { ++ dsa_default_offload_fwd_mark(skb); ++ nskb = skb; ++ } ++ } else { ++ nskb = cpu_dp->rcv(skb, dev); ++ } ++ + if (!nskb) { + kfree_skb(skb); + return 0; diff --git a/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch b/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch new file mode 100644 index 00000000000..beba07238fd --- /dev/null +++ b/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch @@ -0,0 +1,192 @@ +From: Felix Fietkau +Date: Fri, 28 Oct 2022 11:01:12 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix VLAN rx hardware + acceleration + +- enable VLAN untagging for PDMA rx +- make it possible to disable the feature via ethtool +- pass VLAN tag to the DSA driver +- untag special tag on PDMA only if no non-DSA devices are in use +- disable special tag untagging on 7986 for now, since it's not working yet + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include "mtk_eth_soc.h" + #include "mtk_wed.h" +@@ -1974,16 +1975,22 @@ static int mtk_poll_rx(struct napi_struc + htons(RX_DMA_VPID(trxd.rxd4)), + RX_DMA_VID(trxd.rxd4)); + } else if (trxd.rxd2 & RX_DMA_VTAG) { +- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ++ __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)), + RX_DMA_VID(trxd.rxd3)); + } ++ } ++ ++ /* When using VLAN untagging in combination with DSA, the ++ * hardware treats the MTK special tag as a VLAN and untags it. ++ */ ++ if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) { ++ unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0); + +- /* If the device is attached to a dsa switch, the special +- * tag inserted in VLAN field by hw switch can * be offloaded +- * by RX HW VLAN offload. Clear vlan info. +- */ +- if (netdev_uses_dsa(netdev)) +- __vlan_hwaccel_clear_tag(skb); ++ if (port < ARRAY_SIZE(eth->dsa_meta) && ++ eth->dsa_meta[port]) ++ skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); ++ ++ __vlan_hwaccel_clear_tag(skb); + } + + skb_record_rx_queue(skb, 0); +@@ -2800,15 +2807,30 @@ static netdev_features_t mtk_fix_feature + + static int mtk_set_features(struct net_device *dev, netdev_features_t features) + { +- int err = 0; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ netdev_features_t diff = dev->features ^ features; ++ int i; ++ ++ if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO)) ++ mtk_hwlro_netdev_disable(dev); + +- if (!((dev->features ^ features) & NETIF_F_LRO)) ++ /* Set RX VLAN offloading */ ++ if (!(diff & NETIF_F_HW_VLAN_CTAG_RX)) + return 0; + +- if (!(features & NETIF_F_LRO)) +- mtk_hwlro_netdev_disable(dev); ++ mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX), ++ MTK_CDMP_EG_CTRL); + +- return err; ++ /* sync features with other MAC */ ++ for (i = 0; i < MTK_MAC_COUNT; i++) { ++ if (!eth->netdev[i] || eth->netdev[i] == dev) ++ continue; ++ eth->netdev[i]->features &= ~NETIF_F_HW_VLAN_CTAG_RX; ++ eth->netdev[i]->features |= features & NETIF_F_HW_VLAN_CTAG_RX; ++ } ++ ++ return 0; + } + + /* wait for DMA to finish whatever it is doing before we start using it again */ +@@ -3105,11 +3127,45 @@ found: + return NOTIFY_DONE; + } + ++static bool mtk_uses_dsa(struct net_device *dev) ++{ ++#if IS_ENABLED(CONFIG_NET_DSA) ++ return netdev_uses_dsa(dev) && ++ dev->dsa_ptr->tag_ops->proto == DSA_TAG_PROTO_MTK; ++#else ++ return false; ++#endif ++} ++ + static int mtk_open(struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; +- int err; ++ int i, err; ++ ++ if (mtk_uses_dsa(dev) && !eth->prog) { ++ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { ++ struct metadata_dst *md_dst = eth->dsa_meta[i]; ++ ++ if (md_dst) ++ continue; ++ ++ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, ++ GFP_KERNEL); ++ if (!md_dst) ++ return -ENOMEM; ++ ++ md_dst->u.port_info.port_id = i; ++ eth->dsa_meta[i] = md_dst; ++ } ++ } else { ++ /* Hardware special tag parsing needs to be disabled if at least ++ * one MAC does not use DSA. ++ */ ++ u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); ++ val &= ~MTK_CDMP_STAG_EN; ++ mtk_w32(eth, val, MTK_CDMP_IG_CTRL); ++ } + + err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); + if (err) { +@@ -3632,6 +3688,10 @@ static int mtk_hw_init(struct mtk_eth *e + */ + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ val = mtk_r32(eth, MTK_CDMP_IG_CTRL); ++ mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); ++ } + + /* Enable RX VLan Offloading */ + mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); +@@ -3865,6 +3925,12 @@ static int mtk_free_dev(struct mtk_eth * + free_netdev(eth->netdev[i]); + } + ++ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { ++ if (!eth->dsa_meta[i]) ++ break; ++ metadata_dst_free(eth->dsa_meta[i]); ++ } ++ + return 0; + } + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -22,6 +22,9 @@ + #include + #include "mtk_ppe.h" + ++#define MTK_MAX_DSA_PORTS 7 ++#define MTK_DSA_PORT_MASK GENMASK(2, 0) ++ + #define MTK_QDMA_NUM_QUEUES 16 + #define MTK_QDMA_PAGE_SIZE 2048 + #define MTK_MAX_RX_LENGTH 1536 +@@ -105,6 +108,9 @@ + #define MTK_CDMQ_IG_CTRL 0x1400 + #define MTK_CDMQ_STAG_EN BIT(0) + ++/* CDMQ Exgress Control Register */ ++#define MTK_CDMQ_EG_CTRL 0x1404 ++ + /* CDMP Ingress Control Register */ + #define MTK_CDMP_IG_CTRL 0x400 + #define MTK_CDMP_STAG_EN BIT(0) +@@ -1166,6 +1172,8 @@ struct mtk_eth { + + int ip_align; + ++ struct metadata_dst *dsa_meta[MTK_MAX_DSA_PORTS]; ++ + struct mtk_ppe *ppe[2]; + struct rhashtable flow_table; + diff --git a/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch b/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch new file mode 100644 index 00000000000..0bf48b07800 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch @@ -0,0 +1,37 @@ +From: Felix Fietkau +Date: Thu, 3 Nov 2022 17:46:25 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: drop packets to WDMA if the + ring is full + +Improves handling of DMA ring overflow. +Clarify other WDMA drop related comment. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3712,9 +3712,12 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +- /* PSE should not drop port8 and port9 packets */ ++ /* PSE should not drop port8 and port9 packets from WDMA Tx */ + mtk_w32(eth, 0x00000300, PSE_DROP_CFG); + ++ /* PSE should drop packets to port 8/9 on WDMA Rx ring full */ ++ mtk_w32(eth, 0x00000300, PSE_PPE0_DROP); ++ + /* PSE Free Queue Flow Control */ + mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -140,6 +140,7 @@ + #define PSE_FQFC_CFG1 0x100 + #define PSE_FQFC_CFG2 0x104 + #define PSE_DROP_CFG 0x108 ++#define PSE_PPE0_DROP 0x110 + + /* PSE Input Queue Reservation Register*/ + #define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) diff --git a/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch b/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch new file mode 100644 index 00000000000..08bf608bc12 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch @@ -0,0 +1,42 @@ +From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= +Date: Sat, 28 Jan 2023 12:42:32 +0300 +Subject: [PATCH] net: ethernet: mtk_eth_soc: disable hardware DSA untagging + for second MAC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to my tests on MT7621AT and MT7623NI SoCs, hardware DSA untagging +won't work on the second MAC. Therefore, disable this feature when the +second MAC of the MT7621 and MT7623 SoCs is being used. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Link: https://lore.kernel.org/netdev/6249fc14-b38a-c770-36b4-5af6d41c21d3@arinc9.com/ +Tested-by: Arınç ÜNAL +Signed-off-by: Arınç ÜNAL +Link: https://lore.kernel.org/r/20230128094232.2451947-1-arinc.unal@arinc9.com +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3143,7 +3143,8 @@ static int mtk_open(struct net_device *d + struct mtk_eth *eth = mac->hw; + int i, err; + +- if (mtk_uses_dsa(dev) && !eth->prog) { ++ if ((mtk_uses_dsa(dev) && !eth->prog) && ++ !(mac->id == 1 && MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_TRGMII))) { + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + struct metadata_dst *md_dst = eth->dsa_meta[i]; + +@@ -3160,7 +3161,8 @@ static int mtk_open(struct net_device *d + } + } else { + /* Hardware special tag parsing needs to be disabled if at least +- * one MAC does not use DSA. ++ * one MAC does not use DSA, or the second MAC of the MT7621 and ++ * MT7623 SoCs is being used. + */ + u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + val &= ~MTK_CDMP_STAG_EN; diff --git a/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch b/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch new file mode 100644 index 00000000000..efab99ada00 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch @@ -0,0 +1,54 @@ +From: =?UTF-8?q?Ar=C4=B1n=C3=A7=20=C3=9CNAL?= +Date: Sun, 5 Feb 2023 20:53:31 +0300 +Subject: [PATCH] net: ethernet: mtk_eth_soc: enable special tag when any MAC + uses DSA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The special tag is only enabled when the first MAC uses DSA. However, it +must be enabled when any MAC uses DSA. Change the check accordingly. + +This fixes hardware DSA untagging not working on the second MAC of the +MT7621 and MT7623 SoCs, and likely other SoCs too. Therefore, remove the +check that disables hardware DSA untagging for the second MAC of the MT7621 +and MT7623 SoCs. + +Fixes: a1f47752fd62 ("net: ethernet: mtk_eth_soc: disable hardware DSA untagging for second MAC") +Co-developed-by: Richard van Schagen +Signed-off-by: Richard van Schagen +Signed-off-by: Arınç ÜNAL +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3078,7 +3078,7 @@ static void mtk_gdm_config(struct mtk_et + + val |= config; + +- if (!i && eth->netdev[0] && netdev_uses_dsa(eth->netdev[0])) ++ if (eth->netdev[i] && netdev_uses_dsa(eth->netdev[i])) + val |= MTK_GDMA_SPECIAL_TAG; + + mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); +@@ -3143,8 +3143,7 @@ static int mtk_open(struct net_device *d + struct mtk_eth *eth = mac->hw; + int i, err; + +- if ((mtk_uses_dsa(dev) && !eth->prog) && +- !(mac->id == 1 && MTK_HAS_CAPS(eth->soc->caps, MTK_GMAC1_TRGMII))) { ++ if (mtk_uses_dsa(dev) && !eth->prog) { + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { + struct metadata_dst *md_dst = eth->dsa_meta[i]; + +@@ -3161,8 +3160,7 @@ static int mtk_open(struct net_device *d + } + } else { + /* Hardware special tag parsing needs to be disabled if at least +- * one MAC does not use DSA, or the second MAC of the MT7621 and +- * MT7623 SoCs is being used. ++ * one MAC does not use DSA. + */ + u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + val &= ~MTK_CDMP_STAG_EN; diff --git a/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch b/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch new file mode 100644 index 00000000000..c392429b887 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch @@ -0,0 +1,129 @@ +From: Vladimir Oltean +Date: Tue, 7 Feb 2023 12:30:27 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix DSA TX tag hwaccel for switch + port 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Arınç reports that on his MT7621AT Unielec U7621-06 board and MT7623NI +Bananapi BPI-R2, packets received by the CPU over mt7530 switch port 0 +(of which this driver acts as the DSA master) are not processed +correctly by software. More precisely, they arrive without a DSA tag +(in packet or in the hwaccel area - skb_metadata_dst()), so DSA cannot +demux them towards the switch's interface for port 0. Traffic from other +ports receives a skb_metadata_dst() with the correct port and is demuxed +properly. + +Looking at mtk_poll_rx(), it becomes apparent that this driver uses the +skb vlan hwaccel area: + + union { + u32 vlan_all; + struct { + __be16 vlan_proto; + __u16 vlan_tci; + }; + }; + +as a temporary storage for the VLAN hwaccel tag, or the DSA hwaccel tag. +If this is a DSA master it's a DSA hwaccel tag, and finally clears up +the skb VLAN hwaccel header. + +I'm guessing that the problem is the (mis)use of API. +skb_vlan_tag_present() looks like this: + + #define skb_vlan_tag_present(__skb) (!!(__skb)->vlan_all) + +So if both vlan_proto and vlan_tci are zeroes, skb_vlan_tag_present() +returns precisely false. I don't know for sure what is the format of the +DSA hwaccel tag, but I surely know that lowermost 3 bits of vlan_proto +are 0 when receiving from port 0: + + unsigned int port = vlan_proto & GENMASK(2, 0); + +If the RX descriptor has no other bits set to non-zero values in +RX_DMA_VTAG, then the call to __vlan_hwaccel_put_tag() will not, in +fact, make the subsequent skb_vlan_tag_present() return true, because +it's implemented like this: + +static inline void __vlan_hwaccel_put_tag(struct sk_buff *skb, + __be16 vlan_proto, u16 vlan_tci) +{ + skb->vlan_proto = vlan_proto; + skb->vlan_tci = vlan_tci; +} + +What we need to do to fix this problem (assuming this is the problem) is +to stop using skb->vlan_all as temporary storage for driver affairs, and +just create some local variables that serve the same purpose, but +hopefully better. Instead of calling skb_vlan_tag_present(), let's look +at a boolean has_hwaccel_tag which we set to true when the RX DMA +descriptors have something. Disambiguate based on netdev_uses_dsa() +whether this is a VLAN or DSA hwaccel tag, and only call +__vlan_hwaccel_put_tag() if we're certain it's a VLAN tag. + +Arınç confirms that the treatment works, so this validates the +assumption. + +Link: https://lore.kernel.org/netdev/704f3a72-fc9e-714a-db54-272e17612637@arinc9.com/ +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Reported-by: Arınç ÜNAL +Tested-by: Arınç ÜNAL +Signed-off-by: Vladimir Oltean +Reviewed-by: Felix Fietkau +Signed-off-by: David S. Miller +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1830,7 +1830,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; ++ bool has_hwaccel_tag = false; + struct net_device *netdev; ++ u16 vlan_proto, vlan_tci; + dma_addr_t dma_addr; + u32 hash, reason; + int mac = 0; +@@ -1970,27 +1972,29 @@ static int mtk_poll_rx(struct napi_struc + + if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +- if (trxd.rxd3 & RX_DMA_VTAG_V2) +- __vlan_hwaccel_put_tag(skb, +- htons(RX_DMA_VPID(trxd.rxd4)), +- RX_DMA_VID(trxd.rxd4)); ++ if (trxd.rxd3 & RX_DMA_VTAG_V2) { ++ vlan_proto = RX_DMA_VPID(trxd.rxd4); ++ vlan_tci = RX_DMA_VID(trxd.rxd4); ++ has_hwaccel_tag = true; ++ } + } else if (trxd.rxd2 & RX_DMA_VTAG) { +- __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)), +- RX_DMA_VID(trxd.rxd3)); ++ vlan_proto = RX_DMA_VPID(trxd.rxd3); ++ vlan_tci = RX_DMA_VID(trxd.rxd3); ++ has_hwaccel_tag = true; + } + } + + /* When using VLAN untagging in combination with DSA, the + * hardware treats the MTK special tag as a VLAN and untags it. + */ +- if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) { +- unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0); ++ if (has_hwaccel_tag && netdev_uses_dsa(netdev)) { ++ unsigned int port = vlan_proto & GENMASK(2, 0); + + if (port < ARRAY_SIZE(eth->dsa_meta) && + eth->dsa_meta[port]) + skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); +- +- __vlan_hwaccel_clear_tag(skb); ++ } else if (has_hwaccel_tag) { ++ __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci); + } + + skb_record_rx_queue(skb, 0); diff --git a/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch b/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch new file mode 100644 index 00000000000..74a77ddaca2 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch @@ -0,0 +1,26 @@ +From: Christophe JAILLET +Date: Sun, 12 Feb 2023 07:51:51 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: No need to clear memory after a + dma_alloc_coherent() call + +dma_alloc_coherent() already clears the allocated memory, there is no need +to explicitly call memset(). + +Moreover, it is likely that the size in the memset() is incorrect and +should be "size * sizeof(*ring->desc)". + +Signed-off-by: Christophe JAILLET +Link: https://lore.kernel.org/r/d5acce7dd108887832c9719f62c7201b4c83b3fb.1676184599.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -786,7 +786,6 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_de + + ring->desc_size = sizeof(*ring->desc); + ring->size = size; +- memset(ring->desc, 0, size); + + return 0; + } diff --git a/target/linux/generic/backport-6.1/730-16-v6.3-net-ethernet-mtk_wed-fix-some-possible-NULL-pointer-.patch b/target/linux/generic/backport-6.1/730-16-v6.3-net-ethernet-mtk_wed-fix-some-possible-NULL-pointer-.patch new file mode 100644 index 00000000000..e043a681da4 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-16-v6.3-net-ethernet-mtk_wed-fix-some-possible-NULL-pointer-.patch @@ -0,0 +1,61 @@ +From: Lorenzo Bianconi +Date: Wed, 7 Dec 2022 15:04:54 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: fix some possible NULL pointer + dereferences + +Fix possible NULL pointer dereference in mtk_wed_detach routine checking +wo pointer is properly allocated before running mtk_wed_wo_reset() and +mtk_wed_wo_deinit(). +Even if it is just a theoretical issue at the moment check wo pointer is +not NULL in mtk_wed_mcu_msg_update. +Moreover, honor mtk_wed_mcu_send_msg return value in mtk_wed_wo_reset() + +Fixes: 799684448e3e ("net: ethernet: mtk_wed: introduce wed wo support") +Fixes: 4c5de09eb0d0 ("net: ethernet: mtk_wed: add configure wed wo support") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Leon Romanovsky +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -174,9 +174,10 @@ mtk_wed_wo_reset(struct mtk_wed_device * + mtk_wdma_tx_reset(dev); + mtk_wed_reset(dev, MTK_WED_RESET_WED); + +- mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, +- MTK_WED_WO_CMD_CHANGE_STATE, &state, +- sizeof(state), false); ++ if (mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, ++ MTK_WED_WO_CMD_CHANGE_STATE, &state, ++ sizeof(state), false)) ++ return; + + if (readx_poll_timeout(mtk_wed_wo_read_status, dev, val, + val == MTK_WED_WOIF_DISABLE_DONE, +@@ -632,9 +633,11 @@ mtk_wed_detach(struct mtk_wed_device *de + mtk_wed_free_tx_rings(dev); + + if (mtk_wed_get_rx_capa(dev)) { +- mtk_wed_wo_reset(dev); ++ if (hw->wed_wo) ++ mtk_wed_wo_reset(dev); + mtk_wed_free_rx_rings(dev); +- mtk_wed_wo_deinit(hw); ++ if (hw->wed_wo) ++ mtk_wed_wo_deinit(hw); + } + + if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -207,6 +207,9 @@ int mtk_wed_mcu_msg_update(struct mtk_we + if (dev->hw->version == 1) + return 0; + ++ if (WARN_ON(!wo)) ++ return -ENODEV; ++ + return mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO, id, data, len, + true); + } diff --git a/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch b/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch new file mode 100644 index 00000000000..d1c5fb6656d --- /dev/null +++ b/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch @@ -0,0 +1,58 @@ +From: Lorenzo Bianconi +Date: Wed, 7 Dec 2022 15:04:55 +0100 +Subject: [PATCH] net: ethernet: mtk_wed: fix possible deadlock if + mtk_wed_wo_init fails + +Introduce __mtk_wed_detach() in order to avoid a deadlock in +mtk_wed_attach routine if mtk_wed_wo_init fails since both +mtk_wed_attach and mtk_wed_detach run holding hw_lock mutex. + +Fixes: 4c5de09eb0d0 ("net: ethernet: mtk_wed: add configure wed wo support") +Signed-off-by: Lorenzo Bianconi +Reviewed-by: Leon Romanovsky +Signed-off-by: Jakub Kicinski +--- + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -619,12 +619,10 @@ mtk_wed_deinit(struct mtk_wed_device *de + } + + static void +-mtk_wed_detach(struct mtk_wed_device *dev) ++__mtk_wed_detach(struct mtk_wed_device *dev) + { + struct mtk_wed_hw *hw = dev->hw; + +- mutex_lock(&hw_lock); +- + mtk_wed_deinit(dev); + + mtk_wdma_rx_reset(dev); +@@ -657,6 +655,13 @@ mtk_wed_detach(struct mtk_wed_device *de + module_put(THIS_MODULE); + + hw->wed_dev = NULL; ++} ++ ++static void ++mtk_wed_detach(struct mtk_wed_device *dev) ++{ ++ mutex_lock(&hw_lock); ++ __mtk_wed_detach(dev); + mutex_unlock(&hw_lock); + } + +@@ -1545,8 +1550,10 @@ mtk_wed_attach(struct mtk_wed_device *de + ret = mtk_wed_wo_init(hw); + } + out: +- if (ret) +- mtk_wed_detach(dev); ++ if (ret) { ++ dev_err(dev->hw->dev, "failed to attach wed device\n"); ++ __mtk_wed_detach(dev); ++ } + unlock: + mutex_unlock(&hw_lock); + diff --git a/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch b/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch new file mode 100644 index 00000000000..e633f6f1fb8 --- /dev/null +++ b/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch @@ -0,0 +1,31 @@ +From: Felix Fietkau +Date: Fri, 24 Mar 2023 14:56:58 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix tx throughput regression with + direct 1G links + +Using the QDMA tx scheduler to throttle tx to line speed works fine for +switch ports, but apparently caused a regression on non-switch ports. + +Based on a number of tests, it seems that this throttling can be safely +dropped without re-introducing the issues on switch ports that the +tx scheduling changes resolved. + +Link: https://lore.kernel.org/netdev/trinity-92c3826f-c2c8-40af-8339-bc6d0d3ffea4-1678213958520@3c-app-gmx-bs16/ +Fixes: f63959c7eec3 ("net: ethernet: mtk_eth_soc: implement multi-queue support for per-port queues") +Reported-by: Frank Wunderlich +Reported-by: Daniel Golle +Tested-by: Daniel Golle +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -676,8 +676,6 @@ static void mtk_mac_link_up(struct phyli + break; + } + +- mtk_set_queue_speed(mac->hw, mac->id, speed); +- + /* Configure duplex */ + if (duplex == DUPLEX_FULL) + mcr |= MAC_MCR_FORCE_DPX; diff --git a/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch b/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch new file mode 100644 index 00000000000..460c5c23178 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch @@ -0,0 +1,60 @@ +From f3eceaed9edd7c0e0d9fb057613131f92973626f Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Fri, 27 Jan 2023 14:38:54 -0800 +Subject: [PATCH] net: ethernet: mtk_eth_soc: Avoid truncating allocation + +There doesn't appear to be a reason to truncate the allocation used for +flow_info, so do a full allocation and remove the unused empty struct. +GCC does not like having a reference to an object that has been +partially allocated, as bounds checking may become impossible when +such an object is passed to other code. Seen with GCC 13: + +../drivers/net/ethernet/mediatek/mtk_ppe.c: In function 'mtk_foe_entry_commit_subflow': +../drivers/net/ethernet/mediatek/mtk_ppe.c:623:18: warning: array subscript 'struct mtk_flow_entry[0]' is partly outside array bounds of 'unsigned char[48]' [-Warray-bounds=] + 623 | flow_info->l2_data.base_flow = entry; + | ^~ + +Cc: Felix Fietkau +Cc: John Crispin +Cc: Sean Wang +Cc: Mark Lee +Cc: Lorenzo Bianconi +Cc: "David S. Miller" +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: Matthias Brugger +Cc: netdev@vger.kernel.org +Cc: linux-arm-kernel@lists.infradead.org +Cc: linux-mediatek@lists.infradead.org +Signed-off-by: Kees Cook +Reviewed-by: Simon Horman +Link: https://lore.kernel.org/r/20230127223853.never.014-kees@kernel.org +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/mediatek/mtk_ppe.c | 3 +-- + drivers/net/ethernet/mediatek/mtk_ppe.h | 1 - + 2 files changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -621,8 +621,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ + u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + +- flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), +- GFP_ATOMIC); ++ flow_info = kzalloc(sizeof(*flow_info), GFP_ATOMIC); + if (!flow_info) + return; + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -279,7 +279,6 @@ struct mtk_flow_entry { + struct { + struct mtk_flow_entry *base_flow; + struct hlist_node list; +- struct {} end; + } l2_data; + }; + struct rhash_head node; diff --git a/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch b/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch new file mode 100644 index 00000000000..68f3659367a --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch @@ -0,0 +1,55 @@ +From b6a709cb51f7bdc55c01cec886098a9753ce8c28 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:42 +0100 +Subject: [PATCH 01/10] net: mtk_eth_soc: add definitions for PCS + +As a result of help from Frank Wunderlich to investigate and test, we +know a bit more about the PCS on the Mediatek platforms. Update the +definitions from this investigation. + +This PCS appears similar, but not identical to the Lynx PCS. + +Although not included in this patch, but for future reference, the PHY +ID registers at offset 4 read as 0x4d544950 'MTIP'. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -501,8 +501,10 @@ + #define ETHSYS_DMA_AG_MAP_PPE BIT(2) + + /* SGMII subsystem config registers */ +-/* Register to auto-negotiation restart */ ++/* BMCR (low 16) BMSR (high 16) */ + #define SGMSYS_PCS_CONTROL_1 0x0 ++#define SGMII_BMCR GENMASK(15, 0) ++#define SGMII_BMSR GENMASK(31, 16) + #define SGMII_AN_RESTART BIT(9) + #define SGMII_ISOLATE BIT(10) + #define SGMII_AN_ENABLE BIT(12) +@@ -512,13 +514,18 @@ + #define SGMII_PCS_FAULT BIT(23) + #define SGMII_AN_EXPANSION_CLR BIT(30) + ++#define SGMSYS_PCS_ADVERTISE 0x8 ++#define SGMII_ADVERTISE GENMASK(15, 0) ++#define SGMII_LPA GENMASK(31, 16) ++ + /* Register to programmable link timer, the unit in 2 * 8ns */ + #define SGMSYS_PCS_LINK_TIMER 0x18 +-#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & GENMASK(19, 0)) ++#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) ++#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & SGMII_LINK_TIMER_MASK) + + /* Register to control remote fault */ + #define SGMSYS_SGMII_MODE 0x20 +-#define SGMII_IF_MODE_BIT0 BIT(0) ++#define SGMII_IF_MODE_SGMII BIT(0) + #define SGMII_SPEED_DUPLEX_AN BIT(1) + #define SGMII_SPEED_MASK GENMASK(3, 2) + #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) diff --git a/target/linux/generic/backport-6.1/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch b/target/linux/generic/backport-6.1/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch new file mode 100644 index 00000000000..4ea428c9d6b --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-03-net-mtk_eth_soc-eliminate-unnecessary-error-handling.patch @@ -0,0 +1,74 @@ +From 5cf7797526ee81bea0f627bccaa3d887f48f53e0 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:47 +0100 +Subject: [PATCH 02/10] net: mtk_eth_soc: eliminate unnecessary error handling + +The functions called by the pcs_config() method always return zero, so +there is no point trying to handle an error from these functions. Make +these functions void, eliminate the "err" variable and simply return +zero from the pcs_config() function itself. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -20,7 +20,7 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st + } + + /* For SGMII interface mode */ +-static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) ++static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { + unsigned int val; + +@@ -39,16 +39,13 @@ static int mtk_pcs_setup_mode_an(struct + regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- +- return 0; +- + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a + * fixed speed. + */ +-static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, +- phy_interface_t interface) ++static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, ++ phy_interface_t interface) + { + unsigned int val; + +@@ -73,8 +70,6 @@ static int mtk_pcs_setup_mode_force(stru + regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); + val &= ~SGMII_PHYA_PWD; + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); +- +- return 0; + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -83,15 +78,14 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- int err = 0; + + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) +- err = mtk_pcs_setup_mode_force(mpcs, interface); ++ mtk_pcs_setup_mode_force(mpcs, interface); + else if (phylink_autoneg_inband(mode)) +- err = mtk_pcs_setup_mode_an(mpcs); ++ mtk_pcs_setup_mode_an(mpcs); + +- return err; ++ return 0; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/backport-6.1/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch b/target/linux/generic/backport-6.1/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch new file mode 100644 index 00000000000..64a4a72fa6a --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-04-net-mtk_eth_soc-add-pcs_get_state-implementation.patch @@ -0,0 +1,46 @@ +From c000dca098002da193b98099df051c9ead0cacb4 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:52 +0100 +Subject: [PATCH 03/10] net: mtk_eth_soc: add pcs_get_state() implementation + +Add a pcs_get_state() implementation which uses the advertisements +to compute the resulting link modes, and BMSR contents to determine +negotiation and link status. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -19,6 +19,20 @@ static struct mtk_pcs *pcs_to_mtk_pcs(st + return container_of(pcs, struct mtk_pcs, pcs); + } + ++static void mtk_pcs_get_state(struct phylink_pcs *pcs, ++ struct phylink_link_state *state) ++{ ++ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int bm, adv; ++ ++ /* Read the BMSR and LPA */ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ ++ phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), ++ FIELD_GET(SGMII_LPA, adv)); ++} ++ + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +@@ -117,6 +131,7 @@ static void mtk_pcs_link_up(struct phyli + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { ++ .pcs_get_state = mtk_pcs_get_state, + .pcs_config = mtk_pcs_config, + .pcs_an_restart = mtk_pcs_restart_an, + .pcs_link_up = mtk_pcs_link_up, diff --git a/target/linux/generic/backport-6.1/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch b/target/linux/generic/backport-6.1/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch new file mode 100644 index 00000000000..24610fe11e1 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-05-net-mtk_eth_soc-convert-mtk_sgmii-to-use-regmap_upda.patch @@ -0,0 +1,130 @@ +From 0d2351dc2768061689abd4de1529fa206bbd574e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:10:58 +0100 +Subject: [PATCH 04/10] net: mtk_eth_soc: convert mtk_sgmii to use + regmap_update_bits() + +mtk_sgmii does a lot of read-modify-write operations, for which there +is a specific regmap function. Use this function instead of open-coding +the operations. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 61 ++++++++++------------- + 1 file changed, 26 insertions(+), 35 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -36,23 +36,18 @@ static void mtk_pcs_get_state(struct phy + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +- unsigned int val; +- + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, + SGMII_LINK_TIMER_DEFAULT); + +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val |= SGMII_REMOTE_FAULT_DIS; +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); +- +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); +- +- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); +- val &= ~SGMII_PHYA_PWD; +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART, SGMII_AN_RESTART); ++ ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +@@ -61,29 +56,26 @@ static void mtk_pcs_setup_mode_an(struct + static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, + phy_interface_t interface) + { +- unsigned int val; ++ unsigned int rgc3; + +- regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); +- val &= ~RG_PHY_SPEED_MASK; + if (interface == PHY_INTERFACE_MODE_2500BASEX) +- val |= RG_PHY_SPEED_3_125G; +- regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); ++ rgc3 = RG_PHY_SPEED_3_125G; ++ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); + + /* Disable SGMII AN */ +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val &= ~SGMII_AN_ENABLE; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_ENABLE, 0); + + /* Set the speed etc but leave the duplex unchanged */ +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; +- val |= SGMII_SPEED_1000; +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, ++ SGMII_SPEED_1000); + + /* Release PHYA power down state */ +- regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); +- val &= ~SGMII_PHYA_PWD; +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -105,29 +97,28 @@ static int mtk_pcs_config(struct phylink + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int val; + +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); +- val |= SGMII_AN_RESTART; +- regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART, SGMII_AN_RESTART); + } + + static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, int speed, int duplex) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int val; ++ unsigned int sgm_mode; + + if (!phy_interface_mode_is_8023z(interface)) + return; + + /* SGMII force duplex setting */ +- regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); +- val &= ~SGMII_DUPLEX_FULL; + if (duplex == DUPLEX_FULL) +- val |= SGMII_DUPLEX_FULL; ++ sgm_mode = SGMII_DUPLEX_FULL; ++ else ++ sgm_mode = 0; + +- regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_FULL, sgm_mode); + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { diff --git a/target/linux/generic/backport-6.1/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch b/target/linux/generic/backport-6.1/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch new file mode 100644 index 00000000000..ba76ca40ffa --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-06-net-mtk_eth_soc-add-out-of-band-forcing-of-speed-and.patch @@ -0,0 +1,52 @@ +From 12198c3a410fe69843e335c1bbf6d4c2a4d48e4e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:03 +0100 +Subject: [PATCH 05/10] net: mtk_eth_soc: add out of band forcing of speed and + duplex in pcs_link_up + +Add support for forcing the link speed and duplex setting in the +pcs_link_up() method for out of band modes, which will be useful when +we finish converting the pcs_config() method. Until then, we still have +to force duplex for 802.3z modes to work correctly. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 28 ++++++++++++++--------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -108,17 +108,23 @@ static void mtk_pcs_link_up(struct phyli + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int sgm_mode; + +- if (!phy_interface_mode_is_8023z(interface)) +- return; ++ if (!phylink_autoneg_inband(mode) || ++ phy_interface_mode_is_8023z(interface)) { ++ /* Force the speed and duplex setting */ ++ if (speed == SPEED_10) ++ sgm_mode = SGMII_SPEED_10; ++ else if (speed == SPEED_100) ++ sgm_mode = SGMII_SPEED_100; ++ else ++ sgm_mode = SGMII_SPEED_1000; + +- /* SGMII force duplex setting */ +- if (duplex == DUPLEX_FULL) +- sgm_mode = SGMII_DUPLEX_FULL; +- else +- sgm_mode = 0; ++ if (duplex == DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_FULL; + +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_FULL, sgm_mode); ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_DUPLEX_FULL | SGMII_SPEED_MASK, ++ sgm_mode); ++ } + } + + static const struct phylink_pcs_ops mtk_pcs_ops = { diff --git a/target/linux/generic/backport-6.1/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch b/target/linux/generic/backport-6.1/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch new file mode 100644 index 00000000000..b76e1592750 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-07-net-mtk_eth_soc-move-PHY-power-up.patch @@ -0,0 +1,48 @@ +From 6f38fffe2179dd29612aea2c67c46ed6682b4e46 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:08 +0100 +Subject: [PATCH 06/10] net: mtk_eth_soc: move PHY power up + +The PHY power up is common to both configuration paths, so move it into +the parent function. We need to do this for all serdes modes. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -45,9 +45,6 @@ static void mtk_pcs_setup_mode_an(struct + + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_RESTART, SGMII_AN_RESTART); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); + } + + /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +@@ -72,10 +69,6 @@ static void mtk_pcs_setup_mode_force(str + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, + SGMII_SPEED_1000); +- +- /* Release PHYA power down state */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); + } + + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -91,6 +84,10 @@ static int mtk_pcs_config(struct phylink + else if (phylink_autoneg_inband(mode)) + mtk_pcs_setup_mode_an(mpcs); + ++ /* Release PHYA power down state */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, 0); ++ + return 0; + } + diff --git a/target/linux/generic/backport-6.1/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch b/target/linux/generic/backport-6.1/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch new file mode 100644 index 00000000000..cd9f0699b3e --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-08-net-mtk_eth_soc-move-interface-speed-selection.patch @@ -0,0 +1,48 @@ +From f752c0df13dfeb721c11d3debb79f08cf437344f Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:13 +0100 +Subject: [PATCH 07/10] net: mtk_eth_soc: move interface speed selection + +Move the selection of the underlying interface speed to the pcs_config +function, so we always program the interface speed. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -53,14 +53,6 @@ static void mtk_pcs_setup_mode_an(struct + static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, + phy_interface_t interface) + { +- unsigned int rgc3; +- +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); +- + /* Disable SGMII AN */ + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_ENABLE, 0); +@@ -77,6 +69,16 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int rgc3; ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = RG_PHY_SPEED_3_125G; ++ else ++ rgc3 = 0; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); + + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) diff --git a/target/linux/generic/backport-6.1/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch b/target/linux/generic/backport-6.1/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch new file mode 100644 index 00000000000..f08358e963d --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-09-net-mtk_eth_soc-add-advertisement-programming.patch @@ -0,0 +1,52 @@ +From c125c66ea71b9377ae2478c4f1b87b180cc5c6ef Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:18 +0100 +Subject: [PATCH 08/10] net: mtk_eth_soc: add advertisement programming + +Program the advertisement into the mtk PCS block. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -70,16 +70,27 @@ static int mtk_pcs_config(struct phylink + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int rgc3; ++ int advertise; ++ bool changed; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; + else + rgc3 = 0; + ++ advertise = phylink_mii_c22_pcs_encode_advertisement(interface, ++ advertising); ++ if (advertise < 0) ++ return advertise; ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); + ++ /* Update the advertisement, noting whether it has changed */ ++ regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, ++ SGMII_ADVERTISE, advertise, &changed); ++ + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) + mtk_pcs_setup_mode_force(mpcs, interface); +@@ -90,7 +101,7 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, 0); + +- return 0; ++ return changed; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/backport-6.1/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch b/target/linux/generic/backport-6.1/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch new file mode 100644 index 00000000000..602d52c6f46 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-10-net-mtk_eth_soc-move-and-correct-link-timer-programm.patch @@ -0,0 +1,63 @@ +From 3027d89f87707e7f3e5b683e0d37a32afb5bde96 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:23 +0100 +Subject: [PATCH 09/10] net: mtk_eth_soc: move and correct link timer + programming + +Program the link timer appropriately for the interface mode being +used, using the newly introduced phylink helper that provides the +nanosecond link timer interval. + +The intervals are 1.6ms for SGMII based protocols and 10ms for +802.3z based protocols. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -36,10 +36,6 @@ static void mtk_pcs_get_state(struct phy + /* For SGMII interface mode */ + static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) + { +- /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, +- SGMII_LINK_TIMER_DEFAULT); +- + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); + +@@ -69,8 +65,8 @@ static int mtk_pcs_config(struct phylink + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ int advertise, link_timer; + unsigned int rgc3; +- int advertise; + bool changed; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) +@@ -83,6 +79,10 @@ static int mtk_pcs_config(struct phylink + if (advertise < 0) + return advertise; + ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); +@@ -91,6 +91,9 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, + SGMII_ADVERTISE, advertise, &changed); + ++ /* Setup the link timer and QPHY power up inside SGMIISYS */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); ++ + /* Setup SGMIISYS with the determined property */ + if (interface != PHY_INTERFACE_MODE_SGMII) + mtk_pcs_setup_mode_force(mpcs, interface); diff --git a/target/linux/generic/backport-6.1/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch b/target/linux/generic/backport-6.1/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch new file mode 100644 index 00000000000..0e9a0535a7b --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-11-net-mtk_eth_soc-add-support-for-in-band-802.3z-negot.patch @@ -0,0 +1,132 @@ +From 81b0f12a2a8a1699a7d49c3995e5f71e4ec018e6 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 27 Oct 2022 14:11:28 +0100 +Subject: [PATCH 10/10] net: mtk_eth_soc: add support for in-band 802.3z + negotiation + +As a result of help from Frank Wunderlich to investigate and test, we +now know how to program this PCS for in-band 802.3z negotiation. Add +support for this by moving the contents of the two functions into the +common mtk_pcs_config() function and adding the register settings for +802.3z negotiation. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 77 ++++++++++++----------- + 1 file changed, 42 insertions(+), 35 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -33,41 +33,15 @@ static void mtk_pcs_get_state(struct phy + FIELD_GET(SGMII_LPA, adv)); + } + +-/* For SGMII interface mode */ +-static void mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) +-{ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_REMOTE_FAULT_DIS, SGMII_REMOTE_FAULT_DIS); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART, SGMII_AN_RESTART); +-} +- +-/* For 1000BASE-X and 2500BASE-X interface modes, which operate at a +- * fixed speed. +- */ +-static void mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, +- phy_interface_t interface) +-{ +- /* Disable SGMII AN */ +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE, 0); +- +- /* Set the speed etc but leave the duplex unchanged */ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_IF_MODE_MASK & ~SGMII_DUPLEX_FULL, +- SGMII_SPEED_1000); +-} +- + static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) + { + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); ++ unsigned int rgc3, sgm_mode, bmcr; + int advertise, link_timer; +- unsigned int rgc3; +- bool changed; ++ bool changed, use_an; + + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; +@@ -83,6 +57,37 @@ static int mtk_pcs_config(struct phylink + if (link_timer < 0) + return link_timer; + ++ /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and ++ * we assume that fixes it's speed at bitrate = line rate (in ++ * other words, 1000Mbps or 2500Mbps). ++ */ ++ if (interface == PHY_INTERFACE_MODE_SGMII) { ++ sgm_mode = SGMII_IF_MODE_SGMII; ++ if (phylink_autoneg_inband(mode)) { ++ sgm_mode |= SGMII_REMOTE_FAULT_DIS | ++ SGMII_SPEED_DUPLEX_AN; ++ use_an = true; ++ } else { ++ use_an = false; ++ } ++ } else if (phylink_autoneg_inband(mode)) { ++ /* 1000base-X or 2500base-X autoneg */ ++ sgm_mode = SGMII_REMOTE_FAULT_DIS; ++ use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ advertising); ++ } else { ++ /* 1000base-X or 2500base-X without autoneg */ ++ sgm_mode = 0; ++ use_an = false; ++ } ++ ++ if (use_an) { ++ /* FIXME: Do we need to set AN_RESTART here? */ ++ bmcr = SGMII_AN_RESTART | SGMII_AN_ENABLE; ++ } else { ++ bmcr = 0; ++ } ++ + /* Configure the underlying interface speed */ + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); +@@ -94,11 +99,14 @@ static int mtk_pcs_config(struct phylink + /* Setup the link timer and QPHY power up inside SGMIISYS */ + regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); + +- /* Setup SGMIISYS with the determined property */ +- if (interface != PHY_INTERFACE_MODE_SGMII) +- mtk_pcs_setup_mode_force(mpcs, interface); +- else if (phylink_autoneg_inband(mode)) +- mtk_pcs_setup_mode_an(mpcs); ++ /* Update the sgmsys mode register */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | ++ SGMII_IF_MODE_SGMII, sgm_mode); ++ ++ /* Update the BMCR */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, ++ SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); + + /* Release PHYA power down state */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +@@ -121,8 +129,7 @@ static void mtk_pcs_link_up(struct phyli + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int sgm_mode; + +- if (!phylink_autoneg_inband(mode) || +- phy_interface_mode_is_8023z(interface)) { ++ if (!phylink_autoneg_inband(mode)) { + /* Force the speed and duplex setting */ + if (speed == SPEED_10) + sgm_mode = SGMII_SPEED_10; diff --git a/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch b/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch new file mode 100644 index 00000000000..8d2991f4500 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch @@ -0,0 +1,119 @@ +From 7ff82416de8295c61423ef6fd75f052d3837d2f7 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Wed, 1 Feb 2023 19:23:29 +0100 +Subject: [PATCH 11/13] net: mediatek: sgmii: ensure the SGMII PHY is powered + down on configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The code expect the PHY to be in power down which is only true after reset. +Allow changes of the SGMII parameters more than once. + +Only power down when reconfiguring to avoid bouncing the link when there's +no reason to - based on code from Russell King. + +There are cases when the SGMII_PHYA_PWD register contains 0x9 which +prevents SGMII from working. The SGMII still shows link but no traffic +can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was +taken from a good working state of the SGMII interface. + +Fixes: 42c03844e93d ("net-next: mediatek: add support for MediaTek MT7622 SoC") +Suggested-by: Russell King (Oracle) +Signed-off-by: Alexander Couzens +[ bmork: rebased and squashed into one patch ] +Reviewed-by: Russell King (Oracle) +Signed-off-by: Bjørn Mork +Acked-by: Daniel Golle +Tested-by: Daniel Golle +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++ + drivers/net/ethernet/mediatek/mtk_sgmii.c | 39 +++++++++++++++------ + 2 files changed, 30 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1070,11 +1070,13 @@ struct mtk_soc_data { + * @regmap: The register map pointing at the range used to setup + * SGMII modes + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap ++ * @interface: Currently configured interface mode + * @pcs: Phylink PCS structure + */ + struct mtk_pcs { + struct regmap *regmap; + u32 ana_rgc3; ++ phy_interface_t interface; + struct phylink_pcs pcs; + }; + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -43,11 +43,6 @@ static int mtk_pcs_config(struct phylink + int advertise, link_timer; + bool changed, use_an; + +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- else +- rgc3 = 0; +- + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (advertise < 0) +@@ -88,9 +83,22 @@ static int mtk_pcs_config(struct phylink + bmcr = 0; + } + +- /* Configure the underlying interface speed */ +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); ++ if (mpcs->interface != interface) { ++ /* PHYA power down */ ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, ++ SGMII_PHYA_PWD, SGMII_PHYA_PWD); ++ ++ if (interface == PHY_INTERFACE_MODE_2500BASEX) ++ rgc3 = RG_PHY_SPEED_3_125G; ++ else ++ rgc3 = 0; ++ ++ /* Configure the underlying interface speed */ ++ regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, ++ RG_PHY_SPEED_3_125G, rgc3); ++ ++ mpcs->interface = interface; ++ } + + /* Update the advertisement, noting whether it has changed */ + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, +@@ -108,9 +116,17 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, + SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); + +- /* Release PHYA power down state */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, 0); ++ /* Release PHYA power down state ++ * Only removing bit SGMII_PHYA_PWD isn't enough. ++ * There are cases when the SGMII_PHYA_PWD register contains 0x9 which ++ * prevents SGMII from working. The SGMII still shows link but no traffic ++ * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was ++ * taken from a good working state of the SGMII interface. ++ * Unknown how much the QPHY needs but it is racy without a sleep. ++ * Tested on mt7622 & mt7986. ++ */ ++ usleep_range(50, 100); ++ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); + + return changed; + } +@@ -171,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + return PTR_ERR(ss->pcs[i].regmap); + + ss->pcs[i].pcs.ops = &mtk_pcs_ops; ++ ss->pcs[i].interface = PHY_INTERFACE_MODE_NA; + } + + return 0; diff --git a/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch b/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch new file mode 100644 index 00000000000..79e5ad147ce --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch @@ -0,0 +1,52 @@ +From 9d32637122de88f1ef614c29703f0e050cad342e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= +Date: Wed, 1 Feb 2023 19:23:30 +0100 +Subject: [PATCH 12/13] net: mediatek: sgmii: fix duplex configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The logic of the duplex bit is inverted. Setting it means half +duplex, not full duplex. + +Fix and rename macro to avoid confusion. + +Fixes: 7e538372694b ("net: ethernet: mediatek: Re-add support SGMII") +Reviewed-by: Russell King (Oracle) +Signed-off-by: Bjørn Mork +Acked-by: Daniel Golle +Tested-by: Daniel Golle +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 6 +++--- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -531,7 +531,7 @@ + #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) + #define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) + #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) +-#define SGMII_DUPLEX_FULL BIT(4) ++#define SGMII_DUPLEX_HALF BIT(4) + #define SGMII_IF_MODE_BIT5 BIT(5) + #define SGMII_REMOTE_FAULT_DIS BIT(8) + #define SGMII_CODE_SYNC_SET_VAL BIT(9) +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -154,11 +154,11 @@ static void mtk_pcs_link_up(struct phyli + else + sgm_mode = SGMII_SPEED_1000; + +- if (duplex == DUPLEX_FULL) +- sgm_mode |= SGMII_DUPLEX_FULL; ++ if (duplex != DUPLEX_FULL) ++ sgm_mode |= SGMII_DUPLEX_HALF; + + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_FULL | SGMII_SPEED_MASK, ++ SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, + sgm_mode); + } + } diff --git a/target/linux/generic/backport-6.1/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch b/target/linux/generic/backport-6.1/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch new file mode 100644 index 00000000000..56d7a1348fb --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.2-14-mtk_sgmii-enable-PCS-polling-to-allow-SFP-work.patch @@ -0,0 +1,33 @@ +From 3337a6e04ddf2923a1bdcf3d31b3b52412bf82dd Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Wed, 1 Feb 2023 19:23:31 +0100 +Subject: [PATCH 13/13] mtk_sgmii: enable PCS polling to allow SFP work +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently there is no IRQ handling (even the SGMII supports it). +Enable polling to support SFP ports. + +Fixes: 14a44ab0330d ("net: mtk_eth_soc: partially convert to phylink_pcs") +Reviewed-by: Russell King (Oracle) +Signed-off-by: Alexander Couzens +[ bmork: changed "1" => "true" ] +Signed-off-by: Bjørn Mork +Acked-by: Daniel Golle +Tested-by: Daniel Golle +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -187,6 +187,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + return PTR_ERR(ss->pcs[i].regmap); + + ss->pcs[i].pcs.ops = &mtk_pcs_ops; ++ ss->pcs[i].pcs.poll = true; + ss->pcs[i].interface = PHY_INTERFACE_MODE_NA; + } + diff --git a/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch b/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch new file mode 100644 index 00000000000..a63b110914b --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch @@ -0,0 +1,48 @@ +From 611e2dabb4b3243d176739fd6a5a34d007fa3f86 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 14 Mar 2023 00:34:26 +0000 +Subject: [PATCH 1/2] net: ethernet: mtk_eth_soc: reset PCS state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reset the internal PCS state machine when changing interface mode. +This prevents confusing the state machine when changing interface +modes, e.g. from SGMII to 2500Base-X or vice-versa. + +Fixes: 7e538372694b ("net: ethernet: mediatek: Re-add support SGMII") +Reviewed-by: Russell King (Oracle) +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++++ + drivers/net/ethernet/mediatek/mtk_sgmii.c | 4 ++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -539,6 +539,10 @@ + #define SGMII_SEND_AN_ERROR_EN BIT(11) + #define SGMII_IF_MODE_MASK GENMASK(5, 1) + ++/* Register to reset SGMII design */ ++#define SGMII_RESERVED_0 0x34 ++#define SGMII_SW_RESET BIT(0) ++ + /* Register to set SGMII speed, ANA RG_ Control Signals III*/ + #define SGMSYS_ANA_RG_CS3 0x2028 + #define RG_PHY_SPEED_MASK (BIT(2) | BIT(3)) +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -88,6 +88,10 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); + ++ /* Reset SGMII PCS state */ ++ regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, ++ SGMII_SW_RESET, SGMII_SW_RESET); ++ + if (interface == PHY_INTERFACE_MODE_2500BASEX) + rgc3 = RG_PHY_SPEED_3_125G; + else diff --git a/target/linux/generic/backport-6.1/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch b/target/linux/generic/backport-6.1/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch new file mode 100644 index 00000000000..0fabeea20c0 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.3-16-net-ethernet-mtk_eth_soc-only-write-values-if-needed.patch @@ -0,0 +1,103 @@ +From 6e933a804c7db8be64f367f33e63cd7dcc302ebb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 14 Mar 2023 00:34:45 +0000 +Subject: [PATCH 2/2] net: ethernet: mtk_eth_soc: only write values if needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Only restart auto-negotiation and write link timer if actually +necessary. This prevents losing the link in case of minor +changes. + +Fixes: 7e538372694b ("net: ethernet: mediatek: Re-add support SGMII") +Reviewed-by: Russell King (Oracle) +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 24 +++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -38,20 +38,16 @@ static int mtk_pcs_config(struct phylink + const unsigned long *advertising, + bool permit_pause_to_mac) + { ++ bool mode_changed = false, changed, use_an; + struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); + unsigned int rgc3, sgm_mode, bmcr; + int advertise, link_timer; +- bool changed, use_an; + + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (advertise < 0) + return advertise; + +- link_timer = phylink_get_link_timer_ns(interface); +- if (link_timer < 0) +- return link_timer; +- + /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and + * we assume that fixes it's speed at bitrate = line rate (in + * other words, 1000Mbps or 2500Mbps). +@@ -77,13 +73,16 @@ static int mtk_pcs_config(struct phylink + } + + if (use_an) { +- /* FIXME: Do we need to set AN_RESTART here? */ +- bmcr = SGMII_AN_RESTART | SGMII_AN_ENABLE; ++ bmcr = SGMII_AN_ENABLE; + } else { + bmcr = 0; + } + + if (mpcs->interface != interface) { ++ link_timer = phylink_get_link_timer_ns(interface); ++ if (link_timer < 0) ++ return link_timer; ++ + /* PHYA power down */ + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); +@@ -101,16 +100,17 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, + RG_PHY_SPEED_3_125G, rgc3); + ++ /* Setup the link timer */ ++ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); ++ + mpcs->interface = interface; ++ mode_changed = true; + } + + /* Update the advertisement, noting whether it has changed */ + regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, + SGMII_ADVERTISE, advertise, &changed); + +- /* Setup the link timer and QPHY power up inside SGMIISYS */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); +- + /* Update the sgmsys mode register */ + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, + SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | +@@ -118,7 +118,7 @@ static int mtk_pcs_config(struct phylink + + /* Update the BMCR */ + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART | SGMII_AN_ENABLE, bmcr); ++ SGMII_AN_ENABLE, bmcr); + + /* Release PHYA power down state + * Only removing bit SGMII_PHYA_PWD isn't enough. +@@ -132,7 +132,7 @@ static int mtk_pcs_config(struct phylink + usleep_range(50, 100); + regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); + +- return changed; ++ return changed || mode_changed; + } + + static void mtk_pcs_restart_an(struct phylink_pcs *pcs) diff --git a/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch b/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch new file mode 100644 index 00000000000..c1cf323800c --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch @@ -0,0 +1,200 @@ +From f5d43ddd334b7c32fcaed9ba46afbd85cb467f1f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:56:28 +0000 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for MT7981 SoC + +The MediaTek MT7981 SoC comes with two 1G/2.5G SGMII ports, just like +MT7986. + +In addition MT7981 is equipped with a built-in 1000Base-T PHY which can +be used with GMAC1. + +As many MT7981 boards make use of inverting SGMII signal polarity, add +new device-tree attribute 'mediatek,pn_swap' to support them. + +Signed-off-by: Daniel Golle +Signed-off-by: Jakub Kicinski + +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -96,12 +96,20 @@ static int set_mux_gmac2_gmac0_to_gephy( + + static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) + { +- unsigned int val = 0; ++ unsigned int val = 0, mask = 0, reg = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC2_SGMII: +- val = CO_QPHY_SEL; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { ++ reg = USB_PHY_SWITCH_REG; ++ val = SGMII_QPHY_SEL; ++ mask = QPHY_SEL_MASK; ++ } else { ++ reg = INFRA_MISC2; ++ val = CO_QPHY_SEL; ++ mask = val; ++ } + break; + default: + updated = false; +@@ -109,7 +117,7 @@ static int set_mux_u3_gmac2_to_qphy(stru + } + + if (updated) +- regmap_update_bits(eth->infra, INFRA_MISC2, CO_QPHY_SEL, val); ++ regmap_update_bits(eth->infra, reg, mask, val); + + dev_dbg(eth->dev, "path %s in %s updated = %d\n", + mtk_eth_path_name(path), __func__, updated); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4755,6 +4755,26 @@ static const struct mtk_soc_data mt7629_ + }, + }; + ++static const struct mtk_soc_data mt7981_data = { ++ .reg_map = &mt7986_reg_map, ++ .ana_rgc3 = 0x128, ++ .caps = MT7981_CAPS, ++ .hw_features = MTK_HW_FEATURES, ++ .required_clks = MT7981_CLKS_BITMAP, ++ .required_pctl = false, ++ .offload_version = 2, ++ .hash_offset = 4, ++ .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++ .rx_irq_done_mask = MTK_RX_DONE_INT_V2, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ }, ++}; ++ + static const struct mtk_soc_data mt7986_data = { + .reg_map = &mt7986_reg_map, + .ana_rgc3 = 0x128, +@@ -4797,6 +4817,7 @@ const struct of_device_id of_mtk_match[] + { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, + { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, + { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, ++ { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data}, + { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, + { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, + {}, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -553,11 +553,22 @@ + #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 + #define SGMII_PHYA_PWD BIT(4) + ++/* Register to QPHY wrapper control */ ++#define SGMSYS_QPHY_WRAP_CTRL 0xec ++#define SGMII_PN_SWAP_MASK GENMASK(1, 0) ++#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) ++#define MTK_SGMII_FLAG_PN_SWAP BIT(0) ++ + /* Infrasys subsystem config registers */ + #define INFRA_MISC2 0x70c + #define CO_QPHY_SEL BIT(0) + #define GEPHY_MAC_SEL BIT(1) + ++/* Top misc registers */ ++#define USB_PHY_SWITCH_REG 0x218 ++#define QPHY_SEL_MASK GENMASK(1, 0) ++#define SGMII_QPHY_SEL 0x2 ++ + /* MT7628/88 specific stuff */ + #define MT7628_PDMA_OFFSET 0x0800 + #define MT7628_SDM_OFFSET 0x0c00 +@@ -738,6 +749,17 @@ enum mtk_clks_map { + BIT(MTK_CLK_SGMII2_CDR_FB) | \ + BIT(MTK_CLK_SGMII_CK) | \ + BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) ++#define MT7981_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ ++ BIT(MTK_CLK_WOCPU0) | \ ++ BIT(MTK_CLK_SGMII_TX_250M) | \ ++ BIT(MTK_CLK_SGMII_RX_250M) | \ ++ BIT(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT(MTK_CLK_SGMII2_CDR_FB) | \ ++ BIT(MTK_CLK_SGMII_CK)) + #define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ + BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ + BIT(MTK_CLK_SGMII_TX_250M) | \ +@@ -851,6 +873,7 @@ enum mkt_eth_capabilities { + MTK_NETSYS_V2_BIT, + MTK_SOC_MT7628_BIT, + MTK_RSTCTRL_PPE1_BIT, ++ MTK_U3_COPHY_V2_BIT, + + /* MUX BITS*/ + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, +@@ -885,6 +908,7 @@ enum mkt_eth_capabilities { + #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) + #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) + #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) ++#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) + + #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ + BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) +@@ -963,6 +987,11 @@ enum mkt_eth_capabilities { + MTK_MUX_U3_GMAC2_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) + ++#define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ ++ MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ ++ MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) ++ + #define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ + MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) +@@ -1076,12 +1105,14 @@ struct mtk_soc_data { + * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap + * @interface: Currently configured interface mode + * @pcs: Phylink PCS structure ++ * @flags: Flags indicating hardware properties + */ + struct mtk_pcs { + struct regmap *regmap; + u32 ana_rgc3; + phy_interface_t interface; + struct phylink_pcs pcs; ++ u32 flags; + }; + + /* struct mtk_sgmii - This is the structure holding sgmii regmap and its +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c +@@ -87,6 +87,11 @@ static int mtk_pcs_config(struct phylink + regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, + SGMII_PHYA_PWD, SGMII_PHYA_PWD); + ++ if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) ++ regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, ++ SGMII_PN_SWAP_MASK, ++ SGMII_PN_SWAP_TX_RX); ++ + /* Reset SGMII PCS state */ + regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, + SGMII_SW_RESET, SGMII_SW_RESET); +@@ -186,6 +191,11 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, + + ss->pcs[i].ana_rgc3 = ana_rgc3; + ss->pcs[i].regmap = syscon_node_to_regmap(np); ++ ++ ss->pcs[i].flags = 0; ++ if (of_property_read_bool(np, "mediatek,pnswap")) ++ ss->pcs[i].flags |= MTK_SGMII_FLAG_PN_SWAP; ++ + of_node_put(np); + if (IS_ERR(ss->pcs[i].regmap)) + return PTR_ERR(ss->pcs[i].regmap); diff --git a/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch b/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch new file mode 100644 index 00000000000..9def19d67eb --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch @@ -0,0 +1,76 @@ +From c0a440031d4314d1023c1b87f43a4233634eebdb Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:57:15 +0000 +Subject: [PATCH] net: ethernet: mtk_eth_soc: set MDIO bus clock frequency +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Set MDIO bus clock frequency and allow setting a custom maximum +frequency from device tree. + +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 21 +++++++++++++++++++++ + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 +++++++ + 2 files changed, 28 insertions(+) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -702,8 +702,10 @@ static const struct phylink_mac_ops mtk_ + + static int mtk_mdio_init(struct mtk_eth *eth) + { ++ unsigned int max_clk = 2500000, divider; + struct device_node *mii_np; + int ret; ++ u32 val; + + mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); + if (!mii_np) { +@@ -729,6 +731,25 @@ static int mtk_mdio_init(struct mtk_eth + eth->mii_bus->parent = eth->dev; + + snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); ++ ++ if (!of_property_read_u32(mii_np, "clock-frequency", &val)) { ++ if (val > MDC_MAX_FREQ || val < MDC_MAX_FREQ / MDC_MAX_DIVIDER) { ++ dev_err(eth->dev, "MDIO clock frequency out of range"); ++ ret = -EINVAL; ++ goto err_put_node; ++ } ++ max_clk = val; ++ } ++ divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63); ++ ++ /* Configure MDC Divider */ ++ val = mtk_r32(eth, MTK_PPSC); ++ val &= ~PPSC_MDC_CFG; ++ val |= FIELD_PREP(PPSC_MDC_CFG, divider) | PPSC_MDC_TURBO; ++ mtk_w32(eth, val, MTK_PPSC); ++ ++ dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider); ++ + ret = of_mdiobus_register(eth->mii_bus, mii_np); + + err_put_node: +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -363,6 +363,13 @@ + #define RX_DMA_VTAG_V2 BIT(0) + #define RX_DMA_L4_VALID_V2 BIT(2) + ++/* PHY Polling and SMI Master Control registers */ ++#define MTK_PPSC 0x10000 ++#define PPSC_MDC_CFG GENMASK(29, 24) ++#define PPSC_MDC_TURBO BIT(20) ++#define MDC_MAX_FREQ 25000000 ++#define MDC_MAX_DIVIDER 63 ++ + /* PHY Indirect Access Control registers */ + #define MTK_PHY_IAC 0x10004 + #define PHY_IAC_ACCESS BIT(31) diff --git a/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch b/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch new file mode 100644 index 00000000000..203c5dc48bb --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch @@ -0,0 +1,512 @@ +From 2a3ec7ae313310c1092e4256208cc04d1958e469 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 19 Mar 2023 12:58:02 +0000 +Subject: [PATCH] net: ethernet: mtk_eth_soc: switch to external PCS driver + +Now that we got a PCS driver, use it and remove the now redundant +PCS code and it's header macros from the Ethernet driver. + +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +Reviewed-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/mediatek/Kconfig | 2 + + drivers/net/ethernet/mediatek/Makefile | 2 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 61 +++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 93 +-------- + drivers/net/ethernet/mediatek/mtk_sgmii.c | 217 -------------------- + 5 files changed, 56 insertions(+), 319 deletions(-) + delete mode 100644 drivers/net/ethernet/mediatek/mtk_sgmii.c + +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -18,6 +18,8 @@ config NET_MEDIATEK_SOC + select DIMLIB + select PAGE_POOL + select PAGE_POOL_STATS ++ select PCS_MTK_LYNXI ++ select REGMAP_MMIO + help + This driver supports the gigabit ethernet MACs in the + MediaTek SoC family. +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -4,7 +4,7 @@ + # + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o +-mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o ++mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o + ifdef CONFIG_DEBUG_FS + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -357,7 +358,7 @@ static struct phylink_pcs *mtk_mac_selec + sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? + 0 : mac->id; + +- return mtk_sgmii_select_pcs(eth->sgmii, sid); ++ return eth->sgmii_pcs[sid]; + } + + return NULL; +@@ -3977,8 +3978,17 @@ static int mtk_unreg_dev(struct mtk_eth + return 0; + } + ++static void mtk_sgmii_destroy(struct mtk_eth *eth) ++{ ++ int i; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) ++ mtk_pcs_lynxi_destroy(eth->sgmii_pcs[i]); ++} ++ + static int mtk_cleanup(struct mtk_eth *eth) + { ++ mtk_sgmii_destroy(eth); + mtk_unreg_dev(eth); + mtk_free_dev(eth); + cancel_work_sync(ð->pending_work); +@@ -4408,6 +4418,36 @@ void mtk_eth_set_dma_device(struct mtk_e + rtnl_unlock(); + } + ++static int mtk_sgmii_init(struct mtk_eth *eth) ++{ ++ struct device_node *np; ++ struct regmap *regmap; ++ u32 flags; ++ int i; ++ ++ for (i = 0; i < MTK_MAX_DEVS; i++) { ++ np = of_parse_phandle(eth->dev->of_node, "mediatek,sgmiisys", i); ++ if (!np) ++ break; ++ ++ regmap = syscon_node_to_regmap(np); ++ flags = 0; ++ if (of_property_read_bool(np, "mediatek,pnswap")) ++ flags |= MTK_SGMII_FLAG_PN_SWAP; ++ ++ of_node_put(np); ++ ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ eth->sgmii_pcs[i] = mtk_pcs_lynxi_create(eth->dev, regmap, ++ eth->soc->ana_rgc3, ++ flags); ++ } ++ ++ return 0; ++} ++ + static int mtk_probe(struct platform_device *pdev) + { + struct resource *res = NULL; +@@ -4471,13 +4511,7 @@ static int mtk_probe(struct platform_dev + } + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { +- eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), +- GFP_KERNEL); +- if (!eth->sgmii) +- return -ENOMEM; +- +- err = mtk_sgmii_init(eth->sgmii, pdev->dev.of_node, +- eth->soc->ana_rgc3); ++ err = mtk_sgmii_init(eth); + + if (err) + return err; +@@ -4488,14 +4522,17 @@ static int mtk_probe(struct platform_dev + "mediatek,pctl"); + if (IS_ERR(eth->pctl)) { + dev_err(&pdev->dev, "no pctl regmap found\n"); +- return PTR_ERR(eth->pctl); ++ err = PTR_ERR(eth->pctl); ++ goto err_destroy_sgmii; + } + } + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) +- return -EINVAL; ++ if (!res) { ++ err = -EINVAL; ++ goto err_destroy_sgmii; ++ } + } + + if (eth->soc->offload_version) { +@@ -4655,6 +4692,8 @@ err_deinit_hw: + mtk_hw_deinit(eth); + err_wed_exit: + mtk_wed_exit(); ++err_destroy_sgmii: ++ mtk_sgmii_destroy(eth); + + return err; + } +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -507,65 +507,6 @@ + #define ETHSYS_DMA_AG_MAP_QDMA BIT(1) + #define ETHSYS_DMA_AG_MAP_PPE BIT(2) + +-/* SGMII subsystem config registers */ +-/* BMCR (low 16) BMSR (high 16) */ +-#define SGMSYS_PCS_CONTROL_1 0x0 +-#define SGMII_BMCR GENMASK(15, 0) +-#define SGMII_BMSR GENMASK(31, 16) +-#define SGMII_AN_RESTART BIT(9) +-#define SGMII_ISOLATE BIT(10) +-#define SGMII_AN_ENABLE BIT(12) +-#define SGMII_LINK_STATYS BIT(18) +-#define SGMII_AN_ABILITY BIT(19) +-#define SGMII_AN_COMPLETE BIT(21) +-#define SGMII_PCS_FAULT BIT(23) +-#define SGMII_AN_EXPANSION_CLR BIT(30) +- +-#define SGMSYS_PCS_ADVERTISE 0x8 +-#define SGMII_ADVERTISE GENMASK(15, 0) +-#define SGMII_LPA GENMASK(31, 16) +- +-/* Register to programmable link timer, the unit in 2 * 8ns */ +-#define SGMSYS_PCS_LINK_TIMER 0x18 +-#define SGMII_LINK_TIMER_MASK GENMASK(19, 0) +-#define SGMII_LINK_TIMER_DEFAULT (0x186a0 & SGMII_LINK_TIMER_MASK) +- +-/* Register to control remote fault */ +-#define SGMSYS_SGMII_MODE 0x20 +-#define SGMII_IF_MODE_SGMII BIT(0) +-#define SGMII_SPEED_DUPLEX_AN BIT(1) +-#define SGMII_SPEED_MASK GENMASK(3, 2) +-#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) +-#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) +-#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) +-#define SGMII_DUPLEX_HALF BIT(4) +-#define SGMII_IF_MODE_BIT5 BIT(5) +-#define SGMII_REMOTE_FAULT_DIS BIT(8) +-#define SGMII_CODE_SYNC_SET_VAL BIT(9) +-#define SGMII_CODE_SYNC_SET_EN BIT(10) +-#define SGMII_SEND_AN_ERROR_EN BIT(11) +-#define SGMII_IF_MODE_MASK GENMASK(5, 1) +- +-/* Register to reset SGMII design */ +-#define SGMII_RESERVED_0 0x34 +-#define SGMII_SW_RESET BIT(0) +- +-/* Register to set SGMII speed, ANA RG_ Control Signals III*/ +-#define SGMSYS_ANA_RG_CS3 0x2028 +-#define RG_PHY_SPEED_MASK (BIT(2) | BIT(3)) +-#define RG_PHY_SPEED_1_25G 0x0 +-#define RG_PHY_SPEED_3_125G BIT(2) +- +-/* Register to power up QPHY */ +-#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 +-#define SGMII_PHYA_PWD BIT(4) +- +-/* Register to QPHY wrapper control */ +-#define SGMSYS_QPHY_WRAP_CTRL 0xec +-#define SGMII_PN_SWAP_MASK GENMASK(1, 0) +-#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1)) +-#define MTK_SGMII_FLAG_PN_SWAP BIT(0) +- + /* Infrasys subsystem config registers */ + #define INFRA_MISC2 0x70c + #define CO_QPHY_SEL BIT(0) +@@ -1105,31 +1046,6 @@ struct mtk_soc_data { + /* currently no SoC has more than 2 macs */ + #define MTK_MAX_DEVS 2 + +-/* struct mtk_pcs - This structure holds each sgmii regmap and associated +- * data +- * @regmap: The register map pointing at the range used to setup +- * SGMII modes +- * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap +- * @interface: Currently configured interface mode +- * @pcs: Phylink PCS structure +- * @flags: Flags indicating hardware properties +- */ +-struct mtk_pcs { +- struct regmap *regmap; +- u32 ana_rgc3; +- phy_interface_t interface; +- struct phylink_pcs pcs; +- u32 flags; +-}; +- +-/* struct mtk_sgmii - This is the structure holding sgmii regmap and its +- * characteristics +- * @pcs Array of individual PCS structures +- */ +-struct mtk_sgmii { +- struct mtk_pcs pcs[MTK_MAX_DEVS]; +-}; +- + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer +@@ -1149,6 +1065,7 @@ struct mtk_sgmii { + * MII modes + * @infra: The register map pointing at the range used to setup + * SGMII and GePHY path ++ * @sgmii_pcs: Pointers to mtk-pcs-lynxi phylink_pcs instances + * @pctl: The register map pointing at the range used to setup + * GMAC port drive/slew values + * @dma_refcnt: track how many netdevs are using the DMA engine +@@ -1189,8 +1106,8 @@ struct mtk_eth { + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; +- struct regmap *infra; +- struct mtk_sgmii *sgmii; ++ struct regmap *infra; ++ struct phylink_pcs *sgmii_pcs[MTK_MAX_DEVS]; + struct regmap *pctl; + bool hwlro; + refcount_t dma_refcnt; +@@ -1352,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + +-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id); +-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, +- u32 ana_rgc3); +- + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); +--- a/drivers/net/ethernet/mediatek/mtk_sgmii.c ++++ /dev/null +@@ -1,217 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-// Copyright (c) 2018-2019 MediaTek Inc. +- +-/* A library for MediaTek SGMII circuit +- * +- * Author: Sean Wang +- * +- */ +- +-#include +-#include +-#include +-#include +- +-#include "mtk_eth_soc.h" +- +-static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) +-{ +- return container_of(pcs, struct mtk_pcs, pcs); +-} +- +-static void mtk_pcs_get_state(struct phylink_pcs *pcs, +- struct phylink_link_state *state) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int bm, adv; +- +- /* Read the BMSR and LPA */ +- regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); +- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); +- +- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), +- FIELD_GET(SGMII_LPA, adv)); +-} +- +-static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, +- const unsigned long *advertising, +- bool permit_pause_to_mac) +-{ +- bool mode_changed = false, changed, use_an; +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int rgc3, sgm_mode, bmcr; +- int advertise, link_timer; +- +- advertise = phylink_mii_c22_pcs_encode_advertisement(interface, +- advertising); +- if (advertise < 0) +- return advertise; +- +- /* Clearing IF_MODE_BIT0 switches the PCS to BASE-X mode, and +- * we assume that fixes it's speed at bitrate = line rate (in +- * other words, 1000Mbps or 2500Mbps). +- */ +- if (interface == PHY_INTERFACE_MODE_SGMII) { +- sgm_mode = SGMII_IF_MODE_SGMII; +- if (phylink_autoneg_inband(mode)) { +- sgm_mode |= SGMII_REMOTE_FAULT_DIS | +- SGMII_SPEED_DUPLEX_AN; +- use_an = true; +- } else { +- use_an = false; +- } +- } else if (phylink_autoneg_inband(mode)) { +- /* 1000base-X or 2500base-X autoneg */ +- sgm_mode = SGMII_REMOTE_FAULT_DIS; +- use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +- advertising); +- } else { +- /* 1000base-X or 2500base-X without autoneg */ +- sgm_mode = 0; +- use_an = false; +- } +- +- if (use_an) { +- bmcr = SGMII_AN_ENABLE; +- } else { +- bmcr = 0; +- } +- +- if (mpcs->interface != interface) { +- link_timer = phylink_get_link_timer_ns(interface); +- if (link_timer < 0) +- return link_timer; +- +- /* PHYA power down */ +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, +- SGMII_PHYA_PWD, SGMII_PHYA_PWD); +- +- if (mpcs->flags & MTK_SGMII_FLAG_PN_SWAP) +- regmap_update_bits(mpcs->regmap, SGMSYS_QPHY_WRAP_CTRL, +- SGMII_PN_SWAP_MASK, +- SGMII_PN_SWAP_TX_RX); +- +- /* Reset SGMII PCS state */ +- regmap_update_bits(mpcs->regmap, SGMII_RESERVED_0, +- SGMII_SW_RESET, SGMII_SW_RESET); +- +- if (interface == PHY_INTERFACE_MODE_2500BASEX) +- rgc3 = RG_PHY_SPEED_3_125G; +- else +- rgc3 = 0; +- +- /* Configure the underlying interface speed */ +- regmap_update_bits(mpcs->regmap, mpcs->ana_rgc3, +- RG_PHY_SPEED_3_125G, rgc3); +- +- /* Setup the link timer */ +- regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, link_timer / 2 / 8); +- +- mpcs->interface = interface; +- mode_changed = true; +- } +- +- /* Update the advertisement, noting whether it has changed */ +- regmap_update_bits_check(mpcs->regmap, SGMSYS_PCS_ADVERTISE, +- SGMII_ADVERTISE, advertise, &changed); +- +- /* Update the sgmsys mode register */ +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | +- SGMII_IF_MODE_SGMII, sgm_mode); +- +- /* Update the BMCR */ +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_ENABLE, bmcr); +- +- /* Release PHYA power down state +- * Only removing bit SGMII_PHYA_PWD isn't enough. +- * There are cases when the SGMII_PHYA_PWD register contains 0x9 which +- * prevents SGMII from working. The SGMII still shows link but no traffic +- * can flow. Writing 0x0 to the PHYA_PWD register fix the issue. 0x0 was +- * taken from a good working state of the SGMII interface. +- * Unknown how much the QPHY needs but it is racy without a sleep. +- * Tested on mt7622 & mt7986. +- */ +- usleep_range(50, 100); +- regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, 0); +- +- return changed || mode_changed; +-} +- +-static void mtk_pcs_restart_an(struct phylink_pcs *pcs) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- +- regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- SGMII_AN_RESTART, SGMII_AN_RESTART); +-} +- +-static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, int speed, int duplex) +-{ +- struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); +- unsigned int sgm_mode; +- +- if (!phylink_autoneg_inband(mode)) { +- /* Force the speed and duplex setting */ +- if (speed == SPEED_10) +- sgm_mode = SGMII_SPEED_10; +- else if (speed == SPEED_100) +- sgm_mode = SGMII_SPEED_100; +- else +- sgm_mode = SGMII_SPEED_1000; +- +- if (duplex != DUPLEX_FULL) +- sgm_mode |= SGMII_DUPLEX_HALF; +- +- regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, +- SGMII_DUPLEX_HALF | SGMII_SPEED_MASK, +- sgm_mode); +- } +-} +- +-static const struct phylink_pcs_ops mtk_pcs_ops = { +- .pcs_get_state = mtk_pcs_get_state, +- .pcs_config = mtk_pcs_config, +- .pcs_an_restart = mtk_pcs_restart_an, +- .pcs_link_up = mtk_pcs_link_up, +-}; +- +-int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) +-{ +- struct device_node *np; +- int i; +- +- for (i = 0; i < MTK_MAX_DEVS; i++) { +- np = of_parse_phandle(r, "mediatek,sgmiisys", i); +- if (!np) +- break; +- +- ss->pcs[i].ana_rgc3 = ana_rgc3; +- ss->pcs[i].regmap = syscon_node_to_regmap(np); +- +- ss->pcs[i].flags = 0; +- if (of_property_read_bool(np, "mediatek,pnswap")) +- ss->pcs[i].flags |= MTK_SGMII_FLAG_PN_SWAP; +- +- of_node_put(np); +- if (IS_ERR(ss->pcs[i].regmap)) +- return PTR_ERR(ss->pcs[i].regmap); +- +- ss->pcs[i].pcs.ops = &mtk_pcs_ops; +- ss->pcs[i].pcs.poll = true; +- ss->pcs[i].interface = PHY_INTERFACE_MODE_NA; +- } +- +- return 0; +-} +- +-struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) +-{ +- if (!ss->pcs[id].regmap) +- return NULL; +- +- return &ss->pcs[id].pcs; +-} diff --git a/target/linux/generic/backport-6.1/733-v6.4-21-net-mtk_eth_soc-use-WO-firmware-for-MT7981.patch b/target/linux/generic/backport-6.1/733-v6.4-21-net-mtk_eth_soc-use-WO-firmware-for-MT7981.patch new file mode 100644 index 00000000000..9ce2735951c --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.4-21-net-mtk_eth_soc-use-WO-firmware-for-MT7981.patch @@ -0,0 +1,46 @@ +From f5af7931d2a2cae66d0f9dad4ba517b1b00620b3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 19 Apr 2023 19:07:23 +0100 +Subject: [PATCH] net: mtk_eth_soc: use WO firmware for MT7981 + +In order to support wireless offloading on MT7981 we need to load the +appropriate firmware. Recognize MT7981 and load mt7981_wo.bin. + +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 7 ++++++- + drivers/net/ethernet/mediatek/mtk_wed_wo.h | 1 + + 2 files changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c +@@ -326,7 +326,11 @@ mtk_wed_mcu_load_firmware(struct mtk_wed + wo->hw->index + 1); + + /* load firmware */ +- fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1 : MT7986_FIRMWARE_WO0; ++ if (of_device_is_compatible(wo->hw->node, "mediatek,mt7981-wed")) ++ fw_name = MT7981_FIRMWARE_WO; ++ else ++ fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1 : MT7986_FIRMWARE_WO0; ++ + ret = request_firmware(&fw, fw_name, wo->hw->dev); + if (ret) + return ret; +@@ -386,5 +390,6 @@ int mtk_wed_mcu_init(struct mtk_wed_wo * + 100, MTK_FW_DL_TIMEOUT); + } + ++MODULE_FIRMWARE(MT7981_FIRMWARE_WO); + MODULE_FIRMWARE(MT7986_FIRMWARE_WO0); + MODULE_FIRMWARE(MT7986_FIRMWARE_WO1); +--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h ++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h +@@ -88,6 +88,7 @@ enum mtk_wed_dummy_cr_idx { + MTK_WED_DUMMY_CR_WO_STATUS, + }; + ++#define MT7981_FIRMWARE_WO "mediatek/mt7981_wo.bin" + #define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin" + #define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin" + diff --git a/target/linux/generic/backport-6.1/733-v6.4-22-net-ethernet-mtk_eth_soc-fix-NULL-pointer-dereferenc.patch b/target/linux/generic/backport-6.1/733-v6.4-22-net-ethernet-mtk_eth_soc-fix-NULL-pointer-dereferenc.patch new file mode 100644 index 00000000000..d715c4aa686 --- /dev/null +++ b/target/linux/generic/backport-6.1/733-v6.4-22-net-ethernet-mtk_eth_soc-fix-NULL-pointer-dereferenc.patch @@ -0,0 +1,28 @@ +From 7c83e28f10830aa5105c25eaabe890e3adac36aa Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 9 May 2023 03:20:06 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix NULL pointer dereference + +Check for NULL pointer to avoid kernel crashing in case of missing WO +firmware in case only a single WEDv2 device has been initialized, e.g. on +MT7981 which can connect just one wireless frontend. + +Fixes: 86ce0d09e424 ("net: ethernet: mtk_eth_soc: use WO firmware for MT7981") +Signed-off-by: Daniel Golle +Reviewed-by: Simon Horman +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/mediatek/mtk_wed.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -647,7 +647,7 @@ __mtk_wed_detach(struct mtk_wed_device * + BIT(hw->index), BIT(hw->index)); + } + +- if (!hw_list[!hw->index]->wed_dev && ++ if ((!hw_list[!hw->index] || !hw_list[!hw->index]->wed_dev) && + hw->eth->dma_dev != hw->eth->dev) + mtk_eth_set_dma_device(hw->eth, hw->eth->dev); + diff --git a/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch b/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch new file mode 100644 index 00000000000..6788a2ec350 --- /dev/null +++ b/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch @@ -0,0 +1,84 @@ +From b5375509184dc23d2b7fa0c5ed8763899ccc9674 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sat, 2 Oct 2021 19:58:11 +0200 +Subject: [PATCH] net: bgmac: improve handling PHY +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Use info from DT if available + +It allows describing for example a fixed link. It's more accurate than +just guessing there may be one (depending on a chipset). + +2. Verify PHY ID before trying to connect PHY + +PHY addr 0x1e (30) is special in Broadcom routers and means a switch +connected as MDIO devices instead of a real PHY. Don't try connecting to +it. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac-bcma.c | 33 ++++++++++++++-------- + 1 file changed, 21 insertions(+), 12 deletions(-) + +--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include "bgmac.h" + +@@ -86,17 +87,28 @@ static int bcma_phy_connect(struct bgmac + struct phy_device *phy_dev; + char bus_id[MII_BUS_ID_SIZE + 3]; + ++ /* DT info should be the most accurate */ ++ phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node, ++ bgmac_adjust_link); ++ if (phy_dev) ++ return 0; ++ + /* Connect to the PHY */ +- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id, +- bgmac->phyaddr); +- phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link, +- PHY_INTERFACE_MODE_MII); +- if (IS_ERR(phy_dev)) { +- dev_err(bgmac->dev, "PHY connection failed\n"); +- return PTR_ERR(phy_dev); ++ if (bgmac->mii_bus && bgmac->phyaddr != BGMAC_PHY_NOREGS) { ++ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id, ++ bgmac->phyaddr); ++ phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link, ++ PHY_INTERFACE_MODE_MII); ++ if (IS_ERR(phy_dev)) { ++ dev_err(bgmac->dev, "PHY connection failed\n"); ++ return PTR_ERR(phy_dev); ++ } ++ ++ return 0; + } + +- return 0; ++ /* Assume a fixed link to the switch port */ ++ return bgmac_phy_connect_direct(bgmac); + } + + static const struct bcma_device_id bgmac_bcma_tbl[] = { +@@ -297,10 +309,7 @@ static int bgmac_probe(struct bcma_devic + bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset; + bgmac->get_bus_clock = bcma_bgmac_get_bus_clock; + bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32; +- if (bgmac->mii_bus) +- bgmac->phy_connect = bcma_phy_connect; +- else +- bgmac->phy_connect = bgmac_phy_connect_direct; ++ bgmac->phy_connect = bcma_phy_connect; + + err = bgmac_enet_probe(bgmac); + if (err) diff --git a/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch b/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch new file mode 100644 index 00000000000..f1348282739 --- /dev/null +++ b/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch @@ -0,0 +1,54 @@ +From 45c9d966688e7fad7f24bfc450547d91e4304d0b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sat, 2 Oct 2021 19:58:12 +0200 +Subject: [PATCH] net: bgmac: support MDIO described in DT +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Check ethernet controller DT node for "mdio" subnode and use it with +of_mdiobus_register() when present. That allows specifying MDIO and its +PHY devices in a standard DT based way. + +This is required for BCM53573 SoC support. That family is sometimes +called Northstar (by marketing?) but is quite different from it. It uses +different CPU(s) and many different hw blocks. + +One of shared blocks in BCM53573 is Ethernet controller. Switch however +is not SRAB accessible (as it Northstar) but is MDIO attached. + +Signed-off-by: Rafał Miłecki +Signed-off-by: David S. Miller +--- + drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c +@@ -10,6 +10,7 @@ + + #include + #include ++#include + #include "bgmac.h" + + static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask, +@@ -211,6 +212,7 @@ struct mii_bus *bcma_mdio_mii_register(s + { + struct bcma_device *core = bgmac->bcma.core; + struct mii_bus *mii_bus; ++ struct device_node *np; + int err; + + mii_bus = mdiobus_alloc(); +@@ -229,7 +231,9 @@ struct mii_bus *bcma_mdio_mii_register(s + mii_bus->parent = &core->dev; + mii_bus->phy_mask = ~(1 << bgmac->phyaddr); + +- err = mdiobus_register(mii_bus); ++ np = of_get_child_by_name(core->dev.of_node, "mdio"); ++ ++ err = of_mdiobus_register(mii_bus, np); + if (err) { + dev_err(&core->dev, "Registration of mii bus failed\n"); + goto err_free_bus; diff --git a/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch b/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch new file mode 100644 index 00000000000..8f000ba9187 --- /dev/null +++ b/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch @@ -0,0 +1,48 @@ +From 0ccf8511182436183c031e8a2f740ae91a02c625 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 14 Sep 2021 14:33:45 +0200 +Subject: net: phy: at803x: add support for qca 8327 internal phy + +Add support for qca8327 internal phy needed for correct init of the +switch port. It does use the same qca8337 function and reg just with a +different id. + +Signed-off-by: Ansuel Smith +Tested-by: Rosen Penev +Tested-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1412,6 +1412,19 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, ++}, { ++ /* QCA8327 */ ++ .phy_id = QCA8327_PHY_ID, ++ .phy_id_mask = QCA8K_PHY_ID_MASK, ++ .name = "QCA PHY 8327", ++ /* PHY_GBIT_FEATURES */ ++ .probe = at803x_probe, ++ .flags = PHY_IS_INTERNAL, ++ .config_init = qca83xx_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_sset_count = at803x_get_sset_count, ++ .get_strings = at803x_get_strings, ++ .get_stats = at803x_get_stats, + }, }; + + module_phy_driver(at803x_driver); +@@ -1422,6 +1435,8 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, ++ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, ++ { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) }, + { } + }; + diff --git a/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch b/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch new file mode 100644 index 00000000000..dc149a742b1 --- /dev/null +++ b/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch @@ -0,0 +1,131 @@ +From 983d96a9116a328668601555d96736261d33170c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 16 Sep 2021 14:03:51 +0200 +Subject: [PATCH] net: dsa: b53: Include all ports in "enabled_ports" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Make "enabled_ports" bitfield contain all available switch ports +including a CPU port. This way there is no need for fixup during +initialization. + +For BCM53010, BCM53018 and BCM53019 include also other available ports. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Tested-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 23 +++++++++++------------ + 1 file changed, 11 insertions(+), 12 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2300,7 +2300,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5325_DEVICE_ID, + .dev_name = "BCM5325", + .vlans = 16, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x3f, + .arl_bins = 2, + .arl_buckets = 1024, + .imp_port = 5, +@@ -2311,7 +2311,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5365_DEVICE_ID, + .dev_name = "BCM5365", + .vlans = 256, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x3f, + .arl_bins = 2, + .arl_buckets = 1024, + .imp_port = 5, +@@ -2322,7 +2322,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5389_DEVICE_ID, + .dev_name = "BCM5389", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x11f, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2336,7 +2336,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5395_DEVICE_ID, + .dev_name = "BCM5395", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x11f, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2350,7 +2350,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5397_DEVICE_ID, + .dev_name = "BCM5397", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x11f, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2364,7 +2364,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM5398_DEVICE_ID, + .dev_name = "BCM5398", + .vlans = 4096, +- .enabled_ports = 0x7f, ++ .enabled_ports = 0x17f, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2378,7 +2378,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM53115_DEVICE_ID, + .dev_name = "BCM53115", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x11f, + .arl_bins = 4, + .arl_buckets = 1024, + .vta_regs = B53_VTA_REGS, +@@ -2392,7 +2392,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM53125_DEVICE_ID, + .dev_name = "BCM53125", + .vlans = 4096, +- .enabled_ports = 0xff, ++ .enabled_ports = 0x1ff, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2434,7 +2434,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x1bf, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2476,7 +2476,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM53018_DEVICE_ID, + .dev_name = "BCM53018", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x1bf, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2490,7 +2490,7 @@ static const struct b53_chip_data b53_sw + .chip_id = BCM53019_DEVICE_ID, + .dev_name = "BCM53019", + .vlans = 4096, +- .enabled_ports = 0x1f, ++ .enabled_ports = 0x1bf, + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +@@ -2632,7 +2632,6 @@ static int b53_switch_init(struct b53_de + dev->cpu_port = 5; + } + +- dev->enabled_ports |= BIT(dev->cpu_port); + dev->num_ports = fls(dev->enabled_ports); + + dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS); diff --git a/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch b/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch new file mode 100644 index 00000000000..23805a9027b --- /dev/null +++ b/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch @@ -0,0 +1,42 @@ +From b290c6384afabbca5ae6e2af72fb1b2bc37922be Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 16 Sep 2021 14:03:52 +0200 +Subject: [PATCH] net: dsa: b53: Drop BCM5301x workaround for a wrong CPU/IMP + port +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On BCM5301x port 8 requires a fixed link when used. + +Years ago when b53 was an OpenWrt downstream driver (with configuration +based on sometimes bugged NVRAM) there was a need for a fixup. In case +of forcing fixed link for (incorrectly specified) port 5 the code had to +actually setup port 8 link. + +For upstream b53 driver with setup based on DT there is no need for that +workaround. In DT we have and require correct ports setup. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Tested-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 6 ------ + 1 file changed, 6 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1291,12 +1291,6 @@ static void b53_adjust_link(struct dsa_s + return; + } + } +- } else if (is5301x(dev)) { +- if (port != dev->cpu_port) { +- b53_force_port_config(dev, dev->cpu_port, 2000, +- DUPLEX_FULL, true, true); +- b53_force_link(dev, dev->cpu_port, 1); +- } + } + + /* Re-negotiate EEE if it was enabled already */ diff --git a/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch b/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch new file mode 100644 index 00000000000..941fa23eb4c --- /dev/null +++ b/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch @@ -0,0 +1,32 @@ +From 3ff26b29230c54fea2353b63124c589b61953e14 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 16 Sep 2021 14:03:53 +0200 +Subject: [PATCH] net: dsa: b53: Improve flow control setup on BCM5301x +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to the Broadcom's reference driver flow control needs to be +enabled for any CPU switch port (5, 7 or 8 - depending on which one is +used). Current code makes it work only for the port 5. Use +dsa_is_cpu_port() which solved that problem. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Tested-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1222,7 +1222,7 @@ static void b53_adjust_link(struct dsa_s + return; + + /* Enable flow control on BCM5301x's CPU port */ +- if (is5301x(dev) && port == dev->cpu_port) ++ if (is5301x(dev) && dsa_is_cpu_port(ds, port)) + tx_pause = rx_pause = true; + + if (phydev->pause) { diff --git a/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch b/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch new file mode 100644 index 00000000000..07d0ec03cf1 --- /dev/null +++ b/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch @@ -0,0 +1,205 @@ +From 7d5af56418d7d01e43247a33b6fe6492ea871923 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 16 Sep 2021 14:03:54 +0200 +Subject: [PATCH] net: dsa: b53: Drop unused "cpu_port" field +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's set but never used anymore. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Tested-by: Florian Fainelli +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/b53/b53_common.c | 28 ---------------------------- + drivers/net/dsa/b53/b53_priv.h | 1 - + 2 files changed, 29 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2298,7 +2298,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 2, + .arl_buckets = 1024, + .imp_port = 5, +- .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + }, + { +@@ -2309,7 +2308,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 2, + .arl_buckets = 1024, + .imp_port = 5, +- .cpu_port = B53_CPU_PORT_25, + .duplex_reg = B53_DUPLEX_STAT_FE, + }, + { +@@ -2320,7 +2318,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2334,7 +2331,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2348,7 +2344,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2362,7 +2357,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_9798, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2377,7 +2371,6 @@ static const struct b53_chip_data b53_sw + .arl_buckets = 1024, + .vta_regs = B53_VTA_REGS, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, +@@ -2390,7 +2383,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2404,7 +2396,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2418,7 +2409,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS_63XX, + .duplex_reg = B53_DUPLEX_STAT_63XX, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, +@@ -2432,7 +2422,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2446,7 +2435,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2460,7 +2448,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2474,7 +2461,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2488,7 +2474,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2502,7 +2487,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2516,7 +2500,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2545,7 +2528,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 1024, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2559,7 +2541,6 @@ static const struct b53_chip_data b53_sw + .arl_bins = 4, + .arl_buckets = 256, + .imp_port = 8, +- .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, +@@ -2585,7 +2566,6 @@ static int b53_switch_init(struct b53_de + dev->vta_regs[2] = chip->vta_regs[2]; + dev->jumbo_pm_reg = chip->jumbo_pm_reg; + dev->imp_port = chip->imp_port; +- dev->cpu_port = chip->cpu_port; + dev->num_vlans = chip->vlans; + dev->num_arl_bins = chip->arl_bins; + dev->num_arl_buckets = chip->arl_buckets; +@@ -2617,13 +2597,6 @@ static int b53_switch_init(struct b53_de + break; + #endif + } +- } else if (dev->chip_id == BCM53115_DEVICE_ID) { +- u64 strap_value; +- +- b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); +- /* use second IMP port if GMII is enabled */ +- if (strap_value & SV_GMII_CTRL_115) +- dev->cpu_port = 5; + } + + dev->num_ports = fls(dev->enabled_ports); +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -124,7 +124,6 @@ struct b53_device { + /* used ports mask */ + u16 enabled_ports; + unsigned int imp_port; +- unsigned int cpu_port; + + /* connect specific data */ + u8 current_page; diff --git a/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch b/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch new file mode 100644 index 00000000000..99d91dfa765 --- /dev/null +++ b/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch @@ -0,0 +1,65 @@ +From b4df02b562f4aa14ff6811f30e1b4d2159585c59 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 19 Sep 2021 18:28:15 +0200 +Subject: net: phy: at803x: add support for qca 8327 A variant internal phy + +For qca8327 internal phy there are 2 different switch variant with 2 +different phy id. Add this missing variant so the internal phy can be +correctly identified and fixed. + +Signed-off-by: Ansuel Smith +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 25 ++++++++++++++++++++----- + 1 file changed, 20 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -150,7 +150,8 @@ + #define ATH8035_PHY_ID 0x004dd072 + #define AT8030_PHY_ID_MASK 0xffffffef + +-#define QCA8327_PHY_ID 0x004dd034 ++#define QCA8327_A_PHY_ID 0x004dd033 ++#define QCA8327_B_PHY_ID 0x004dd034 + #define QCA8337_PHY_ID 0x004dd036 + #define QCA8K_PHY_ID_MASK 0xffffffff + +@@ -1413,10 +1414,23 @@ static struct phy_driver at803x_driver[] + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, + }, { +- /* QCA8327 */ +- .phy_id = QCA8327_PHY_ID, ++ /* QCA8327-A from switch QCA8327-AL1A */ ++ .phy_id = QCA8327_A_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, +- .name = "QCA PHY 8327", ++ .name = "QCA PHY 8327-A", ++ /* PHY_GBIT_FEATURES */ ++ .probe = at803x_probe, ++ .flags = PHY_IS_INTERNAL, ++ .config_init = qca83xx_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_sset_count = at803x_get_sset_count, ++ .get_strings = at803x_get_strings, ++ .get_stats = at803x_get_stats, ++}, { ++ /* QCA8327-B from switch QCA8327-BL1A */ ++ .phy_id = QCA8327_B_PHY_ID, ++ .phy_id_mask = QCA8K_PHY_ID_MASK, ++ .name = "QCA PHY 8327-B", + /* PHY_GBIT_FEATURES */ + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, +@@ -1436,7 +1450,8 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, +- { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) }, ++ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, ++ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, + { } + }; + diff --git a/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch b/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch new file mode 100644 index 00000000000..cd83fac83c8 --- /dev/null +++ b/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch @@ -0,0 +1,45 @@ +From 15b9df4ece17d084f14eb0ca1cf05f2ad497e425 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 19 Sep 2021 18:28:16 +0200 +Subject: net: phy: at803x: add resume/suspend function to qca83xx phy + +Add resume/suspend function to qca83xx internal phy. +We can't use the at803x generic function as the documentation lacks of +any support for WoL regs. + +Signed-off-by: Ansuel Smith +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1413,6 +1413,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, + }, { + /* QCA8327-A from switch QCA8327-AL1A */ + .phy_id = QCA8327_A_PHY_ID, +@@ -1426,6 +1428,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, + }, { + /* QCA8327-B from switch QCA8327-BL1A */ + .phy_id = QCA8327_B_PHY_ID, +@@ -1439,6 +1443,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, + }, }; + + module_phy_driver(at803x_driver); diff --git a/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch b/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch new file mode 100644 index 00000000000..586d8953b2b --- /dev/null +++ b/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch @@ -0,0 +1,95 @@ +From d44fd8604a4ab92119adb35f05fd87612af722b5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 19 Sep 2021 18:28:17 +0200 +Subject: net: phy: at803x: fix spacing and improve name for 83xx phy + +Fix spacing and improve name for 83xx phy following other phy in the +same driver. + +Signed-off-by: Ansuel Smith +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 60 ++++++++++++++++++++++++------------------------ + 1 file changed, 30 insertions(+), 30 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1402,47 +1402,47 @@ static struct phy_driver at803x_driver[] + .config_aneg = at803x_config_aneg, + }, { + /* QCA8337 */ +- .phy_id = QCA8337_PHY_ID, +- .phy_id_mask = QCA8K_PHY_ID_MASK, +- .name = "QCA PHY 8337", ++ .phy_id = QCA8337_PHY_ID, ++ .phy_id_mask = QCA8K_PHY_ID_MASK, ++ .name = "Qualcomm Atheros 8337 internal PHY", + /* PHY_GBIT_FEATURES */ +- .probe = at803x_probe, +- .flags = PHY_IS_INTERNAL, +- .config_init = qca83xx_config_init, +- .soft_reset = genphy_soft_reset, +- .get_sset_count = at803x_get_sset_count, +- .get_strings = at803x_get_strings, +- .get_stats = at803x_get_stats, ++ .probe = at803x_probe, ++ .flags = PHY_IS_INTERNAL, ++ .config_init = qca83xx_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_sset_count = at803x_get_sset_count, ++ .get_strings = at803x_get_strings, ++ .get_stats = at803x_get_stats, + .suspend = genphy_suspend, + .resume = genphy_resume, + }, { + /* QCA8327-A from switch QCA8327-AL1A */ +- .phy_id = QCA8327_A_PHY_ID, +- .phy_id_mask = QCA8K_PHY_ID_MASK, +- .name = "QCA PHY 8327-A", ++ .phy_id = QCA8327_A_PHY_ID, ++ .phy_id_mask = QCA8K_PHY_ID_MASK, ++ .name = "Qualcomm Atheros 8327-A internal PHY", + /* PHY_GBIT_FEATURES */ +- .probe = at803x_probe, +- .flags = PHY_IS_INTERNAL, +- .config_init = qca83xx_config_init, +- .soft_reset = genphy_soft_reset, +- .get_sset_count = at803x_get_sset_count, +- .get_strings = at803x_get_strings, +- .get_stats = at803x_get_stats, ++ .probe = at803x_probe, ++ .flags = PHY_IS_INTERNAL, ++ .config_init = qca83xx_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_sset_count = at803x_get_sset_count, ++ .get_strings = at803x_get_strings, ++ .get_stats = at803x_get_stats, + .suspend = genphy_suspend, + .resume = genphy_resume, + }, { + /* QCA8327-B from switch QCA8327-BL1A */ +- .phy_id = QCA8327_B_PHY_ID, +- .phy_id_mask = QCA8K_PHY_ID_MASK, +- .name = "QCA PHY 8327-B", ++ .phy_id = QCA8327_B_PHY_ID, ++ .phy_id_mask = QCA8K_PHY_ID_MASK, ++ .name = "Qualcomm Atheros 8327-B internal PHY", + /* PHY_GBIT_FEATURES */ +- .probe = at803x_probe, +- .flags = PHY_IS_INTERNAL, +- .config_init = qca83xx_config_init, +- .soft_reset = genphy_soft_reset, +- .get_sset_count = at803x_get_sset_count, +- .get_strings = at803x_get_strings, +- .get_stats = at803x_get_stats, ++ .probe = at803x_probe, ++ .flags = PHY_IS_INTERNAL, ++ .config_init = qca83xx_config_init, ++ .soft_reset = genphy_soft_reset, ++ .get_sset_count = at803x_get_sset_count, ++ .get_strings = at803x_get_strings, ++ .get_stats = at803x_get_stats, + .suspend = genphy_suspend, + .resume = genphy_resume, + }, }; diff --git a/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch b/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch new file mode 100644 index 00000000000..09797ae83bc --- /dev/null +++ b/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch @@ -0,0 +1,131 @@ +From ba3c01ee02ed0d821c9f241f179bbc9457542b8f Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 10 Oct 2021 00:46:15 +0200 +Subject: net: phy: at803x: fix resume for QCA8327 phy + +From Documentation phy resume triggers phy reset and restart +auto-negotiation. Add a dedicated function to wait reset to finish as +it was notice a regression where port sometime are not reliable after a +suspend/resume session. The reset wait logic is copied from phy_poll_reset. +Add dedicated suspend function to use genphy_suspend only with QCA8337 +phy and set only additional debug settings for QCA8327. With more test +it was reported that QCA8327 doesn't proprely support this mode and +using this cause the unreliability of the switch ports, especially the +malfunction of the port0. + +Fixes: 15b9df4ece17 ("net: phy: at803x: add resume/suspend function to qca83xx phy") +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 69 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 63 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -92,9 +92,14 @@ + #define AT803X_DEBUG_REG_5 0x05 + #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) + ++#define AT803X_DEBUG_REG_HIB_CTRL 0x0b ++#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) ++#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) ++ + #define AT803X_DEBUG_REG_3C 0x3C + + #define AT803X_DEBUG_REG_3D 0x3D ++#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) + + #define AT803X_DEBUG_REG_1F 0x1F + #define AT803X_DEBUG_PLL_ON BIT(2) +@@ -1304,6 +1309,58 @@ static int qca83xx_config_init(struct ph + return 0; + } + ++static int qca83xx_resume(struct phy_device *phydev) ++{ ++ int ret, val; ++ ++ /* Skip reset if not suspended */ ++ if (!phydev->suspended) ++ return 0; ++ ++ /* Reinit the port, reset values set by suspend */ ++ qca83xx_config_init(phydev); ++ ++ /* Reset the port on port resume */ ++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); ++ ++ /* On resume from suspend the switch execute a reset and ++ * restart auto-negotiation. Wait for reset to complete. ++ */ ++ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), ++ 50000, 600000, true); ++ if (ret) ++ return ret; ++ ++ msleep(1); ++ ++ return 0; ++} ++ ++static int qca83xx_suspend(struct phy_device *phydev) ++{ ++ u16 mask = 0; ++ ++ /* Only QCA8337 support actual suspend. ++ * QCA8327 cause port unreliability when phy suspend ++ * is set. ++ */ ++ if (phydev->drv->phy_id == QCA8337_PHY_ID) { ++ genphy_suspend(phydev); ++ } else { ++ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); ++ phy_modify(phydev, MII_BMCR, mask, 0); ++ } ++ ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D, ++ AT803X_DEBUG_GATE_CLK_IN1000, 0); ++ ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, ++ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | ++ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); ++ ++ return 0; ++} ++ + static struct phy_driver at803x_driver[] = { + { + /* Qualcomm Atheros AR8035 */ +@@ -1413,8 +1470,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, +- .suspend = genphy_suspend, +- .resume = genphy_resume, ++ .suspend = qca83xx_suspend, ++ .resume = qca83xx_resume, + }, { + /* QCA8327-A from switch QCA8327-AL1A */ + .phy_id = QCA8327_A_PHY_ID, +@@ -1428,8 +1485,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, +- .suspend = genphy_suspend, +- .resume = genphy_resume, ++ .suspend = qca83xx_suspend, ++ .resume = qca83xx_resume, + }, { + /* QCA8327-B from switch QCA8327-BL1A */ + .phy_id = QCA8327_B_PHY_ID, +@@ -1443,8 +1500,8 @@ static struct phy_driver at803x_driver[] + .get_sset_count = at803x_get_sset_count, + .get_strings = at803x_get_strings, + .get_stats = at803x_get_stats, +- .suspend = genphy_suspend, +- .resume = genphy_resume, ++ .suspend = qca83xx_suspend, ++ .resume = qca83xx_resume, + }, }; + + module_phy_driver(at803x_driver); diff --git a/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch b/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch new file mode 100644 index 00000000000..c504c37c84f --- /dev/null +++ b/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch @@ -0,0 +1,91 @@ +From 1ca8311949aec5c9447645731ef1c6bc5bd71350 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 10 Oct 2021 00:46:16 +0200 +Subject: net: phy: at803x: add DAC amplitude fix for 8327 phy + +QCA8327 internal phy require DAC amplitude adjustement set to +6% with +100m speed. Also add additional define to report a change of the same +reg in QCA8337. (different scope it does set 1000m voltage) +Add link_change_notify function to set the proper amplitude adjustement +on PHY_RUNNING state and disable on any other state. + +Fixes: b4df02b562f4 ("net: phy: at803x: add support for qca 8327 A variant internal phy") +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -87,6 +87,8 @@ + #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 + + #define AT803X_DEBUG_REG_0 0x00 ++#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) ++#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) + #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) + + #define AT803X_DEBUG_REG_5 0x05 +@@ -1306,9 +1308,37 @@ static int qca83xx_config_init(struct ph + break; + } + ++ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. ++ * Disable on init and enable only with 100m speed following ++ * qca original source code. ++ */ ++ if (phydev->drv->phy_id == QCA8327_A_PHY_ID || ++ phydev->drv->phy_id == QCA8327_B_PHY_ID) ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ QCA8327_DEBUG_MANU_CTRL_EN, 0); ++ + return 0; + } + ++static void qca83xx_link_change_notify(struct phy_device *phydev) ++{ ++ /* QCA8337 doesn't require DAC Amplitude adjustement */ ++ if (phydev->drv->phy_id == QCA8337_PHY_ID) ++ return; ++ ++ /* Set DAC Amplitude adjustment to +6% for 100m on link running */ ++ if (phydev->state == PHY_RUNNING) { ++ if (phydev->speed == SPEED_100) ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ QCA8327_DEBUG_MANU_CTRL_EN, ++ QCA8327_DEBUG_MANU_CTRL_EN); ++ } else { ++ /* Reset DAC Amplitude adjustment */ ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ QCA8327_DEBUG_MANU_CTRL_EN, 0); ++ } ++} ++ + static int qca83xx_resume(struct phy_device *phydev) + { + int ret, val; +@@ -1463,6 +1493,7 @@ static struct phy_driver at803x_driver[] + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8337 internal PHY", + /* PHY_GBIT_FEATURES */ ++ .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, +@@ -1478,6 +1509,7 @@ static struct phy_driver at803x_driver[] + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-A internal PHY", + /* PHY_GBIT_FEATURES */ ++ .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, +@@ -1493,6 +1525,7 @@ static struct phy_driver at803x_driver[] + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-B internal PHY", + /* PHY_GBIT_FEATURES */ ++ .link_change_notify = qca83xx_link_change_notify, + .probe = at803x_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, diff --git a/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch b/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch new file mode 100644 index 00000000000..9f880593f12 --- /dev/null +++ b/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch @@ -0,0 +1,27 @@ +From 9d1c29b4028557a496be9c5eb2b4b86063700636 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 10 Oct 2021 00:46:17 +0200 +Subject: net: phy: at803x: enable prefer master for 83xx internal phy + +From original QCA source code the port was set to prefer master as port +type in 1000BASE-T mode. Apply the same settings also here. + +Signed-off-by: Ansuel Smith +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1317,6 +1317,9 @@ static int qca83xx_config_init(struct ph + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + ++ /* Following original QCA sourcecode set port to prefer master */ ++ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); ++ + return 0; + } + diff --git a/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch b/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch new file mode 100644 index 00000000000..89e9b3f6623 --- /dev/null +++ b/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch @@ -0,0 +1,127 @@ +From 67999555ff42e91de7654488d9a7735bd9e84555 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 10 Oct 2021 00:46:18 +0200 +Subject: net: phy: at803x: better describe debug regs + +Give a name to known debug regs from Documentation instead of using +unknown hex values. + +Signed-off-by: Ansuel Smith +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -86,12 +86,12 @@ + #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ + #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 + +-#define AT803X_DEBUG_REG_0 0x00 ++#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 + #define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) + #define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) + #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) + +-#define AT803X_DEBUG_REG_5 0x05 ++#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 + #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) + + #define AT803X_DEBUG_REG_HIB_CTRL 0x0b +@@ -100,7 +100,7 @@ + + #define AT803X_DEBUG_REG_3C 0x3C + +-#define AT803X_DEBUG_REG_3D 0x3D ++#define AT803X_DEBUG_REG_GREEN 0x3D + #define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) + + #define AT803X_DEBUG_REG_1F 0x1F +@@ -284,25 +284,25 @@ static int at803x_read_page(struct phy_d + + static int at803x_enable_rx_delay(struct phy_device *phydev) + { +- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0, ++ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, + AT803X_DEBUG_RX_CLK_DLY_EN); + } + + static int at803x_enable_tx_delay(struct phy_device *phydev) + { +- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0, ++ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, + AT803X_DEBUG_TX_CLK_DLY_EN); + } + + static int at803x_disable_rx_delay(struct phy_device *phydev) + { +- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + AT803X_DEBUG_RX_CLK_DLY_EN, 0); + } + + static int at803x_disable_tx_delay(struct phy_device *phydev) + { +- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, ++ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, + AT803X_DEBUG_TX_CLK_DLY_EN, 0); + } + +@@ -1292,9 +1292,9 @@ static int qca83xx_config_init(struct ph + switch (switch_revision) { + case 1: + /* For 100M waveform */ +- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea); ++ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); + /* Turn on Gigabit clock */ +- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0); ++ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); + break; + + case 2: +@@ -1302,8 +1302,8 @@ static int qca83xx_config_init(struct ph + fallthrough; + case 4: + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); +- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860); +- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46); ++ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); ++ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); + break; + } +@@ -1314,7 +1314,7 @@ static int qca83xx_config_init(struct ph + */ + if (phydev->drv->phy_id == QCA8327_A_PHY_ID || + phydev->drv->phy_id == QCA8327_B_PHY_ID) +- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + + /* Following original QCA sourcecode set port to prefer master */ +@@ -1332,12 +1332,12 @@ static void qca83xx_link_change_notify(s + /* Set DAC Amplitude adjustment to +6% for 100m on link running */ + if (phydev->state == PHY_RUNNING) { + if (phydev->speed == SPEED_100) +- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, + QCA8327_DEBUG_MANU_CTRL_EN); + } else { + /* Reset DAC Amplitude adjustment */ +- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + } + } +@@ -1384,7 +1384,7 @@ static int qca83xx_suspend(struct phy_de + phy_modify(phydev, MII_BMCR, mask, 0); + } + +- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D, ++ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, + AT803X_DEBUG_GATE_CLK_IN1000, 0); + + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, diff --git a/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch b/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch new file mode 100644 index 00000000000..c8d424de38c --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch @@ -0,0 +1,80 @@ +From d8b6f5bae6d3b648a67b6958cb98e4e97256d652 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:06 +0200 +Subject: dsa: qca8k: add mac_power_sel support + +Add missing mac power sel support needed for ipq8064/5 SoC that require +1.8v for the internal regulator port instead of the default 1.5v. +If other device needs this, consider adding a dedicated binding to +support this. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 31 +++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 5 +++++ + 2 files changed, 36 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -951,6 +951,33 @@ qca8k_setup_of_rgmii_delay(struct qca8k_ + } + + static int ++qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) ++{ ++ u32 mask = 0; ++ int ret = 0; ++ ++ /* SoC specific settings for ipq8064. ++ * If more device require this consider adding ++ * a dedicated binding. ++ */ ++ if (of_machine_is_compatible("qcom,ipq8064")) ++ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; ++ ++ /* SoC specific settings for ipq8065 */ ++ if (of_machine_is_compatible("qcom,ipq8065")) ++ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; ++ ++ if (mask) { ++ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, ++ QCA8K_MAC_PWR_RGMII0_1_8V | ++ QCA8K_MAC_PWR_RGMII1_1_8V, ++ mask); ++ } ++ ++ return ret; ++} ++ ++static int + qca8k_setup(struct dsa_switch *ds) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +@@ -979,6 +1006,10 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + ++ ret = qca8k_setup_mac_pwr_sel(priv); ++ if (ret) ++ return ret; ++ + /* Enable CPU Port */ + ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, + QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -100,6 +100,11 @@ + #define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) + #define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) + ++/* MAC_PWR_SEL registers */ ++#define QCA8K_REG_MAC_PWR_SEL 0x0e4 ++#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) ++#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) ++ + /* EEE control registers */ + #define QCA8K_REG_EEE_CTRL 0x100 + #define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) diff --git a/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch b/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch new file mode 100644 index 00000000000..bd768ec27d4 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch @@ -0,0 +1,30 @@ +From fdbf35df9c091db9c46e57e9938e3f7a4f603a7c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:07 +0200 +Subject: dt-bindings: net: dsa: qca8k: Add SGMII clock phase properties + +Add names and descriptions of additional PORT0_PAD_CTRL properties. +qca,sgmii-(rx|tx)clk-falling-edge are for setting the respective clock +phase to failling edge. + +Co-developed-by: Matthew Hagan +Signed-off-by: Matthew Hagan +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/qca8k.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt +@@ -37,6 +37,10 @@ A CPU port node has the following option + managed entity. See + Documentation/devicetree/bindings/net/fixed-link.txt + for details. ++- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge. ++ Mostly used in qca8327 with CPU port 0 set to ++ sgmii. ++- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. + + For QCA8K the 'fixed-link' sub-node supports only the following properties: + diff --git a/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch b/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch new file mode 100644 index 00000000000..e464452d82c --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch @@ -0,0 +1,127 @@ +From 6c43809bf1bee76c434e365a26546a92a5fbec14 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:08 +0200 +Subject: net: dsa: qca8k: add support for sgmii falling edge + +Add support for this in the qca8k driver. Also add support for SGMII +rx/tx clock falling edge. This is only present for pad0, pad5 and +pad6 have these bit reserved from Documentation. Add a comment that this +is hardcoded to PAD0 as qca8327/28/34/37 have an unique sgmii line and +setting falling in port0 applies to both configuration with sgmii used +for port0 or port6. + +Co-developed-by: Matthew Hagan +Signed-off-by: Matthew Hagan +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 4 ++++ + 2 files changed, 67 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -978,6 +978,42 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri + } + + static int ++qca8k_parse_port_config(struct qca8k_priv *priv) ++{ ++ struct device_node *port_dn; ++ phy_interface_t mode; ++ struct dsa_port *dp; ++ int port, ret; ++ ++ /* We have 2 CPU port. Check them */ ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Skip every other port */ ++ if (port != 0 && port != 6) ++ continue; ++ ++ dp = dsa_to_port(priv->ds, port); ++ port_dn = dp->dn; ++ ++ if (!of_device_is_available(port_dn)) ++ continue; ++ ++ ret = of_get_phy_mode(port_dn, &mode); ++ if (ret) ++ continue; ++ ++ if (mode == PHY_INTERFACE_MODE_SGMII) { ++ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) ++ priv->sgmii_tx_clk_falling_edge = true; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) ++ priv->sgmii_rx_clk_falling_edge = true; ++ } ++ } ++ ++ return 0; ++} ++ ++static int + qca8k_setup(struct dsa_switch *ds) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +@@ -990,6 +1026,11 @@ qca8k_setup(struct dsa_switch *ds) + return -EINVAL; + } + ++ /* Parse CPU port config to be later used in phy_link mac_config */ ++ ret = qca8k_parse_port_config(priv); ++ if (ret) ++ return ret; ++ + mutex_init(&priv->reg_mutex); + + /* Start by setting up the register mapping */ +@@ -1274,6 +1315,28 @@ qca8k_phylink_mac_config(struct dsa_swit + } + + qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); ++ ++ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and ++ * falling edge is set writing in the PORT0 PAD reg ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327 || ++ priv->switch_id == QCA8K_ID_QCA8337) ++ reg = QCA8K_REG_PORT0_PAD_CTRL; ++ ++ val = 0; ++ ++ /* SGMII Clock phase configuration */ ++ if (priv->sgmii_rx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; ++ ++ if (priv->sgmii_tx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; ++ ++ if (val) ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | ++ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, ++ val); + break; + default: + dev_err(ds->dev, "xMII mode %s not supported for port %d\n", +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -35,6 +35,8 @@ + #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) + #define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) + #define QCA8K_REG_PORT0_PAD_CTRL 0x004 ++#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) ++#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) + #define QCA8K_REG_PORT5_PAD_CTRL 0x008 + #define QCA8K_REG_PORT6_PAD_CTRL 0x00c + #define QCA8K_PORT_PAD_RGMII_EN BIT(26) +@@ -260,6 +262,8 @@ struct qca8k_priv { + u8 switch_revision; + u8 rgmii_tx_delay; + u8 rgmii_rx_delay; ++ bool sgmii_rx_clk_falling_edge; ++ bool sgmii_tx_clk_falling_edge; + bool legacy_phy_port_mapping; + struct regmap *regmap; + struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch b/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch new file mode 100644 index 00000000000..606ac0af3da --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch @@ -0,0 +1,29 @@ +From 731d613338ec6de482053ffa3f71be2325b0f8eb Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:09 +0200 +Subject: dt-bindings: net: dsa: qca8k: Document support for CPU port 6 + +The switch now support CPU port to be set 6 instead of be hardcoded to +0. Document support for it and describe logic selection. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/qca8k.txt | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt +@@ -29,7 +29,11 @@ the mdio MASTER is used as communication + Don't use mixed external and internal mdio-bus configurations, as this is + not supported by the hardware. + +-The CPU port of this switch is always port 0. ++This switch support 2 CPU port. Normally and advised configuration is with ++CPU port set to port 0. It is also possible to set the CPU port to port 6 ++if the device requires it. The driver will configure the switch to the defined ++port. With both CPU port declared the first CPU port is selected as primary ++and the secondary CPU ignored. + + A CPU port node has the following optional node: + diff --git a/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch b/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch new file mode 100644 index 00000000000..320db8fa9f9 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch @@ -0,0 +1,153 @@ +From 3fcf734aa482487df83cf8f18608438fcf59127f Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:10 +0200 +Subject: net: dsa: qca8k: add support for cpu port 6 + +Currently CPU port is always hardcoded to port 0. This switch have 2 CPU +ports. The original intention of this driver seems to be use the +mac06_exchange bit to swap MAC0 with MAC6 in the strange configuration +where device have connected only the CPU port 6. To skip the +introduction of a new binding, rework the driver to address the +secondary CPU port as primary and drop any reference of hardcoded port. +With configuration of mac06 exchange, just skip the definition of port0 +and define the CPU port as a secondary. The driver will autoconfigure +the switch to use that as the primary CPU port. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 51 ++++++++++++++++++++++++++++++++++--------------- + drivers/net/dsa/qca8k.h | 2 -- + 2 files changed, 36 insertions(+), 17 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -977,6 +977,22 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri + return ret; + } + ++static int qca8k_find_cpu_port(struct dsa_switch *ds) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Find the connected cpu port. Valid port are 0 or 6 */ ++ if (dsa_is_cpu_port(ds, 0)) ++ return 0; ++ ++ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); ++ ++ if (dsa_is_cpu_port(ds, 6)) ++ return 6; ++ ++ return -EINVAL; ++} ++ + static int + qca8k_parse_port_config(struct qca8k_priv *priv) + { +@@ -1017,13 +1033,13 @@ static int + qca8k_setup(struct dsa_switch *ds) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int ret, i; ++ int cpu_port, ret, i; + u32 mask; + +- /* Make sure that port 0 is the cpu port */ +- if (!dsa_is_cpu_port(ds, 0)) { +- dev_err(priv->dev, "port 0 is not the CPU port"); +- return -EINVAL; ++ cpu_port = qca8k_find_cpu_port(ds); ++ if (cpu_port < 0) { ++ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); ++ return cpu_port; + } + + /* Parse CPU port config to be later used in phy_link mac_config */ +@@ -1065,7 +1081,7 @@ qca8k_setup(struct dsa_switch *ds) + dev_warn(priv->dev, "mib init failed"); + + /* Enable QCA header mode on the cpu port */ +- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT), ++ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port), + QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | + QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); + if (ret) { +@@ -1087,10 +1103,10 @@ qca8k_setup(struct dsa_switch *ds) + + /* Forward all unknown frames to CPU port for Linux processing */ + ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, +- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | +- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | +- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | +- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); ++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | ++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | ++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | ++ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); + if (ret) + return ret; + +@@ -1098,7 +1114,7 @@ qca8k_setup(struct dsa_switch *ds) + for (i = 0; i < QCA8K_NUM_PORTS; i++) { + /* CPU port gets connected to all user ports of the switch */ + if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT), ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port), + QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); + if (ret) + return ret; +@@ -1110,7 +1126,7 @@ qca8k_setup(struct dsa_switch *ds) + + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_MEMBER, +- BIT(QCA8K_CPU_PORT)); ++ BIT(cpu_port)); + if (ret) + return ret; + +@@ -1616,9 +1632,12 @@ static int + qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int port_mask = BIT(QCA8K_CPU_PORT); ++ int port_mask, cpu_port; + int i, ret; + ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ port_mask = BIT(cpu_port); ++ + for (i = 1; i < QCA8K_NUM_PORTS; i++) { + if (dsa_to_port(ds, i)->bridge_dev != br) + continue; +@@ -1645,7 +1664,9 @@ static void + qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int i; ++ int cpu_port, i; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + + for (i = 1; i < QCA8K_NUM_PORTS; i++) { + if (dsa_to_port(ds, i)->bridge_dev != br) +@@ -1662,7 +1683,7 @@ qca8k_port_bridge_leave(struct dsa_switc + * this port + */ + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT)); ++ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); + } + + static int +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -24,8 +24,6 @@ + + #define QCA8K_NUM_FDB_RECORDS 2048 + +-#define QCA8K_CPU_PORT 0 +- + #define QCA8K_PORT_VID_DEF 1 + + /* Global control registers */ diff --git a/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch b/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch new file mode 100644 index 00000000000..de201764f98 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch @@ -0,0 +1,295 @@ +From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:11 +0200 +Subject: net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6 + +Future proof commit. This switch have 2 CPU ports and one valid +configuration is first CPU port set to sgmii and second CPU port set to +rgmii-id. The current implementation detects delay only for CPU port +zero set to rgmii and doesn't count any delay set in a secondary CPU +port. Drop the current delay scan function and move it to the sgmii +parser function to generalize and implicitly add support for secondary +CPU port set to rgmii-id. Introduce new logic where delay is enabled +also with internal delay binding declared and rgmii set as PHY mode. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 165 ++++++++++++++++++++++++------------------------ + drivers/net/dsa/qca8k.h | 10 ++- + 2 files changed, 89 insertions(+), 86 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -889,68 +889,6 @@ qca8k_setup_mdio_bus(struct qca8k_priv * + } + + static int +-qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv) +-{ +- struct device_node *port_dn; +- phy_interface_t mode; +- struct dsa_port *dp; +- u32 val; +- +- /* CPU port is already checked */ +- dp = dsa_to_port(priv->ds, 0); +- +- port_dn = dp->dn; +- +- /* Check if port 0 is set to the correct type */ +- of_get_phy_mode(port_dn, &mode); +- if (mode != PHY_INTERFACE_MODE_RGMII_ID && +- mode != PHY_INTERFACE_MODE_RGMII_RXID && +- mode != PHY_INTERFACE_MODE_RGMII_TXID) { +- return 0; +- } +- +- switch (mode) { +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val)) +- val = 2; +- else +- /* Switch regs accept value in ns, convert ps to ns */ +- val = val / 1000; +- +- if (val > QCA8K_MAX_DELAY) { +- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); +- val = 3; +- } +- +- priv->rgmii_rx_delay = val; +- /* Stop here if we need to check only for rx delay */ +- if (mode != PHY_INTERFACE_MODE_RGMII_ID) +- break; +- +- fallthrough; +- case PHY_INTERFACE_MODE_RGMII_TXID: +- if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val)) +- val = 1; +- else +- /* Switch regs accept value in ns, convert ps to ns */ +- val = val / 1000; +- +- if (val > QCA8K_MAX_DELAY) { +- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); +- val = 3; +- } +- +- priv->rgmii_tx_delay = val; +- break; +- default: +- return 0; +- } +- +- return 0; +-} +- +-static int + qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) + { + u32 mask = 0; +@@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct ds + static int + qca8k_parse_port_config(struct qca8k_priv *priv) + { ++ int port, cpu_port_index = 0, ret; + struct device_node *port_dn; + phy_interface_t mode; + struct dsa_port *dp; +- int port, ret; ++ u32 delay; + + /* We have 2 CPU port. Check them */ +- for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { + /* Skip every other port */ + if (port != 0 && port != 6) + continue; + + dp = dsa_to_port(priv->ds, port); + port_dn = dp->dn; ++ cpu_port_index++; + + if (!of_device_is_available(port_dn)) + continue; +@@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_pri + if (ret) + continue; + +- if (mode == PHY_INTERFACE_MODE_SGMII) { ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID) ++ delay = 1; ++ ++ if (delay > QCA8K_MAX_DELAY) { ++ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->rgmii_tx_delay[cpu_port_index] = delay; ++ ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ delay = 2; ++ ++ if (delay > QCA8K_MAX_DELAY) { ++ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->rgmii_rx_delay[cpu_port_index] = delay; ++ ++ break; ++ case PHY_INTERFACE_MODE_SGMII: + if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) + priv->sgmii_tx_clk_falling_edge = true; + + if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) + priv->sgmii_rx_clk_falling_edge = true; ++ ++ break; ++ default: ++ continue; + } + } + +@@ -1059,10 +1041,6 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + +- ret = qca8k_setup_of_rgmii_delay(priv); +- if (ret) +- return ret; +- + ret = qca8k_setup_mac_pwr_sel(priv); + if (ret) + return ret; +@@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_swit + const struct phylink_link_state *state) + { + struct qca8k_priv *priv = ds->priv; +- u32 reg, val; +- int ret; ++ int cpu_port_index, ret; ++ u32 reg, val, delay; + + switch (port) { + case 0: /* 1st CPU port */ +@@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_swit + return; + + reg = QCA8K_REG_PORT0_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT0; + break; + case 1: + case 2: +@@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_swit + return; + + reg = QCA8K_REG_PORT6_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT6; + break; + default: + dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); +@@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_swit + + switch (state->interface) { + case PHY_INTERFACE_MODE_RGMII: +- /* RGMII mode means no delay so don't enable the delay */ +- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); +- break; + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: +- /* RGMII_ID needs internal delay. This is enabled through +- * PORT5_PAD_CTRL for all ports, rather than individual port +- * registers ++ val = QCA8K_PORT_PAD_RGMII_EN; ++ ++ /* Delay can be declared in 3 different way. ++ * Mode to rgmii and internal-delay standard binding defined ++ * rgmii-id or rgmii-tx/rx phy mode set. ++ * The parse logic set a delay different than 0 only when one ++ * of the 3 different way is used. In all other case delay is ++ * not enabled. With ID or TX/RXID delay is enabled and set ++ * to the default and recommended value. ++ */ ++ if (priv->rgmii_tx_delay[cpu_port_index]) { ++ delay = priv->rgmii_tx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; ++ } ++ ++ if (priv->rgmii_rx_delay[cpu_port_index]) { ++ delay = priv->rgmii_rx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; ++ } ++ ++ /* Set RGMII delay based on the selected values */ ++ qca8k_write(priv, reg, val); ++ ++ /* QCA8337 requires to set rgmii rx delay for all ports. ++ * This is enabled through PORT5_PAD_CTRL for all ports, ++ * rather than individual port registers. + */ +- qca8k_write(priv, reg, +- QCA8K_PORT_PAD_RGMII_EN | +- QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) | +- QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); +- /* QCA8337 requires to set rgmii rx delay */ + if (priv->switch_id == QCA8K_ID_QCA8337) + qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -13,6 +13,7 @@ + #include + + #define QCA8K_NUM_PORTS 7 ++#define QCA8K_NUM_CPU_PORTS 2 + #define QCA8K_MAX_MTU 9000 + + #define PHY_ID_QCA8327 0x004dd034 +@@ -255,13 +256,18 @@ struct qca8k_match_data { + u8 id; + }; + ++enum { ++ QCA8K_CPU_PORT0, ++ QCA8K_CPU_PORT6, ++}; ++ + struct qca8k_priv { + u8 switch_id; + u8 switch_revision; +- u8 rgmii_tx_delay; +- u8 rgmii_rx_delay; + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; ++ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ ++ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ + bool legacy_phy_port_mapping; + struct regmap *regmap; + struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch b/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch new file mode 100644 index 00000000000..8abd264e794 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch @@ -0,0 +1,33 @@ +From 13ad5ccc093ff448b99ac7e138e91e78796adb48 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:12 +0200 +Subject: dt-bindings: net: dsa: qca8k: Document qca,sgmii-enable-pll + +Document qca,sgmii-enable-pll binding used in the CPU nodes to +enable SGMII PLL on MAC config. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/qca8k.txt | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt +@@ -45,6 +45,16 @@ A CPU port node has the following option + Mostly used in qca8327 with CPU port 0 set to + sgmii. + - qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. ++- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX ++ chain along with Signal Detection. ++ This should NOT be enabled for qca8327. If enabled with ++ qca8327 the sgmii port won't correctly init and an err ++ is printed. ++ This can be required for qca8337 switch with revision 2. ++ A warning is displayed when used with revision greater ++ 2. ++ With CPU port set to sgmii and qca8337 it is advised ++ to set this unless a communication problem is observed. + + For QCA8K the 'fixed-link' sub-node supports only the following properties: + diff --git a/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch b/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch new file mode 100644 index 00000000000..2b5a84a1b0e --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch @@ -0,0 +1,65 @@ +From bbc4799e8bb6c397e3b3fec13de68e179f5db9ff Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:13 +0200 +Subject: net: dsa: qca8k: add explicit SGMII PLL enable + +Support enabling PLL on the SGMII CPU port. Some device require this +special configuration or no traffic is transmitted and the switch +doesn't work at all. A dedicated binding is added to the CPU node +port to apply the correct reg on mac config. +Fail to correctly configure sgmii with qca8327 switch and warn if pll is +used on qca8337 with a revision greater than 1. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 19 +++++++++++++++++-- + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 18 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1002,6 +1002,18 @@ qca8k_parse_port_config(struct qca8k_pri + if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) + priv->sgmii_rx_clk_falling_edge = true; + ++ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { ++ priv->sgmii_enable_pll = true; ++ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); ++ priv->sgmii_enable_pll = false; ++ } ++ ++ if (priv->switch_revision < 2) ++ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); ++ } ++ + break; + default: + continue; +@@ -1312,8 +1324,11 @@ qca8k_phylink_mac_config(struct dsa_swit + if (ret) + return; + +- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | +- QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD; ++ val |= QCA8K_SGMII_EN_SD; ++ ++ if (priv->sgmii_enable_pll) ++ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | ++ QCA8K_SGMII_EN_TX; + + if (dsa_is_cpu_port(ds, port)) { + /* CPU port, we're talking to the CPU MAC, be a PHY */ +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -266,6 +266,7 @@ struct qca8k_priv { + u8 switch_revision; + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; ++ bool sgmii_enable_pll; + u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ + u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ + bool legacy_phy_port_mapping; diff --git a/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch b/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch new file mode 100644 index 00000000000..38dc954e8cb --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch @@ -0,0 +1,37 @@ +From 924087c5c3d41553700b0eb83ca2a53b91643dca Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:14 +0200 +Subject: dt-bindings: net: dsa: qca8k: Document qca,led-open-drain binding + +Document new binding qca,ignore-power-on-sel used to ignore +power on strapping and use sw regs instead. +Document qca,led-open.drain to set led to open drain mode, the +qca,ignore-power-on-sel is mandatory with this enabled or an error will +be reported. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/qca8k.txt | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt +@@ -13,6 +13,17 @@ Required properties: + Optional properties: + + - reset-gpios: GPIO to be used to reset the whole device ++- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open ++ drain or eeprom presence. This is needed for broken ++ devices that have wrong configuration or when the oem ++ decided to not use pin strapping and fallback to sw ++ regs. ++- qca,led-open-drain: Set leds to open-drain mode. This requires the ++ qca,ignore-power-on-sel to be set or the driver will fail ++ to probe. This is needed if the oem doesn't use pin ++ strapping to set this mode and prefers to set it using sw ++ regs. The pin strapping related to led open drain mode is ++ the pin B68 for QCA832x and B49 for QCA833x + + Subnodes: + diff --git a/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch b/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch new file mode 100644 index 00000000000..aa5d92a4fde --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch @@ -0,0 +1,92 @@ +From 362bb238d8bf1470424214a8a5968d9c6cce68fa Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:15 +0200 +Subject: net: dsa: qca8k: add support for pws config reg + +Some qca8327 switch require to force the ignore of power on sel +strapping. Some switch require to set the led open drain mode in regs +instead of using strapping. While most of the device implements this +using the correct way using pin strapping, there are still some broken +device that require to be set using sw regs. +Introduce a new binding and support these special configuration. +As led open drain require to ignore pin strapping to work, the probe +fails with EINVAL error with incorrect configuration. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 39 +++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 6 ++++++ + 2 files changed, 45 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -932,6 +932,41 @@ static int qca8k_find_cpu_port(struct ds + } + + static int ++qca8k_setup_of_pws_reg(struct qca8k_priv *priv) ++{ ++ struct device_node *node = priv->dev->of_node; ++ u32 val = 0; ++ int ret; ++ ++ /* QCA8327 require to set to the correct mode. ++ * His bigger brother QCA8328 have the 172 pin layout. ++ * Should be applied by default but we set this just to make sure. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, ++ QCA8327_PWS_PACKAGE148_EN); ++ if (ret) ++ return ret; ++ } ++ ++ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) ++ val |= QCA8K_PWS_POWER_ON_SEL; ++ ++ if (of_property_read_bool(node, "qca,led-open-drain")) { ++ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { ++ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); ++ return -EINVAL; ++ } ++ ++ val |= QCA8K_PWS_LED_OPEN_EN_CSR; ++ } ++ ++ return qca8k_rmw(priv, QCA8K_REG_PWS, ++ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, ++ val); ++} ++ ++static int + qca8k_parse_port_config(struct qca8k_priv *priv) + { + int port, cpu_port_index = 0, ret; +@@ -1053,6 +1088,10 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + ++ ret = qca8k_setup_of_pws_reg(priv); ++ if (ret) ++ return ret; ++ + ret = qca8k_setup_mac_pwr_sel(priv); + if (ret) + return ret; +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -46,6 +46,12 @@ + #define QCA8K_MAX_DELAY 3 + #define QCA8K_PORT_PAD_SGMII_EN BIT(7) + #define QCA8K_REG_PWS 0x010 ++#define QCA8K_PWS_POWER_ON_SEL BIT(31) ++/* This reg is only valid for QCA832x and toggle the package ++ * type from 176 pin (by default) to 148 pin used on QCA8327 ++ */ ++#define QCA8327_PWS_PACKAGE148_EN BIT(30) ++#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) + #define QCA8K_PWS_SERDES_AEN_DIS BIT(7) + #define QCA8K_REG_MODULE_EN 0x030 + #define QCA8K_MODULE_EN_MIB BIT(0) diff --git a/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch b/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch new file mode 100644 index 00000000000..1bfb00c5b2c --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch @@ -0,0 +1,32 @@ +From ed7988d77fbfb79366b68f9e7fa60a6080da23d4 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:16 +0200 +Subject: dt-bindings: net: dsa: qca8k: document support for qca8328 + +QCA8328 is the bigger brother of qca8327. Document the new compatible +binding and add some information to understand the various switch +compatible. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/dsa/qca8k.txt | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt +@@ -3,9 +3,10 @@ + Required properties: + + - compatible: should be one of: +- "qca,qca8327" +- "qca,qca8334" +- "qca,qca8337" ++ "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package ++ "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package ++ "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package ++ "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package + + - #size-cells: must be 0 + - #address-cells: must be 1 diff --git a/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch b/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch new file mode 100644 index 00000000000..b300621e63e --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch @@ -0,0 +1,78 @@ +From f477d1c8bdbef4f400718238e350f16f521d2a3e Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:17 +0200 +Subject: net: dsa: qca8k: add support for QCA8328 + +QCA8328 switch is the bigger brother of the qca8327. Same regs different +chip. Change the function to set the correct pin layout and introduce a +new match_data to differentiate the 2 switch as they have the same ID +and their internal PHY have the same ID. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 19 ++++++++++++++++--- + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 17 insertions(+), 3 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -935,6 +935,7 @@ static int + qca8k_setup_of_pws_reg(struct qca8k_priv *priv) + { + struct device_node *node = priv->dev->of_node; ++ const struct qca8k_match_data *data; + u32 val = 0; + int ret; + +@@ -943,8 +944,14 @@ qca8k_setup_of_pws_reg(struct qca8k_priv + * Should be applied by default but we set this just to make sure. + */ + if (priv->switch_id == QCA8K_ID_QCA8327) { ++ data = of_device_get_match_data(priv->dev); ++ ++ /* Set the correct package of 148 pin for QCA8327 */ ++ if (data->reduced_package) ++ val |= QCA8327_PWS_PACKAGE148_EN; ++ + ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, +- QCA8327_PWS_PACKAGE148_EN); ++ val); + if (ret) + return ret; + } +@@ -2124,7 +2131,12 @@ static int qca8k_resume(struct device *d + static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, + qca8k_suspend, qca8k_resume); + +-static const struct qca8k_match_data qca832x = { ++static const struct qca8k_match_data qca8327 = { ++ .id = QCA8K_ID_QCA8327, ++ .reduced_package = true, ++}; ++ ++static const struct qca8k_match_data qca8328 = { + .id = QCA8K_ID_QCA8327, + }; + +@@ -2133,7 +2145,8 @@ static const struct qca8k_match_data qca + }; + + static const struct of_device_id qca8k_of_match[] = { +- { .compatible = "qca,qca8327", .data = &qca832x }, ++ { .compatible = "qca,qca8327", .data = &qca8327 }, ++ { .compatible = "qca,qca8328", .data = &qca8328 }, + { .compatible = "qca,qca8334", .data = &qca833x }, + { .compatible = "qca,qca8337", .data = &qca833x }, + { /* sentinel */ }, +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -260,6 +260,7 @@ struct ar8xxx_port_status { + + struct qca8k_match_data { + u8 id; ++ bool reduced_package; + }; + + enum { diff --git a/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch b/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch new file mode 100644 index 00000000000..27f94dca027 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch @@ -0,0 +1,159 @@ +From cef08115846e581f80ff99abf7bf218da1840616 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:18 +0200 +Subject: net: dsa: qca8k: set internal delay also for sgmii + +QCA original code report port instability and sa that SGMII also require +to set internal delay. Generalize the rgmii delay function and apply the +advised value if they are not defined in DT. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 88 +++++++++++++++++++++++++++++++++---------------- + drivers/net/dsa/qca8k.h | 2 ++ + 2 files changed, 62 insertions(+), 28 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1004,6 +1004,7 @@ qca8k_parse_port_config(struct qca8k_pri + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_SGMII: + delay = 0; + + if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) +@@ -1036,8 +1037,13 @@ qca8k_parse_port_config(struct qca8k_pri + + priv->rgmii_rx_delay[cpu_port_index] = delay; + +- break; +- case PHY_INTERFACE_MODE_SGMII: ++ /* Skip sgmii parsing for rgmii* mode */ ++ if (mode == PHY_INTERFACE_MODE_RGMII || ++ mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ break; ++ + if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) + priv->sgmii_tx_clk_falling_edge = true; + +@@ -1261,12 +1267,53 @@ qca8k_setup(struct dsa_switch *ds) + } + + static void ++qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, ++ u32 reg) ++{ ++ u32 delay, val = 0; ++ int ret; ++ ++ /* Delay can be declared in 3 different way. ++ * Mode to rgmii and internal-delay standard binding defined ++ * rgmii-id or rgmii-tx/rx phy mode set. ++ * The parse logic set a delay different than 0 only when one ++ * of the 3 different way is used. In all other case delay is ++ * not enabled. With ID or TX/RXID delay is enabled and set ++ * to the default and recommended value. ++ */ ++ if (priv->rgmii_tx_delay[cpu_port_index]) { ++ delay = priv->rgmii_tx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; ++ } ++ ++ if (priv->rgmii_rx_delay[cpu_port_index]) { ++ delay = priv->rgmii_rx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; ++ } ++ ++ /* Set RGMII delay based on the selected values */ ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, ++ val); ++ if (ret) ++ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", ++ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); ++} ++ ++static void + qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, + const struct phylink_link_state *state) + { + struct qca8k_priv *priv = ds->priv; + int cpu_port_index, ret; +- u32 reg, val, delay; ++ u32 reg, val; + + switch (port) { + case 0: /* 1st CPU port */ +@@ -1315,32 +1362,10 @@ qca8k_phylink_mac_config(struct dsa_swit + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: +- val = QCA8K_PORT_PAD_RGMII_EN; +- +- /* Delay can be declared in 3 different way. +- * Mode to rgmii and internal-delay standard binding defined +- * rgmii-id or rgmii-tx/rx phy mode set. +- * The parse logic set a delay different than 0 only when one +- * of the 3 different way is used. In all other case delay is +- * not enabled. With ID or TX/RXID delay is enabled and set +- * to the default and recommended value. +- */ +- if (priv->rgmii_tx_delay[cpu_port_index]) { +- delay = priv->rgmii_tx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; +- } +- +- if (priv->rgmii_rx_delay[cpu_port_index]) { +- delay = priv->rgmii_rx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; +- } ++ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); + +- /* Set RGMII delay based on the selected values */ +- qca8k_write(priv, reg, val); ++ /* Configure rgmii delay */ ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); + + /* QCA8337 requires to set rgmii rx delay for all ports. + * This is enabled through PORT5_PAD_CTRL for all ports, +@@ -1411,6 +1436,13 @@ qca8k_phylink_mac_config(struct dsa_swit + QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | + QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, + val); ++ ++ /* From original code is reported port instability as SGMII also ++ * require delay set. Apply advised values here or take them from DT. ++ */ ++ if (state->interface == PHY_INTERFACE_MODE_SGMII) ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ + break; + default: + dev_err(ds->dev, "xMII mode %s not supported for port %d\n", +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -39,7 +39,9 @@ + #define QCA8K_REG_PORT5_PAD_CTRL 0x008 + #define QCA8K_REG_PORT6_PAD_CTRL 0x00c + #define QCA8K_PORT_PAD_RGMII_EN BIT(26) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) + #define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) ++#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) + #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) + #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) + #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) diff --git a/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch b/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch new file mode 100644 index 00000000000..b991798c87f --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch @@ -0,0 +1,124 @@ +From fd0bb28c547f7c8affb1691128cece38f5b626a1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:19 +0200 +Subject: net: dsa: qca8k: move port config to dedicated struct + +Move ports related config to dedicated struct to keep things organized. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 26 +++++++++++++------------- + drivers/net/dsa/qca8k.h | 10 +++++++--- + 2 files changed, 20 insertions(+), 16 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1019,7 +1019,7 @@ qca8k_parse_port_config(struct qca8k_pri + delay = 3; + } + +- priv->rgmii_tx_delay[cpu_port_index] = delay; ++ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; + + delay = 0; + +@@ -1035,7 +1035,7 @@ qca8k_parse_port_config(struct qca8k_pri + delay = 3; + } + +- priv->rgmii_rx_delay[cpu_port_index] = delay; ++ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; + + /* Skip sgmii parsing for rgmii* mode */ + if (mode == PHY_INTERFACE_MODE_RGMII || +@@ -1045,17 +1045,17 @@ qca8k_parse_port_config(struct qca8k_pri + break; + + if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) +- priv->sgmii_tx_clk_falling_edge = true; ++ priv->ports_config.sgmii_tx_clk_falling_edge = true; + + if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) +- priv->sgmii_rx_clk_falling_edge = true; ++ priv->ports_config.sgmii_rx_clk_falling_edge = true; + + if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { +- priv->sgmii_enable_pll = true; ++ priv->ports_config.sgmii_enable_pll = true; + + if (priv->switch_id == QCA8K_ID_QCA8327) { + dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); +- priv->sgmii_enable_pll = false; ++ priv->ports_config.sgmii_enable_pll = false; + } + + if (priv->switch_revision < 2) +@@ -1281,15 +1281,15 @@ qca8k_mac_config_setup_internal_delay(st + * not enabled. With ID or TX/RXID delay is enabled and set + * to the default and recommended value. + */ +- if (priv->rgmii_tx_delay[cpu_port_index]) { +- delay = priv->rgmii_tx_delay[cpu_port_index]; ++ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; + + val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | + QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; + } + +- if (priv->rgmii_rx_delay[cpu_port_index]) { +- delay = priv->rgmii_rx_delay[cpu_port_index]; ++ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; + + val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | + QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; +@@ -1397,7 +1397,7 @@ qca8k_phylink_mac_config(struct dsa_swit + + val |= QCA8K_SGMII_EN_SD; + +- if (priv->sgmii_enable_pll) ++ if (priv->ports_config.sgmii_enable_pll) + val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | + QCA8K_SGMII_EN_TX; + +@@ -1425,10 +1425,10 @@ qca8k_phylink_mac_config(struct dsa_swit + val = 0; + + /* SGMII Clock phase configuration */ +- if (priv->sgmii_rx_clk_falling_edge) ++ if (priv->ports_config.sgmii_rx_clk_falling_edge) + val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; + +- if (priv->sgmii_tx_clk_falling_edge) ++ if (priv->ports_config.sgmii_tx_clk_falling_edge) + val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; + + if (val) +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -270,15 +270,19 @@ enum { + QCA8K_CPU_PORT6, + }; + +-struct qca8k_priv { +- u8 switch_id; +- u8 switch_revision; ++struct qca8k_ports_config { + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; + bool sgmii_enable_pll; + u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ + u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ ++}; ++ ++struct qca8k_priv { ++ u8 switch_id; ++ u8 switch_revision; + bool legacy_phy_port_mapping; ++ struct qca8k_ports_config ports_config; + struct regmap *regmap; + struct mii_bus *bus; + struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; diff --git a/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch b/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch new file mode 100644 index 00000000000..f7cb5141763 --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch @@ -0,0 +1,26 @@ +From e52073a8e3086046a098b8a7cbeb282ff0cdb424 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Thu, 14 Oct 2021 00:39:20 +0200 +Subject: dt-bindings: net: ipq8064-mdio: fix warning with new qca8k switch + +Fix warning now that we have qca8k switch Documentation using yaml. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml ++++ b/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml +@@ -51,6 +51,9 @@ examples: + switch@10 { + compatible = "qca,qca8337"; + reg = <0x10>; +- /* ... */ ++ ++ ports { ++ /* ... */ ++ }; + }; + }; diff --git a/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch b/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch new file mode 100644 index 00000000000..b9bce97dd3d --- /dev/null +++ b/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch @@ -0,0 +1,631 @@ +From d291fbb8245d5ba04979fed85575860a5cea7196 Mon Sep 17 00:00:00 2001 +From: Matthew Hagan +Date: Thu, 14 Oct 2021 00:39:21 +0200 +Subject: dt-bindings: net: dsa: qca8k: convert to YAML schema + +Convert the qca8k bindings to YAML format. + +Signed-off-by: Matthew Hagan +Co-developed-by: Ansuel Smith +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + .../devicetree/bindings/net/dsa/qca8k.txt | 245 -------------- + .../devicetree/bindings/net/dsa/qca8k.yaml | 362 +++++++++++++++++++++ + 2 files changed, 362 insertions(+), 245 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.txt + create mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.yaml + +--- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt ++++ /dev/null +@@ -1,245 +0,0 @@ +-* Qualcomm Atheros QCA8xxx switch family +- +-Required properties: +- +-- compatible: should be one of: +- "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package +- "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package +- "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package +- "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package +- +-- #size-cells: must be 0 +-- #address-cells: must be 1 +- +-Optional properties: +- +-- reset-gpios: GPIO to be used to reset the whole device +-- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open +- drain or eeprom presence. This is needed for broken +- devices that have wrong configuration or when the oem +- decided to not use pin strapping and fallback to sw +- regs. +-- qca,led-open-drain: Set leds to open-drain mode. This requires the +- qca,ignore-power-on-sel to be set or the driver will fail +- to probe. This is needed if the oem doesn't use pin +- strapping to set this mode and prefers to set it using sw +- regs. The pin strapping related to led open drain mode is +- the pin B68 for QCA832x and B49 for QCA833x +- +-Subnodes: +- +-The integrated switch subnode should be specified according to the binding +-described in dsa/dsa.txt. If the QCA8K switch is connect to a SoC's external +-mdio-bus each subnode describing a port needs to have a valid phandle +-referencing the internal PHY it is connected to. This is because there's no +-N:N mapping of port and PHY id. +-To declare the internal mdio-bus configuration, declare a mdio node in the +-switch node and declare the phandle for the port referencing the internal +-PHY is connected to. In this config a internal mdio-bus is registered and +-the mdio MASTER is used as communication. +- +-Don't use mixed external and internal mdio-bus configurations, as this is +-not supported by the hardware. +- +-This switch support 2 CPU port. Normally and advised configuration is with +-CPU port set to port 0. It is also possible to set the CPU port to port 6 +-if the device requires it. The driver will configure the switch to the defined +-port. With both CPU port declared the first CPU port is selected as primary +-and the secondary CPU ignored. +- +-A CPU port node has the following optional node: +- +-- fixed-link : Fixed-link subnode describing a link to a non-MDIO +- managed entity. See +- Documentation/devicetree/bindings/net/fixed-link.txt +- for details. +-- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge. +- Mostly used in qca8327 with CPU port 0 set to +- sgmii. +-- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. +-- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX +- chain along with Signal Detection. +- This should NOT be enabled for qca8327. If enabled with +- qca8327 the sgmii port won't correctly init and an err +- is printed. +- This can be required for qca8337 switch with revision 2. +- A warning is displayed when used with revision greater +- 2. +- With CPU port set to sgmii and qca8337 it is advised +- to set this unless a communication problem is observed. +- +-For QCA8K the 'fixed-link' sub-node supports only the following properties: +- +-- 'speed' (integer, mandatory), to indicate the link speed. Accepted +- values are 10, 100 and 1000 +-- 'full-duplex' (boolean, optional), to indicate that full duplex is +- used. When absent, half duplex is assumed. +- +-Examples: +- +-for the external mdio-bus configuration: +- +- &mdio0 { +- phy_port1: phy@0 { +- reg = <0>; +- }; +- +- phy_port2: phy@1 { +- reg = <1>; +- }; +- +- phy_port3: phy@2 { +- reg = <2>; +- }; +- +- phy_port4: phy@3 { +- reg = <3>; +- }; +- +- phy_port5: phy@4 { +- reg = <4>; +- }; +- +- switch@10 { +- compatible = "qca,qca8337"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; +- reg = <0x10>; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- port@0 { +- reg = <0>; +- label = "cpu"; +- ethernet = <&gmac1>; +- phy-mode = "rgmii"; +- fixed-link { +- speed = 1000; +- full-duplex; +- }; +- }; +- +- port@1 { +- reg = <1>; +- label = "lan1"; +- phy-handle = <&phy_port1>; +- }; +- +- port@2 { +- reg = <2>; +- label = "lan2"; +- phy-handle = <&phy_port2>; +- }; +- +- port@3 { +- reg = <3>; +- label = "lan3"; +- phy-handle = <&phy_port3>; +- }; +- +- port@4 { +- reg = <4>; +- label = "lan4"; +- phy-handle = <&phy_port4>; +- }; +- +- port@5 { +- reg = <5>; +- label = "wan"; +- phy-handle = <&phy_port5>; +- }; +- }; +- }; +- }; +- +-for the internal master mdio-bus configuration: +- +- &mdio0 { +- switch@10 { +- compatible = "qca,qca8337"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; +- reg = <0x10>; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- port@0 { +- reg = <0>; +- label = "cpu"; +- ethernet = <&gmac1>; +- phy-mode = "rgmii"; +- fixed-link { +- speed = 1000; +- full-duplex; +- }; +- }; +- +- port@1 { +- reg = <1>; +- label = "lan1"; +- phy-mode = "internal"; +- phy-handle = <&phy_port1>; +- }; +- +- port@2 { +- reg = <2>; +- label = "lan2"; +- phy-mode = "internal"; +- phy-handle = <&phy_port2>; +- }; +- +- port@3 { +- reg = <3>; +- label = "lan3"; +- phy-mode = "internal"; +- phy-handle = <&phy_port3>; +- }; +- +- port@4 { +- reg = <4>; +- label = "lan4"; +- phy-mode = "internal"; +- phy-handle = <&phy_port4>; +- }; +- +- port@5 { +- reg = <5>; +- label = "wan"; +- phy-mode = "internal"; +- phy-handle = <&phy_port5>; +- }; +- }; +- +- mdio { +- #address-cells = <1>; +- #size-cells = <0>; +- +- phy_port1: phy@0 { +- reg = <0>; +- }; +- +- phy_port2: phy@1 { +- reg = <1>; +- }; +- +- phy_port3: phy@2 { +- reg = <2>; +- }; +- +- phy_port4: phy@3 { +- reg = <3>; +- }; +- +- phy_port5: phy@4 { +- reg = <4>; +- }; +- }; +- }; +- }; +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml +@@ -0,0 +1,362 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/dsa/qca8k.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Qualcomm Atheros QCA83xx switch family ++ ++maintainers: ++ - John Crispin ++ ++description: ++ If the QCA8K switch is connect to an SoC's external mdio-bus, each subnode ++ describing a port needs to have a valid phandle referencing the internal PHY ++ it is connected to. This is because there is no N:N mapping of port and PHY ++ ID. To declare the internal mdio-bus configuration, declare an MDIO node in ++ the switch node and declare the phandle for the port, referencing the internal ++ PHY it is connected to. In this config, an internal mdio-bus is registered and ++ the MDIO master is used for communication. Mixed external and internal ++ mdio-bus configurations are not supported by the hardware. ++ ++properties: ++ compatible: ++ oneOf: ++ - enum: ++ - qca,qca8327 ++ - qca,qca8328 ++ - qca,qca8334 ++ - qca,qca8337 ++ description: | ++ qca,qca8328: referenced as AR8328(N)-AK1(A/B) QFN 176 pin package ++ qca,qca8327: referenced as AR8327(N)-AL1A DR-QFN 148 pin package ++ qca,qca8334: referenced as QCA8334-AL3C QFN 88 pin package ++ qca,qca8337: referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package ++ ++ reg: ++ maxItems: 1 ++ ++ reset-gpios: ++ description: ++ GPIO to be used to reset the whole device ++ maxItems: 1 ++ ++ qca,ignore-power-on-sel: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Ignore power-on pin strapping to configure LED open-drain or EEPROM ++ presence. This is needed for devices with incorrect configuration or when ++ the OEM has decided not to use pin strapping and falls back to SW regs. ++ ++ qca,led-open-drain: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Set LEDs to open-drain mode. This requires the qca,ignore-power-on-sel to ++ be set, otherwise the driver will fail at probe. This is required if the ++ OEM does not use pin strapping to set this mode and prefers to set it ++ using SW regs. The pin strappings related to LED open-drain mode are ++ B68 on the QCA832x and B49 on the QCA833x. ++ ++ mdio: ++ type: object ++ description: Qca8k switch have an internal mdio to access switch port. ++ If this is not present, the legacy mapping is used and the ++ internal mdio access is used. ++ With the legacy mapping the reg corresponding to the internal ++ mdio is the switch reg with an offset of -1. ++ ++ properties: ++ '#address-cells': ++ const: 1 ++ '#size-cells': ++ const: 0 ++ ++ patternProperties: ++ "^(ethernet-)?phy@[0-4]$": ++ type: object ++ ++ allOf: ++ - $ref: "http://devicetree.org/schemas/net/mdio.yaml#" ++ ++ properties: ++ reg: ++ maxItems: 1 ++ ++ required: ++ - reg ++ ++patternProperties: ++ "^(ethernet-)?ports$": ++ type: object ++ properties: ++ '#address-cells': ++ const: 1 ++ '#size-cells': ++ const: 0 ++ ++ patternProperties: ++ "^(ethernet-)?port@[0-6]$": ++ type: object ++ description: Ethernet switch ports ++ ++ properties: ++ reg: ++ description: Port number ++ ++ label: ++ description: ++ Describes the label associated with this port, which will become ++ the netdev name ++ $ref: /schemas/types.yaml#/definitions/string ++ ++ link: ++ description: ++ Should be a list of phandles to other switch's DSA port. This ++ port is used as the outgoing port towards the phandle ports. The ++ full routing information must be given, not just the one hop ++ routes to neighbouring switches ++ $ref: /schemas/types.yaml#/definitions/phandle-array ++ ++ ethernet: ++ description: ++ Should be a phandle to a valid Ethernet device node. This host ++ device is what the switch port is connected to ++ $ref: /schemas/types.yaml#/definitions/phandle ++ ++ phy-handle: true ++ ++ phy-mode: true ++ ++ fixed-link: true ++ ++ mac-address: true ++ ++ sfp: true ++ ++ qca,sgmii-rxclk-falling-edge: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Set the receive clock phase to falling edge. Mostly commonly used on ++ the QCA8327 with CPU port 0 set to SGMII. ++ ++ qca,sgmii-txclk-falling-edge: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Set the transmit clock phase to falling edge. ++ ++ qca,sgmii-enable-pll: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ For SGMII CPU port, explicitly enable PLL, TX and RX chain along with ++ Signal Detection. On the QCA8327 this should not be enabled, otherwise ++ the SGMII port will not initialize. When used on the QCA8337, revision 3 ++ or greater, a warning will be displayed. When the CPU port is set to ++ SGMII on the QCA8337, it is advised to set this unless a communication ++ issue is observed. ++ ++ required: ++ - reg ++ ++ additionalProperties: false ++ ++oneOf: ++ - required: ++ - ports ++ - required: ++ - ethernet-ports ++ ++required: ++ - compatible ++ - reg ++ ++additionalProperties: true ++ ++examples: ++ - | ++ #include ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ external_phy_port1: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ ++ external_phy_port2: ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ external_phy_port3: ethernet-phy@2 { ++ reg = <2>; ++ }; ++ ++ external_phy_port4: ethernet-phy@3 { ++ reg = <3>; ++ }; ++ ++ external_phy_port5: ethernet-phy@4 { ++ reg = <4>; ++ }; ++ ++ switch@10 { ++ compatible = "qca,qca8337"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; ++ reg = <0x10>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac1>; ++ phy-mode = "rgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ phy-handle = <&external_phy_port1>; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ phy-handle = <&external_phy_port2>; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ phy-handle = <&external_phy_port3>; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "lan4"; ++ phy-handle = <&external_phy_port4>; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "wan"; ++ phy-handle = <&external_phy_port5>; ++ }; ++ }; ++ }; ++ }; ++ - | ++ #include ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ switch@10 { ++ compatible = "qca,qca8337"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; ++ reg = <0x10>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac1>; ++ phy-mode = "rgmii"; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "lan1"; ++ phy-mode = "internal"; ++ phy-handle = <&internal_phy_port1>; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "lan2"; ++ phy-mode = "internal"; ++ phy-handle = <&internal_phy_port2>; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "lan3"; ++ phy-mode = "internal"; ++ phy-handle = <&internal_phy_port3>; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "lan4"; ++ phy-mode = "internal"; ++ phy-handle = <&internal_phy_port4>; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "wan"; ++ phy-mode = "internal"; ++ phy-handle = <&internal_phy_port5>; ++ }; ++ ++ port@6 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac1>; ++ phy-mode = "sgmii"; ++ ++ qca,sgmii-rxclk-falling-edge; ++ ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ }; ++ ++ mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ internal_phy_port1: ethernet-phy@0 { ++ reg = <0>; ++ }; ++ ++ internal_phy_port2: ethernet-phy@1 { ++ reg = <1>; ++ }; ++ ++ internal_phy_port3: ethernet-phy@2 { ++ reg = <2>; ++ }; ++ ++ internal_phy_port4: ethernet-phy@3 { ++ reg = <3>; ++ }; ++ ++ internal_phy_port5: ethernet-phy@4 { ++ reg = <4>; ++ }; ++ }; ++ }; ++ }; diff --git a/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch b/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch new file mode 100644 index 00000000000..a510cfdc183 --- /dev/null +++ b/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch @@ -0,0 +1,28 @@ +From 06dd34a628ae5b6a839b757e746de165d6789ca8 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sun, 17 Oct 2021 16:56:46 +0200 +Subject: net: dsa: qca8k: fix delay applied to wrong cpu in parse_port_config + +Fix delay settings applied to wrong cpu in parse_port_config. The delay +values is set to the wrong index as the cpu_port_index is incremented +too early. Start the cpu_port_index to -1 so the correct value is +applied to address also the case with invalid phy mode and not available +port. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -976,7 +976,7 @@ qca8k_setup_of_pws_reg(struct qca8k_priv + static int + qca8k_parse_port_config(struct qca8k_priv *priv) + { +- int port, cpu_port_index = 0, ret; ++ int port, cpu_port_index = -1, ret; + struct device_node *port_dn; + phy_interface_t mode; + struct dsa_port *dp; diff --git a/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch b/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch new file mode 100644 index 00000000000..71fa3022d55 --- /dev/null +++ b/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch @@ -0,0 +1,151 @@ +From 040e926f5813a5f4cc18dbff7c942d1e52f368f2 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 19 Oct 2021 02:08:50 +0200 +Subject: net: dsa: qca8k: tidy for loop in setup and add cpu port check + +Tidy and organize qca8k setup function from multiple for loop. +Change for loop in bridge leave/join to scan all port and skip cpu port. +No functional change intended. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 74 +++++++++++++++++++++++++++++-------------------- + 1 file changed, 44 insertions(+), 30 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1122,28 +1122,34 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + dev_warn(priv->dev, "mib init failed"); + +- /* Enable QCA header mode on the cpu port */ +- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port), +- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | +- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); +- if (ret) { +- dev_err(priv->dev, "failed enabling QCA header mode"); +- return ret; +- } +- +- /* Disable forwarding by default on all ports */ ++ /* Initial setup of all ports */ + for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_MEMBER, 0); + if (ret) + return ret; +- } + +- /* Disable MAC by default on all ports */ +- for (i = 1; i < QCA8K_NUM_PORTS; i++) +- qca8k_port_set_status(priv, i, 0); ++ /* Enable QCA header mode on all cpu ports */ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), ++ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | ++ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); ++ if (ret) { ++ dev_err(priv->dev, "failed enabling QCA header mode"); ++ return ret; ++ } ++ } ++ ++ /* Disable MAC by default on all user ports */ ++ if (dsa_is_user_port(ds, i)) ++ qca8k_port_set_status(priv, i, 0); ++ } + +- /* Forward all unknown frames to CPU port for Linux processing */ ++ /* Forward all unknown frames to CPU port for Linux processing ++ * Notice that in multi-cpu config only one port should be set ++ * for igmp, unknown, multicast and broadcast packet ++ */ + ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, + BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | + BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | +@@ -1152,11 +1158,13 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + +- /* Setup connection between CPU port & user ports */ ++ /* Setup connection between CPU port & user ports ++ * Configure specific switch configuration for ports ++ */ + for (i = 0; i < QCA8K_NUM_PORTS; i++) { + /* CPU port gets connected to all user ports of the switch */ + if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port), ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); + if (ret) + return ret; +@@ -1193,16 +1201,14 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + } +- } + +- /* The port 5 of the qca8337 have some problem in flood condition. The +- * original legacy driver had some specific buffer and priority settings +- * for the different port suggested by the QCA switch team. Add this +- * missing settings to improve switch stability under load condition. +- * This problem is limited to qca8337 and other qca8k switch are not affected. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8337) { +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* The port 5 of the qca8337 have some problem in flood condition. The ++ * original legacy driver had some specific buffer and priority settings ++ * for the different port suggested by the QCA switch team. Add this ++ * missing settings to improve switch stability under load condition. ++ * This problem is limited to qca8337 and other qca8k switch are not affected. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8337) { + switch (i) { + /* The 2 CPU port and port 5 requires some different + * priority than any other ports. +@@ -1238,6 +1244,12 @@ qca8k_setup(struct dsa_switch *ds) + QCA8K_PORT_HOL_CTRL1_WRED_EN, + mask); + } ++ ++ /* Set initial MTU for every port. ++ * We have only have a general MTU setting. So track ++ * every port and set the max across all port. ++ */ ++ priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; + } + + /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ +@@ -1251,8 +1263,6 @@ qca8k_setup(struct dsa_switch *ds) + } + + /* Setup our port MTUs to match power on defaults */ +- for (i = 0; i < QCA8K_NUM_PORTS; i++) +- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; + ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); + if (ret) + dev_warn(priv->dev, "failed setting MTU settings"); +@@ -1728,7 +1738,9 @@ qca8k_port_bridge_join(struct dsa_switch + cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + port_mask = BIT(cpu_port); + +- for (i = 1; i < QCA8K_NUM_PORTS; i++) { ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; + if (dsa_to_port(ds, i)->bridge_dev != br) + continue; + /* Add this port to the portvlan mask of the other ports +@@ -1758,7 +1770,9 @@ qca8k_port_bridge_leave(struct dsa_switc + + cpu_port = dsa_to_port(ds, port)->cpu_dp->index; + +- for (i = 1; i < QCA8K_NUM_PORTS; i++) { ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; + if (dsa_to_port(ds, i)->bridge_dev != br) + continue; + /* Remove this port to the portvlan mask of the other ports diff --git a/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch b/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch new file mode 100644 index 00000000000..4a61703c527 --- /dev/null +++ b/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch @@ -0,0 +1,47 @@ +From 5f15d392dcb4aa250a63d6f2c5adfc26c0aedc78 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 2 Nov 2021 19:30:41 +0100 +Subject: net: dsa: qca8k: make sure PAD0 MAC06 exchange is disabled + +Some device set MAC06 exchange in the bootloader. This cause some +problem as we don't support this strange mode and we just set the port6 +as the primary CPU port. With MAC06 exchange, PAD0 reg configure port6 +instead of port0. Add an extra check and explicitly disable MAC06 exchange +to correctly configure the port PAD config. + +Signed-off-by: Ansuel Smith +Fixes: 3fcf734aa482 ("net: dsa: qca8k: add support for cpu port 6") +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 8 ++++++++ + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 9 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1109,6 +1109,14 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + ++ /* Make sure MAC06 is disabled */ ++ ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, ++ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); ++ if (ret) { ++ dev_err(priv->dev, "failed disabling MAC06 exchange"); ++ return ret; ++ } ++ + /* Enable CPU Port */ + ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, + QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -34,6 +34,7 @@ + #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) + #define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) + #define QCA8K_REG_PORT0_PAD_CTRL 0x004 ++#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) + #define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) + #define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) + #define QCA8K_REG_PORT5_PAD_CTRL 0x008 diff --git a/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch b/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch new file mode 100644 index 00000000000..df9518d86cd --- /dev/null +++ b/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch @@ -0,0 +1,48 @@ +From 3b00a07c2443745d62babfe08dbb2ad8e649526e Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Fri, 19 Nov 2021 03:03:49 +0100 +Subject: [PATCH] net: dsa: qca8k: fix internal delay applied to the wrong PAD + config + +With SGMII phy the internal delay is always applied to the PAD0 config. +This is caused by the falling edge configuration that hardcode the reg +to PAD0 (as the falling edge bits are present only in PAD0 reg) +Move the delay configuration before the reg overwrite to correctly apply +the delay. + +Fixes: cef08115846e ("net: dsa: qca8k: set internal delay also for sgmii") +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1433,6 +1433,12 @@ qca8k_phylink_mac_config(struct dsa_swit + + qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); + ++ /* From original code is reported port instability as SGMII also ++ * require delay set. Apply advised values here or take them from DT. ++ */ ++ if (state->interface == PHY_INTERFACE_MODE_SGMII) ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ + /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and + * falling edge is set writing in the PORT0 PAD reg + */ +@@ -1455,12 +1461,6 @@ qca8k_phylink_mac_config(struct dsa_swit + QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, + val); + +- /* From original code is reported port instability as SGMII also +- * require delay set. Apply advised values here or take them from DT. +- */ +- if (state->interface == PHY_INTERFACE_MODE_SGMII) +- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +- + break; + default: + dev_err(ds->dev, "xMII mode %s not supported for port %d\n", diff --git a/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch b/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch new file mode 100644 index 00000000000..7348d93ec44 --- /dev/null +++ b/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch @@ -0,0 +1,46 @@ +From 65258b9d8cde45689bdc86ca39b50f01f983733b Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Fri, 19 Nov 2021 03:03:50 +0100 +Subject: [PATCH] net: dsa: qca8k: fix MTU calculation + +qca8k has a global MTU, so its tracking the MTU per port to make sure +that the largest MTU gets applied. +Since it uses the frame size instead of MTU the driver MTU change function +will then add the size of Ethernet header and checksum on top of MTU. + +The driver currently populates the per port MTU size as Ethernet frame +length + checksum which equals 1518. + +The issue is that then MTU change function will go through all of the +ports, find the largest MTU and apply the Ethernet header + checksum on +top of it again, so for a desired MTU of 1500 you will end up with 1536. + +This is obviously incorrect, so to correct it populate the per port struct +MTU with just the MTU and not include the Ethernet header + checksum size +as those will be added by the MTU change function. + +Fixes: f58d2598cf70 ("net: dsa: qca8k: implement the port MTU callbacks") +Signed-off-by: Robert Marko +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1256,8 +1256,12 @@ qca8k_setup(struct dsa_switch *ds) + /* Set initial MTU for every port. + * We have only have a general MTU setting. So track + * every port and set the max across all port. ++ * Set per port MTU to 1500 as the MTU change function ++ * will add the overhead and if its set to 1518 then it ++ * will apply the overhead again and we will end up with ++ * MTU of 1536 instead of 1518 + */ +- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; ++ priv->port_mtu[i] = ETH_DATA_LEN; + } + + /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ diff --git a/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch b/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch new file mode 100644 index 00000000000..f477b1b9298 --- /dev/null +++ b/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch @@ -0,0 +1,29 @@ +From b9133f3ef5a2659730cf47a74bd0a9259f1cf8ff Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:40 +0100 +Subject: net: dsa: qca8k: remove redundant check in parse_port_config + +The very next check for port 0 and 6 already makes sure we don't go out +of bounds with the ports_config delay table. +Remove the redundant check. + +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -983,7 +983,7 @@ qca8k_parse_port_config(struct qca8k_pri + u32 delay; + + /* We have 2 CPU port. Check them */ +- for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { + /* Skip every other port */ + if (port != 0 && port != 6) + continue; diff --git a/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch b/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch new file mode 100644 index 00000000000..2cea88089db --- /dev/null +++ b/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch @@ -0,0 +1,507 @@ +From 90ae68bfc2ffcb54a4ba4f64edbeb84a80cbb57c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:41 +0100 +Subject: net: dsa: qca8k: convert to GENMASK/FIELD_PREP/FIELD_GET + +Convert and try to standardize bit fields using +GENMASK/FIELD_PREP/FIELD_GET macros. Rework some logic to support the +standard macro and tidy things up. No functional change intended. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 98 +++++++++++++++---------------- + drivers/net/dsa/qca8k.h | 153 ++++++++++++++++++++++++++---------------------- + 2 files changed, 130 insertions(+), 121 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -319,18 +320,18 @@ qca8k_fdb_read(struct qca8k_priv *priv, + } + + /* vid - 83:72 */ +- fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M; ++ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); + /* aging - 67:64 */ +- fdb->aging = reg[2] & QCA8K_ATU_STATUS_M; ++ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); + /* portmask - 54:48 */ +- fdb->port_mask = (reg[1] >> QCA8K_ATU_PORT_S) & QCA8K_ATU_PORT_M; ++ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); + /* mac - 47:0 */ +- fdb->mac[0] = (reg[1] >> QCA8K_ATU_ADDR0_S) & 0xff; +- fdb->mac[1] = reg[1] & 0xff; +- fdb->mac[2] = (reg[0] >> QCA8K_ATU_ADDR2_S) & 0xff; +- fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff; +- fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff; +- fdb->mac[5] = reg[0] & 0xff; ++ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); ++ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); ++ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); ++ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); ++ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); ++ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); + + return 0; + } +@@ -343,18 +344,18 @@ qca8k_fdb_write(struct qca8k_priv *priv, + int i; + + /* vid - 83:72 */ +- reg[2] = (vid & QCA8K_ATU_VID_M) << QCA8K_ATU_VID_S; ++ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); + /* aging - 67:64 */ +- reg[2] |= aging & QCA8K_ATU_STATUS_M; ++ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); + /* portmask - 54:48 */ +- reg[1] = (port_mask & QCA8K_ATU_PORT_M) << QCA8K_ATU_PORT_S; ++ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); + /* mac - 47:0 */ +- reg[1] |= mac[0] << QCA8K_ATU_ADDR0_S; +- reg[1] |= mac[1]; +- reg[0] |= mac[2] << QCA8K_ATU_ADDR2_S; +- reg[0] |= mac[3] << QCA8K_ATU_ADDR3_S; +- reg[0] |= mac[4] << QCA8K_ATU_ADDR4_S; +- reg[0] |= mac[5]; ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); + + /* load the array into the ARL table */ + for (i = 0; i < 3; i++) +@@ -372,7 +373,7 @@ qca8k_fdb_access(struct qca8k_priv *priv + reg |= cmd; + if (port >= 0) { + reg |= QCA8K_ATU_FUNC_PORT_EN; +- reg |= (port & QCA8K_ATU_FUNC_PORT_M) << QCA8K_ATU_FUNC_PORT_S; ++ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); + } + + /* Write the function register triggering the table access */ +@@ -454,7 +455,7 @@ qca8k_vlan_access(struct qca8k_priv *pri + /* Set the command and VLAN index */ + reg = QCA8K_VTU_FUNC1_BUSY; + reg |= cmd; +- reg |= vid << QCA8K_VTU_FUNC1_VID_S; ++ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); + + /* Write the function register triggering the table access */ + ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); +@@ -500,13 +501,11 @@ qca8k_vlan_add(struct qca8k_priv *priv, + if (ret < 0) + goto out; + reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; +- reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port)); ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); + if (untagged) +- reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG << +- QCA8K_VTU_FUNC0_EG_MODE_S(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); + else +- reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG << +- QCA8K_VTU_FUNC0_EG_MODE_S(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); + + ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); + if (ret) +@@ -534,15 +533,13 @@ qca8k_vlan_del(struct qca8k_priv *priv, + ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); + if (ret < 0) + goto out; +- reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port)); +- reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT << +- QCA8K_VTU_FUNC0_EG_MODE_S(port); ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); + + /* Check if we're the last member to be removed */ + del = true; + for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- mask = QCA8K_VTU_FUNC0_EG_MODE_NOT; +- mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i); ++ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); + + if ((reg & mask) != mask) { + del = false; +@@ -1014,7 +1011,7 @@ qca8k_parse_port_config(struct qca8k_pri + mode == PHY_INTERFACE_MODE_RGMII_TXID) + delay = 1; + +- if (delay > QCA8K_MAX_DELAY) { ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { + dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); + delay = 3; + } +@@ -1030,7 +1027,7 @@ qca8k_parse_port_config(struct qca8k_pri + mode == PHY_INTERFACE_MODE_RGMII_RXID) + delay = 2; + +- if (delay > QCA8K_MAX_DELAY) { ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { + dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); + delay = 3; + } +@@ -1141,8 +1138,8 @@ qca8k_setup(struct dsa_switch *ds) + /* Enable QCA header mode on all cpu ports */ + if (dsa_is_cpu_port(ds, i)) { + ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), +- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | +- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); + if (ret) { + dev_err(priv->dev, "failed enabling QCA header mode"); + return ret; +@@ -1159,10 +1156,10 @@ qca8k_setup(struct dsa_switch *ds) + * for igmp, unknown, multicast and broadcast packet + */ + ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, +- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | +- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | +- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | +- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); + if (ret) + return ret; + +@@ -1180,8 +1177,6 @@ qca8k_setup(struct dsa_switch *ds) + + /* Individual user ports get connected to CPU port only */ + if (dsa_is_user_port(ds, i)) { +- int shift = 16 * (i % 2); +- + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), + QCA8K_PORT_LOOKUP_MEMBER, + BIT(cpu_port)); +@@ -1198,8 +1193,8 @@ qca8k_setup(struct dsa_switch *ds) + * default egress vid + */ + ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), +- 0xfff << shift, +- QCA8K_PORT_VID_DEF << shift); ++ QCA8K_EGREES_VLAN_PORT_MASK(i), ++ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); + if (ret) + return ret; + +@@ -1246,7 +1241,7 @@ qca8k_setup(struct dsa_switch *ds) + QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | + QCA8K_PORT_HOL_CTRL1_WRED_EN; + qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), +- QCA8K_PORT_HOL_CTRL1_ING_BUF | ++ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | + QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | + QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | + QCA8K_PORT_HOL_CTRL1_WRED_EN, +@@ -1269,8 +1264,8 @@ qca8k_setup(struct dsa_switch *ds) + mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | + QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); + qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, +- QCA8K_GLOBAL_FC_GOL_XON_THRES_S | +- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S, ++ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | ++ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, + mask); + } + +@@ -1935,11 +1930,11 @@ qca8k_port_vlan_filtering(struct dsa_swi + + if (vlan_filtering) { + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, + QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); + } else { + ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, + QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); + } + +@@ -1963,10 +1958,9 @@ qca8k_port_vlan_add(struct dsa_switch *d + } + + if (pvid) { +- int shift = 16 * (port % 2); +- + ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), +- 0xfff << shift, vlan->vid << shift); ++ QCA8K_EGREES_VLAN_PORT_MASK(port), ++ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); + if (ret) + return ret; + +@@ -2060,7 +2054,7 @@ static int qca8k_read_switch_id(struct q + if (ret < 0) + return -ENODEV; + +- id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK); ++ id = QCA8K_MASK_CTRL_DEVICE_ID(val); + if (id != data->id) { + dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); + return -ENODEV; +@@ -2069,7 +2063,7 @@ static int qca8k_read_switch_id(struct q + priv->switch_id = id; + + /* Save revision to communicate to the internal PHY driver */ +- priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK); ++ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); + + return 0; + } +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -30,9 +30,9 @@ + /* Global control registers */ + #define QCA8K_REG_MASK_CTRL 0x000 + #define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) +-#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0) ++#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) + #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) +-#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) ++#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) + #define QCA8K_REG_PORT0_PAD_CTRL 0x004 + #define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) + #define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) +@@ -41,12 +41,11 @@ + #define QCA8K_REG_PORT6_PAD_CTRL 0x00c + #define QCA8K_PORT_PAD_RGMII_EN BIT(26) + #define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) +-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) + #define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) +-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) ++#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) + #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) + #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) +-#define QCA8K_MAX_DELAY 3 + #define QCA8K_PORT_PAD_SGMII_EN BIT(7) + #define QCA8K_REG_PWS 0x010 + #define QCA8K_PWS_POWER_ON_SEL BIT(31) +@@ -68,10 +67,12 @@ + #define QCA8K_MDIO_MASTER_READ BIT(27) + #define QCA8K_MDIO_MASTER_WRITE 0 + #define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) +-#define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21) +-#define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16) +-#define QCA8K_MDIO_MASTER_DATA(x) (x) ++#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) ++#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) ++#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) ++#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) + #define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) ++#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) + #define QCA8K_MDIO_MASTER_MAX_PORTS 5 + #define QCA8K_MDIO_MASTER_MAX_REG 32 + #define QCA8K_GOL_MAC_ADDR0 0x60 +@@ -93,9 +94,7 @@ + #define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) + #define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) + #define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) +-#define QCA8K_PORT_HDR_CTRL_RX_S 2 + #define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) +-#define QCA8K_PORT_HDR_CTRL_TX_S 0 + #define QCA8K_PORT_HDR_CTRL_ALL 2 + #define QCA8K_PORT_HDR_CTRL_MGMT 1 + #define QCA8K_PORT_HDR_CTRL_NONE 0 +@@ -105,10 +104,11 @@ + #define QCA8K_SGMII_EN_TX BIT(3) + #define QCA8K_SGMII_EN_SD BIT(4) + #define QCA8K_SGMII_CLK125M_DELAY BIT(7) +-#define QCA8K_SGMII_MODE_CTRL_MASK (BIT(22) | BIT(23)) +-#define QCA8K_SGMII_MODE_CTRL_BASEX (0 << 22) +-#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) +-#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) ++#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) ++#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) ++#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) ++#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) ++#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) + + /* MAC_PWR_SEL registers */ + #define QCA8K_REG_MAC_PWR_SEL 0x0e4 +@@ -121,100 +121,115 @@ + + /* ACL registers */ + #define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) +-#define QCA8K_PORT_VLAN_CVID(x) (x << 16) +-#define QCA8K_PORT_VLAN_SVID(x) x ++#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) ++#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) ++#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) ++#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) + #define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) + #define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 + #define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 + + /* Lookup registers */ + #define QCA8K_REG_ATU_DATA0 0x600 +-#define QCA8K_ATU_ADDR2_S 24 +-#define QCA8K_ATU_ADDR3_S 16 +-#define QCA8K_ATU_ADDR4_S 8 ++#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) ++#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) ++#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) ++#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) + #define QCA8K_REG_ATU_DATA1 0x604 +-#define QCA8K_ATU_PORT_M 0x7f +-#define QCA8K_ATU_PORT_S 16 +-#define QCA8K_ATU_ADDR0_S 8 ++#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) ++#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) ++#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) + #define QCA8K_REG_ATU_DATA2 0x608 +-#define QCA8K_ATU_VID_M 0xfff +-#define QCA8K_ATU_VID_S 8 +-#define QCA8K_ATU_STATUS_M 0xf ++#define QCA8K_ATU_VID_MASK GENMASK(19, 8) ++#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) + #define QCA8K_ATU_STATUS_STATIC 0xf + #define QCA8K_REG_ATU_FUNC 0x60c + #define QCA8K_ATU_FUNC_BUSY BIT(31) + #define QCA8K_ATU_FUNC_PORT_EN BIT(14) + #define QCA8K_ATU_FUNC_MULTI_EN BIT(13) + #define QCA8K_ATU_FUNC_FULL BIT(12) +-#define QCA8K_ATU_FUNC_PORT_M 0xf +-#define QCA8K_ATU_FUNC_PORT_S 8 ++#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) + #define QCA8K_REG_VTU_FUNC0 0x610 + #define QCA8K_VTU_FUNC0_VALID BIT(20) + #define QCA8K_VTU_FUNC0_IVL_EN BIT(19) +-#define QCA8K_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) +-#define QCA8K_VTU_FUNC0_EG_MODE_MASK 3 +-#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD 0 +-#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG 1 +-#define QCA8K_VTU_FUNC0_EG_MODE_TAG 2 +-#define QCA8K_VTU_FUNC0_EG_MODE_NOT 3 ++/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) ++ * It does contain VLAN_MODE for each port [5:4] for port0, ++ * [7:6] for port1 ... [17:16] for port6. Use virtual port ++ * define to handle this. ++ */ ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) ++#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) + #define QCA8K_REG_VTU_FUNC1 0x614 + #define QCA8K_VTU_FUNC1_BUSY BIT(31) +-#define QCA8K_VTU_FUNC1_VID_S 16 ++#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) + #define QCA8K_VTU_FUNC1_FULL BIT(4) + #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 + #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) + #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 +-#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24 +-#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16 +-#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8 +-#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0 ++#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) ++#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) ++#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) ++#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) + #define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) + #define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE GENMASK(9, 8) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE (0 << 8) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) + #define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) +-#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16) +-#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16) +-#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16) +-#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16) +-#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16) +-#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16) ++#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) ++#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) ++#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) ++#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) ++#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) ++#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) + #define QCA8K_PORT_LOOKUP_LEARN BIT(20) + + #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 +-#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16) +-#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16) +-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0) +-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0) ++#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) ++#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) ++#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) ++#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) + + #define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20) +-#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24) +-#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) ++#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) + + #define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +-#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0) +-#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0) ++#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) ++#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) + #define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) + #define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) + #define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) + #define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) + + /* Pkt edit registers */ ++#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) ++#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) ++#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) + #define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) + + /* L3 registers */ diff --git a/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch b/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch new file mode 100644 index 00000000000..8c39b8ea295 --- /dev/null +++ b/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch @@ -0,0 +1,25 @@ +From 994c28b6f971fa5db8ae977daea37eee87d93d51 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:42 +0100 +Subject: net: dsa: qca8k: remove extra mutex_init in qca8k_setup + +Mutex is already init in sw_probe. Remove the extra init in qca8k_setup. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1086,8 +1086,6 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + +- mutex_init(&priv->reg_mutex); +- + /* Start by setting up the register mapping */ + priv->regmap = devm_regmap_init(ds->dev, NULL, priv, + &qca8k_regmap_config); diff --git a/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch b/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch new file mode 100644 index 00000000000..44d938c53e8 --- /dev/null +++ b/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch @@ -0,0 +1,46 @@ +From 36b8af12f424e7a7f60a935c60a0fd4aa0822378 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:43 +0100 +Subject: net: dsa: qca8k: move regmap init in probe and set it mandatory + +In preparation for regmap conversion, move regmap init in the probe +function and make it mandatory as any read/write/rmw operation will be +converted to regmap API. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1086,12 +1086,6 @@ qca8k_setup(struct dsa_switch *ds) + if (ret) + return ret; + +- /* Start by setting up the register mapping */ +- priv->regmap = devm_regmap_init(ds->dev, NULL, priv, +- &qca8k_regmap_config); +- if (IS_ERR(priv->regmap)) +- dev_warn(priv->dev, "regmap initialization failed"); +- + ret = qca8k_setup_mdio_bus(priv); + if (ret) + return ret; +@@ -2096,6 +2090,14 @@ qca8k_sw_probe(struct mdio_device *mdiod + gpiod_set_value_cansleep(priv->reset_gpio, 0); + } + ++ /* Start by setting up the register mapping */ ++ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, ++ &qca8k_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ dev_err(priv->dev, "regmap initialization failed"); ++ return PTR_ERR(priv->regmap); ++ } ++ + /* Check the detected switch id */ + ret = qca8k_read_switch_id(priv); + if (ret) diff --git a/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch b/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch new file mode 100644 index 00000000000..4ca9c8ba41d --- /dev/null +++ b/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch @@ -0,0 +1,249 @@ +From 8b5f3f29a81a71934d004e21a1292c1148b05926 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:44 +0100 +Subject: net: dsa: qca8k: initial conversion to regmap helper + +Convert any qca8k set/clear/pool to regmap helper and add +missing config to regmap_config struct. +Read/write/rmw operation are reworked to use the regmap helper +internally to keep the delta of this patch low. These additional +function will then be dropped when the code split will be proposed. + +Ipq40xx SoC have the internal switch based on the qca8k regmap but use +mmio for read/write/rmw operation instead of mdio. +In preparation for the support of this internal switch, convert the +driver to regmap API to later split the driver to common and specific +code. The overhead introduced by the use of regamp API is marginal as the +internal mdio will bypass it by using its direct access and regmap will be +used only by configuration functions or fdb access. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 107 +++++++++++++++++++++--------------------------- + 1 file changed, 47 insertions(+), 60 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -152,6 +153,25 @@ qca8k_set_page(struct mii_bus *bus, u16 + static int + qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) + { ++ return regmap_read(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) ++{ ++ return regmap_write(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ return regmap_update_bits(priv->regmap, reg, mask, write_val); ++} ++ ++static int ++qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; + struct mii_bus *bus = priv->bus; + u16 r1, r2, page; + int ret; +@@ -172,8 +192,9 @@ exit: + } + + static int +-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) ++qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) + { ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; + struct mii_bus *bus = priv->bus; + u16 r1, r2, page; + int ret; +@@ -194,8 +215,9 @@ exit: + } + + static int +-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) + { ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; + struct mii_bus *bus = priv->bus; + u16 r1, r2, page; + u32 val; +@@ -223,34 +245,6 @@ exit: + return ret; + } + +-static int +-qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) +-{ +- return qca8k_rmw(priv, reg, 0, val); +-} +- +-static int +-qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val) +-{ +- return qca8k_rmw(priv, reg, val, 0); +-} +- +-static int +-qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- +- return qca8k_read(priv, reg, val); +-} +- +-static int +-qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- +- return qca8k_write(priv, reg, val); +-} +- + static const struct regmap_range qca8k_readable_ranges[] = { + regmap_reg_range(0x0000, 0x00e4), /* Global control */ + regmap_reg_range(0x0100, 0x0168), /* EEE control */ +@@ -282,26 +276,19 @@ static struct regmap_config qca8k_regmap + .max_register = 0x16ac, /* end MIB - Port6 range */ + .reg_read = qca8k_regmap_read, + .reg_write = qca8k_regmap_write, ++ .reg_update_bits = qca8k_regmap_update_bits, + .rd_table = &qca8k_readable_table, ++ .disable_locking = true, /* Locking is handled by qca8k read/write */ ++ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ + }; + + static int + qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) + { +- int ret, ret1; + u32 val; + +- ret = read_poll_timeout(qca8k_read, ret1, !(val & mask), +- 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- priv, reg, &val); +- +- /* Check if qca8k_read has failed for a different reason +- * before returning -ETIMEDOUT +- */ +- if (ret < 0 && ret1 < 0) +- return ret1; +- +- return ret; ++ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); + } + + static int +@@ -568,7 +555,7 @@ qca8k_mib_init(struct qca8k_priv *priv) + int ret; + + mutex_lock(&priv->reg_mutex); +- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); + if (ret) + goto exit; + +@@ -576,7 +563,7 @@ qca8k_mib_init(struct qca8k_priv *priv) + if (ret) + goto exit; + +- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); + if (ret) + goto exit; + +@@ -597,9 +584,9 @@ qca8k_port_set_status(struct qca8k_priv + mask |= QCA8K_PORT_STATUS_LINK_AUTO; + + if (enable) +- qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask); ++ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); + else +- qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); ++ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); + } + + static u32 +@@ -861,8 +848,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv * + * a dt-overlay and driver reload changed the configuration + */ + +- return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_EN); ++ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_EN); + } + + /* Check if the devicetree declare the port:phy mapping */ +@@ -1099,16 +1086,16 @@ qca8k_setup(struct dsa_switch *ds) + return ret; + + /* Make sure MAC06 is disabled */ +- ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, +- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); ++ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, ++ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); + if (ret) { + dev_err(priv->dev, "failed disabling MAC06 exchange"); + return ret; + } + + /* Enable CPU Port */ +- ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); + if (ret) { + dev_err(priv->dev, "failed enabling CPU port"); + return ret; +@@ -1176,8 +1163,8 @@ qca8k_setup(struct dsa_switch *ds) + return ret; + + /* Enable ARP Auto-learning by default */ +- ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_LEARN); ++ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_LEARN); + if (ret) + return ret; + +@@ -1745,9 +1732,9 @@ qca8k_port_bridge_join(struct dsa_switch + /* Add this port to the portvlan mask of the other ports + * in the bridge + */ +- ret = qca8k_reg_set(priv, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); ++ ret = regmap_set_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); + if (ret) + return ret; + if (i != port) +@@ -1777,9 +1764,9 @@ qca8k_port_bridge_leave(struct dsa_switc + /* Remove this port to the portvlan mask of the other ports + * in the bridge + */ +- qca8k_reg_clear(priv, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); ++ regmap_clear_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); + } + + /* Set the cpu port to be the only one in the portvlan mask of diff --git a/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch b/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch new file mode 100644 index 00000000000..c8c050933b6 --- /dev/null +++ b/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch @@ -0,0 +1,120 @@ +From c126f118b330ccf0db0dda4a4bd6c729865a205f Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:45 +0100 +Subject: net: dsa: qca8k: add additional MIB counter and make it dynamic + +We are currently missing 2 additionals MIB counter present in QCA833x +switch. +QC832x switch have 39 MIB counter and QCA833X have 41 MIB counter. +Add the additional MIB counter and rework the MIB function to print the +correct supported counter from the match_data struct. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 23 ++++++++++++++++++++--- + drivers/net/dsa/qca8k.h | 4 ++++ + 2 files changed, 24 insertions(+), 3 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -70,6 +70,8 @@ static const struct qca8k_mib_desc ar832 + MIB_DESC(1, 0x9c, "TxExcDefer"), + MIB_DESC(1, 0xa0, "TxDefer"), + MIB_DESC(1, 0xa4, "TxLateCol"), ++ MIB_DESC(1, 0xa8, "RXUnicast"), ++ MIB_DESC(1, 0xac, "TXUnicast"), + }; + + /* The 32bit switch registers are accessed indirectly. To achieve this we need +@@ -1605,12 +1607,16 @@ qca8k_phylink_mac_link_up(struct dsa_swi + static void + qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) + { ++ const struct qca8k_match_data *match_data; ++ struct qca8k_priv *priv = ds->priv; + int i; + + if (stringset != ETH_SS_STATS) + return; + +- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) ++ match_data = of_device_get_match_data(priv->dev); ++ ++ for (i = 0; i < match_data->mib_count; i++) + strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, + ETH_GSTRING_LEN); + } +@@ -1620,12 +1626,15 @@ qca8k_get_ethtool_stats(struct dsa_switc + uint64_t *data) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ const struct qca8k_match_data *match_data; + const struct qca8k_mib_desc *mib; + u32 reg, i, val; + u32 hi = 0; + int ret; + +- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) { ++ match_data = of_device_get_match_data(priv->dev); ++ ++ for (i = 0; i < match_data->mib_count; i++) { + mib = &ar8327_mib[i]; + reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; + +@@ -1648,10 +1657,15 @@ qca8k_get_ethtool_stats(struct dsa_switc + static int + qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) + { ++ const struct qca8k_match_data *match_data; ++ struct qca8k_priv *priv = ds->priv; ++ + if (sset != ETH_SS_STATS) + return 0; + +- return ARRAY_SIZE(ar8327_mib); ++ match_data = of_device_get_match_data(priv->dev); ++ ++ return match_data->mib_count; + } + + static int +@@ -2173,14 +2187,17 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, + static const struct qca8k_match_data qca8327 = { + .id = QCA8K_ID_QCA8327, + .reduced_package = true, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, + }; + + static const struct qca8k_match_data qca8328 = { + .id = QCA8K_ID_QCA8327, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, + }; + + static const struct qca8k_match_data qca833x = { + .id = QCA8K_ID_QCA8337, ++ .mib_count = QCA8K_QCA833X_MIB_COUNT, + }; + + static const struct of_device_id qca8k_of_match[] = { +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -21,6 +21,9 @@ + #define PHY_ID_QCA8337 0x004dd036 + #define QCA8K_ID_QCA8337 0x13 + ++#define QCA8K_QCA832X_MIB_COUNT 39 ++#define QCA8K_QCA833X_MIB_COUNT 41 ++ + #define QCA8K_BUSY_WAIT_TIMEOUT 2000 + + #define QCA8K_NUM_FDB_RECORDS 2048 +@@ -279,6 +282,7 @@ struct ar8xxx_port_status { + struct qca8k_match_data { + u8 id; + bool reduced_package; ++ u8 mib_count; + }; + + enum { diff --git a/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch b/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch new file mode 100644 index 00000000000..8ad7ab472d4 --- /dev/null +++ b/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch @@ -0,0 +1,53 @@ +From 4592538bfb0d5d3c3c8a1d7071724d081412ac91 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:46 +0100 +Subject: net: dsa: qca8k: add support for port fast aging + +The switch supports fast aging by flushing any rule in the ARL +table for a specific port. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 11 +++++++++++ + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 12 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1790,6 +1790,16 @@ qca8k_port_bridge_leave(struct dsa_switc + QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); + } + ++static void ++qca8k_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); ++ mutex_unlock(&priv->reg_mutex); ++} ++ + static int + qca8k_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) +@@ -2017,6 +2027,7 @@ static const struct dsa_switch_ops qca8k + .port_stp_state_set = qca8k_port_stp_state_set, + .port_bridge_join = qca8k_port_bridge_join, + .port_bridge_leave = qca8k_port_bridge_leave, ++ .port_fast_age = qca8k_port_fast_age, + .port_fdb_add = qca8k_port_fdb_add, + .port_fdb_del = qca8k_port_fdb_del, + .port_fdb_dump = qca8k_port_fdb_dump, +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -262,6 +262,7 @@ enum qca8k_fdb_cmd { + QCA8K_FDB_FLUSH = 1, + QCA8K_FDB_LOAD = 2, + QCA8K_FDB_PURGE = 3, ++ QCA8K_FDB_FLUSH_PORT = 5, + QCA8K_FDB_NEXT = 6, + QCA8K_FDB_SEARCH = 7, + }; diff --git a/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch b/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch new file mode 100644 index 00000000000..659e482405a --- /dev/null +++ b/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch @@ -0,0 +1,78 @@ +From 6a3bdc5209f45d2af83aa92433ab6e5cf2297aa4 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:47 +0100 +Subject: net: dsa: qca8k: add set_ageing_time support + +qca8k support setting ageing time in step of 7s. Add support for it and +set the max value accepted of 7645m. +Documentation talks about support for 10000m but that values doesn't +make sense as the value doesn't match the max value in the reg. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 25 +++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 3 +++ + 2 files changed, 28 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1261,6 +1261,10 @@ qca8k_setup(struct dsa_switch *ds) + /* We don't have interrupts for link changes, so we need to poll */ + ds->pcs_poll = true; + ++ /* Set min a max ageing value supported */ ++ ds->ageing_time_min = 7000; ++ ds->ageing_time_max = 458745000; ++ + return 0; + } + +@@ -1801,6 +1805,26 @@ qca8k_port_fast_age(struct dsa_switch *d + } + + static int ++qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ unsigned int secs = msecs / 1000; ++ u32 val; ++ ++ /* AGE_TIME reg is set in 7s step */ ++ val = secs / 7; ++ ++ /* Handle case with 0 as val to NOT disable ++ * learning ++ */ ++ if (!val) ++ val = 1; ++ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, ++ QCA8K_ATU_AGE_TIME(val)); ++} ++ ++static int + qca8k_port_enable(struct dsa_switch *ds, int port, + struct phy_device *phy) + { +@@ -2018,6 +2042,7 @@ static const struct dsa_switch_ops qca8k + .get_strings = qca8k_get_strings, + .get_ethtool_stats = qca8k_get_ethtool_stats, + .get_sset_count = qca8k_get_sset_count, ++ .set_ageing_time = qca8k_set_ageing_time, + .get_mac_eee = qca8k_get_mac_eee, + .set_mac_eee = qca8k_set_mac_eee, + .port_enable = qca8k_port_enable, +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -175,6 +175,9 @@ + #define QCA8K_VTU_FUNC1_BUSY BIT(31) + #define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) + #define QCA8K_VTU_FUNC1_FULL BIT(4) ++#define QCA8K_REG_ATU_CTRL 0x618 ++#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) ++#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) + #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 + #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) + #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 diff --git a/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch b/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch new file mode 100644 index 00000000000..8b97939ecb2 --- /dev/null +++ b/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch @@ -0,0 +1,142 @@ +From ba8f870dfa635113ce6e8095a5eb1835ecde2e9e Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 22 Nov 2021 16:23:48 +0100 +Subject: net: dsa: qca8k: add support for mdb_add/del + +Add support for mdb add/del function. The ARL table is used to insert +the rule. The rule will be searched, deleted and reinserted with the +port mask updated. The function will check if the rule has to be updated +or insert directly with no deletion of the old rule. +If every port is removed from the port mask, the rule is removed. +The rule is set STATIC in the ARL table (aka it doesn't age) to not be +flushed by fast age function. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 99 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -436,6 +436,81 @@ qca8k_fdb_flush(struct qca8k_priv *priv) + } + + static int ++qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_fdb_read(priv, &fdb); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule exist. Delete first */ ++ if (!fdb.aging) { ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ } ++ ++ /* Add port to fdb portmask */ ++ fdb.port_mask |= port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule doesn't exist. Why delete? */ ++ if (!fdb.aging) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ ++ /* Only port in the rule is this port. Don't re insert */ ++ if (fdb.port_mask == port_mask) ++ goto exit; ++ ++ /* Remove port from port mask */ ++ fdb.port_mask &= ~port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int + qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) + { + u32 reg; +@@ -1949,6 +2024,28 @@ qca8k_port_fdb_dump(struct dsa_switch *d + } + + static int ++qca8k_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); ++} ++ ++static int ++qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); ++} ++ ++static int + qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack) + { +@@ -2056,6 +2153,8 @@ static const struct dsa_switch_ops qca8k + .port_fdb_add = qca8k_port_fdb_add, + .port_fdb_del = qca8k_port_fdb_del, + .port_fdb_dump = qca8k_port_fdb_dump, ++ .port_mdb_add = qca8k_port_mdb_add, ++ .port_mdb_del = qca8k_port_mdb_del, + .port_vlan_filtering = qca8k_port_vlan_filtering, + .port_vlan_add = qca8k_port_vlan_add, + .port_vlan_del = qca8k_port_vlan_del, diff --git a/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch b/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch new file mode 100644 index 00000000000..dc5a22935f1 --- /dev/null +++ b/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch @@ -0,0 +1,155 @@ +From 2c1bdbc7e7560d7de754cad277d968d56bb1899e Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 23 Nov 2021 03:59:10 +0100 +Subject: net: dsa: qca8k: add support for mirror mode + +The switch supports mirror mode. Only one port can set as mirror port and +every other port can set to both ingress and egress mode. The mirror +port is disabled and reverted to normal operation once every port is +removed from sending packet to it. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 4 +++ + 2 files changed, 99 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -2046,6 +2046,99 @@ qca8k_port_mdb_del(struct dsa_switch *ds + } + + static int ++qca8k_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int monitor_port, ret; ++ u32 reg, val; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* QCA83xx can have only one port set to mirror mode. ++ * Check that the correct port is requested and return error otherwise. ++ * When no mirror port is set, the values is set to 0xF ++ */ ++ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) ++ return -EEXIST; ++ ++ /* Set the monitor port */ ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, ++ mirror->to_local_port); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ return ret; ++ ++ if (ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_update_bits(priv->regmap, reg, val, val); ++ if (ret) ++ return ret; ++ ++ /* Track mirror port for tx and rx to decide when the ++ * mirror port has to be disabled. ++ */ ++ if (ingress) ++ priv->mirror_rx |= BIT(port); ++ else ++ priv->mirror_tx |= BIT(port); ++ ++ return 0; ++} ++ ++static void ++qca8k_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg, val; ++ int ret; ++ ++ if (mirror->ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_clear_bits(priv->regmap, reg, val); ++ if (ret) ++ goto err; ++ ++ if (mirror->ingress) ++ priv->mirror_rx &= ~BIT(port); ++ else ++ priv->mirror_tx &= ~BIT(port); ++ ++ /* No port set to send packet to mirror port. Disable mirror port */ ++ if (!priv->mirror_rx && !priv->mirror_tx) { ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ goto err; ++ } ++err: ++ dev_err(priv->dev, "Failed to del mirror port from %d", port); ++} ++ ++static int + qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack) + { +@@ -2155,6 +2248,8 @@ static const struct dsa_switch_ops qca8k + .port_fdb_dump = qca8k_port_fdb_dump, + .port_mdb_add = qca8k_port_mdb_add, + .port_mdb_del = qca8k_port_mdb_del, ++ .port_mirror_add = qca8k_port_mirror_add, ++ .port_mirror_del = qca8k_port_mirror_del, + .port_vlan_filtering = qca8k_port_vlan_filtering, + .port_vlan_add = qca8k_port_vlan_add, + .port_vlan_del = qca8k_port_vlan_del, +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -180,6 +180,7 @@ + #define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) + #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 + #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) ++#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) + #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 + #define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) + #define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) +@@ -201,6 +202,7 @@ + #define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) + #define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) + #define QCA8K_PORT_LOOKUP_LEARN BIT(20) ++#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) + + #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 + #define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) +@@ -305,6 +307,8 @@ struct qca8k_ports_config { + struct qca8k_priv { + u8 switch_id; + u8 switch_revision; ++ u8 mirror_rx; ++ u8 mirror_tx; + bool legacy_phy_port_mapping; + struct qca8k_ports_config ports_config; + struct regmap *regmap; diff --git a/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch b/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch new file mode 100644 index 00000000000..b53f1288d5a --- /dev/null +++ b/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch @@ -0,0 +1,288 @@ +From def975307c01191b6f0170048c3724b0ed3348af Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 23 Nov 2021 03:59:11 +0100 +Subject: net: dsa: qca8k: add LAG support + +Add LAG support to this switch. In Documentation this is described as +trunk mode. A max of 4 LAGs are supported and each can support up to 4 +port. The current tx mode supported is Hash mode with both L2 and L2+3 +mode. +When no port are present in the trunk, the trunk is disabled in the +switch. +When a port is disconnected, the traffic is redirected to the other +available port. +The hash mode is global and each LAG require to have the same hash mode +set. To change the hash mode when multiple LAG are configured, it's +required to remove each LAG and set the desired hash mode to the last. +An error is printed when it's asked to set a not supported hadh mode. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 33 +++++++++ + 2 files changed, 210 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1340,6 +1340,9 @@ qca8k_setup(struct dsa_switch *ds) + ds->ageing_time_min = 7000; + ds->ageing_time_max = 458745000; + ++ /* Set max number of LAGs supported */ ++ ds->num_lag_ids = QCA8K_NUM_LAGS; ++ + return 0; + } + +@@ -2226,6 +2229,178 @@ qca8k_get_tag_protocol(struct dsa_switch + return DSA_TAG_PROTO_QCA; + } + ++static bool ++qca8k_lag_can_offload(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct dsa_port *dp; ++ int id, members = 0; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ if (id < 0 || id >= ds->num_lag_ids) ++ return false; ++ ++ dsa_lag_foreach_port(dp, ds->dst, lag) ++ /* Includes the port joining the LAG */ ++ members++; ++ ++ if (members > QCA8K_NUM_PORTS_FOR_LAG) ++ return false; ++ ++ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) ++ return false; ++ ++ if (info->hash_type != NETDEV_LAG_HASH_L2 || ++ info->hash_type != NETDEV_LAG_HASH_L23) ++ return false; ++ ++ return true; ++} ++ ++static int ++qca8k_lag_setup_hash(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ bool unique_lag = true; ++ int i, id; ++ u32 hash; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ switch (info->hash_type) { ++ case NETDEV_LAG_HASH_L23: ++ hash |= QCA8K_TRUNK_HASH_SIP_EN; ++ hash |= QCA8K_TRUNK_HASH_DIP_EN; ++ fallthrough; ++ case NETDEV_LAG_HASH_L2: ++ hash |= QCA8K_TRUNK_HASH_SA_EN; ++ hash |= QCA8K_TRUNK_HASH_DA_EN; ++ break; ++ default: /* We should NEVER reach this */ ++ return -EOPNOTSUPP; ++ } ++ ++ /* Check if we are the unique configured LAG */ ++ dsa_lags_foreach_id(i, ds->dst) ++ if (i != id && dsa_lag_dev(ds->dst, i)) { ++ unique_lag = false; ++ break; ++ } ++ ++ /* Hash Mode is global. Make sure the same Hash Mode ++ * is set to all the 4 possible lag. ++ * If we are the unique LAG we can set whatever hash ++ * mode we want. ++ * To change hash mode it's needed to remove all LAG ++ * and change the mode with the latest. ++ */ ++ if (unique_lag) { ++ priv->lag_hash_mode = hash; ++ } else if (priv->lag_hash_mode != hash) { ++ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, ++ QCA8K_TRUNK_HASH_MASK, hash); ++} ++ ++static int ++qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, ++ struct net_device *lag, bool delete) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret, id, i; ++ u32 val; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ /* Read current port member */ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* Shift val to the correct trunk */ ++ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); ++ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; ++ if (delete) ++ val &= ~BIT(port); ++ else ++ val |= BIT(port); ++ ++ /* Update port member. With empty portmap disable trunk */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, ++ QCA8K_REG_GOL_TRUNK_MEMBER(id) | ++ QCA8K_REG_GOL_TRUNK_EN(id), ++ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | ++ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); ++ ++ /* Search empty member if adding or port on deleting */ ++ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); ++ if (ret) ++ return ret; ++ ++ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; ++ ++ if (delete) { ++ /* If port flagged to be disabled assume this member is ++ * empty ++ */ ++ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; ++ if (val != port) ++ continue; ++ } else { ++ /* If port flagged to be enabled assume this member is ++ * already set ++ */ ++ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ } ++ ++ /* We have found the member to add/remove */ ++ break; ++ } ++ ++ /* Set port in the correct port mask or disable port if in delete mode */ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), ++ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | ++ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); ++} ++ ++static int ++qca8k_port_lag_join(struct dsa_switch *ds, int port, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ int ret; ++ ++ if (!qca8k_lag_can_offload(ds, lag, info)) ++ return -EOPNOTSUPP; ++ ++ ret = qca8k_lag_setup_hash(ds, lag, info); ++ if (ret) ++ return ret; ++ ++ return qca8k_lag_refresh_portmap(ds, port, lag, false); ++} ++ ++static int ++qca8k_port_lag_leave(struct dsa_switch *ds, int port, ++ struct net_device *lag) ++{ ++ return qca8k_lag_refresh_portmap(ds, port, lag, true); ++} ++ + static const struct dsa_switch_ops qca8k_switch_ops = { + .get_tag_protocol = qca8k_get_tag_protocol, + .setup = qca8k_setup, +@@ -2259,6 +2434,8 @@ static const struct dsa_switch_ops qca8k + .phylink_mac_link_down = qca8k_phylink_mac_link_down, + .phylink_mac_link_up = qca8k_phylink_mac_link_up, + .get_phy_flags = qca8k_get_phy_flags, ++ .port_lag_join = qca8k_port_lag_join, ++ .port_lag_leave = qca8k_port_lag_leave, + }; + + static int qca8k_read_switch_id(struct qca8k_priv *priv) +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -15,6 +15,8 @@ + #define QCA8K_NUM_PORTS 7 + #define QCA8K_NUM_CPU_PORTS 2 + #define QCA8K_MAX_MTU 9000 ++#define QCA8K_NUM_LAGS 4 ++#define QCA8K_NUM_PORTS_FOR_LAG 4 + + #define PHY_ID_QCA8327 0x004dd034 + #define QCA8K_ID_QCA8327 0x12 +@@ -122,6 +124,14 @@ + #define QCA8K_REG_EEE_CTRL 0x100 + #define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) + ++/* TRUNK_HASH_EN registers */ ++#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 ++#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) ++#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) ++#define QCA8K_TRUNK_HASH_SA_EN BIT(1) ++#define QCA8K_TRUNK_HASH_DA_EN BIT(0) ++#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) ++ + /* ACL registers */ + #define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) + #define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) +@@ -204,6 +214,28 @@ + #define QCA8K_PORT_LOOKUP_LEARN BIT(20) + #define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) + ++#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 ++/* 4 max trunk first ++ * first 6 bit for member bitmap ++ * 7th bit is to enable trunk port ++ */ ++#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) ++#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) ++#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) ++#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) ++#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) ++/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ ++#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) ++#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) ++#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) ++/* Complex shift: FIRST shift for port THEN shift for trunk */ ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) ++ + #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 + #define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) + #define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) +@@ -309,6 +341,7 @@ struct qca8k_priv { + u8 switch_revision; + u8 mirror_rx; + u8 mirror_tx; ++ u8 lag_hash_mode; + bool legacy_phy_port_mapping; + struct qca8k_ports_config ports_config; + struct regmap *regmap; diff --git a/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch b/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch new file mode 100644 index 00000000000..7d811be11ce --- /dev/null +++ b/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch @@ -0,0 +1,40 @@ +From 0898ca67b86e14207d4feb3f3fea8b87cec5aab1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 23 Nov 2021 16:44:46 +0100 +Subject: net: dsa: qca8k: fix warning in LAG feature + +Fix warning reported by bot. +Make sure hash is init to 0 and fix wrong logic for hash_type in +qca8k_lag_can_offload. + +Reported-by: kernel test robot +Fixes: def975307c01 ("net: dsa: qca8k: add LAG support") +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Link: https://lore.kernel.org/r/20211123154446.31019-1-ansuelsmth@gmail.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca8k.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -2251,7 +2251,7 @@ qca8k_lag_can_offload(struct dsa_switch + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) + return false; + +- if (info->hash_type != NETDEV_LAG_HASH_L2 || ++ if (info->hash_type != NETDEV_LAG_HASH_L2 && + info->hash_type != NETDEV_LAG_HASH_L23) + return false; + +@@ -2265,8 +2265,8 @@ qca8k_lag_setup_hash(struct dsa_switch * + { + struct qca8k_priv *priv = ds->priv; + bool unique_lag = true; ++ u32 hash = 0; + int i, id; +- u32 hash; + + id = dsa_lag_id(ds->dst, lag); + diff --git a/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch b/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch new file mode 100644 index 00000000000..77cf63b809b --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch @@ -0,0 +1,52 @@ +From 904e112ad431492b34f235f59738e8312802bbf9 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:12 +0200 +Subject: [PATCH 1/6] net: dsa: reorder PHY initialization with MTU setup in + slave.c + +In dsa_slave_create() there are 2 sections that take rtnl_lock(): +MTU change and netdev registration. They are separated by PHY +initialization. + +There isn't any strict ordering requirement except for the fact that +netdev registration should be last. Therefore, we can perform the MTU +change a bit later, after the PHY setup. A future change will then be +able to merge the two rtnl_lock sections into one. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/slave.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1977,13 +1977,6 @@ int dsa_slave_create(struct dsa_port *po + port->slave = slave_dev; + dsa_slave_setup_tagger(slave_dev); + +- rtnl_lock(); +- ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); +- rtnl_unlock(); +- if (ret && ret != -EOPNOTSUPP) +- dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", +- ret, ETH_DATA_LEN, port->index); +- + netif_carrier_off(slave_dev); + + ret = dsa_slave_phy_setup(slave_dev); +@@ -1995,6 +1988,13 @@ int dsa_slave_create(struct dsa_port *po + } + + rtnl_lock(); ++ ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); ++ rtnl_unlock(); ++ if (ret && ret != -EOPNOTSUPP) ++ dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", ++ ret, ETH_DATA_LEN, port->index); ++ ++ rtnl_lock(); + + ret = register_netdevice(slave_dev); + if (ret) { diff --git a/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch b/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch new file mode 100644 index 00000000000..50aa5d8f0dd --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch @@ -0,0 +1,34 @@ +From e31dbd3b6aba585231cd84a87adeb22e7c6a8c19 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:13 +0200 +Subject: [PATCH 2/6] net: dsa: merge rtnl_lock sections in dsa_slave_create + +Currently dsa_slave_create() has two sequences of rtnl_lock/rtnl_unlock +in a row. Remove the rtnl_unlock() and rtnl_lock() in between, such that +the operation can execute slighly faster. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/slave.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -1988,14 +1988,12 @@ int dsa_slave_create(struct dsa_port *po + } + + rtnl_lock(); ++ + ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); +- rtnl_unlock(); + if (ret && ret != -EOPNOTSUPP) + dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", + ret, ETH_DATA_LEN, port->index); + +- rtnl_lock(); +- + ret = register_netdevice(slave_dev); + if (ret) { + netdev_err(master, "error %d registering interface %s\n", diff --git a/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch b/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch new file mode 100644 index 00000000000..6c7aad69288 --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch @@ -0,0 +1,91 @@ +From a1ff94c2973c43bc1e2677ac63ebb15b1d1ff846 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:14 +0200 +Subject: [PATCH 3/6] net: dsa: stop updating master MTU from master.c + +At present there are two paths for changing the MTU of the DSA master. + +The first is: + +dsa_tree_setup +-> dsa_tree_setup_ports + -> dsa_port_setup + -> dsa_slave_create + -> dsa_slave_change_mtu + -> dev_set_mtu(master) + +The second is: + +dsa_tree_setup +-> dsa_tree_setup_master + -> dsa_master_setup + -> dev_set_mtu(dev) + +So the dev_set_mtu() call from dsa_master_setup() has been effectively +superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is +done from dsa_slave_create() for each user port. The later function also +updates the master MTU according to the largest user port MTU from the +tree. Therefore, updating the master MTU through a separate code path +isn't needed. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/master.c | 25 +------------------------ + 1 file changed, 1 insertion(+), 24 deletions(-) + +--- a/net/dsa/master.c ++++ b/net/dsa/master.c +@@ -329,28 +329,13 @@ static const struct attribute_group dsa_ + .attrs = dsa_slave_attrs, + }; + +-static void dsa_master_reset_mtu(struct net_device *dev) +-{ +- int err; +- +- rtnl_lock(); +- err = dev_set_mtu(dev, ETH_DATA_LEN); +- if (err) +- netdev_dbg(dev, +- "Unable to reset MTU to exclude DSA overheads\n"); +- rtnl_unlock(); +-} +- + static struct lock_class_key dsa_master_addr_list_lock_key; + + int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) + { +- const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops; + struct dsa_switch *ds = cpu_dp->ds; + struct device_link *consumer_link; +- int mtu, ret; +- +- mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops); ++ int ret; + + /* The DSA master must use SET_NETDEV_DEV for this to work. */ + consumer_link = device_link_add(ds->dev, dev->dev.parent, +@@ -360,13 +345,6 @@ int dsa_master_setup(struct net_device * + "Failed to create a device link to DSA switch %s\n", + dev_name(ds->dev)); + +- rtnl_lock(); +- ret = dev_set_mtu(dev, mtu); +- rtnl_unlock(); +- if (ret) +- netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n", +- ret, mtu); +- + /* If we use a tagging format that doesn't have an ethertype + * field, make sure that all packets from this point on get + * sent to the tag format's receive function. +@@ -404,7 +382,6 @@ void dsa_master_teardown(struct net_devi + sysfs_remove_group(&dev->dev.kobj, &dsa_group); + dsa_netdev_ops_set(dev, NULL); + dsa_master_ethtool_teardown(dev); +- dsa_master_reset_mtu(dev); + dsa_master_set_promiscuity(dev, -1); + + dev->dsa_ptr = NULL; diff --git a/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch b/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch new file mode 100644 index 00000000000..e331226fc41 --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch @@ -0,0 +1,78 @@ +From c146f9bc195a9dc3ad7fd000a14540e7c9df952d Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:15 +0200 +Subject: [PATCH 4/6] net: dsa: hold rtnl_mutex when calling + dsa_master_{setup,teardown} + +DSA needs to simulate master tracking events when a binding is first +with a DSA master established and torn down, in order to give drivers +the simplifying guarantee that ->master_state_change calls are made +only when the master's readiness state to pass traffic changes. +master_state_change() provide a operational bool that DSA driver can use +to understand if DSA master is operational or not. +To avoid races, we need to block the reception of +NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier +chain while we are changing the master's dev->dsa_ptr (this changes what +netdev_uses_dsa(dev) reports). + +The dsa_master_setup() and dsa_master_teardown() functions optionally +require the rtnl_mutex to be held, if the tagger needs the master to be +promiscuous, these functions call dev_set_promiscuity(). Move the +rtnl_lock() from that function and make it top-level. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/dsa2.c | 8 ++++++++ + net/dsa/master.c | 4 ++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -1034,6 +1034,8 @@ static int dsa_tree_setup_master(struct + struct dsa_port *dp; + int err; + ++ rtnl_lock(); ++ + list_for_each_entry(dp, &dst->ports, list) { + if (dsa_port_is_cpu(dp)) { + err = dsa_master_setup(dp->master, dp); +@@ -1042,6 +1044,8 @@ static int dsa_tree_setup_master(struct + } + } + ++ rtnl_unlock(); ++ + return 0; + } + +@@ -1049,9 +1053,13 @@ static void dsa_tree_teardown_master(str + { + struct dsa_port *dp; + ++ rtnl_lock(); ++ + list_for_each_entry(dp, &dst->ports, list) + if (dsa_port_is_cpu(dp)) + dsa_master_teardown(dp->master); ++ ++ rtnl_unlock(); + } + + static int dsa_tree_setup_lags(struct dsa_switch_tree *dst) +--- a/net/dsa/master.c ++++ b/net/dsa/master.c +@@ -266,9 +266,9 @@ static void dsa_master_set_promiscuity(s + if (!ops->promisc_on_master) + return; + +- rtnl_lock(); ++ ASSERT_RTNL(); ++ + dev_set_promiscuity(dev, inc); +- rtnl_unlock(); + } + + static ssize_t tagging_show(struct device *d, struct device_attribute *attr, diff --git a/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch b/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch new file mode 100644 index 00000000000..e6472c61da6 --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch @@ -0,0 +1,118 @@ +From 1e3f407f3cacc5dcfe27166c412ed9bc263d82bf Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:16 +0200 +Subject: [PATCH 5/6] net: dsa: first set up shared ports, then non-shared + ports + +After commit a57d8c217aad ("net: dsa: flush switchdev workqueue before +tearing down CPU/DSA ports"), the port setup and teardown procedure +became asymmetric. + +The fact of the matter is that user ports need the shared ports to be up +before they can be used for CPU-initiated termination. And since we +register net devices for the user ports, those won't be functional until +we also call the setup for the shared (CPU, DSA) ports. But we may do +that later, depending on the port numbering scheme of the hardware we +are dealing with. + +It just makes sense that all shared ports are brought up before any user +port is. I can't pinpoint any issue due to the current behavior, but +let's change it nonetheless, for consistency's sake. + +Signed-off-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + net/dsa/dsa2.c | 50 +++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 37 insertions(+), 13 deletions(-) + +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -999,23 +999,28 @@ static void dsa_tree_teardown_switches(s + dsa_switch_teardown(dp->ds); + } + +-static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) ++/* Bring shared ports up first, then non-shared ports */ ++static int dsa_tree_setup_ports(struct dsa_switch_tree *dst) + { + struct dsa_port *dp; +- int err; ++ int err = 0; + + list_for_each_entry(dp, &dst->ports, list) { +- err = dsa_switch_setup(dp->ds); +- if (err) +- goto teardown; ++ if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) { ++ err = dsa_port_setup(dp); ++ if (err) ++ goto teardown; ++ } + } + + list_for_each_entry(dp, &dst->ports, list) { +- err = dsa_port_setup(dp); +- if (err) { +- err = dsa_port_reinit_as_unused(dp); +- if (err) +- goto teardown; ++ if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) { ++ err = dsa_port_setup(dp); ++ if (err) { ++ err = dsa_port_reinit_as_unused(dp); ++ if (err) ++ goto teardown; ++ } + } + } + +@@ -1024,7 +1029,21 @@ static int dsa_tree_setup_switches(struc + teardown: + dsa_tree_teardown_ports(dst); + +- dsa_tree_teardown_switches(dst); ++ return err; ++} ++ ++static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) ++{ ++ struct dsa_port *dp; ++ int err = 0; ++ ++ list_for_each_entry(dp, &dst->ports, list) { ++ err = dsa_switch_setup(dp->ds); ++ if (err) { ++ dsa_tree_teardown_switches(dst); ++ break; ++ } ++ } + + return err; + } +@@ -1111,10 +1130,14 @@ static int dsa_tree_setup(struct dsa_swi + if (err) + goto teardown_cpu_ports; + +- err = dsa_tree_setup_master(dst); ++ err = dsa_tree_setup_ports(dst); + if (err) + goto teardown_switches; + ++ err = dsa_tree_setup_master(dst); ++ if (err) ++ goto teardown_ports; ++ + err = dsa_tree_setup_lags(dst); + if (err) + goto teardown_master; +@@ -1127,8 +1150,9 @@ static int dsa_tree_setup(struct dsa_swi + + teardown_master: + dsa_tree_teardown_master(dst); +-teardown_switches: ++teardown_ports: + dsa_tree_teardown_ports(dst); ++teardown_switches: + dsa_tree_teardown_switches(dst); + teardown_cpu_ports: + dsa_tree_teardown_cpu_ports(dst); diff --git a/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch b/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch new file mode 100644 index 00000000000..93cad0c98aa --- /dev/null +++ b/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch @@ -0,0 +1,115 @@ +From 11fd667dac315ea3f2469961f6d2869271a46cae Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Thu, 6 Jan 2022 01:11:17 +0200 +Subject: [PATCH 6/6] net: dsa: setup master before ports + +It is said that as soon as a network interface is registered, all its +resources should have already been prepared, so that it is available for +sending and receiving traffic. One of the resources needed by a DSA +slave interface is the master. + +dsa_tree_setup +-> dsa_tree_setup_ports + -> dsa_port_setup + -> dsa_slave_create + -> register_netdevice +-> dsa_tree_setup_master + -> dsa_master_setup + -> sets up master->dsa_ptr, which enables reception + +Therefore, there is a short period of time after register_netdevice() +during which the master isn't prepared to pass traffic to the DSA layer +(master->dsa_ptr is checked by eth_type_trans). Same thing during +unregistration, there is a time frame in which packets might be missed. + +Note that this change opens us to another race: dsa_master_find_slave() +will get invoked potentially earlier than the slave creation, and later +than the slave deletion. Since dp->slave starts off as a NULL pointer, +the earlier calls aren't a problem, but the later calls are. To avoid +use-after-free, we should zeroize dp->slave before calling +dsa_slave_destroy(). + +In practice I cannot really test real life improvements brought by this +change, since in my systems, netdevice creation races with PHY autoneg +which takes a few seconds to complete, and that masks quite a few races. +Effects might be noticeable in a setup with fixed links all the way to +an external system. + +Signed-off-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + net/dsa/dsa2.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -545,6 +545,7 @@ static void dsa_port_teardown(struct dsa + struct devlink_port *dlp = &dp->devlink_port; + struct dsa_switch *ds = dp->ds; + struct dsa_mac_addr *a, *tmp; ++ struct net_device *slave; + + if (!dp->setup) + return; +@@ -566,9 +567,11 @@ static void dsa_port_teardown(struct dsa + dsa_port_link_unregister_of(dp); + break; + case DSA_PORT_TYPE_USER: +- if (dp->slave) { +- dsa_slave_destroy(dp->slave); ++ slave = dp->slave; ++ ++ if (slave) { + dp->slave = NULL; ++ dsa_slave_destroy(slave); + } + break; + } +@@ -1130,17 +1133,17 @@ static int dsa_tree_setup(struct dsa_swi + if (err) + goto teardown_cpu_ports; + +- err = dsa_tree_setup_ports(dst); ++ err = dsa_tree_setup_master(dst); + if (err) + goto teardown_switches; + +- err = dsa_tree_setup_master(dst); ++ err = dsa_tree_setup_ports(dst); + if (err) +- goto teardown_ports; ++ goto teardown_master; + + err = dsa_tree_setup_lags(dst); + if (err) +- goto teardown_master; ++ goto teardown_ports; + + dst->setup = true; + +@@ -1148,10 +1151,10 @@ static int dsa_tree_setup(struct dsa_swi + + return 0; + +-teardown_master: +- dsa_tree_teardown_master(dst); + teardown_ports: + dsa_tree_teardown_ports(dst); ++teardown_master: ++ dsa_tree_teardown_master(dst); + teardown_switches: + dsa_tree_teardown_switches(dst); + teardown_cpu_ports: +@@ -1169,10 +1172,10 @@ static void dsa_tree_teardown(struct dsa + + dsa_tree_teardown_lags(dst); + +- dsa_tree_teardown_master(dst); +- + dsa_tree_teardown_ports(dst); + ++ dsa_tree_teardown_master(dst); ++ + dsa_tree_teardown_switches(dst); + + dsa_tree_teardown_cpu_ports(dst); diff --git a/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch b/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch new file mode 100644 index 00000000000..bffdcb28819 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch @@ -0,0 +1,254 @@ +From 295ab96f478d0fa56393e85406f19a867e26ce22 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 2 Feb 2022 01:03:20 +0100 +Subject: [PATCH 01/16] net: dsa: provide switch operations for tracking the + master state + +Certain drivers may need to send management traffic to the switch for +things like register access, FDB dump, etc, to accelerate what their +slow bus (SPI, I2C, MDIO) can already do. + +Ethernet is faster (especially in bulk transactions) but is also more +unreliable, since the user may decide to bring the DSA master down (or +not bring it up), therefore severing the link between the host and the +attached switch. + +Drivers needing Ethernet-based register access already should have +fallback logic to the slow bus if the Ethernet method fails, but that +fallback may be based on a timeout, and the I/O to the switch may slow +down to a halt if the master is down, because every Ethernet packet will +have to time out. The driver also doesn't have the option to turn off +Ethernet-based I/O momentarily, because it wouldn't know when to turn it +back on. + +Which is where this change comes in. By tracking NETDEV_CHANGE, +NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know +the exact interval of time during which this interface is reliably +available for traffic. Provide this information to switches so they can +use it as they wish. + +An helper is added dsa_port_master_is_operational() to check if a master +port is operational. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/net/dsa.h | 17 +++++++++++++++++ + net/dsa/dsa2.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ + net/dsa/dsa_priv.h | 13 +++++++++++++ + net/dsa/slave.c | 32 ++++++++++++++++++++++++++++++++ + net/dsa/switch.c | 15 +++++++++++++++ + 5 files changed, 123 insertions(+) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -291,6 +291,10 @@ struct dsa_port { + struct list_head mdbs; + + bool setup; ++ /* Master state bits, valid only on CPU ports */ ++ u8 master_admin_up:1; ++ u8 master_oper_up:1; ++ + }; + + /* TODO: ideally DSA ports would have a single dp->link_dp member, +@@ -456,6 +460,12 @@ static inline bool dsa_port_is_unused(st + return dp->type == DSA_PORT_TYPE_UNUSED; + } + ++static inline bool dsa_port_master_is_operational(struct dsa_port *dp) ++{ ++ return dsa_port_is_cpu(dp) && dp->master_admin_up && ++ dp->master_oper_up; ++} ++ + static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p) + { + return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_UNUSED; +@@ -949,6 +959,13 @@ struct dsa_switch_ops { + int (*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid, + u16 flags); + int (*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid); ++ ++ /* ++ * DSA master tracking operations ++ */ ++ void (*master_state_change)(struct dsa_switch *ds, ++ const struct net_device *master, ++ bool operational); + }; + + #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \ +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -1275,6 +1275,52 @@ out_unlock: + return err; + } + ++static void dsa_tree_master_state_change(struct dsa_switch_tree *dst, ++ struct net_device *master) ++{ ++ struct dsa_notifier_master_state_info info; ++ struct dsa_port *cpu_dp = master->dsa_ptr; ++ ++ info.master = master; ++ info.operational = dsa_port_master_is_operational(cpu_dp); ++ ++ dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info); ++} ++ ++void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, ++ struct net_device *master, ++ bool up) ++{ ++ struct dsa_port *cpu_dp = master->dsa_ptr; ++ bool notify = false; ++ ++ if ((dsa_port_master_is_operational(cpu_dp)) != ++ (up && cpu_dp->master_oper_up)) ++ notify = true; ++ ++ cpu_dp->master_admin_up = up; ++ ++ if (notify) ++ dsa_tree_master_state_change(dst, master); ++} ++ ++void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, ++ struct net_device *master, ++ bool up) ++{ ++ struct dsa_port *cpu_dp = master->dsa_ptr; ++ bool notify = false; ++ ++ if ((dsa_port_master_is_operational(cpu_dp)) != ++ (cpu_dp->master_admin_up && up)) ++ notify = true; ++ ++ cpu_dp->master_oper_up = up; ++ ++ if (notify) ++ dsa_tree_master_state_change(dst, master); ++} ++ + static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) + { + struct dsa_switch_tree *dst = ds->dst; +--- a/net/dsa/dsa_priv.h ++++ b/net/dsa/dsa_priv.h +@@ -45,6 +45,7 @@ enum { + DSA_NOTIFIER_MRP_DEL_RING_ROLE, + DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, + DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, ++ DSA_NOTIFIER_MASTER_STATE_CHANGE, + }; + + /* DSA_NOTIFIER_AGEING_TIME */ +@@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info + u16 vid; + }; + ++/* DSA_NOTIFIER_MASTER_STATE_CHANGE */ ++struct dsa_notifier_master_state_info { ++ const struct net_device *master; ++ bool operational; ++}; ++ + struct dsa_switchdev_event_work { + struct dsa_switch *ds; + int port; +@@ -549,6 +556,12 @@ int dsa_tree_change_tag_proto(struct dsa + struct net_device *master, + const struct dsa_device_ops *tag_ops, + const struct dsa_device_ops *old_tag_ops); ++void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, ++ struct net_device *master, ++ bool up); ++void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, ++ struct net_device *master, ++ bool up); + int dsa_bridge_num_get(const struct net_device *bridge_dev, int max); + void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num); + +--- a/net/dsa/slave.c ++++ b/net/dsa/slave.c +@@ -2311,6 +2311,36 @@ static int dsa_slave_netdevice_event(str + err = dsa_port_lag_change(dp, info->lower_state_info); + return notifier_from_errno(err); + } ++ case NETDEV_CHANGE: ++ case NETDEV_UP: { ++ /* Track state of master port. ++ * DSA driver may require the master port (and indirectly ++ * the tagger) to be available for some special operation. ++ */ ++ if (netdev_uses_dsa(dev)) { ++ struct dsa_port *cpu_dp = dev->dsa_ptr; ++ struct dsa_switch_tree *dst = cpu_dp->ds->dst; ++ ++ /* Track when the master port is UP */ ++ dsa_tree_master_oper_state_change(dst, dev, ++ netif_oper_up(dev)); ++ ++ /* Track when the master port is ready and can accept ++ * packet. ++ * NETDEV_UP event is not enough to flag a port as ready. ++ * We also have to wait for linkwatch_do_dev to dev_activate ++ * and emit a NETDEV_CHANGE event. ++ * We check if a master port is ready by checking if the dev ++ * have a qdisc assigned and is not noop. ++ */ ++ dsa_tree_master_admin_state_change(dst, dev, ++ !qdisc_tx_is_noop(dev)); ++ ++ return NOTIFY_OK; ++ } ++ ++ return NOTIFY_DONE; ++ } + case NETDEV_GOING_DOWN: { + struct dsa_port *dp, *cpu_dp; + struct dsa_switch_tree *dst; +@@ -2322,6 +2352,8 @@ static int dsa_slave_netdevice_event(str + cpu_dp = dev->dsa_ptr; + dst = cpu_dp->ds->dst; + ++ dsa_tree_master_admin_state_change(dst, dev, false); ++ + list_for_each_entry(dp, &dst->ports, list) { + if (!dsa_is_user_port(dp->ds, dp->index)) + continue; +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -722,6 +722,18 @@ dsa_switch_mrp_del_ring_role(struct dsa_ + return 0; + } + ++static int ++dsa_switch_master_state_change(struct dsa_switch *ds, ++ struct dsa_notifier_master_state_info *info) ++{ ++ if (!ds->ops->master_state_change) ++ return 0; ++ ++ ds->ops->master_state_change(ds, info->master, info->operational); ++ ++ return 0; ++} ++ + static int dsa_switch_event(struct notifier_block *nb, + unsigned long event, void *info) + { +@@ -813,6 +825,9 @@ static int dsa_switch_event(struct notif + case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL: + err = dsa_switch_tag_8021q_vlan_del(ds, info); + break; ++ case DSA_NOTIFIER_MASTER_STATE_CHANGE: ++ err = dsa_switch_master_state_change(ds, info); ++ break; + default: + err = -EOPNOTSUPP; + break; diff --git a/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch b/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch new file mode 100644 index 00000000000..6478d580c01 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch @@ -0,0 +1,89 @@ +From e83d56537859849f2223b90749e554831b1f3c27 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Wed, 2 Feb 2022 01:03:21 +0100 +Subject: [PATCH 02/16] net: dsa: replay master state events in + dsa_tree_{setup,teardown}_master + +In order for switch driver to be able to make simple and reliable use of +the master tracking operations, they must also be notified of the +initial state of the DSA master, not just of the changes. This is +because they might enable certain features only during the time when +they know that the DSA master is up and running. + +Therefore, this change explicitly checks the state of the DSA master +under the same rtnl_mutex as we were holding during the +dsa_master_setup() and dsa_master_teardown() call. The idea being that +if the DSA master became operational in between the moment in which it +became a DSA master (dsa_master_setup set dev->dsa_ptr) and the moment +when we checked for the master being up, there is a chance that we +would emit a ->master_state_change() call with no actual state change. +We need to avoid that by serializing the concurrent netdevice event with +us. If the netdevice event started before, we force it to finish before +we begin, because we take rtnl_lock before making netdev_uses_dsa() +return true. So we also handle that early event and do nothing on it. +Similarly, if the dev_open() attempt is concurrent with us, it will +attempt to take the rtnl_mutex, but we're holding it. We'll see that +the master flag IFF_UP isn't set, then when we release the rtnl_mutex +we'll process the NETDEV_UP notifier. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/dsa2.c | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +--- a/net/dsa/dsa2.c ++++ b/net/dsa/dsa2.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "dsa_priv.h" + +@@ -1060,9 +1061,18 @@ static int dsa_tree_setup_master(struct + + list_for_each_entry(dp, &dst->ports, list) { + if (dsa_port_is_cpu(dp)) { +- err = dsa_master_setup(dp->master, dp); ++ struct net_device *master = dp->master; ++ bool admin_up = (master->flags & IFF_UP) && ++ !qdisc_tx_is_noop(master); ++ ++ err = dsa_master_setup(master, dp); + if (err) + return err; ++ ++ /* Replay master state event */ ++ dsa_tree_master_admin_state_change(dst, master, admin_up); ++ dsa_tree_master_oper_state_change(dst, master, ++ netif_oper_up(master)); + } + } + +@@ -1077,9 +1087,19 @@ static void dsa_tree_teardown_master(str + + rtnl_lock(); + +- list_for_each_entry(dp, &dst->ports, list) +- if (dsa_port_is_cpu(dp)) +- dsa_master_teardown(dp->master); ++ list_for_each_entry(dp, &dst->ports, list) { ++ if (dsa_port_is_cpu(dp)) { ++ struct net_device *master = dp->master; ++ ++ /* Synthesizing an "admin down" state is sufficient for ++ * the switches to get a notification if the master is ++ * currently up and running. ++ */ ++ dsa_tree_master_admin_state_change(dst, master, false); ++ ++ dsa_master_teardown(master); ++ } ++ } + + rtnl_unlock(); + } diff --git a/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch b/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch new file mode 100644 index 00000000000..82c94b385b5 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch @@ -0,0 +1,86 @@ +From 6b0458299297ca4ab6fb295800e29a4e501d50c1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:22 +0100 +Subject: [PATCH 03/16] net: dsa: tag_qca: convert to FIELD macro + +Convert driver to FIELD macro to drop redundant define. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/tag_qca.c | 34 +++++++++++++++------------------- + 1 file changed, 15 insertions(+), 19 deletions(-) + +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -4,29 +4,24 @@ + */ + + #include ++#include + + #include "dsa_priv.h" + + #define QCA_HDR_LEN 2 + #define QCA_HDR_VERSION 0x2 + +-#define QCA_HDR_RECV_VERSION_MASK GENMASK(15, 14) +-#define QCA_HDR_RECV_VERSION_S 14 +-#define QCA_HDR_RECV_PRIORITY_MASK GENMASK(13, 11) +-#define QCA_HDR_RECV_PRIORITY_S 11 +-#define QCA_HDR_RECV_TYPE_MASK GENMASK(10, 6) +-#define QCA_HDR_RECV_TYPE_S 6 ++#define QCA_HDR_RECV_VERSION GENMASK(15, 14) ++#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) ++#define QCA_HDR_RECV_TYPE GENMASK(10, 6) + #define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) +-#define QCA_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) ++#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) + +-#define QCA_HDR_XMIT_VERSION_MASK GENMASK(15, 14) +-#define QCA_HDR_XMIT_VERSION_S 14 +-#define QCA_HDR_XMIT_PRIORITY_MASK GENMASK(13, 11) +-#define QCA_HDR_XMIT_PRIORITY_S 11 +-#define QCA_HDR_XMIT_CONTROL_MASK GENMASK(10, 8) +-#define QCA_HDR_XMIT_CONTROL_S 8 ++#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) ++#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) ++#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) + #define QCA_HDR_XMIT_FROM_CPU BIT(7) +-#define QCA_HDR_XMIT_DP_BIT_MASK GENMASK(6, 0) ++#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) + + static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) + { +@@ -40,8 +35,9 @@ static struct sk_buff *qca_tag_xmit(stru + phdr = dsa_etype_header_pos_tx(skb); + + /* Set the version field, and set destination port information */ +- hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S | +- QCA_HDR_XMIT_FROM_CPU | BIT(dp->index); ++ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); ++ hdr |= QCA_HDR_XMIT_FROM_CPU; ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index)); + + *phdr = htons(hdr); + +@@ -62,7 +58,7 @@ static struct sk_buff *qca_tag_rcv(struc + hdr = ntohs(*phdr); + + /* Make sure the version is correct */ +- ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S; ++ ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr); + if (unlikely(ver != QCA_HDR_VERSION)) + return NULL; + +@@ -71,7 +67,7 @@ static struct sk_buff *qca_tag_rcv(struc + dsa_strip_etype_header(skb, QCA_HDR_LEN); + + /* Get source port information */ +- port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK); ++ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr); + + skb->dev = dsa_master_find_slave(dev, 0, port); + if (!skb->dev) diff --git a/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch b/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch new file mode 100644 index 00000000000..c1e74ceeeb5 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch @@ -0,0 +1,71 @@ +From 3ec762fb13c7e7273800b94c80db1c2cc37590d1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:23 +0100 +Subject: [PATCH 04/16] net: dsa: tag_qca: move define to include linux/dsa + +Move tag_qca define to include dir linux/dsa as the qca8k require access +to the tagger define to support in-band mdio read/write using ethernet +packet. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/linux/dsa/tag_qca.h | 21 +++++++++++++++++++++ + net/dsa/tag_qca.c | 16 +--------------- + 2 files changed, 22 insertions(+), 15 deletions(-) + create mode 100644 include/linux/dsa/tag_qca.h + +--- /dev/null ++++ b/include/linux/dsa/tag_qca.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef __TAG_QCA_H ++#define __TAG_QCA_H ++ ++#define QCA_HDR_LEN 2 ++#define QCA_HDR_VERSION 0x2 ++ ++#define QCA_HDR_RECV_VERSION GENMASK(15, 14) ++#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) ++#define QCA_HDR_RECV_TYPE GENMASK(10, 6) ++#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) ++#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) ++ ++#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) ++#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) ++#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) ++#define QCA_HDR_XMIT_FROM_CPU BIT(7) ++#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) ++ ++#endif /* __TAG_QCA_H */ +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -5,24 +5,10 @@ + + #include + #include ++#include + + #include "dsa_priv.h" + +-#define QCA_HDR_LEN 2 +-#define QCA_HDR_VERSION 0x2 +- +-#define QCA_HDR_RECV_VERSION GENMASK(15, 14) +-#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) +-#define QCA_HDR_RECV_TYPE GENMASK(10, 6) +-#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) +-#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) +- +-#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) +-#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) +-#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) +-#define QCA_HDR_XMIT_FROM_CPU BIT(7) +-#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) +- + static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); diff --git a/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch b/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch new file mode 100644 index 00000000000..9394a0dabbe --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch @@ -0,0 +1,27 @@ +From 101c04c3463b87061e6a3d4f72c1bc57670685a6 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:24 +0100 +Subject: [PATCH 05/16] net: dsa: tag_qca: enable promisc_on_master flag + +Ethernet MDIO packets are non-standard and DSA master expects the first +6 octets to be the MAC DA. To address these kind of packet, enable +promisc_on_master flag for the tagger. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + net/dsa/tag_qca.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -68,6 +68,7 @@ static const struct dsa_device_ops qca_n + .xmit = qca_tag_xmit, + .rcv = qca_tag_rcv, + .needed_headroom = QCA_HDR_LEN, ++ .promisc_on_master = true, + }; + + MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch b/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch new file mode 100644 index 00000000000..459454e03ba --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch @@ -0,0 +1,110 @@ +From c2ee8181fddb293d296477f60b3eb4fa3ce4e1a6 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:25 +0100 +Subject: [PATCH 06/16] net: dsa: tag_qca: add define for handling mgmt + Ethernet packet + +Add all the required define to prepare support for mgmt read/write in +Ethernet packet. Any packet of this type has to be dropped as the only +use of these special packet is receive ack for an mgmt write request or +receive data for an mgmt read request. +A struct is used that emulates the Ethernet header but is used for a +different purpose. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/linux/dsa/tag_qca.h | 44 +++++++++++++++++++++++++++++++++++++ + net/dsa/tag_qca.c | 15 ++++++++++--- + 2 files changed, 56 insertions(+), 3 deletions(-) + +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -12,10 +12,54 @@ + #define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) + #define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) + ++/* Packet type for recv */ ++#define QCA_HDR_RECV_TYPE_NORMAL 0x0 ++#define QCA_HDR_RECV_TYPE_MIB 0x1 ++#define QCA_HDR_RECV_TYPE_RW_REG_ACK 0x2 ++ + #define QCA_HDR_XMIT_VERSION GENMASK(15, 14) + #define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) + #define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) + #define QCA_HDR_XMIT_FROM_CPU BIT(7) + #define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) + ++/* Packet type for xmit */ ++#define QCA_HDR_XMIT_TYPE_NORMAL 0x0 ++#define QCA_HDR_XMIT_TYPE_RW_REG 0x1 ++ ++/* Check code for a valid mgmt packet. Switch will ignore the packet ++ * with this wrong. ++ */ ++#define QCA_HDR_MGMT_CHECK_CODE_VAL 0x5 ++ ++/* Specific define for in-band MDIO read/write with Ethernet packet */ ++#define QCA_HDR_MGMT_SEQ_LEN 4 /* 4 byte for the seq */ ++#define QCA_HDR_MGMT_COMMAND_LEN 4 /* 4 byte for the command */ ++#define QCA_HDR_MGMT_DATA1_LEN 4 /* First 4 byte for the mdio data */ ++#define QCA_HDR_MGMT_HEADER_LEN (QCA_HDR_MGMT_SEQ_LEN + \ ++ QCA_HDR_MGMT_COMMAND_LEN + \ ++ QCA_HDR_MGMT_DATA1_LEN) ++ ++#define QCA_HDR_MGMT_DATA2_LEN 12 /* Other 12 byte for the mdio data */ ++#define QCA_HDR_MGMT_PADDING_LEN 34 /* Padding to reach the min Ethernet packet */ ++ ++#define QCA_HDR_MGMT_PKT_LEN (QCA_HDR_MGMT_HEADER_LEN + \ ++ QCA_HDR_LEN + \ ++ QCA_HDR_MGMT_DATA2_LEN + \ ++ QCA_HDR_MGMT_PADDING_LEN) ++ ++#define QCA_HDR_MGMT_SEQ_NUM GENMASK(31, 0) /* 63, 32 */ ++#define QCA_HDR_MGMT_CHECK_CODE GENMASK(31, 29) /* 31, 29 */ ++#define QCA_HDR_MGMT_CMD BIT(28) /* 28 */ ++#define QCA_HDR_MGMT_LENGTH GENMASK(23, 20) /* 23, 20 */ ++#define QCA_HDR_MGMT_ADDR GENMASK(18, 0) /* 18, 0 */ ++ ++/* Special struct emulating a Ethernet header */ ++struct qca_mgmt_ethhdr { ++ u32 command; /* command bit 31:0 */ ++ u32 seq; /* seq 63:32 */ ++ u32 mdio_data; /* first 4byte mdio */ ++ __be16 hdr; /* qca hdr */ ++} __packed; ++ + #endif /* __TAG_QCA_H */ +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -32,10 +32,12 @@ static struct sk_buff *qca_tag_xmit(stru + + static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) + { +- u8 ver; +- u16 hdr; +- int port; ++ u8 ver, pk_type; + __be16 *phdr; ++ int port; ++ u16 hdr; ++ ++ BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); + + if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) + return NULL; +@@ -48,6 +50,13 @@ static struct sk_buff *qca_tag_rcv(struc + if (unlikely(ver != QCA_HDR_VERSION)) + return NULL; + ++ /* Get pk type */ ++ pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); ++ ++ /* Ethernet MDIO read/write packet */ ++ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) ++ return NULL; ++ + /* Remove QCA tag and recalculate checksum */ + skb_pull_rcsum(skb, QCA_HDR_LEN); + dsa_strip_etype_header(skb, QCA_HDR_LEN); diff --git a/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch b/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch new file mode 100644 index 00000000000..7e5dc657306 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch @@ -0,0 +1,45 @@ +From 18be654a4345f7d937b4bfbad74bea8093e3a93c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:26 +0100 +Subject: [PATCH 07/16] net: dsa: tag_qca: add define for handling MIB packet + +Add struct to correctly parse a mib Ethernet packet. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/linux/dsa/tag_qca.h | 10 ++++++++++ + net/dsa/tag_qca.c | 4 ++++ + 2 files changed, 14 insertions(+) + +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -62,4 +62,14 @@ struct qca_mgmt_ethhdr { + __be16 hdr; /* qca hdr */ + } __packed; + ++enum mdio_cmd { ++ MDIO_WRITE = 0x0, ++ MDIO_READ ++}; ++ ++struct mib_ethhdr { ++ u32 data[3]; /* first 3 mib counter */ ++ __be16 hdr; /* qca hdr */ ++} __packed; ++ + #endif /* __TAG_QCA_H */ +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -57,6 +57,10 @@ static struct sk_buff *qca_tag_rcv(struc + if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) + return NULL; + ++ /* Ethernet MIB counter packet */ ++ if (pk_type == QCA_HDR_RECV_TYPE_MIB) ++ return NULL; ++ + /* Remove QCA tag and recalculate checksum */ + skb_pull_rcsum(skb, QCA_HDR_LEN); + dsa_strip_etype_header(skb, QCA_HDR_LEN); diff --git a/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch b/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch new file mode 100644 index 00000000000..ad25da30e6d --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch @@ -0,0 +1,116 @@ +From 31eb6b4386ad91930417e3f5c8157a4b5e31cbd5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:27 +0100 +Subject: [PATCH 08/16] net: dsa: tag_qca: add support for handling mgmt and + MIB Ethernet packet + +Add connect/disconnect helper to assign private struct to the DSA switch. +Add support for Ethernet mgmt and MIB if the DSA driver provide an handler +to correctly parse and elaborate the data. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + include/linux/dsa/tag_qca.h | 7 +++++++ + net/dsa/tag_qca.c | 39 ++++++++++++++++++++++++++++++++++--- + 2 files changed, 43 insertions(+), 3 deletions(-) + +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -72,4 +72,11 @@ struct mib_ethhdr { + __be16 hdr; /* qca hdr */ + } __packed; + ++struct qca_tagger_data { ++ void (*rw_reg_ack_handler)(struct dsa_switch *ds, ++ struct sk_buff *skb); ++ void (*mib_autocast_handler)(struct dsa_switch *ds, ++ struct sk_buff *skb); ++}; ++ + #endif /* __TAG_QCA_H */ +--- a/net/dsa/tag_qca.c ++++ b/net/dsa/tag_qca.c +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + + #include "dsa_priv.h" +@@ -32,6 +33,9 @@ static struct sk_buff *qca_tag_xmit(stru + + static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) + { ++ struct qca_tagger_data *tagger_data; ++ struct dsa_port *dp = dev->dsa_ptr; ++ struct dsa_switch *ds = dp->ds; + u8 ver, pk_type; + __be16 *phdr; + int port; +@@ -39,6 +43,8 @@ static struct sk_buff *qca_tag_rcv(struc + + BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); + ++ tagger_data = ds->tagger_data; ++ + if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) + return NULL; + +@@ -53,13 +59,19 @@ static struct sk_buff *qca_tag_rcv(struc + /* Get pk type */ + pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); + +- /* Ethernet MDIO read/write packet */ +- if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) ++ /* Ethernet mgmt read/write packet */ ++ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) { ++ if (likely(tagger_data->rw_reg_ack_handler)) ++ tagger_data->rw_reg_ack_handler(ds, skb); + return NULL; ++ } + + /* Ethernet MIB counter packet */ +- if (pk_type == QCA_HDR_RECV_TYPE_MIB) ++ if (pk_type == QCA_HDR_RECV_TYPE_MIB) { ++ if (likely(tagger_data->mib_autocast_handler)) ++ tagger_data->mib_autocast_handler(ds, skb); + return NULL; ++ } + + /* Remove QCA tag and recalculate checksum */ + skb_pull_rcsum(skb, QCA_HDR_LEN); +@@ -75,9 +87,30 @@ static struct sk_buff *qca_tag_rcv(struc + return skb; + } + ++static int qca_tag_connect(struct dsa_switch *ds) ++{ ++ struct qca_tagger_data *tagger_data; ++ ++ tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL); ++ if (!tagger_data) ++ return -ENOMEM; ++ ++ ds->tagger_data = tagger_data; ++ ++ return 0; ++} ++ ++static void qca_tag_disconnect(struct dsa_switch *ds) ++{ ++ kfree(ds->tagger_data); ++ ds->tagger_data = NULL; ++} ++ + static const struct dsa_device_ops qca_netdev_ops = { + .name = "qca", + .proto = DSA_TAG_PROTO_QCA, ++ .connect = qca_tag_connect, ++ .disconnect = qca_tag_disconnect, + .xmit = qca_tag_xmit, + .rcv = qca_tag_rcv, + .needed_headroom = QCA_HDR_LEN, diff --git a/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch b/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch new file mode 100644 index 00000000000..eb21cc39124 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch @@ -0,0 +1,67 @@ +From cddbec19466a1dfb4d45ddd507d9f09f991d54ae Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:28 +0100 +Subject: [PATCH 09/16] net: dsa: qca8k: add tracking state of master port + +MDIO/MIB Ethernet require the master port and the tagger availabale to +correctly work. Use the new api master_state_change to track when master +is operational or not and set a bool in qca8k_priv. +We cache the first cached master available and we check if other cpu +port are operational when the cached one goes down. +This cached master will later be used by mdio read/write and mib request to +correctly use the working function. + +qca8k implementation for MDIO/MIB Ethernet is bad. CPU port0 is the only +one that answers with the ack packet or sends MIB Ethernet packets. For +this reason the master_state_change ignore CPU port6 and only checks +CPU port0 if it's operational and enables this mode. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 15 +++++++++++++++ + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 16 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -2401,6 +2401,20 @@ qca8k_port_lag_leave(struct dsa_switch * + return qca8k_lag_refresh_portmap(ds, port, lag, true); + } + ++static void ++qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, ++ bool operational) ++{ ++ struct dsa_port *dp = master->dsa_ptr; ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ ++ if (dp->index != 0) ++ return; ++ ++ priv->mgmt_master = operational ? (struct net_device *)master : NULL; ++} ++ + static const struct dsa_switch_ops qca8k_switch_ops = { + .get_tag_protocol = qca8k_get_tag_protocol, + .setup = qca8k_setup, +@@ -2436,6 +2450,7 @@ static const struct dsa_switch_ops qca8k + .get_phy_flags = qca8k_get_phy_flags, + .port_lag_join = qca8k_port_lag_join, + .port_lag_leave = qca8k_port_lag_leave, ++ .master_state_change = qca8k_master_change, + }; + + static int qca8k_read_switch_id(struct qca8k_priv *priv) +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -353,6 +353,7 @@ struct qca8k_priv { + struct dsa_switch_ops ops; + struct gpio_desc *reset_gpio; + unsigned int port_mtu[QCA8K_NUM_PORTS]; ++ struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + }; + + struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch b/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch new file mode 100644 index 00000000000..07c5ba46210 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch @@ -0,0 +1,363 @@ +From 5950c7c0a68c915b336c70f79388626e2d576ab7 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:29 +0100 +Subject: [PATCH 10/16] net: dsa: qca8k: add support for mgmt read/write in + Ethernet packet + +Add qca8k side support for mgmt read/write in Ethernet packet. +qca8k supports some specially crafted Ethernet packet that can be used +for mgmt read/write instead of the legacy method uart/internal mdio. +This add support for the qca8k side to craft the packet and enqueue it. +Each port and the qca8k_priv have a special struct to put data in it. +The completion API is used to wait for the packet to be received back +with the requested data. + +The various steps are: +1. Craft the special packet with the qca hdr set to mgmt read/write + mode. +2. Set the lock in the dedicated mgmt struct. +3. Increment the seq number and set it in the mgmt pkt +4. Reinit the completion. +5. Enqueue the packet. +6. Wait the packet to be received. +7. Use the data set by the tagger to complete the mdio operation. + +If the completion timeouts or the ack value is not true, the legacy +mdio way is used. + +It has to be considered that in the initial setup mdio is still used and +mdio is still used until DSA is ready to accept and tag packet. + +tag_proto_connect() is used to fill the required handler for the tagger +to correctly parse and elaborate the special Ethernet mdio packet. + +Locking is added to qca8k_master_change() to make sure no mgmt Ethernet +are in progress. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 225 ++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 13 +++ + 2 files changed, 238 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include "qca8k.h" + +@@ -170,6 +171,194 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r + return regmap_update_bits(priv->regmap, reg, mask, write_val); + } + ++static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ u8 len, cmd; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); ++ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); ++ ++ /* Make sure the seq match the requested packet */ ++ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) ++ mgmt_eth_data->ack = true; ++ ++ if (cmd == MDIO_READ) { ++ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; ++ ++ /* Get the rest of the 12 byte of data */ ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(mgmt_eth_data->data + 1, skb->data, ++ QCA_HDR_MGMT_DATA2_LEN); ++ } ++ ++ complete(&mgmt_eth_data->rw_done); ++} ++ ++static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, ++ int priority) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ struct sk_buff *skb; ++ u16 hdr; ++ ++ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); ++ if (!skb) ++ return NULL; ++ ++ skb_reset_mac_header(skb); ++ skb_set_network_header(skb, skb->len); ++ ++ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); ++ ++ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); ++ hdr |= QCA_HDR_XMIT_FROM_CPU; ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); ++ ++ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, ++ QCA_HDR_MGMT_CHECK_CODE_VAL); ++ ++ if (cmd == MDIO_WRITE) ++ mgmt_ethhdr->mdio_data = *val; ++ ++ mgmt_ethhdr->hdr = htons(hdr); ++ ++ skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); ++ ++ return skb; ++} ++ ++static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; ++ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); ++} ++ ++static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, ++ QCA8K_ETHERNET_MDIO_PRIORITY); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ *val = mgmt_eth_data->data[0]; ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val, ++ QCA8K_ETHERNET_MDIO_PRIORITY); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ++qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ u32 val = 0; ++ int ret; ++ ++ ret = qca8k_read_eth(priv, reg, &val); ++ if (ret) ++ return ret; ++ ++ val &= ~mask; ++ val |= write_val; ++ ++ return qca8k_write_eth(priv, reg, val); ++} ++ + static int + qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) + { +@@ -178,6 +367,9 @@ qca8k_regmap_read(void *ctx, uint32_t re + u16 r1, r2, page; + int ret; + ++ if (!qca8k_read_eth(priv, reg, val)) ++ return 0; ++ + qca8k_split_addr(reg, &r1, &r2, &page); + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +@@ -201,6 +393,9 @@ qca8k_regmap_write(void *ctx, uint32_t r + u16 r1, r2, page; + int ret; + ++ if (!qca8k_write_eth(priv, reg, val)) ++ return 0; ++ + qca8k_split_addr(reg, &r1, &r2, &page); + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +@@ -225,6 +420,9 @@ qca8k_regmap_update_bits(void *ctx, uint + u32 val; + int ret; + ++ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) ++ return 0; ++ + qca8k_split_addr(reg, &r1, &r2, &page); + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +@@ -2412,7 +2610,30 @@ qca8k_master_change(struct dsa_switch *d + if (dp->index != 0) + return; + ++ mutex_lock(&priv->mgmt_eth_data.mutex); ++ + priv->mgmt_master = operational ? (struct net_device *)master : NULL; ++ ++ mutex_unlock(&priv->mgmt_eth_data.mutex); ++} ++ ++static int qca8k_connect_tag_protocol(struct dsa_switch *ds, ++ enum dsa_tag_protocol proto) ++{ ++ struct qca_tagger_data *tagger_data; ++ ++ switch (proto) { ++ case DSA_TAG_PROTO_QCA: ++ tagger_data = ds->tagger_data; ++ ++ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; ++ ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; + } + + static const struct dsa_switch_ops qca8k_switch_ops = { +@@ -2451,6 +2672,7 @@ static const struct dsa_switch_ops qca8k + .port_lag_join = qca8k_port_lag_join, + .port_lag_leave = qca8k_port_lag_leave, + .master_state_change = qca8k_master_change, ++ .connect_tag_protocol = qca8k_connect_tag_protocol, + }; + + static int qca8k_read_switch_id(struct qca8k_priv *priv) +@@ -2530,6 +2752,9 @@ qca8k_sw_probe(struct mdio_device *mdiod + if (!priv->ds) + return -ENOMEM; + ++ mutex_init(&priv->mgmt_eth_data.mutex); ++ init_completion(&priv->mgmt_eth_data.rw_done); ++ + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = QCA8K_NUM_PORTS; + priv->ds->priv = priv; +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -11,6 +11,10 @@ + #include + #include + #include ++#include ++ ++#define QCA8K_ETHERNET_MDIO_PRIORITY 7 ++#define QCA8K_ETHERNET_TIMEOUT 100 + + #define QCA8K_NUM_PORTS 7 + #define QCA8K_NUM_CPU_PORTS 2 +@@ -328,6 +332,14 @@ enum { + QCA8K_CPU_PORT6, + }; + ++struct qca8k_mgmt_eth_data { ++ struct completion rw_done; ++ struct mutex mutex; /* Enforce one mdio read/write at time */ ++ bool ack; ++ u32 seq; ++ u32 data[4]; ++}; ++ + struct qca8k_ports_config { + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; +@@ -354,6 +366,7 @@ struct qca8k_priv { + struct gpio_desc *reset_gpio; + unsigned int port_mtu[QCA8K_NUM_PORTS]; + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ ++ struct qca8k_mgmt_eth_data mgmt_eth_data; + }; + + struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch b/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch new file mode 100644 index 00000000000..0dcf2794338 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch @@ -0,0 +1,226 @@ +From 5c957c7ca78cce5e4b96866722b0115bd758d945 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:30 +0100 +Subject: [PATCH 11/16] net: dsa: qca8k: add support for mib autocast in + Ethernet packet + +The switch can autocast MIB counter using Ethernet packet. +Add support for this and provide a handler for the tagger. +The switch will send packet with MIB counter for each port, the switch +will use completion API to wait for the correct packet to be received +and will complete the task only when each packet is received. +Although the handler will drop all the other packet, we still have to +consume each MIB packet to complete the request. This is done to prevent +mixed data with concurrent ethtool request. + +connect_tag_protocol() is used to add the handler to the tag_qca tagger, +master_state_change() use the MIB lock to make sure no MIB Ethernet is +in progress. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++- + drivers/net/dsa/qca8k.h | 17 ++++++- + 2 files changed, 121 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv) + int ret; + + mutex_lock(&priv->reg_mutex); +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | ++ QCA8K_MIB_BUSY); + if (ret) + goto exit; + +@@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds, + ETH_GSTRING_LEN); + } + ++static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ const struct qca8k_match_data *match_data; ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ const struct qca8k_mib_desc *mib; ++ struct mib_ethhdr *mib_ethhdr; ++ int i, mib_len, offset = 0; ++ u64 *data; ++ u8 port; ++ ++ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); ++ mib_eth_data = &priv->mib_eth_data; ++ ++ /* The switch autocast every port. Ignore other packet and ++ * parse only the requested one. ++ */ ++ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); ++ if (port != mib_eth_data->req_port) ++ goto exit; ++ ++ match_data = device_get_match_data(priv->dev); ++ data = mib_eth_data->data; ++ ++ for (i = 0; i < match_data->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ ++ /* First 3 mib are present in the skb head */ ++ if (i < 3) { ++ data[i] = mib_ethhdr->data[i]; ++ continue; ++ } ++ ++ mib_len = sizeof(uint32_t); ++ ++ /* Some mib are 64 bit wide */ ++ if (mib->size == 2) ++ mib_len = sizeof(uint64_t); ++ ++ /* Copy the mib value from packet to the */ ++ memcpy(data + i, skb->data + offset, mib_len); ++ ++ /* Set the offset for the next mib */ ++ offset += mib_len; ++ } ++ ++exit: ++ /* Complete on receiving all the mib packet */ ++ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) ++ complete(&mib_eth_data->rw_done); ++} ++ ++static int ++qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ mib_eth_data = &priv->mib_eth_data; ++ ++ mutex_lock(&mib_eth_data->mutex); ++ ++ reinit_completion(&mib_eth_data->rw_done); ++ ++ mib_eth_data->req_port = dp->index; ++ mib_eth_data->data = data; ++ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Send mib autocast request */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | ++ QCA8K_MIB_BUSY); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ if (ret) ++ goto exit; ++ ++ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); ++ ++exit: ++ mutex_unlock(&mib_eth_data->mutex); ++ ++ return ret; ++} ++ + static void + qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, + uint64_t *data) +@@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switc + u32 hi = 0; + int ret; + ++ if (priv->mgmt_master && ++ qca8k_get_ethtool_stats_eth(ds, port, data) > 0) ++ return; ++ + match_data = of_device_get_match_data(priv->dev); + + for (i = 0; i < match_data->mib_count; i++) { +@@ -2611,9 +2709,11 @@ qca8k_master_change(struct dsa_switch *d + return; + + mutex_lock(&priv->mgmt_eth_data.mutex); ++ mutex_lock(&priv->mib_eth_data.mutex); + + priv->mgmt_master = operational ? (struct net_device *)master : NULL; + ++ mutex_unlock(&priv->mib_eth_data.mutex); + mutex_unlock(&priv->mgmt_eth_data.mutex); + } + +@@ -2627,6 +2727,7 @@ static int qca8k_connect_tag_protocol(st + tagger_data = ds->tagger_data; + + tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; ++ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; + + break; + default: +@@ -2755,6 +2856,9 @@ qca8k_sw_probe(struct mdio_device *mdiod + mutex_init(&priv->mgmt_eth_data.mutex); + init_completion(&priv->mgmt_eth_data.rw_done); + ++ mutex_init(&priv->mib_eth_data.mutex); ++ init_completion(&priv->mib_eth_data.rw_done); ++ + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = QCA8K_NUM_PORTS; + priv->ds->priv = priv; +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -67,7 +67,7 @@ + #define QCA8K_REG_MODULE_EN 0x030 + #define QCA8K_MODULE_EN_MIB BIT(0) + #define QCA8K_REG_MIB 0x034 +-#define QCA8K_MIB_FLUSH BIT(24) ++#define QCA8K_MIB_FUNC GENMASK(26, 24) + #define QCA8K_MIB_CPU_KEEP BIT(20) + #define QCA8K_MIB_BUSY BIT(17) + #define QCA8K_MDIO_MASTER_CTRL 0x3c +@@ -317,6 +317,12 @@ enum qca8k_vlan_cmd { + QCA8K_VLAN_READ = 6, + }; + ++enum qca8k_mid_cmd { ++ QCA8K_MIB_FLUSH = 1, ++ QCA8K_MIB_FLUSH_PORT = 2, ++ QCA8K_MIB_CAST = 3, ++}; ++ + struct ar8xxx_port_status { + int enabled; + }; +@@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data { + u32 data[4]; + }; + ++struct qca8k_mib_eth_data { ++ struct completion rw_done; ++ struct mutex mutex; /* Process one command at time */ ++ refcount_t port_parsed; /* Counter to track parsed port */ ++ u8 req_port; ++ u64 *data; /* pointer to ethtool data */ ++}; ++ + struct qca8k_ports_config { + bool sgmii_rx_clk_falling_edge; + bool sgmii_tx_clk_falling_edge; +@@ -367,6 +381,7 @@ struct qca8k_priv { + unsigned int port_mtu[QCA8K_NUM_PORTS]; + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct qca8k_mgmt_eth_data mgmt_eth_data; ++ struct qca8k_mib_eth_data mib_eth_data; + }; + + struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch b/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch new file mode 100644 index 00000000000..f5899eb5901 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch @@ -0,0 +1,287 @@ +From 2cd5485663847d468dc207b3ff85fb1fab44d97f Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:31 +0100 +Subject: [PATCH 12/16] net: dsa: qca8k: add support for phy read/write with + mgmt Ethernet + +Use mgmt Ethernet also for phy read/write if availabale. Use a different +seq number to make sure we receive the correct packet. +On any error, we fallback to the legacy mdio read/write. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 216 ++++++++++++++++++++++++++++++++++++++++ + drivers/net/dsa/qca8k.h | 1 + + 2 files changed, 217 insertions(+) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -867,6 +867,199 @@ qca8k_port_set_status(struct qca8k_priv + regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); + } + ++static int ++qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, ++ struct sk_buff *read_skb, u32 *val) ++{ ++ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); ++ bool ack; ++ int ret; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the copy pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ *val = mgmt_eth_data->data[0]; ++ ++ return 0; ++} ++ ++static int ++qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, ++ int regnum, u16 data) ++{ ++ struct sk_buff *write_skb, *clear_skb, *read_skb; ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ u32 write_val, clear_val = 0, val; ++ struct net_device *mgmt_master; ++ int ret, ret1; ++ bool ack; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum); ++ ++ if (read) { ++ write_val |= QCA8K_MDIO_MASTER_READ; ++ } else { ++ write_val |= QCA8K_MDIO_MASTER_WRITE; ++ write_val |= QCA8K_MDIO_MASTER_DATA(data); ++ } ++ ++ /* Prealloc all the needed skb before the lock */ ++ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, ++ &write_val, QCA8K_ETHERNET_PHY_PRIORITY); ++ if (!write_skb) ++ return -ENOMEM; ++ ++ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, ++ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); ++ if (!write_skb) { ++ ret = -ENOMEM; ++ goto err_clear_skb; ++ } ++ ++ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, ++ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); ++ if (!write_skb) { ++ ret = -ENOMEM; ++ goto err_read_skb; ++ } ++ ++ /* Actually start the request: ++ * 1. Send mdio master packet ++ * 2. Busy Wait for mdio master command ++ * 3. Get the data if we are reading ++ * 4. Reset the mdio master (even with error) ++ */ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check if mgmt_master is operational */ ++ mgmt_master = priv->mgmt_master; ++ if (!mgmt_master) { ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ret = -EINVAL; ++ goto err_mgmt_master; ++ } ++ ++ read_skb->dev = mgmt_master; ++ clear_skb->dev = mgmt_master; ++ write_skb->dev = mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the write pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(write_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, ++ !(val & QCA8K_MDIO_MASTER_BUSY), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, ++ mgmt_eth_data, read_skb, &val); ++ ++ if (ret < 0 && ret1 < 0) { ++ ret = ret1; ++ goto exit; ++ } ++ ++ if (read) { ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the read pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(read_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; ++ } else { ++ kfree_skb(read_skb); ++ } ++exit: ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the clear pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(clear_skb); ++ ++ wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ return ret; ++ ++ /* Error handling before lock */ ++err_mgmt_master: ++ kfree_skb(read_skb); ++err_read_skb: ++ kfree_skb(clear_skb); ++err_clear_skb: ++ kfree_skb(write_skb); ++ ++ return ret; ++} ++ + static u32 + qca8k_port_to_phy(int port) + { +@@ -989,6 +1182,12 @@ qca8k_internal_mdio_write(struct mii_bus + { + struct qca8k_priv *priv = slave_bus->priv; + struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); ++ if (!ret) ++ return 0; + + return qca8k_mdio_write(bus, phy, regnum, data); + } +@@ -998,6 +1197,12 @@ qca8k_internal_mdio_read(struct mii_bus + { + struct qca8k_priv *priv = slave_bus->priv; + struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); ++ if (ret >= 0) ++ return ret; + + return qca8k_mdio_read(bus, phy, regnum); + } +@@ -1006,6 +1211,7 @@ static int + qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) + { + struct qca8k_priv *priv = ds->priv; ++ int ret; + + /* Check if the legacy mapping should be used and the + * port is not correctly mapped to the right PHY in the +@@ -1014,6 +1220,11 @@ qca8k_phy_write(struct dsa_switch *ds, i + if (priv->legacy_phy_port_mapping) + port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; + ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, false, port, regnum, 0); ++ if (!ret) ++ return ret; ++ + return qca8k_mdio_write(priv->bus, port, regnum, data); + } + +@@ -1030,6 +1241,11 @@ qca8k_phy_read(struct dsa_switch *ds, in + if (priv->legacy_phy_port_mapping) + port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; + ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, true, port, regnum, 0); ++ if (ret >= 0) ++ return ret; ++ + ret = qca8k_mdio_read(priv->bus, port, regnum); + + if (ret < 0) +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -14,6 +14,7 @@ + #include + + #define QCA8K_ETHERNET_MDIO_PRIORITY 7 ++#define QCA8K_ETHERNET_PHY_PRIORITY 6 + #define QCA8K_ETHERNET_TIMEOUT 100 + + #define QCA8K_NUM_PORTS 7 diff --git a/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch b/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch new file mode 100644 index 00000000000..4ac0bc32fdb --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch @@ -0,0 +1,208 @@ +From 4264350acb75430d5021a1d7de56a33faf69a097 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:32 +0100 +Subject: [PATCH 13/16] net: dsa: qca8k: move page cache to driver priv + +There can be multiple qca8k switch on the same system. Move the static +qca8k_current_page to qca8k_priv and make it specific for each switch. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 42 ++++++++++++++++++++--------------------- + drivers/net/dsa/qca8k.h | 9 +++++++++ + 2 files changed, 29 insertions(+), 22 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -75,12 +75,6 @@ static const struct qca8k_mib_desc ar832 + MIB_DESC(1, 0xac, "TXUnicast"), + }; + +-/* The 32bit switch registers are accessed indirectly. To achieve this we need +- * to set the page of the register. Track the last page that was set to reduce +- * mdio writes +- */ +-static u16 qca8k_current_page = 0xffff; +- + static void + qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) + { +@@ -134,11 +128,13 @@ qca8k_mii_write32(struct mii_bus *bus, i + } + + static int +-qca8k_set_page(struct mii_bus *bus, u16 page) ++qca8k_set_page(struct qca8k_priv *priv, u16 page) + { ++ u16 *cached_page = &priv->mdio_cache.page; ++ struct mii_bus *bus = priv->bus; + int ret; + +- if (page == qca8k_current_page) ++ if (page == *cached_page) + return 0; + + ret = bus->write(bus, 0x18, 0, page); +@@ -148,7 +144,7 @@ qca8k_set_page(struct mii_bus *bus, u16 + return ret; + } + +- qca8k_current_page = page; ++ *cached_page = page; + usleep_range(1000, 2000); + return 0; + } +@@ -374,7 +370,7 @@ qca8k_regmap_read(void *ctx, uint32_t re + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- ret = qca8k_set_page(bus, page); ++ ret = qca8k_set_page(priv, page); + if (ret < 0) + goto exit; + +@@ -400,7 +396,7 @@ qca8k_regmap_write(void *ctx, uint32_t r + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- ret = qca8k_set_page(bus, page); ++ ret = qca8k_set_page(priv, page); + if (ret < 0) + goto exit; + +@@ -427,7 +423,7 @@ qca8k_regmap_update_bits(void *ctx, uint + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- ret = qca8k_set_page(bus, page); ++ ret = qca8k_set_page(priv, page); + if (ret < 0) + goto exit; + +@@ -1098,8 +1094,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus + } + + static int +-qca8k_mdio_write(struct mii_bus *bus, int phy, int regnum, u16 data) ++qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) + { ++ struct mii_bus *bus = priv->bus; + u16 r1, r2, page; + u32 val; + int ret; +@@ -1116,7 +1113,7 @@ qca8k_mdio_write(struct mii_bus *bus, in + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- ret = qca8k_set_page(bus, page); ++ ret = qca8k_set_page(priv, page); + if (ret) + goto exit; + +@@ -1135,8 +1132,9 @@ exit: + } + + static int +-qca8k_mdio_read(struct mii_bus *bus, int phy, int regnum) ++qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) + { ++ struct mii_bus *bus = priv->bus; + u16 r1, r2, page; + u32 val; + int ret; +@@ -1152,7 +1150,7 @@ qca8k_mdio_read(struct mii_bus *bus, int + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- ret = qca8k_set_page(bus, page); ++ ret = qca8k_set_page(priv, page); + if (ret) + goto exit; + +@@ -1181,7 +1179,6 @@ static int + qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) + { + struct qca8k_priv *priv = slave_bus->priv; +- struct mii_bus *bus = priv->bus; + int ret; + + /* Use mdio Ethernet when available, fallback to legacy one on error */ +@@ -1189,14 +1186,13 @@ qca8k_internal_mdio_write(struct mii_bus + if (!ret) + return 0; + +- return qca8k_mdio_write(bus, phy, regnum, data); ++ return qca8k_mdio_write(priv, phy, regnum, data); + } + + static int + qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) + { + struct qca8k_priv *priv = slave_bus->priv; +- struct mii_bus *bus = priv->bus; + int ret; + + /* Use mdio Ethernet when available, fallback to legacy one on error */ +@@ -1204,7 +1200,7 @@ qca8k_internal_mdio_read(struct mii_bus + if (ret >= 0) + return ret; + +- return qca8k_mdio_read(bus, phy, regnum); ++ return qca8k_mdio_read(priv, phy, regnum); + } + + static int +@@ -1225,7 +1221,7 @@ qca8k_phy_write(struct dsa_switch *ds, i + if (!ret) + return ret; + +- return qca8k_mdio_write(priv->bus, port, regnum, data); ++ return qca8k_mdio_write(priv, port, regnum, data); + } + + static int +@@ -1246,7 +1242,7 @@ qca8k_phy_read(struct dsa_switch *ds, in + if (ret >= 0) + return ret; + +- ret = qca8k_mdio_read(priv->bus, port, regnum); ++ ret = qca8k_mdio_read(priv, port, regnum); + + if (ret < 0) + return 0xffff; +@@ -3060,6 +3056,8 @@ qca8k_sw_probe(struct mdio_device *mdiod + return PTR_ERR(priv->regmap); + } + ++ priv->mdio_cache.page = 0xffff; ++ + /* Check the detected switch id */ + ret = qca8k_read_switch_id(priv); + if (ret) +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -363,6 +363,14 @@ struct qca8k_ports_config { + u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ + }; + ++struct qca8k_mdio_cache { ++/* The 32bit switch registers are accessed indirectly. To achieve this we need ++ * to set the page of the register. Track the last page that was set to reduce ++ * mdio writes ++ */ ++ u16 page; ++}; ++ + struct qca8k_priv { + u8 switch_id; + u8 switch_revision; +@@ -383,6 +391,7 @@ struct qca8k_priv { + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct qca8k_mgmt_eth_data mgmt_eth_data; + struct qca8k_mib_eth_data mib_eth_data; ++ struct qca8k_mdio_cache mdio_cache; + }; + + struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch b/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch new file mode 100644 index 00000000000..e2cb2721ce9 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch @@ -0,0 +1,164 @@ +From 2481d206fae7884cd07014fd1318e63af35e99eb Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:33 +0100 +Subject: [PATCH 14/16] net: dsa: qca8k: cache lo and hi for mdio write + +From Documentation, we can cache lo and hi the same way we do with the +page. This massively reduce the mdio write as 3/4 of the time as we only +require to write the lo or hi part for a mdio write. + +Signed-off-by: Ansuel Smith +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++++++++-------- + drivers/net/dsa/qca8k.h | 5 ++++ + 2 files changed, 54 insertions(+), 12 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -89,6 +89,44 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u + } + + static int ++qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) ++{ ++ u16 *cached_lo = &priv->mdio_cache.lo; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (lo == *cached_lo) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, lo); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit lo register\n"); ++ ++ *cached_lo = lo; ++ return 0; ++} ++ ++static int ++qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) ++{ ++ u16 *cached_hi = &priv->mdio_cache.hi; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (hi == *cached_hi) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, hi); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit hi register\n"); ++ ++ *cached_hi = hi; ++ return 0; ++} ++ ++static int + qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) + { + int ret; +@@ -111,7 +149,7 @@ qca8k_mii_read32(struct mii_bus *bus, in + } + + static void +-qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) ++qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) + { + u16 lo, hi; + int ret; +@@ -119,12 +157,9 @@ qca8k_mii_write32(struct mii_bus *bus, i + lo = val & 0xffff; + hi = (u16)(val >> 16); + +- ret = bus->write(bus, phy_id, regnum, lo); ++ ret = qca8k_set_lo(priv, phy_id, regnum, lo); + if (ret >= 0) +- ret = bus->write(bus, phy_id, regnum + 1, hi); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit register\n"); ++ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); + } + + static int +@@ -400,7 +435,7 @@ qca8k_regmap_write(void *ctx, uint32_t r + if (ret < 0) + goto exit; + +- qca8k_mii_write32(bus, 0x10 | r2, r1, val); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); + + exit: + mutex_unlock(&bus->mdio_lock); +@@ -433,7 +468,7 @@ qca8k_regmap_update_bits(void *ctx, uint + + val &= ~mask; + val |= write_val; +- qca8k_mii_write32(bus, 0x10 | r2, r1, val); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); + + exit: + mutex_unlock(&bus->mdio_lock); +@@ -1117,14 +1152,14 @@ qca8k_mdio_write(struct qca8k_priv *priv + if (ret) + goto exit; + +- qca8k_mii_write32(bus, 0x10 | r2, r1, val); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); + + ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_BUSY); + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); + + mutex_unlock(&bus->mdio_lock); + +@@ -1154,7 +1189,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, + if (ret) + goto exit; + +- qca8k_mii_write32(bus, 0x10 | r2, r1, val); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); + + ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_BUSY); +@@ -1165,7 +1200,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); + + mutex_unlock(&bus->mdio_lock); + +@@ -3057,6 +3092,8 @@ qca8k_sw_probe(struct mdio_device *mdiod + } + + priv->mdio_cache.page = 0xffff; ++ priv->mdio_cache.lo = 0xffff; ++ priv->mdio_cache.hi = 0xffff; + + /* Check the detected switch id */ + ret = qca8k_read_switch_id(priv); +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -369,6 +369,11 @@ struct qca8k_mdio_cache { + * mdio writes + */ + u16 page; ++/* lo and hi can also be cached and from Documentation we can skip one ++ * extra mdio write if lo or hi is didn't change. ++ */ ++ u16 lo; ++ u16 hi; + }; + + struct qca8k_priv { diff --git a/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch b/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch new file mode 100644 index 00000000000..5acd13dbad8 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch @@ -0,0 +1,206 @@ +From 90386223f44e2a751d7e9e9ac8f78ea33358a891 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:34 +0100 +Subject: [PATCH 15/16] net: dsa: qca8k: add support for larger read/write size + with mgmt Ethernet + +mgmt Ethernet packet can read/write up to 16byte at times. The len reg +is limited to 15 (0xf). The switch actually sends and accepts data in 4 +different steps of len values. +Len steps: +- 0: nothing +- 1-4: first 4 byte +- 5-6: first 12 byte +- 7-15: all 16 byte + +In the alloc skb function we check if the len is 16 and we fix it to a +len of 15. It the read/write function interest to extract the real asked +data. The tagger handler will always copy the fully 16byte with a READ +command. This is useful for some big regs like the fdb reg that are +more than 4byte of data. This permits to introduce a bulk function that +will send and request the entire entry in one go. +Write function is changed and it does now require to pass the pointer to +val to also handle array val. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++-------------- + 1 file changed, 41 insertions(+), 20 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -222,7 +222,9 @@ static void qca8k_rw_reg_ack_handler(str + if (cmd == MDIO_READ) { + mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; + +- /* Get the rest of the 12 byte of data */ ++ /* Get the rest of the 12 byte of data. ++ * The read/write function will extract the requested data. ++ */ + if (len > QCA_HDR_MGMT_DATA1_LEN) + memcpy(mgmt_eth_data->data + 1, skb->data, + QCA_HDR_MGMT_DATA2_LEN); +@@ -232,16 +234,30 @@ static void qca8k_rw_reg_ack_handler(str + } + + static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, +- int priority) ++ int priority, unsigned int len) + { + struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ unsigned int real_len; + struct sk_buff *skb; ++ u32 *data2; + u16 hdr; + + skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); + if (!skb) + return NULL; + ++ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte ++ * Actually for some reason the steps are: ++ * 0: nothing ++ * 1-4: first 4 byte ++ * 5-6: first 12 byte ++ * 7-15: all 16 byte ++ */ ++ if (len == 16) ++ real_len = 15; ++ else ++ real_len = len; ++ + skb_reset_mac_header(skb); + skb_set_network_header(skb, skb->len); + +@@ -254,7 +270,7 @@ static struct sk_buff *qca8k_alloc_mdio_ + hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); + + mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); + mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); + mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, + QCA_HDR_MGMT_CHECK_CODE_VAL); +@@ -264,7 +280,9 @@ static struct sk_buff *qca8k_alloc_mdio_ + + mgmt_ethhdr->hdr = htons(hdr); + +- skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); ++ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); ++ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); + + return skb; + } +@@ -277,7 +295,7 @@ static void qca8k_mdio_header_fill_seq_n + mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); + } + +-static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val) ++static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) + { + struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; + struct sk_buff *skb; +@@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_p + int ret; + + skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, +- QCA8K_ETHERNET_MDIO_PRIORITY); ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); + if (!skb) + return -ENOMEM; + +@@ -313,6 +331,9 @@ static int qca8k_read_eth(struct qca8k_p + msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); + + *val = mgmt_eth_data->data[0]; ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ + ack = mgmt_eth_data->ack; + + mutex_unlock(&mgmt_eth_data->mutex); +@@ -326,15 +347,15 @@ static int qca8k_read_eth(struct qca8k_p + return 0; + } + +-static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val) ++static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) + { + struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; + struct sk_buff *skb; + bool ack; + int ret; + +- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val, +- QCA8K_ETHERNET_MDIO_PRIORITY); ++ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); + if (!skb) + return -ENOMEM; + +@@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8 + u32 val = 0; + int ret; + +- ret = qca8k_read_eth(priv, reg, &val); ++ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); + if (ret) + return ret; + + val &= ~mask; + val |= write_val; + +- return qca8k_write_eth(priv, reg, val); ++ return qca8k_write_eth(priv, reg, &val, sizeof(val)); + } + + static int +@@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t re + u16 r1, r2, page; + int ret; + +- if (!qca8k_read_eth(priv, reg, val)) ++ if (!qca8k_read_eth(priv, reg, val, sizeof(val))) + return 0; + + qca8k_split_addr(reg, &r1, &r2, &page); +@@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t r + u16 r1, r2, page; + int ret; + +- if (!qca8k_write_eth(priv, reg, val)) ++ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) + return 0; + + qca8k_split_addr(reg, &r1, &r2, &page); +@@ -959,21 +980,21 @@ qca8k_phy_eth_command(struct qca8k_priv + } + + /* Prealloc all the needed skb before the lock */ +- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, +- &write_val, QCA8K_ETHERNET_PHY_PRIORITY); ++ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); + if (!write_skb) + return -ENOMEM; + +- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, +- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); ++ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); + if (!write_skb) { + ret = -ENOMEM; + goto err_clear_skb; + } + +- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, +- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); +- if (!write_skb) { ++ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); ++ if (!read_skb) { + ret = -ENOMEM; + goto err_read_skb; + } diff --git a/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch b/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch new file mode 100644 index 00000000000..f26c6b91ac5 --- /dev/null +++ b/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch @@ -0,0 +1,104 @@ +From 4f3701fc599820568ba4395070d34e4248800fc0 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Wed, 2 Feb 2022 01:03:35 +0100 +Subject: [PATCH 16/16] net: dsa: qca8k: introduce qca8k_bulk_read/write + function + +Introduce qca8k_bulk_read/write() function to use mgmt Ethernet way to +read/write packet in bulk. Make use of this new function in the fdb +function and while at it reduce the reg for fdb_read from 4 to 3 as the +max bit for the ARL(fdb) table is 83 bits. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 55 ++++++++++++++++++++++++++++++++--------- + 1 file changed, 43 insertions(+), 12 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -412,6 +412,43 @@ qca8k_regmap_update_bits_eth(struct qca8 + } + + static int ++qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ ++ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ u32 tmp; ++ ++ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ tmp = val[i]; ++ ++ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int + qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +@@ -546,17 +583,13 @@ qca8k_busy_wait(struct qca8k_priv *priv, + static int + qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) + { +- u32 reg[4], val; +- int i, ret; ++ u32 reg[3]; ++ int ret; + + /* load the ARL table into an array */ +- for (i = 0; i < 4; i++) { +- ret = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4), &val); +- if (ret < 0) +- return ret; +- +- reg[i] = val; +- } ++ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++ if (ret) ++ return ret; + + /* vid - 83:72 */ + fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); +@@ -580,7 +613,6 @@ qca8k_fdb_write(struct qca8k_priv *priv, + u8 aging) + { + u32 reg[3] = { 0 }; +- int i; + + /* vid - 83:72 */ + reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); +@@ -597,8 +629,7 @@ qca8k_fdb_write(struct qca8k_priv *priv, + reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); + + /* load the array into the ARL table */ +- for (i = 0; i < 3; i++) +- qca8k_write(priv, QCA8K_REG_ATU_DATA0 + (i * 4), reg[i]); ++ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); + } + + static int diff --git a/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch b/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch new file mode 100644 index 00000000000..34607c223ce --- /dev/null +++ b/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch @@ -0,0 +1,28 @@ +From c3664d913dc115cab4a5fdb5634df4887048000e Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Fri, 4 Feb 2022 13:03:36 +0300 +Subject: [PATCH 1/1] net: dsa: qca8k: check correct variable in + qca8k_phy_eth_command() + +This is a copy and paste bug. It was supposed to check "clear_skb" +instead of "write_skb". + +Fixes: 2cd548566384 ("net: dsa: qca8k: add support for phy read/write with mgmt Ethernet") +Signed-off-by: Dan Carpenter +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1018,7 +1018,7 @@ qca8k_phy_eth_command(struct qca8k_priv + + clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, + QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); +- if (!write_skb) { ++ if (!clear_skb) { + ret = -ENOMEM; + goto err_clear_skb; + } diff --git a/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch b/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch new file mode 100644 index 00000000000..d8cf2663090 --- /dev/null +++ b/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch @@ -0,0 +1,34 @@ +From 4f5e483b8c7a644733db941a1ae00173baa7b463 Mon Sep 17 00:00:00 2001 +From: kernel test robot +Date: Thu, 10 Feb 2022 06:13:04 +0800 +Subject: [PATCH 1/1] net: dsa: qca8k: fix noderef.cocci warnings + +drivers/net/dsa/qca8k.c:422:37-43: ERROR: application of sizeof to pointer + + sizeof when applied to a pointer typed expression gives the size of + the pointer + +Generated by: scripts/coccinelle/misc/noderef.cocci + +Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet") +CC: Ansuel Smith +Reported-by: kernel test robot +Signed-off-by: kernel test robot +Reviewed-by: Florian Fainelli +Link: https://lore.kernel.org/r/20220209221304.GA17529@d2214a582157 +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca8k.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -456,7 +456,7 @@ qca8k_regmap_read(void *ctx, uint32_t re + u16 r1, r2, page; + int ret; + +- if (!qca8k_read_eth(priv, reg, val, sizeof(val))) ++ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) + return 0; + + qca8k_split_addr(reg, &r1, &r2, &page); diff --git a/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch new file mode 100644 index 00000000000..57df4c126e4 --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch @@ -0,0 +1,79 @@ +From 69fd055957a02309ffdc23d887a01988b6e5bab1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:12 +0200 +Subject: [PATCH 1/6] net: dsa: qca8k: drop MTU tracking from qca8k_priv + +DSA set the CPU port based on the largest MTU of all the slave ports. +Based on this we can drop the MTU array from qca8k_priv and set the +port_change_mtu logic on DSA changing MTU of the CPU port as the switch +have a global MTU settingfor each port. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 26 +++++++++----------------- + drivers/net/dsa/qca8k.h | 1 - + 2 files changed, 9 insertions(+), 18 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1803,16 +1803,6 @@ qca8k_setup(struct dsa_switch *ds) + QCA8K_PORT_HOL_CTRL1_WRED_EN, + mask); + } +- +- /* Set initial MTU for every port. +- * We have only have a general MTU setting. So track +- * every port and set the max across all port. +- * Set per port MTU to 1500 as the MTU change function +- * will add the overhead and if its set to 1518 then it +- * will apply the overhead again and we will end up with +- * MTU of 1536 instead of 1518 +- */ +- priv->port_mtu[i] = ETH_DATA_LEN; + } + + /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ +@@ -2525,13 +2515,16 @@ static int + qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct qca8k_priv *priv = ds->priv; +- int ret, i, mtu = 0; +- +- priv->port_mtu[port] = new_mtu; ++ int ret; + +- for (i = 0; i < QCA8K_NUM_PORTS; i++) +- if (priv->port_mtu[i] > mtu) +- mtu = priv->port_mtu[i]; ++ /* We have only have a general MTU setting. ++ * DSA always set the CPU port's MTU to the largest MTU of the slave ++ * ports. ++ * Setting MTU just for the CPU port is sufficient to correctly set a ++ * value for every port. ++ */ ++ if (!dsa_is_cpu_port(ds, port)) ++ return 0; + + /* To change the MAX_FRAME_SIZE the cpu ports must be off or + * the switch panics. +@@ -2545,7 +2538,7 @@ qca8k_port_change_mtu(struct dsa_switch + qca8k_port_set_status(priv, 6, 0); + + /* Include L2 header / FCS length */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN); ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); + + if (priv->port_sts[0].enabled) + qca8k_port_set_status(priv, 0, 1); +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -392,7 +392,6 @@ struct qca8k_priv { + struct device *dev; + struct dsa_switch_ops ops; + struct gpio_desc *reset_gpio; +- unsigned int port_mtu[QCA8K_NUM_PORTS]; + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct qca8k_mgmt_eth_data mgmt_eth_data; + struct qca8k_mib_eth_data mib_eth_data; diff --git a/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch new file mode 100644 index 00000000000..3cacd7e4fdb --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch @@ -0,0 +1,116 @@ +From 2b8fd87af7f156942971789abac8ee2bb60c03bc Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:13 +0200 +Subject: [PATCH 2/6] net: dsa: qca8k: drop port_sts from qca8k_priv + +Port_sts is a thing of the past for this driver. It was something +present on the initial implementation of this driver and parts of the +original struct were dropped over time. Using an array of int to store if +a port is enabled or not to handle PM operation seems overkill. Switch +and use a simple u8 to store the port status where each bit correspond +to a port. (bit is set port is enabled, bit is not set, port is disabled) +Also add some comments to better describe why we need to track port +status. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 15 +++++++++------ + drivers/net/dsa/qca8k.h | 9 ++++----- + 2 files changed, 13 insertions(+), 11 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -2494,7 +2494,7 @@ qca8k_port_enable(struct dsa_switch *ds, + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + + qca8k_port_set_status(priv, port, 1); +- priv->port_sts[port].enabled = 1; ++ priv->port_enabled_map |= BIT(port); + + if (dsa_is_user_port(ds, port)) + phy_support_asym_pause(phy); +@@ -2508,7 +2508,7 @@ qca8k_port_disable(struct dsa_switch *ds + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; + + qca8k_port_set_status(priv, port, 0); +- priv->port_sts[port].enabled = 0; ++ priv->port_enabled_map &= ~BIT(port); + } + + static int +@@ -2531,19 +2531,19 @@ qca8k_port_change_mtu(struct dsa_switch + * Turn off both cpu ports before applying the new value to prevent + * this. + */ +- if (priv->port_sts[0].enabled) ++ if (priv->port_enabled_map & BIT(0)) + qca8k_port_set_status(priv, 0, 0); + +- if (priv->port_sts[6].enabled) ++ if (priv->port_enabled_map & BIT(6)) + qca8k_port_set_status(priv, 6, 0); + + /* Include L2 header / FCS length */ + ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); + +- if (priv->port_sts[0].enabled) ++ if (priv->port_enabled_map & BIT(0)) + qca8k_port_set_status(priv, 0, 1); + +- if (priv->port_sts[6].enabled) ++ if (priv->port_enabled_map & BIT(6)) + qca8k_port_set_status(priv, 6, 1); + + return ret; +@@ -3199,13 +3199,16 @@ static void qca8k_sw_shutdown(struct mdi + static void + qca8k_set_pm(struct qca8k_priv *priv, int enable) + { +- int i; ++ int port; + +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (!priv->port_sts[i].enabled) ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Do not enable on resume if the port was ++ * disabled before. ++ */ ++ if (!(priv->port_enabled_map & BIT(port))) + continue; + +- qca8k_port_set_status(priv, i, enable); ++ qca8k_port_set_status(priv, port, enable); + } + } + +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -324,10 +324,6 @@ enum qca8k_mid_cmd { + QCA8K_MIB_CAST = 3, + }; + +-struct ar8xxx_port_status { +- int enabled; +-}; +- + struct qca8k_match_data { + u8 id; + bool reduced_package; +@@ -382,11 +378,14 @@ struct qca8k_priv { + u8 mirror_rx; + u8 mirror_tx; + u8 lag_hash_mode; ++ /* Each bit correspond to a port. This switch can support a max of 7 port. ++ * Bit 1: port enabled. Bit 0: port disabled. ++ */ ++ u8 port_enabled_map; + bool legacy_phy_port_mapping; + struct qca8k_ports_config ports_config; + struct regmap *regmap; + struct mii_bus *bus; +- struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; + struct dsa_switch *ds; + struct mutex reg_mutex; + struct device *dev; diff --git a/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch b/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch new file mode 100644 index 00000000000..12c3221077c --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch @@ -0,0 +1,173 @@ +From 8255212e4130bd2dc1463286a3dddb74797bbdc1 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:14 +0200 +Subject: [PATCH 3/6] net: dsa: qca8k: rework and simplify mdiobus logic + +In an attempt to reduce qca8k_priv space, rework and simplify mdiobus +logic. +We now declare a mdiobus instead of relying on DSA phy_read/write even +if a mdio node is not present. This is all to make the qca8k ops static +and not switch specific. With a legacy implementation where port doesn't +have a phy map declared in the dts with a mdio node, we declare a +'qca8k-legacy' mdiobus. The conversion logic is used as legacy read and +write ops are used instead of the internal one. +Also drop the legacy_phy_port_mapping as we now declare mdiobus with ops +that already address the workaround. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 95 +++++++++++++---------------------------- + drivers/net/dsa/qca8k.h | 1 - + 2 files changed, 29 insertions(+), 67 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1291,83 +1291,63 @@ qca8k_internal_mdio_read(struct mii_bus + } + + static int +-qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) ++qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) + { +- struct qca8k_priv *priv = ds->priv; +- int ret; ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; + +- /* Check if the legacy mapping should be used and the +- * port is not correctly mapped to the right PHY in the +- * devicetree +- */ +- if (priv->legacy_phy_port_mapping) +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, false, port, regnum, 0); +- if (!ret) +- return ret; +- +- return qca8k_mdio_write(priv, port, regnum, data); ++ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); + } + + static int +-qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) ++qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) + { +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- /* Check if the legacy mapping should be used and the +- * port is not correctly mapped to the right PHY in the +- * devicetree +- */ +- if (priv->legacy_phy_port_mapping) +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, true, port, regnum, 0); +- if (ret >= 0) +- return ret; +- +- ret = qca8k_mdio_read(priv, port, regnum); +- +- if (ret < 0) +- return 0xffff; ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; + +- return ret; ++ return qca8k_internal_mdio_read(slave_bus, port, regnum); + } + + static int +-qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio) ++qca8k_mdio_register(struct qca8k_priv *priv) + { + struct dsa_switch *ds = priv->ds; ++ struct device_node *mdio; + struct mii_bus *bus; + + bus = devm_mdiobus_alloc(ds->dev); +- + if (!bus) + return -ENOMEM; + + bus->priv = (void *)priv; +- bus->name = "qca8k slave mii"; +- bus->read = qca8k_internal_mdio_read; +- bus->write = qca8k_internal_mdio_write; +- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", +- ds->index); +- + bus->parent = ds->dev; + bus->phy_mask = ~ds->phys_mii_mask; +- + ds->slave_mii_bus = bus; + +- return devm_of_mdiobus_register(priv->dev, bus, mdio); ++ /* Check if the devicetree declare the port:phy mapping */ ++ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); ++ if (of_device_is_available(mdio)) { ++ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index); ++ bus->name = "qca8k slave mii"; ++ bus->read = qca8k_internal_mdio_read; ++ bus->write = qca8k_internal_mdio_write; ++ return devm_of_mdiobus_register(priv->dev, bus, mdio); ++ } ++ ++ /* If a mapping can't be found the legacy mapping is used, ++ * using the qca8k_port_to_phy function ++ */ ++ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", ++ ds->dst->index, ds->index); ++ bus->name = "qca8k-legacy slave mii"; ++ bus->read = qca8k_legacy_mdio_read; ++ bus->write = qca8k_legacy_mdio_write; ++ return devm_mdiobus_register(priv->dev, bus); + } + + static int + qca8k_setup_mdio_bus(struct qca8k_priv *priv) + { + u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; +- struct device_node *ports, *port, *mdio; ++ struct device_node *ports, *port; + phy_interface_t mode; + int err; + +@@ -1429,24 +1409,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv * + QCA8K_MDIO_MASTER_EN); + } + +- /* Check if the devicetree declare the port:phy mapping */ +- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); +- if (of_device_is_available(mdio)) { +- err = qca8k_mdio_register(priv, mdio); +- if (err) +- of_node_put(mdio); +- +- return err; +- } +- +- /* If a mapping can't be found the legacy mapping is used, +- * using the qca8k_port_to_phy function +- */ +- priv->legacy_phy_port_mapping = true; +- priv->ops.phy_read = qca8k_phy_read; +- priv->ops.phy_write = qca8k_phy_write; +- +- return 0; ++ return qca8k_mdio_register(priv); + } + + static int +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -382,7 +382,6 @@ struct qca8k_priv { + * Bit 1: port enabled. Bit 0: port disabled. + */ + u8 port_enabled_map; +- bool legacy_phy_port_mapping; + struct qca8k_ports_config ports_config; + struct regmap *regmap; + struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch new file mode 100644 index 00000000000..8641000abbc --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch @@ -0,0 +1,39 @@ +From 2349b83a2486c55b9dd225326f0172a84a43c5e4 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:15 +0200 +Subject: [PATCH 4/6] net: dsa: qca8k: drop dsa_switch_ops from qca8k_priv + +Now that dsa_switch_ops is not switch specific anymore, we can drop it +from qca8k_priv and use the static ops directly for the dsa_switch +pointer. + +Signed-off-by: Ansuel Smith +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 3 +-- + drivers/net/dsa/qca8k.h | 1 - + 2 files changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -3121,8 +3121,7 @@ qca8k_sw_probe(struct mdio_device *mdiod + priv->ds->dev = &mdiodev->dev; + priv->ds->num_ports = QCA8K_NUM_PORTS; + priv->ds->priv = priv; +- priv->ops = qca8k_switch_ops; +- priv->ds->ops = &priv->ops; ++ priv->ds->ops = &qca8k_switch_ops; + mutex_init(&priv->reg_mutex); + dev_set_drvdata(&mdiodev->dev, priv); + +--- a/drivers/net/dsa/qca8k.h ++++ b/drivers/net/dsa/qca8k.h +@@ -388,7 +388,6 @@ struct qca8k_priv { + struct dsa_switch *ds; + struct mutex reg_mutex; + struct device *dev; +- struct dsa_switch_ops ops; + struct gpio_desc *reset_gpio; + struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ + struct qca8k_mgmt_eth_data mgmt_eth_data; diff --git a/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch b/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch new file mode 100644 index 00000000000..b14b22091bc --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch @@ -0,0 +1,33 @@ +From 6cfc03b602200c5cbbd8d906fd905547814e83df Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:16 +0200 +Subject: [PATCH 5/6] net: dsa: qca8k: correctly handle mdio read error + +Restore original way to handle mdio read error by returning 0xffff. +This was wrongly changed when the internal_mdio_read was introduced, +now that both legacy and internal use the same function, make sure that +they behave the same way. + +Fixes: ce062a0adbfe ("net: dsa: qca8k: fix kernel panic with legacy mdio mapping") +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1287,7 +1287,12 @@ qca8k_internal_mdio_read(struct mii_bus + if (ret >= 0) + return ret; + +- return qca8k_mdio_read(priv, phy, regnum); ++ ret = qca8k_mdio_read(priv, phy, regnum); ++ ++ if (ret < 0) ++ return 0xffff; ++ ++ return ret; + } + + static int diff --git a/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch b/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch new file mode 100644 index 00000000000..094686f11be --- /dev/null +++ b/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch @@ -0,0 +1,44 @@ +From 8d1af50842bf2774f4edc57054206e909117469b Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 16 Apr 2022 01:30:17 +0200 +Subject: [PATCH 6/6] net: dsa: qca8k: unify bus id naming with legacy and OF + mdio bus + +Add support for multiple switch with OF mdio bus declaration. +Unify the bus id naming and use the same logic for both legacy and OF +mdio bus. + +Signed-off-by: Ansuel Smith +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca8k.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/net/dsa/qca8k.c ++++ b/drivers/net/dsa/qca8k.c +@@ -1323,6 +1323,8 @@ qca8k_mdio_register(struct qca8k_priv *p + return -ENOMEM; + + bus->priv = (void *)priv; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", ++ ds->dst->index, ds->index); + bus->parent = ds->dev; + bus->phy_mask = ~ds->phys_mii_mask; + ds->slave_mii_bus = bus; +@@ -1330,7 +1332,6 @@ qca8k_mdio_register(struct qca8k_priv *p + /* Check if the devicetree declare the port:phy mapping */ + mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); + if (of_device_is_available(mdio)) { +- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index); + bus->name = "qca8k slave mii"; + bus->read = qca8k_internal_mdio_read; + bus->write = qca8k_internal_mdio_write; +@@ -1340,8 +1341,6 @@ qca8k_mdio_register(struct qca8k_priv *p + /* If a mapping can't be found the legacy mapping is used, + * using the qca8k_port_to_phy function + */ +- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", +- ds->dst->index, ds->index); + bus->name = "qca8k-legacy slave mii"; + bus->read = qca8k_legacy_mdio_read; + bus->write = qca8k_legacy_mdio_write; diff --git a/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch b/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch new file mode 100644 index 00000000000..1534113f1df --- /dev/null +++ b/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch @@ -0,0 +1,7389 @@ +From 4bbaf764e1e1786eb937fdb62172f656f512e116 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 13 Jul 2022 22:53:50 +0200 +Subject: [PATCH 1/1] net: dsa: qca8k: move driver to qca dir + +Move qca8k driver to qca dir in preparation for code split and +introduction of ipq4019 switch based on qca8k. + +Signed-off-by: Christian Marangi +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +--- + drivers/net/dsa/Kconfig | 8 -------- + drivers/net/dsa/Makefile | 1 - + drivers/net/dsa/qca/Kconfig | 8 ++++++++ + drivers/net/dsa/qca/Makefile | 1 + + drivers/net/dsa/{ => qca}/qca8k.c | 0 + drivers/net/dsa/{ => qca}/qca8k.h | 0 + 6 files changed, 9 insertions(+), 9 deletions(-) + rename drivers/net/dsa/{ => qca}/qca8k.c (100%) + rename drivers/net/dsa/{ => qca}/qca8k.h (100%) + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -60,14 +60,6 @@ source "drivers/net/dsa/sja1105/Kconfig" + + source "drivers/net/dsa/xrs700x/Kconfig" + +-config NET_DSA_QCA8K +- tristate "Qualcomm Atheros QCA8K Ethernet switch family support" +- select NET_DSA_TAG_QCA +- select REGMAP +- help +- This enables support for the Qualcomm Atheros QCA8K Ethernet +- switch chips. +- + config NET_DSA_REALTEK_SMI + tristate "Realtek SMI Ethernet switch family support" + select NET_DSA_TAG_RTL4_A +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -8,7 +8,6 @@ endif + obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o + obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o +-obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o + obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o + realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o + obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o +--- a/drivers/net/dsa/qca/Kconfig ++++ b/drivers/net/dsa/qca/Kconfig +@@ -7,3 +7,11 @@ config NET_DSA_AR9331 + help + This enables support for the Qualcomm Atheros AR9331 built-in Ethernet + switch. ++ ++config NET_DSA_QCA8K ++ tristate "Qualcomm Atheros QCA8K Ethernet switch family support" ++ select NET_DSA_TAG_QCA ++ select REGMAP ++ help ++ This enables support for the Qualcomm Atheros QCA8K Ethernet ++ switch chips. +--- a/drivers/net/dsa/qca/Makefile ++++ b/drivers/net/dsa/qca/Makefile +@@ -1,2 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o ++obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o +--- /dev/null ++++ b/drivers/net/dsa/qca/qca8k.c +@@ -0,0 +1,3243 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "qca8k.h" ++ ++#define MIB_DESC(_s, _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++static const struct qca8k_mib_desc ar8327_mib[] = { ++ MIB_DESC(1, 0x00, "RxBroad"), ++ MIB_DESC(1, 0x04, "RxPause"), ++ MIB_DESC(1, 0x08, "RxMulti"), ++ MIB_DESC(1, 0x0c, "RxFcsErr"), ++ MIB_DESC(1, 0x10, "RxAlignErr"), ++ MIB_DESC(1, 0x14, "RxRunt"), ++ MIB_DESC(1, 0x18, "RxFragment"), ++ MIB_DESC(1, 0x1c, "Rx64Byte"), ++ MIB_DESC(1, 0x20, "Rx128Byte"), ++ MIB_DESC(1, 0x24, "Rx256Byte"), ++ MIB_DESC(1, 0x28, "Rx512Byte"), ++ MIB_DESC(1, 0x2c, "Rx1024Byte"), ++ MIB_DESC(1, 0x30, "Rx1518Byte"), ++ MIB_DESC(1, 0x34, "RxMaxByte"), ++ MIB_DESC(1, 0x38, "RxTooLong"), ++ MIB_DESC(2, 0x3c, "RxGoodByte"), ++ MIB_DESC(2, 0x44, "RxBadByte"), ++ MIB_DESC(1, 0x4c, "RxOverFlow"), ++ MIB_DESC(1, 0x50, "Filtered"), ++ MIB_DESC(1, 0x54, "TxBroad"), ++ MIB_DESC(1, 0x58, "TxPause"), ++ MIB_DESC(1, 0x5c, "TxMulti"), ++ MIB_DESC(1, 0x60, "TxUnderRun"), ++ MIB_DESC(1, 0x64, "Tx64Byte"), ++ MIB_DESC(1, 0x68, "Tx128Byte"), ++ MIB_DESC(1, 0x6c, "Tx256Byte"), ++ MIB_DESC(1, 0x70, "Tx512Byte"), ++ MIB_DESC(1, 0x74, "Tx1024Byte"), ++ MIB_DESC(1, 0x78, "Tx1518Byte"), ++ MIB_DESC(1, 0x7c, "TxMaxByte"), ++ MIB_DESC(1, 0x80, "TxOverSize"), ++ MIB_DESC(2, 0x84, "TxByte"), ++ MIB_DESC(1, 0x8c, "TxCollision"), ++ MIB_DESC(1, 0x90, "TxAbortCol"), ++ MIB_DESC(1, 0x94, "TxMultiCol"), ++ MIB_DESC(1, 0x98, "TxSingleCol"), ++ MIB_DESC(1, 0x9c, "TxExcDefer"), ++ MIB_DESC(1, 0xa0, "TxDefer"), ++ MIB_DESC(1, 0xa4, "TxLateCol"), ++ MIB_DESC(1, 0xa8, "RXUnicast"), ++ MIB_DESC(1, 0xac, "TXUnicast"), ++}; ++ ++static void ++qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) ++{ ++ regaddr >>= 1; ++ *r1 = regaddr & 0x1e; ++ ++ regaddr >>= 5; ++ *r2 = regaddr & 0x7; ++ ++ regaddr >>= 3; ++ *page = regaddr & 0x3ff; ++} ++ ++static int ++qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) ++{ ++ u16 *cached_lo = &priv->mdio_cache.lo; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (lo == *cached_lo) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, lo); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit lo register\n"); ++ ++ *cached_lo = lo; ++ return 0; ++} ++ ++static int ++qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) ++{ ++ u16 *cached_hi = &priv->mdio_cache.hi; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (hi == *cached_hi) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, hi); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit hi register\n"); ++ ++ *cached_hi = hi; ++ return 0; ++} ++ ++static int ++qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) ++{ ++ int ret; ++ ++ ret = bus->read(bus, phy_id, regnum); ++ if (ret >= 0) { ++ *val = ret; ++ ret = bus->read(bus, phy_id, regnum + 1); ++ *val |= ret << 16; ++ } ++ ++ if (ret < 0) { ++ dev_err_ratelimited(&bus->dev, ++ "failed to read qca8k 32bit register\n"); ++ *val = 0; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ++qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) ++{ ++ u16 lo, hi; ++ int ret; ++ ++ lo = val & 0xffff; ++ hi = (u16)(val >> 16); ++ ++ ret = qca8k_set_lo(priv, phy_id, regnum, lo); ++ if (ret >= 0) ++ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); ++} ++ ++static int ++qca8k_set_page(struct qca8k_priv *priv, u16 page) ++{ ++ u16 *cached_page = &priv->mdio_cache.page; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (page == *cached_page) ++ return 0; ++ ++ ret = bus->write(bus, 0x18, 0, page); ++ if (ret < 0) { ++ dev_err_ratelimited(&bus->dev, ++ "failed to set qca8k page\n"); ++ return ret; ++ } ++ ++ *cached_page = page; ++ usleep_range(1000, 2000); ++ return 0; ++} ++ ++static int ++qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) ++{ ++ return regmap_read(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) ++{ ++ return regmap_write(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ return regmap_update_bits(priv->regmap, reg, mask, write_val); ++} ++ ++static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ u8 len, cmd; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); ++ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); ++ ++ /* Make sure the seq match the requested packet */ ++ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) ++ mgmt_eth_data->ack = true; ++ ++ if (cmd == MDIO_READ) { ++ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; ++ ++ /* Get the rest of the 12 byte of data. ++ * The read/write function will extract the requested data. ++ */ ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(mgmt_eth_data->data + 1, skb->data, ++ QCA_HDR_MGMT_DATA2_LEN); ++ } ++ ++ complete(&mgmt_eth_data->rw_done); ++} ++ ++static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, ++ int priority, unsigned int len) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ unsigned int real_len; ++ struct sk_buff *skb; ++ u32 *data2; ++ u16 hdr; ++ ++ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); ++ if (!skb) ++ return NULL; ++ ++ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte ++ * Actually for some reason the steps are: ++ * 0: nothing ++ * 1-4: first 4 byte ++ * 5-6: first 12 byte ++ * 7-15: all 16 byte ++ */ ++ if (len == 16) ++ real_len = 15; ++ else ++ real_len = len; ++ ++ skb_reset_mac_header(skb); ++ skb_set_network_header(skb, skb->len); ++ ++ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); ++ ++ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); ++ hdr |= QCA_HDR_XMIT_FROM_CPU; ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); ++ ++ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, ++ QCA_HDR_MGMT_CHECK_CODE_VAL); ++ ++ if (cmd == MDIO_WRITE) ++ mgmt_ethhdr->mdio_data = *val; ++ ++ mgmt_ethhdr->hdr = htons(hdr); ++ ++ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); ++ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ return skb; ++} ++ ++static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; ++ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); ++} ++ ++static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ *val = mgmt_eth_data->data[0]; ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ++qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ u32 val = 0; ++ int ret; ++ ++ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); ++ if (ret) ++ return ret; ++ ++ val &= ~mask; ++ val |= write_val; ++ ++ return qca8k_write_eth(priv, reg, &val, sizeof(val)); ++} ++ ++static int ++qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ ++ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ u32 tmp; ++ ++ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ tmp = val[i]; ++ ++ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ int ret; ++ ++ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ return ret; ++} ++ ++static int ++qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ int ret; ++ ++ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ return ret; ++} ++ ++static int ++qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); ++ if (ret < 0) ++ goto exit; ++ ++ val &= ~mask; ++ val |= write_val; ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret; ++} ++ ++static const struct regmap_range qca8k_readable_ranges[] = { ++ regmap_reg_range(0x0000, 0x00e4), /* Global control */ ++ regmap_reg_range(0x0100, 0x0168), /* EEE control */ ++ regmap_reg_range(0x0200, 0x0270), /* Parser control */ ++ regmap_reg_range(0x0400, 0x0454), /* ACL */ ++ regmap_reg_range(0x0600, 0x0718), /* Lookup */ ++ regmap_reg_range(0x0800, 0x0b70), /* QM */ ++ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ ++ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ ++ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ ++ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ ++ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ ++ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ ++ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ ++ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ ++ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ ++ ++}; ++ ++static const struct regmap_access_table qca8k_readable_table = { ++ .yes_ranges = qca8k_readable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), ++}; ++ ++static struct regmap_config qca8k_regmap_config = { ++ .reg_bits = 16, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = 0x16ac, /* end MIB - Port6 range */ ++ .reg_read = qca8k_regmap_read, ++ .reg_write = qca8k_regmap_write, ++ .reg_update_bits = qca8k_regmap_update_bits, ++ .rd_table = &qca8k_readable_table, ++ .disable_locking = true, /* Locking is handled by qca8k read/write */ ++ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ ++}; ++ ++static int ++qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) ++{ ++ u32 val; ++ ++ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); ++} ++ ++static int ++qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) ++{ ++ u32 reg[3]; ++ int ret; ++ ++ /* load the ARL table into an array */ ++ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++ if (ret) ++ return ret; ++ ++ /* vid - 83:72 */ ++ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); ++ /* aging - 67:64 */ ++ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); ++ /* portmask - 54:48 */ ++ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); ++ /* mac - 47:0 */ ++ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); ++ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); ++ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); ++ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); ++ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); ++ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); ++ ++ return 0; ++} ++ ++static void ++qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, ++ u8 aging) ++{ ++ u32 reg[3] = { 0 }; ++ ++ /* vid - 83:72 */ ++ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); ++ /* aging - 67:64 */ ++ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); ++ /* portmask - 54:48 */ ++ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); ++ /* mac - 47:0 */ ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); ++ ++ /* load the array into the ARL table */ ++ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++} ++ ++static int ++qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and FDB index */ ++ reg = QCA8K_ATU_FUNC_BUSY; ++ reg |= cmd; ++ if (port >= 0) { ++ reg |= QCA8K_ATU_FUNC_PORT_EN; ++ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); ++ } ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_FDB_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_ATU_FUNC_FULL) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) ++{ ++ int ret; ++ ++ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); ++ if (ret < 0) ++ return ret; ++ ++ return qca8k_fdb_read(priv, fdb); ++} ++ ++static int ++qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, ++ u16 vid, u8 aging) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static void ++qca8k_fdb_flush(struct qca8k_priv *priv) ++{ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_fdb_read(priv, &fdb); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule exist. Delete first */ ++ if (!fdb.aging) { ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ } ++ ++ /* Add port to fdb portmask */ ++ fdb.port_mask |= port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule doesn't exist. Why delete? */ ++ if (!fdb.aging) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ ++ /* Only port in the rule is this port. Don't re insert */ ++ if (fdb.port_mask == port_mask) ++ goto exit; ++ ++ /* Remove port from port mask */ ++ fdb.port_mask &= ~port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and VLAN index */ ++ reg = QCA8K_VTU_FUNC1_BUSY; ++ reg |= cmd; ++ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_VLAN_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_VTU_FUNC1_FULL) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) ++{ ++ u32 reg; ++ int ret; ++ ++ /* ++ We do the right thing with VLAN 0 and treat it as untagged while ++ preserving the tag on egress. ++ */ ++ if (vid == 0) ++ return 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ if (untagged) ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); ++ else ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); ++ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) ++{ ++ u32 reg, mask; ++ int ret, i; ++ bool del; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); ++ ++ /* Check if we're the last member to be removed */ ++ del = true; ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); ++ ++ if ((reg & mask) != mask) { ++ del = false; ++ break; ++ } ++ } ++ ++ if (del) { ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); ++ } else { ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ } ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_mib_init(struct qca8k_priv *priv) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | ++ QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static void ++qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) ++{ ++ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; ++ ++ /* Port 0 and 6 have no internal PHY */ ++ if (port > 0 && port < 6) ++ mask |= QCA8K_PORT_STATUS_LINK_AUTO; ++ ++ if (enable) ++ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++ else ++ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++} ++ ++static int ++qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, ++ struct sk_buff *read_skb, u32 *val) ++{ ++ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); ++ bool ack; ++ int ret; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the copy pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ *val = mgmt_eth_data->data[0]; ++ ++ return 0; ++} ++ ++static int ++qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, ++ int regnum, u16 data) ++{ ++ struct sk_buff *write_skb, *clear_skb, *read_skb; ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ u32 write_val, clear_val = 0, val; ++ struct net_device *mgmt_master; ++ int ret, ret1; ++ bool ack; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum); ++ ++ if (read) { ++ write_val |= QCA8K_MDIO_MASTER_READ; ++ } else { ++ write_val |= QCA8K_MDIO_MASTER_WRITE; ++ write_val |= QCA8K_MDIO_MASTER_DATA(data); ++ } ++ ++ /* Prealloc all the needed skb before the lock */ ++ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); ++ if (!write_skb) ++ return -ENOMEM; ++ ++ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); ++ if (!clear_skb) { ++ ret = -ENOMEM; ++ goto err_clear_skb; ++ } ++ ++ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); ++ if (!read_skb) { ++ ret = -ENOMEM; ++ goto err_read_skb; ++ } ++ ++ /* Actually start the request: ++ * 1. Send mdio master packet ++ * 2. Busy Wait for mdio master command ++ * 3. Get the data if we are reading ++ * 4. Reset the mdio master (even with error) ++ */ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check if mgmt_master is operational */ ++ mgmt_master = priv->mgmt_master; ++ if (!mgmt_master) { ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ret = -EINVAL; ++ goto err_mgmt_master; ++ } ++ ++ read_skb->dev = mgmt_master; ++ clear_skb->dev = mgmt_master; ++ write_skb->dev = mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the write pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(write_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, ++ !(val & QCA8K_MDIO_MASTER_BUSY), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, ++ mgmt_eth_data, read_skb, &val); ++ ++ if (ret < 0 && ret1 < 0) { ++ ret = ret1; ++ goto exit; ++ } ++ ++ if (read) { ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the read pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(read_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; ++ } else { ++ kfree_skb(read_skb); ++ } ++exit: ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the clear pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(clear_skb); ++ ++ wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ return ret; ++ ++ /* Error handling before lock */ ++err_mgmt_master: ++ kfree_skb(read_skb); ++err_read_skb: ++ kfree_skb(clear_skb); ++err_clear_skb: ++ kfree_skb(write_skb); ++ ++ return ret; ++} ++ ++static u32 ++qca8k_port_to_phy(int port) ++{ ++ /* From Andrew Lunn: ++ * Port 0 has no internal phy. ++ * Port 1 has an internal PHY at MDIO address 0. ++ * Port 2 has an internal PHY at MDIO address 1. ++ * ... ++ * Port 5 has an internal PHY at MDIO address 4. ++ * Port 6 has no internal PHY. ++ */ ++ ++ return port - 1; ++} ++ ++static int ++qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) ++{ ++ u16 r1, r2, page; ++ u32 val; ++ int ret, ret1; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, ++ bus, 0x10 | r2, r1, &val); ++ ++ /* Check if qca8k_read has failed for a different reason ++ * before returnting -ETIMEDOUT ++ */ ++ if (ret < 0 && ret1 < 0) ++ return ret1; ++ ++ return ret; ++} ++ ++static int ++qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum) | ++ QCA8K_MDIO_MASTER_DATA(data); ++ ++ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_BUSY); ++ ++exit: ++ /* even if the busy_wait timeouts try to clear the MASTER_EN */ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret; ++} ++ ++static int ++qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum); ++ ++ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); ++ ++exit: ++ /* even if the busy_wait timeouts try to clear the MASTER_EN */ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ if (ret >= 0) ++ ret = val & QCA8K_MDIO_MASTER_DATA_MASK; ++ ++ return ret; ++} ++ ++static int ++qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) ++{ ++ struct qca8k_priv *priv = slave_bus->priv; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); ++ if (!ret) ++ return 0; ++ ++ return qca8k_mdio_write(priv, phy, regnum, data); ++} ++ ++static int ++qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) ++{ ++ struct qca8k_priv *priv = slave_bus->priv; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); ++ if (ret >= 0) ++ return ret; ++ ++ ret = qca8k_mdio_read(priv, phy, regnum); ++ ++ if (ret < 0) ++ return 0xffff; ++ ++ return ret; ++} ++ ++static int ++qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) ++{ ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; ++ ++ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); ++} ++ ++static int ++qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) ++{ ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; ++ ++ return qca8k_internal_mdio_read(slave_bus, port, regnum); ++} ++ ++static int ++qca8k_mdio_register(struct qca8k_priv *priv) ++{ ++ struct dsa_switch *ds = priv->ds; ++ struct device_node *mdio; ++ struct mii_bus *bus; ++ ++ bus = devm_mdiobus_alloc(ds->dev); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->priv = (void *)priv; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", ++ ds->dst->index, ds->index); ++ bus->parent = ds->dev; ++ bus->phy_mask = ~ds->phys_mii_mask; ++ ds->slave_mii_bus = bus; ++ ++ /* Check if the devicetree declare the port:phy mapping */ ++ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); ++ if (of_device_is_available(mdio)) { ++ bus->name = "qca8k slave mii"; ++ bus->read = qca8k_internal_mdio_read; ++ bus->write = qca8k_internal_mdio_write; ++ return devm_of_mdiobus_register(priv->dev, bus, mdio); ++ } ++ ++ /* If a mapping can't be found the legacy mapping is used, ++ * using the qca8k_port_to_phy function ++ */ ++ bus->name = "qca8k-legacy slave mii"; ++ bus->read = qca8k_legacy_mdio_read; ++ bus->write = qca8k_legacy_mdio_write; ++ return devm_mdiobus_register(priv->dev, bus); ++} ++ ++static int ++qca8k_setup_mdio_bus(struct qca8k_priv *priv) ++{ ++ u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; ++ struct device_node *ports, *port; ++ phy_interface_t mode; ++ int err; ++ ++ ports = of_get_child_by_name(priv->dev->of_node, "ports"); ++ if (!ports) ++ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); ++ ++ if (!ports) ++ return -EINVAL; ++ ++ for_each_available_child_of_node(ports, port) { ++ err = of_property_read_u32(port, "reg", ®); ++ if (err) { ++ of_node_put(port); ++ of_node_put(ports); ++ return err; ++ } ++ ++ if (!dsa_is_user_port(priv->ds, reg)) ++ continue; ++ ++ of_get_phy_mode(port, &mode); ++ ++ if (of_property_read_bool(port, "phy-handle") && ++ mode != PHY_INTERFACE_MODE_INTERNAL) ++ external_mdio_mask |= BIT(reg); ++ else ++ internal_mdio_mask |= BIT(reg); ++ } ++ ++ of_node_put(ports); ++ if (!external_mdio_mask && !internal_mdio_mask) { ++ dev_err(priv->dev, "no PHYs are defined.\n"); ++ return -EINVAL; ++ } ++ ++ /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through ++ * the MDIO_MASTER register also _disconnects_ the external MDC ++ * passthrough to the internal PHYs. It's not possible to use both ++ * configurations at the same time! ++ * ++ * Because this came up during the review process: ++ * If the external mdio-bus driver is capable magically disabling ++ * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's ++ * accessors for the time being, it would be possible to pull this ++ * off. ++ */ ++ if (!!external_mdio_mask && !!internal_mdio_mask) { ++ dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); ++ return -EINVAL; ++ } ++ ++ if (external_mdio_mask) { ++ /* Make sure to disable the internal mdio bus in cases ++ * a dt-overlay and driver reload changed the configuration ++ */ ++ ++ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_EN); ++ } ++ ++ return qca8k_mdio_register(priv); ++} ++ ++static int ++qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) ++{ ++ u32 mask = 0; ++ int ret = 0; ++ ++ /* SoC specific settings for ipq8064. ++ * If more device require this consider adding ++ * a dedicated binding. ++ */ ++ if (of_machine_is_compatible("qcom,ipq8064")) ++ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; ++ ++ /* SoC specific settings for ipq8065 */ ++ if (of_machine_is_compatible("qcom,ipq8065")) ++ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; ++ ++ if (mask) { ++ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, ++ QCA8K_MAC_PWR_RGMII0_1_8V | ++ QCA8K_MAC_PWR_RGMII1_1_8V, ++ mask); ++ } ++ ++ return ret; ++} ++ ++static int qca8k_find_cpu_port(struct dsa_switch *ds) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Find the connected cpu port. Valid port are 0 or 6 */ ++ if (dsa_is_cpu_port(ds, 0)) ++ return 0; ++ ++ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); ++ ++ if (dsa_is_cpu_port(ds, 6)) ++ return 6; ++ ++ return -EINVAL; ++} ++ ++static int ++qca8k_setup_of_pws_reg(struct qca8k_priv *priv) ++{ ++ struct device_node *node = priv->dev->of_node; ++ const struct qca8k_match_data *data; ++ u32 val = 0; ++ int ret; ++ ++ /* QCA8327 require to set to the correct mode. ++ * His bigger brother QCA8328 have the 172 pin layout. ++ * Should be applied by default but we set this just to make sure. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ data = of_device_get_match_data(priv->dev); ++ ++ /* Set the correct package of 148 pin for QCA8327 */ ++ if (data->reduced_package) ++ val |= QCA8327_PWS_PACKAGE148_EN; ++ ++ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, ++ val); ++ if (ret) ++ return ret; ++ } ++ ++ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) ++ val |= QCA8K_PWS_POWER_ON_SEL; ++ ++ if (of_property_read_bool(node, "qca,led-open-drain")) { ++ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { ++ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); ++ return -EINVAL; ++ } ++ ++ val |= QCA8K_PWS_LED_OPEN_EN_CSR; ++ } ++ ++ return qca8k_rmw(priv, QCA8K_REG_PWS, ++ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, ++ val); ++} ++ ++static int ++qca8k_parse_port_config(struct qca8k_priv *priv) ++{ ++ int port, cpu_port_index = -1, ret; ++ struct device_node *port_dn; ++ phy_interface_t mode; ++ struct dsa_port *dp; ++ u32 delay; ++ ++ /* We have 2 CPU port. Check them */ ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Skip every other port */ ++ if (port != 0 && port != 6) ++ continue; ++ ++ dp = dsa_to_port(priv->ds, port); ++ port_dn = dp->dn; ++ cpu_port_index++; ++ ++ if (!of_device_is_available(port_dn)) ++ continue; ++ ++ ret = of_get_phy_mode(port_dn, &mode); ++ if (ret) ++ continue; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_SGMII: ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID) ++ delay = 1; ++ ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { ++ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; ++ ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ delay = 2; ++ ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { ++ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; ++ ++ /* Skip sgmii parsing for rgmii* mode */ ++ if (mode == PHY_INTERFACE_MODE_RGMII || ++ mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ break; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) ++ priv->ports_config.sgmii_tx_clk_falling_edge = true; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) ++ priv->ports_config.sgmii_rx_clk_falling_edge = true; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { ++ priv->ports_config.sgmii_enable_pll = true; ++ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); ++ priv->ports_config.sgmii_enable_pll = false; ++ } ++ ++ if (priv->switch_revision < 2) ++ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); ++ } ++ ++ break; ++ default: ++ continue; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_setup(struct dsa_switch *ds) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int cpu_port, ret, i; ++ u32 mask; ++ ++ cpu_port = qca8k_find_cpu_port(ds); ++ if (cpu_port < 0) { ++ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); ++ return cpu_port; ++ } ++ ++ /* Parse CPU port config to be later used in phy_link mac_config */ ++ ret = qca8k_parse_port_config(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_mdio_bus(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_of_pws_reg(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_mac_pwr_sel(priv); ++ if (ret) ++ return ret; ++ ++ /* Make sure MAC06 is disabled */ ++ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, ++ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); ++ if (ret) { ++ dev_err(priv->dev, "failed disabling MAC06 exchange"); ++ return ret; ++ } ++ ++ /* Enable CPU Port */ ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ++ if (ret) { ++ dev_err(priv->dev, "failed enabling CPU port"); ++ return ret; ++ } ++ ++ /* Enable MIB counters */ ++ ret = qca8k_mib_init(priv); ++ if (ret) ++ dev_warn(priv->dev, "mib init failed"); ++ ++ /* Initial setup of all ports */ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, 0); ++ if (ret) ++ return ret; ++ ++ /* Enable QCA header mode on all cpu ports */ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); ++ if (ret) { ++ dev_err(priv->dev, "failed enabling QCA header mode"); ++ return ret; ++ } ++ } ++ ++ /* Disable MAC by default on all user ports */ ++ if (dsa_is_user_port(ds, i)) ++ qca8k_port_set_status(priv, i, 0); ++ } ++ ++ /* Forward all unknown frames to CPU port for Linux processing ++ * Notice that in multi-cpu config only one port should be set ++ * for igmp, unknown, multicast and broadcast packet ++ */ ++ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); ++ if (ret) ++ return ret; ++ ++ /* Setup connection between CPU port & user ports ++ * Configure specific switch configuration for ports ++ */ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* CPU port gets connected to all user ports of the switch */ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); ++ if (ret) ++ return ret; ++ } ++ ++ /* Individual user ports get connected to CPU port only */ ++ if (dsa_is_user_port(ds, i)) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, ++ BIT(cpu_port)); ++ if (ret) ++ return ret; ++ ++ /* Enable ARP Auto-learning by default */ ++ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_LEARN); ++ if (ret) ++ return ret; ++ ++ /* For port based vlans to work we need to set the ++ * default egress vid ++ */ ++ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), ++ QCA8K_EGREES_VLAN_PORT_MASK(i), ++ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), ++ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | ++ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); ++ if (ret) ++ return ret; ++ } ++ ++ /* The port 5 of the qca8337 have some problem in flood condition. The ++ * original legacy driver had some specific buffer and priority settings ++ * for the different port suggested by the QCA switch team. Add this ++ * missing settings to improve switch stability under load condition. ++ * This problem is limited to qca8337 and other qca8k switch are not affected. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8337) { ++ switch (i) { ++ /* The 2 CPU port and port 5 requires some different ++ * priority than any other ports. ++ */ ++ case 0: ++ case 5: ++ case 6: ++ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | ++ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); ++ break; ++ default: ++ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | ++ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); ++ } ++ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); ++ ++ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | ++ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_WRED_EN; ++ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), ++ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | ++ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_WRED_EN, ++ mask); ++ } ++ } ++ ++ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | ++ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); ++ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, ++ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | ++ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, ++ mask); ++ } ++ ++ /* Setup our port MTUs to match power on defaults */ ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); ++ if (ret) ++ dev_warn(priv->dev, "failed setting MTU settings"); ++ ++ /* Flush the FDB table */ ++ qca8k_fdb_flush(priv); ++ ++ /* We don't have interrupts for link changes, so we need to poll */ ++ ds->pcs_poll = true; ++ ++ /* Set min a max ageing value supported */ ++ ds->ageing_time_min = 7000; ++ ds->ageing_time_max = 458745000; ++ ++ /* Set max number of LAGs supported */ ++ ds->num_lag_ids = QCA8K_NUM_LAGS; ++ ++ return 0; ++} ++ ++static void ++qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, ++ u32 reg) ++{ ++ u32 delay, val = 0; ++ int ret; ++ ++ /* Delay can be declared in 3 different way. ++ * Mode to rgmii and internal-delay standard binding defined ++ * rgmii-id or rgmii-tx/rx phy mode set. ++ * The parse logic set a delay different than 0 only when one ++ * of the 3 different way is used. In all other case delay is ++ * not enabled. With ID or TX/RXID delay is enabled and set ++ * to the default and recommended value. ++ */ ++ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; ++ } ++ ++ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; ++ } ++ ++ /* Set RGMII delay based on the selected values */ ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, ++ val); ++ if (ret) ++ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", ++ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); ++} ++ ++static void ++qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int cpu_port_index, ret; ++ u32 reg, val; ++ ++ switch (port) { ++ case 0: /* 1st CPU port */ ++ if (state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII) ++ return; ++ ++ reg = QCA8K_REG_PORT0_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT0; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ /* Internal PHY, nothing to do */ ++ return; ++ case 6: /* 2nd CPU port / external PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII && ++ state->interface != PHY_INTERFACE_MODE_1000BASEX) ++ return; ++ ++ reg = QCA8K_REG_PORT6_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT6; ++ break; ++ default: ++ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); ++ return; ++ } ++ ++ if (port != 6 && phylink_autoneg_inband(mode)) { ++ dev_err(ds->dev, "%s: in-band negotiation unsupported\n", ++ __func__); ++ return; ++ } ++ ++ switch (state->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); ++ ++ /* Configure rgmii delay */ ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ ++ /* QCA8337 requires to set rgmii rx delay for all ports. ++ * This is enabled through PORT5_PAD_CTRL for all ports, ++ * rather than individual port registers. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8337) ++ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_1000BASEX: ++ /* Enable SGMII on the port */ ++ qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); ++ ++ /* Enable/disable SerDes auto-negotiation as necessary */ ++ ret = qca8k_read(priv, QCA8K_REG_PWS, &val); ++ if (ret) ++ return; ++ if (phylink_autoneg_inband(mode)) ++ val &= ~QCA8K_PWS_SERDES_AEN_DIS; ++ else ++ val |= QCA8K_PWS_SERDES_AEN_DIS; ++ qca8k_write(priv, QCA8K_REG_PWS, val); ++ ++ /* Configure the SGMII parameters */ ++ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); ++ if (ret) ++ return; ++ ++ val |= QCA8K_SGMII_EN_SD; ++ ++ if (priv->ports_config.sgmii_enable_pll) ++ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | ++ QCA8K_SGMII_EN_TX; ++ ++ if (dsa_is_cpu_port(ds, port)) { ++ /* CPU port, we're talking to the CPU MAC, be a PHY */ ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_PHY; ++ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_MAC; ++ } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_BASEX; ++ } ++ ++ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); ++ ++ /* From original code is reported port instability as SGMII also ++ * require delay set. Apply advised values here or take them from DT. ++ */ ++ if (state->interface == PHY_INTERFACE_MODE_SGMII) ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ ++ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and ++ * falling edge is set writing in the PORT0 PAD reg ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327 || ++ priv->switch_id == QCA8K_ID_QCA8337) ++ reg = QCA8K_REG_PORT0_PAD_CTRL; ++ ++ val = 0; ++ ++ /* SGMII Clock phase configuration */ ++ if (priv->ports_config.sgmii_rx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; ++ ++ if (priv->ports_config.sgmii_tx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; ++ ++ if (val) ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | ++ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, ++ val); ++ ++ break; ++ default: ++ dev_err(ds->dev, "xMII mode %s not supported for port %d\n", ++ phy_modes(state->interface), port); ++ return; ++ } ++} ++ ++static void ++qca8k_phylink_validate(struct dsa_switch *ds, int port, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; ++ ++ switch (port) { ++ case 0: /* 1st CPU port */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII) ++ goto unsupported; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ /* Internal PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_GMII && ++ state->interface != PHY_INTERFACE_MODE_INTERNAL) ++ goto unsupported; ++ break; ++ case 6: /* 2nd CPU port / external PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII && ++ state->interface != PHY_INTERFACE_MODE_1000BASEX) ++ goto unsupported; ++ break; ++ default: ++unsupported: ++ linkmode_zero(supported); ++ return; ++ } ++ ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++ ++ phylink_set(mask, 1000baseT_Full); ++ phylink_set(mask, 10baseT_Half); ++ phylink_set(mask, 10baseT_Full); ++ phylink_set(mask, 100baseT_Half); ++ phylink_set(mask, 100baseT_Full); ++ ++ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) ++ phylink_set(mask, 1000baseX_Full); ++ ++ phylink_set(mask, Pause); ++ phylink_set(mask, Asym_Pause); ++ ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); ++} ++ ++static int ++qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, ++ struct phylink_link_state *state) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg; ++ int ret; ++ ++ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); ++ if (ret < 0) ++ return ret; ++ ++ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); ++ state->an_complete = state->link; ++ state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); ++ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : ++ DUPLEX_HALF; ++ ++ switch (reg & QCA8K_PORT_STATUS_SPEED) { ++ case QCA8K_PORT_STATUS_SPEED_10: ++ state->speed = SPEED_10; ++ break; ++ case QCA8K_PORT_STATUS_SPEED_100: ++ state->speed = SPEED_100; ++ break; ++ case QCA8K_PORT_STATUS_SPEED_1000: ++ state->speed = SPEED_1000; ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ state->pause = MLO_PAUSE_NONE; ++ if (reg & QCA8K_PORT_STATUS_RXFLOW) ++ state->pause |= MLO_PAUSE_RX; ++ if (reg & QCA8K_PORT_STATUS_TXFLOW) ++ state->pause |= MLO_PAUSE_TX; ++ ++ return 1; ++} ++ ++static void ++qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ qca8k_port_set_status(priv, port, 0); ++} ++ ++static void ++qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, ++ phy_interface_t interface, struct phy_device *phydev, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg; ++ ++ if (phylink_autoneg_inband(mode)) { ++ reg = QCA8K_PORT_STATUS_LINK_AUTO; ++ } else { ++ switch (speed) { ++ case SPEED_10: ++ reg = QCA8K_PORT_STATUS_SPEED_10; ++ break; ++ case SPEED_100: ++ reg = QCA8K_PORT_STATUS_SPEED_100; ++ break; ++ case SPEED_1000: ++ reg = QCA8K_PORT_STATUS_SPEED_1000; ++ break; ++ default: ++ reg = QCA8K_PORT_STATUS_LINK_AUTO; ++ break; ++ } ++ ++ if (duplex == DUPLEX_FULL) ++ reg |= QCA8K_PORT_STATUS_DUPLEX; ++ ++ if (rx_pause || dsa_is_cpu_port(ds, port)) ++ reg |= QCA8K_PORT_STATUS_RXFLOW; ++ ++ if (tx_pause || dsa_is_cpu_port(ds, port)) ++ reg |= QCA8K_PORT_STATUS_TXFLOW; ++ } ++ ++ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; ++ ++ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); ++} ++ ++static void ++qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) ++{ ++ const struct qca8k_match_data *match_data; ++ struct qca8k_priv *priv = ds->priv; ++ int i; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ match_data = of_device_get_match_data(priv->dev); ++ ++ for (i = 0; i < match_data->mib_count; i++) ++ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, ++ ETH_GSTRING_LEN); ++} ++ ++static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ const struct qca8k_match_data *match_data; ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ const struct qca8k_mib_desc *mib; ++ struct mib_ethhdr *mib_ethhdr; ++ int i, mib_len, offset = 0; ++ u64 *data; ++ u8 port; ++ ++ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); ++ mib_eth_data = &priv->mib_eth_data; ++ ++ /* The switch autocast every port. Ignore other packet and ++ * parse only the requested one. ++ */ ++ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); ++ if (port != mib_eth_data->req_port) ++ goto exit; ++ ++ match_data = device_get_match_data(priv->dev); ++ data = mib_eth_data->data; ++ ++ for (i = 0; i < match_data->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ ++ /* First 3 mib are present in the skb head */ ++ if (i < 3) { ++ data[i] = mib_ethhdr->data[i]; ++ continue; ++ } ++ ++ mib_len = sizeof(uint32_t); ++ ++ /* Some mib are 64 bit wide */ ++ if (mib->size == 2) ++ mib_len = sizeof(uint64_t); ++ ++ /* Copy the mib value from packet to the */ ++ memcpy(data + i, skb->data + offset, mib_len); ++ ++ /* Set the offset for the next mib */ ++ offset += mib_len; ++ } ++ ++exit: ++ /* Complete on receiving all the mib packet */ ++ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) ++ complete(&mib_eth_data->rw_done); ++} ++ ++static int ++qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ mib_eth_data = &priv->mib_eth_data; ++ ++ mutex_lock(&mib_eth_data->mutex); ++ ++ reinit_completion(&mib_eth_data->rw_done); ++ ++ mib_eth_data->req_port = dp->index; ++ mib_eth_data->data = data; ++ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Send mib autocast request */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | ++ QCA8K_MIB_BUSY); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ if (ret) ++ goto exit; ++ ++ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); ++ ++exit: ++ mutex_unlock(&mib_eth_data->mutex); ++ ++ return ret; ++} ++ ++static void ++qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ const struct qca8k_match_data *match_data; ++ const struct qca8k_mib_desc *mib; ++ u32 reg, i, val; ++ u32 hi = 0; ++ int ret; ++ ++ if (priv->mgmt_master && ++ qca8k_get_ethtool_stats_eth(ds, port, data) > 0) ++ return; ++ ++ match_data = of_device_get_match_data(priv->dev); ++ ++ for (i = 0; i < match_data->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; ++ ++ ret = qca8k_read(priv, reg, &val); ++ if (ret < 0) ++ continue; ++ ++ if (mib->size == 2) { ++ ret = qca8k_read(priv, reg + 4, &hi); ++ if (ret < 0) ++ continue; ++ } ++ ++ data[i] = val; ++ if (mib->size == 2) ++ data[i] |= (u64)hi << 32; ++ } ++} ++ ++static int ++qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) ++{ ++ const struct qca8k_match_data *match_data; ++ struct qca8k_priv *priv = ds->priv; ++ ++ if (sset != ETH_SS_STATS) ++ return 0; ++ ++ match_data = of_device_get_match_data(priv->dev); ++ ++ return match_data->mib_count; ++} ++ ++static int ++qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); ++ u32 reg; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); ++ if (ret < 0) ++ goto exit; ++ ++ if (eee->eee_enabled) ++ reg |= lpi_en; ++ else ++ reg &= ~lpi_en; ++ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) ++{ ++ /* Nothing to do on the port's MAC */ ++ return 0; ++} ++ ++static void ++qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ default: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; ++ break; ++ } ++ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); ++} ++ ++static int ++qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int port_mask, cpu_port; ++ int i, ret; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ port_mask = BIT(cpu_port); ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Add this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ ret = regmap_set_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ if (ret) ++ return ret; ++ if (i != port) ++ port_mask |= BIT(i); ++ } ++ ++ /* Add all other ports to this ports portvlan mask */ ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, port_mask); ++ ++ return ret; ++} ++ ++static void ++qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int cpu_port, i; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Remove this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ regmap_clear_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ } ++ ++ /* Set the cpu port to be the only one in the portvlan mask of ++ * this port ++ */ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); ++} ++ ++static void ++qca8k_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ unsigned int secs = msecs / 1000; ++ u32 val; ++ ++ /* AGE_TIME reg is set in 7s step */ ++ val = secs / 7; ++ ++ /* Handle case with 0 as val to NOT disable ++ * learning ++ */ ++ if (!val) ++ val = 1; ++ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, ++ QCA8K_ATU_AGE_TIME(val)); ++} ++ ++static int ++qca8k_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ ++ qca8k_port_set_status(priv, port, 1); ++ priv->port_enabled_map |= BIT(port); ++ ++ if (dsa_is_user_port(ds, port)) ++ phy_support_asym_pause(phy); ++ ++ return 0; ++} ++ ++static void ++qca8k_port_disable(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ ++ qca8k_port_set_status(priv, port, 0); ++ priv->port_enabled_map &= ~BIT(port); ++} ++ ++static int ++qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ /* We have only have a general MTU setting. ++ * DSA always set the CPU port's MTU to the largest MTU of the slave ++ * ports. ++ * Setting MTU just for the CPU port is sufficient to correctly set a ++ * value for every port. ++ */ ++ if (!dsa_is_cpu_port(ds, port)) ++ return 0; ++ ++ /* To change the MAX_FRAME_SIZE the cpu ports must be off or ++ * the switch panics. ++ * Turn off both cpu ports before applying the new value to prevent ++ * this. ++ */ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 0); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 0); ++ ++ /* Include L2 header / FCS length */ ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); ++ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 1); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 1); ++ ++ return ret; ++} ++ ++static int ++qca8k_port_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return QCA8K_MAX_MTU; ++} ++ ++static int ++qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, ++ u16 port_mask, u16 vid) ++{ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_add(priv, addr, port_mask, vid, ++ QCA8K_ATU_STATUS_STATIC); ++} ++ ++static int ++qca8k_port_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); ++} ++ ++static int ++qca8k_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_del(priv, addr, port_mask, vid); ++} ++ ++static int ++qca8k_port_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ struct qca8k_fdb _fdb = { 0 }; ++ int cnt = QCA8K_NUM_FDB_RECORDS; ++ bool is_static; ++ int ret = 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { ++ if (!_fdb.aging) ++ break; ++ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); ++ ret = cb(_fdb.mac, _fdb.vid, is_static, data); ++ if (ret) ++ break; ++ } ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++qca8k_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); ++} ++ ++static int ++qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); ++} ++ ++static int ++qca8k_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int monitor_port, ret; ++ u32 reg, val; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* QCA83xx can have only one port set to mirror mode. ++ * Check that the correct port is requested and return error otherwise. ++ * When no mirror port is set, the values is set to 0xF ++ */ ++ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) ++ return -EEXIST; ++ ++ /* Set the monitor port */ ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, ++ mirror->to_local_port); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ return ret; ++ ++ if (ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_update_bits(priv->regmap, reg, val, val); ++ if (ret) ++ return ret; ++ ++ /* Track mirror port for tx and rx to decide when the ++ * mirror port has to be disabled. ++ */ ++ if (ingress) ++ priv->mirror_rx |= BIT(port); ++ else ++ priv->mirror_tx |= BIT(port); ++ ++ return 0; ++} ++ ++static void ++qca8k_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg, val; ++ int ret; ++ ++ if (mirror->ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_clear_bits(priv->regmap, reg, val); ++ if (ret) ++ goto err; ++ ++ if (mirror->ingress) ++ priv->mirror_rx &= ~BIT(port); ++ else ++ priv->mirror_tx &= ~BIT(port); ++ ++ /* No port set to send packet to mirror port. Disable mirror port */ ++ if (!priv->mirror_rx && !priv->mirror_tx) { ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ goto err; ++ } ++err: ++ dev_err(priv->dev, "Failed to del mirror port from %d", port); ++} ++ ++static int ++qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, ++ struct netlink_ext_ack *extack) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ if (vlan_filtering) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); ++ } else { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); ++ } ++ ++ return ret; ++} ++ ++static int ++qca8k_port_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack) ++{ ++ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; ++ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); ++ if (ret) { ++ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); ++ return ret; ++ } ++ ++ if (pvid) { ++ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), ++ QCA8K_EGREES_VLAN_PORT_MASK(port), ++ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), ++ QCA8K_PORT_VLAN_CVID(vlan->vid) | ++ QCA8K_PORT_VLAN_SVID(vlan->vid)); ++ } ++ ++ return ret; ++} ++ ++static int ++qca8k_port_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_del(priv, port, vlan->vid); ++ if (ret) ++ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); ++ ++ return ret; ++} ++ ++static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Communicate to the phy internal driver the switch revision. ++ * Based on the switch revision different values needs to be ++ * set to the dbg and mmd reg on the phy. ++ * The first 2 bit are used to communicate the switch revision ++ * to the phy driver. ++ */ ++ if (port > 0 && port < 6) ++ return priv->switch_revision; ++ ++ return 0; ++} ++ ++static enum dsa_tag_protocol ++qca8k_get_tag_protocol(struct dsa_switch *ds, int port, ++ enum dsa_tag_protocol mp) ++{ ++ return DSA_TAG_PROTO_QCA; ++} ++ ++static bool ++qca8k_lag_can_offload(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct dsa_port *dp; ++ int id, members = 0; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ if (id < 0 || id >= ds->num_lag_ids) ++ return false; ++ ++ dsa_lag_foreach_port(dp, ds->dst, lag) ++ /* Includes the port joining the LAG */ ++ members++; ++ ++ if (members > QCA8K_NUM_PORTS_FOR_LAG) ++ return false; ++ ++ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) ++ return false; ++ ++ if (info->hash_type != NETDEV_LAG_HASH_L2 && ++ info->hash_type != NETDEV_LAG_HASH_L23) ++ return false; ++ ++ return true; ++} ++ ++static int ++qca8k_lag_setup_hash(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ bool unique_lag = true; ++ u32 hash = 0; ++ int i, id; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ switch (info->hash_type) { ++ case NETDEV_LAG_HASH_L23: ++ hash |= QCA8K_TRUNK_HASH_SIP_EN; ++ hash |= QCA8K_TRUNK_HASH_DIP_EN; ++ fallthrough; ++ case NETDEV_LAG_HASH_L2: ++ hash |= QCA8K_TRUNK_HASH_SA_EN; ++ hash |= QCA8K_TRUNK_HASH_DA_EN; ++ break; ++ default: /* We should NEVER reach this */ ++ return -EOPNOTSUPP; ++ } ++ ++ /* Check if we are the unique configured LAG */ ++ dsa_lags_foreach_id(i, ds->dst) ++ if (i != id && dsa_lag_dev(ds->dst, i)) { ++ unique_lag = false; ++ break; ++ } ++ ++ /* Hash Mode is global. Make sure the same Hash Mode ++ * is set to all the 4 possible lag. ++ * If we are the unique LAG we can set whatever hash ++ * mode we want. ++ * To change hash mode it's needed to remove all LAG ++ * and change the mode with the latest. ++ */ ++ if (unique_lag) { ++ priv->lag_hash_mode = hash; ++ } else if (priv->lag_hash_mode != hash) { ++ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, ++ QCA8K_TRUNK_HASH_MASK, hash); ++} ++ ++static int ++qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, ++ struct net_device *lag, bool delete) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret, id, i; ++ u32 val; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ /* Read current port member */ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* Shift val to the correct trunk */ ++ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); ++ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; ++ if (delete) ++ val &= ~BIT(port); ++ else ++ val |= BIT(port); ++ ++ /* Update port member. With empty portmap disable trunk */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, ++ QCA8K_REG_GOL_TRUNK_MEMBER(id) | ++ QCA8K_REG_GOL_TRUNK_EN(id), ++ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | ++ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); ++ ++ /* Search empty member if adding or port on deleting */ ++ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); ++ if (ret) ++ return ret; ++ ++ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; ++ ++ if (delete) { ++ /* If port flagged to be disabled assume this member is ++ * empty ++ */ ++ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; ++ if (val != port) ++ continue; ++ } else { ++ /* If port flagged to be enabled assume this member is ++ * already set ++ */ ++ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ } ++ ++ /* We have found the member to add/remove */ ++ break; ++ } ++ ++ /* Set port in the correct port mask or disable port if in delete mode */ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), ++ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | ++ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); ++} ++ ++static int ++qca8k_port_lag_join(struct dsa_switch *ds, int port, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ int ret; ++ ++ if (!qca8k_lag_can_offload(ds, lag, info)) ++ return -EOPNOTSUPP; ++ ++ ret = qca8k_lag_setup_hash(ds, lag, info); ++ if (ret) ++ return ret; ++ ++ return qca8k_lag_refresh_portmap(ds, port, lag, false); ++} ++ ++static int ++qca8k_port_lag_leave(struct dsa_switch *ds, int port, ++ struct net_device *lag) ++{ ++ return qca8k_lag_refresh_portmap(ds, port, lag, true); ++} ++ ++static void ++qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, ++ bool operational) ++{ ++ struct dsa_port *dp = master->dsa_ptr; ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ ++ if (dp->index != 0) ++ return; ++ ++ mutex_lock(&priv->mgmt_eth_data.mutex); ++ mutex_lock(&priv->mib_eth_data.mutex); ++ ++ priv->mgmt_master = operational ? (struct net_device *)master : NULL; ++ ++ mutex_unlock(&priv->mib_eth_data.mutex); ++ mutex_unlock(&priv->mgmt_eth_data.mutex); ++} ++ ++static int qca8k_connect_tag_protocol(struct dsa_switch *ds, ++ enum dsa_tag_protocol proto) ++{ ++ struct qca_tagger_data *tagger_data; ++ ++ switch (proto) { ++ case DSA_TAG_PROTO_QCA: ++ tagger_data = ds->tagger_data; ++ ++ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; ++ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; ++ ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static const struct dsa_switch_ops qca8k_switch_ops = { ++ .get_tag_protocol = qca8k_get_tag_protocol, ++ .setup = qca8k_setup, ++ .get_strings = qca8k_get_strings, ++ .get_ethtool_stats = qca8k_get_ethtool_stats, ++ .get_sset_count = qca8k_get_sset_count, ++ .set_ageing_time = qca8k_set_ageing_time, ++ .get_mac_eee = qca8k_get_mac_eee, ++ .set_mac_eee = qca8k_set_mac_eee, ++ .port_enable = qca8k_port_enable, ++ .port_disable = qca8k_port_disable, ++ .port_change_mtu = qca8k_port_change_mtu, ++ .port_max_mtu = qca8k_port_max_mtu, ++ .port_stp_state_set = qca8k_port_stp_state_set, ++ .port_bridge_join = qca8k_port_bridge_join, ++ .port_bridge_leave = qca8k_port_bridge_leave, ++ .port_fast_age = qca8k_port_fast_age, ++ .port_fdb_add = qca8k_port_fdb_add, ++ .port_fdb_del = qca8k_port_fdb_del, ++ .port_fdb_dump = qca8k_port_fdb_dump, ++ .port_mdb_add = qca8k_port_mdb_add, ++ .port_mdb_del = qca8k_port_mdb_del, ++ .port_mirror_add = qca8k_port_mirror_add, ++ .port_mirror_del = qca8k_port_mirror_del, ++ .port_vlan_filtering = qca8k_port_vlan_filtering, ++ .port_vlan_add = qca8k_port_vlan_add, ++ .port_vlan_del = qca8k_port_vlan_del, ++ .phylink_validate = qca8k_phylink_validate, ++ .phylink_mac_link_state = qca8k_phylink_mac_link_state, ++ .phylink_mac_config = qca8k_phylink_mac_config, ++ .phylink_mac_link_down = qca8k_phylink_mac_link_down, ++ .phylink_mac_link_up = qca8k_phylink_mac_link_up, ++ .get_phy_flags = qca8k_get_phy_flags, ++ .port_lag_join = qca8k_port_lag_join, ++ .port_lag_leave = qca8k_port_lag_leave, ++ .master_state_change = qca8k_master_change, ++ .connect_tag_protocol = qca8k_connect_tag_protocol, ++}; ++ ++static int qca8k_read_switch_id(struct qca8k_priv *priv) ++{ ++ const struct qca8k_match_data *data; ++ u32 val; ++ u8 id; ++ int ret; ++ ++ /* get the switches ID from the compatible */ ++ data = of_device_get_match_data(priv->dev); ++ if (!data) ++ return -ENODEV; ++ ++ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); ++ if (ret < 0) ++ return -ENODEV; ++ ++ id = QCA8K_MASK_CTRL_DEVICE_ID(val); ++ if (id != data->id) { ++ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); ++ return -ENODEV; ++ } ++ ++ priv->switch_id = id; ++ ++ /* Save revision to communicate to the internal PHY driver */ ++ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); ++ ++ return 0; ++} ++ ++static int ++qca8k_sw_probe(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv; ++ int ret; ++ ++ /* allocate the private data struct so that we can probe the switches ++ * ID register ++ */ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ ++ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", ++ GPIOD_ASIS); ++ if (IS_ERR(priv->reset_gpio)) ++ return PTR_ERR(priv->reset_gpio); ++ ++ if (priv->reset_gpio) { ++ gpiod_set_value_cansleep(priv->reset_gpio, 1); ++ /* The active low duration must be greater than 10 ms ++ * and checkpatch.pl wants 20 ms. ++ */ ++ msleep(20); ++ gpiod_set_value_cansleep(priv->reset_gpio, 0); ++ } ++ ++ /* Start by setting up the register mapping */ ++ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, ++ &qca8k_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ dev_err(priv->dev, "regmap initialization failed"); ++ return PTR_ERR(priv->regmap); ++ } ++ ++ priv->mdio_cache.page = 0xffff; ++ priv->mdio_cache.lo = 0xffff; ++ priv->mdio_cache.hi = 0xffff; ++ ++ /* Check the detected switch id */ ++ ret = qca8k_read_switch_id(priv); ++ if (ret) ++ return ret; ++ ++ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); ++ if (!priv->ds) ++ return -ENOMEM; ++ ++ mutex_init(&priv->mgmt_eth_data.mutex); ++ init_completion(&priv->mgmt_eth_data.rw_done); ++ ++ mutex_init(&priv->mib_eth_data.mutex); ++ init_completion(&priv->mib_eth_data.rw_done); ++ ++ priv->ds->dev = &mdiodev->dev; ++ priv->ds->num_ports = QCA8K_NUM_PORTS; ++ priv->ds->priv = priv; ++ priv->ds->ops = &qca8k_switch_ops; ++ mutex_init(&priv->reg_mutex); ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static void ++qca8k_sw_remove(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ int i; ++ ++ if (!priv) ++ return; ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) ++ qca8k_port_set_status(priv, i, 0); ++ ++ dsa_unregister_switch(priv->ds); ++ ++ dev_set_drvdata(&mdiodev->dev, NULL); ++} ++ ++static void qca8k_sw_shutdown(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ ++ if (!priv) ++ return; ++ ++ dsa_switch_shutdown(priv->ds); ++ ++ dev_set_drvdata(&mdiodev->dev, NULL); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static void ++qca8k_set_pm(struct qca8k_priv *priv, int enable) ++{ ++ int port; ++ ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Do not enable on resume if the port was ++ * disabled before. ++ */ ++ if (!(priv->port_enabled_map & BIT(port))) ++ continue; ++ ++ qca8k_port_set_status(priv, port, enable); ++ } ++} ++ ++static int qca8k_suspend(struct device *dev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(dev); ++ ++ qca8k_set_pm(priv, 0); ++ ++ return dsa_switch_suspend(priv->ds); ++} ++ ++static int qca8k_resume(struct device *dev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(dev); ++ ++ qca8k_set_pm(priv, 1); ++ ++ return dsa_switch_resume(priv->ds); ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, ++ qca8k_suspend, qca8k_resume); ++ ++static const struct qca8k_match_data qca8327 = { ++ .id = QCA8K_ID_QCA8327, ++ .reduced_package = true, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, ++}; ++ ++static const struct qca8k_match_data qca8328 = { ++ .id = QCA8K_ID_QCA8327, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, ++}; ++ ++static const struct qca8k_match_data qca833x = { ++ .id = QCA8K_ID_QCA8337, ++ .mib_count = QCA8K_QCA833X_MIB_COUNT, ++}; ++ ++static const struct of_device_id qca8k_of_match[] = { ++ { .compatible = "qca,qca8327", .data = &qca8327 }, ++ { .compatible = "qca,qca8328", .data = &qca8328 }, ++ { .compatible = "qca,qca8334", .data = &qca833x }, ++ { .compatible = "qca,qca8337", .data = &qca833x }, ++ { /* sentinel */ }, ++}; ++ ++static struct mdio_driver qca8kmdio_driver = { ++ .probe = qca8k_sw_probe, ++ .remove = qca8k_sw_remove, ++ .shutdown = qca8k_sw_shutdown, ++ .mdiodrv.driver = { ++ .name = "qca8k", ++ .of_match_table = qca8k_of_match, ++ .pm = &qca8k_pm_ops, ++ }, ++}; ++ ++mdio_module_driver(qca8kmdio_driver); ++ ++MODULE_AUTHOR("Mathieu Olivari, John Crispin "); ++MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:qca8k"); +--- /dev/null ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -0,0 +1,411 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * Copyright (c) 2015, The Linux Foundation. All rights reserved. ++ */ ++ ++#ifndef __QCA8K_H ++#define __QCA8K_H ++ ++#include ++#include ++#include ++#include ++ ++#define QCA8K_ETHERNET_MDIO_PRIORITY 7 ++#define QCA8K_ETHERNET_PHY_PRIORITY 6 ++#define QCA8K_ETHERNET_TIMEOUT 100 ++ ++#define QCA8K_NUM_PORTS 7 ++#define QCA8K_NUM_CPU_PORTS 2 ++#define QCA8K_MAX_MTU 9000 ++#define QCA8K_NUM_LAGS 4 ++#define QCA8K_NUM_PORTS_FOR_LAG 4 ++ ++#define PHY_ID_QCA8327 0x004dd034 ++#define QCA8K_ID_QCA8327 0x12 ++#define PHY_ID_QCA8337 0x004dd036 ++#define QCA8K_ID_QCA8337 0x13 ++ ++#define QCA8K_QCA832X_MIB_COUNT 39 ++#define QCA8K_QCA833X_MIB_COUNT 41 ++ ++#define QCA8K_BUSY_WAIT_TIMEOUT 2000 ++ ++#define QCA8K_NUM_FDB_RECORDS 2048 ++ ++#define QCA8K_PORT_VID_DEF 1 ++ ++/* Global control registers */ ++#define QCA8K_REG_MASK_CTRL 0x000 ++#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) ++#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) ++#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) ++#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) ++#define QCA8K_REG_PORT0_PAD_CTRL 0x004 ++#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) ++#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) ++#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) ++#define QCA8K_REG_PORT5_PAD_CTRL 0x008 ++#define QCA8K_REG_PORT6_PAD_CTRL 0x00c ++#define QCA8K_PORT_PAD_RGMII_EN BIT(26) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) ++#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) ++#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) ++#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) ++#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) ++#define QCA8K_PORT_PAD_SGMII_EN BIT(7) ++#define QCA8K_REG_PWS 0x010 ++#define QCA8K_PWS_POWER_ON_SEL BIT(31) ++/* This reg is only valid for QCA832x and toggle the package ++ * type from 176 pin (by default) to 148 pin used on QCA8327 ++ */ ++#define QCA8327_PWS_PACKAGE148_EN BIT(30) ++#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) ++#define QCA8K_PWS_SERDES_AEN_DIS BIT(7) ++#define QCA8K_REG_MODULE_EN 0x030 ++#define QCA8K_MODULE_EN_MIB BIT(0) ++#define QCA8K_REG_MIB 0x034 ++#define QCA8K_MIB_FUNC GENMASK(26, 24) ++#define QCA8K_MIB_CPU_KEEP BIT(20) ++#define QCA8K_MIB_BUSY BIT(17) ++#define QCA8K_MDIO_MASTER_CTRL 0x3c ++#define QCA8K_MDIO_MASTER_BUSY BIT(31) ++#define QCA8K_MDIO_MASTER_EN BIT(30) ++#define QCA8K_MDIO_MASTER_READ BIT(27) ++#define QCA8K_MDIO_MASTER_WRITE 0 ++#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) ++#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) ++#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) ++#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) ++#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) ++#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) ++#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) ++#define QCA8K_MDIO_MASTER_MAX_PORTS 5 ++#define QCA8K_MDIO_MASTER_MAX_REG 32 ++#define QCA8K_GOL_MAC_ADDR0 0x60 ++#define QCA8K_GOL_MAC_ADDR1 0x64 ++#define QCA8K_MAX_FRAME_SIZE 0x78 ++#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) ++#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) ++#define QCA8K_PORT_STATUS_SPEED_10 0 ++#define QCA8K_PORT_STATUS_SPEED_100 0x1 ++#define QCA8K_PORT_STATUS_SPEED_1000 0x2 ++#define QCA8K_PORT_STATUS_TXMAC BIT(2) ++#define QCA8K_PORT_STATUS_RXMAC BIT(3) ++#define QCA8K_PORT_STATUS_TXFLOW BIT(4) ++#define QCA8K_PORT_STATUS_RXFLOW BIT(5) ++#define QCA8K_PORT_STATUS_DUPLEX BIT(6) ++#define QCA8K_PORT_STATUS_LINK_UP BIT(8) ++#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) ++#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) ++#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) ++#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) ++#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) ++#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) ++#define QCA8K_PORT_HDR_CTRL_ALL 2 ++#define QCA8K_PORT_HDR_CTRL_MGMT 1 ++#define QCA8K_PORT_HDR_CTRL_NONE 0 ++#define QCA8K_REG_SGMII_CTRL 0x0e0 ++#define QCA8K_SGMII_EN_PLL BIT(1) ++#define QCA8K_SGMII_EN_RX BIT(2) ++#define QCA8K_SGMII_EN_TX BIT(3) ++#define QCA8K_SGMII_EN_SD BIT(4) ++#define QCA8K_SGMII_CLK125M_DELAY BIT(7) ++#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) ++#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) ++#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) ++#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) ++#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) ++ ++/* MAC_PWR_SEL registers */ ++#define QCA8K_REG_MAC_PWR_SEL 0x0e4 ++#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) ++#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) ++ ++/* EEE control registers */ ++#define QCA8K_REG_EEE_CTRL 0x100 ++#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) ++ ++/* TRUNK_HASH_EN registers */ ++#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 ++#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) ++#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) ++#define QCA8K_TRUNK_HASH_SA_EN BIT(1) ++#define QCA8K_TRUNK_HASH_DA_EN BIT(0) ++#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) ++ ++/* ACL registers */ ++#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) ++#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) ++#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) ++#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) ++#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) ++#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) ++#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 ++#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 ++ ++/* Lookup registers */ ++#define QCA8K_REG_ATU_DATA0 0x600 ++#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) ++#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) ++#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) ++#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) ++#define QCA8K_REG_ATU_DATA1 0x604 ++#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) ++#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) ++#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) ++#define QCA8K_REG_ATU_DATA2 0x608 ++#define QCA8K_ATU_VID_MASK GENMASK(19, 8) ++#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) ++#define QCA8K_ATU_STATUS_STATIC 0xf ++#define QCA8K_REG_ATU_FUNC 0x60c ++#define QCA8K_ATU_FUNC_BUSY BIT(31) ++#define QCA8K_ATU_FUNC_PORT_EN BIT(14) ++#define QCA8K_ATU_FUNC_MULTI_EN BIT(13) ++#define QCA8K_ATU_FUNC_FULL BIT(12) ++#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) ++#define QCA8K_REG_VTU_FUNC0 0x610 ++#define QCA8K_VTU_FUNC0_VALID BIT(20) ++#define QCA8K_VTU_FUNC0_IVL_EN BIT(19) ++/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) ++ * It does contain VLAN_MODE for each port [5:4] for port0, ++ * [7:6] for port1 ... [17:16] for port6. Use virtual port ++ * define to handle this. ++ */ ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) ++#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) ++#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) ++#define QCA8K_REG_VTU_FUNC1 0x614 ++#define QCA8K_VTU_FUNC1_BUSY BIT(31) ++#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) ++#define QCA8K_VTU_FUNC1_FULL BIT(4) ++#define QCA8K_REG_ATU_CTRL 0x618 ++#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) ++#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) ++#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 ++#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) ++#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) ++#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 ++#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) ++#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) ++#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) ++#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) ++#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) ++#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) ++#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) ++#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) ++#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) ++#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) ++#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) ++#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) ++#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) ++#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) ++#define QCA8K_PORT_LOOKUP_LEARN BIT(20) ++#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) ++ ++#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 ++/* 4 max trunk first ++ * first 6 bit for member bitmap ++ * 7th bit is to enable trunk port ++ */ ++#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) ++#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) ++#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) ++#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) ++#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) ++/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ ++#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) ++#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) ++#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) ++/* Complex shift: FIRST shift for port THEN shift for trunk */ ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) ++#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) ++ ++#define QCA8K_REG_GLOBAL_FC_THRESH 0x800 ++#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) ++#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) ++#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) ++#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) ++ ++#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) ++#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) ++#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) ++ ++#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) ++#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) ++#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) ++#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) ++#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) ++#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) ++#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) ++ ++/* Pkt edit registers */ ++#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) ++#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) ++#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) ++#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) ++ ++/* L3 registers */ ++#define QCA8K_HROUTER_CONTROL 0xe00 ++#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16) ++#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16 ++#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1 ++#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08 ++#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c ++#define QCA8K_HNAT_CONTROL 0xe38 ++ ++/* MIB registers */ ++#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100) ++ ++/* QCA specific MII registers */ ++#define MII_ATH_MMD_ADDR 0x0d ++#define MII_ATH_MMD_DATA 0x0e ++ ++enum { ++ QCA8K_PORT_SPEED_10M = 0, ++ QCA8K_PORT_SPEED_100M = 1, ++ QCA8K_PORT_SPEED_1000M = 2, ++ QCA8K_PORT_SPEED_ERR = 3, ++}; ++ ++enum qca8k_fdb_cmd { ++ QCA8K_FDB_FLUSH = 1, ++ QCA8K_FDB_LOAD = 2, ++ QCA8K_FDB_PURGE = 3, ++ QCA8K_FDB_FLUSH_PORT = 5, ++ QCA8K_FDB_NEXT = 6, ++ QCA8K_FDB_SEARCH = 7, ++}; ++ ++enum qca8k_vlan_cmd { ++ QCA8K_VLAN_FLUSH = 1, ++ QCA8K_VLAN_LOAD = 2, ++ QCA8K_VLAN_PURGE = 3, ++ QCA8K_VLAN_REMOVE_PORT = 4, ++ QCA8K_VLAN_NEXT = 5, ++ QCA8K_VLAN_READ = 6, ++}; ++ ++enum qca8k_mid_cmd { ++ QCA8K_MIB_FLUSH = 1, ++ QCA8K_MIB_FLUSH_PORT = 2, ++ QCA8K_MIB_CAST = 3, ++}; ++ ++struct qca8k_match_data { ++ u8 id; ++ bool reduced_package; ++ u8 mib_count; ++}; ++ ++enum { ++ QCA8K_CPU_PORT0, ++ QCA8K_CPU_PORT6, ++}; ++ ++struct qca8k_mgmt_eth_data { ++ struct completion rw_done; ++ struct mutex mutex; /* Enforce one mdio read/write at time */ ++ bool ack; ++ u32 seq; ++ u32 data[4]; ++}; ++ ++struct qca8k_mib_eth_data { ++ struct completion rw_done; ++ struct mutex mutex; /* Process one command at time */ ++ refcount_t port_parsed; /* Counter to track parsed port */ ++ u8 req_port; ++ u64 *data; /* pointer to ethtool data */ ++}; ++ ++struct qca8k_ports_config { ++ bool sgmii_rx_clk_falling_edge; ++ bool sgmii_tx_clk_falling_edge; ++ bool sgmii_enable_pll; ++ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ ++ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ ++}; ++ ++struct qca8k_mdio_cache { ++/* The 32bit switch registers are accessed indirectly. To achieve this we need ++ * to set the page of the register. Track the last page that was set to reduce ++ * mdio writes ++ */ ++ u16 page; ++/* lo and hi can also be cached and from Documentation we can skip one ++ * extra mdio write if lo or hi is didn't change. ++ */ ++ u16 lo; ++ u16 hi; ++}; ++ ++struct qca8k_priv { ++ u8 switch_id; ++ u8 switch_revision; ++ u8 mirror_rx; ++ u8 mirror_tx; ++ u8 lag_hash_mode; ++ /* Each bit correspond to a port. This switch can support a max of 7 port. ++ * Bit 1: port enabled. Bit 0: port disabled. ++ */ ++ u8 port_enabled_map; ++ struct qca8k_ports_config ports_config; ++ struct regmap *regmap; ++ struct mii_bus *bus; ++ struct dsa_switch *ds; ++ struct mutex reg_mutex; ++ struct device *dev; ++ struct gpio_desc *reset_gpio; ++ struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ ++ struct qca8k_mgmt_eth_data mgmt_eth_data; ++ struct qca8k_mib_eth_data mib_eth_data; ++ struct qca8k_mdio_cache mdio_cache; ++}; ++ ++struct qca8k_mib_desc { ++ unsigned int size; ++ unsigned int offset; ++ const char *name; ++}; ++ ++struct qca8k_fdb { ++ u16 vid; ++ u8 port_mask; ++ u8 aging; ++ u8 mac[6]; ++}; ++ ++#endif /* __QCA8K_H */ +--- a/drivers/net/dsa/qca8k.c ++++ /dev/null +@@ -1,3243 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* +- * Copyright (C) 2009 Felix Fietkau +- * Copyright (C) 2011-2012 Gabor Juhos +- * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. +- * Copyright (c) 2016 John Crispin +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "qca8k.h" +- +-#define MIB_DESC(_s, _o, _n) \ +- { \ +- .size = (_s), \ +- .offset = (_o), \ +- .name = (_n), \ +- } +- +-static const struct qca8k_mib_desc ar8327_mib[] = { +- MIB_DESC(1, 0x00, "RxBroad"), +- MIB_DESC(1, 0x04, "RxPause"), +- MIB_DESC(1, 0x08, "RxMulti"), +- MIB_DESC(1, 0x0c, "RxFcsErr"), +- MIB_DESC(1, 0x10, "RxAlignErr"), +- MIB_DESC(1, 0x14, "RxRunt"), +- MIB_DESC(1, 0x18, "RxFragment"), +- MIB_DESC(1, 0x1c, "Rx64Byte"), +- MIB_DESC(1, 0x20, "Rx128Byte"), +- MIB_DESC(1, 0x24, "Rx256Byte"), +- MIB_DESC(1, 0x28, "Rx512Byte"), +- MIB_DESC(1, 0x2c, "Rx1024Byte"), +- MIB_DESC(1, 0x30, "Rx1518Byte"), +- MIB_DESC(1, 0x34, "RxMaxByte"), +- MIB_DESC(1, 0x38, "RxTooLong"), +- MIB_DESC(2, 0x3c, "RxGoodByte"), +- MIB_DESC(2, 0x44, "RxBadByte"), +- MIB_DESC(1, 0x4c, "RxOverFlow"), +- MIB_DESC(1, 0x50, "Filtered"), +- MIB_DESC(1, 0x54, "TxBroad"), +- MIB_DESC(1, 0x58, "TxPause"), +- MIB_DESC(1, 0x5c, "TxMulti"), +- MIB_DESC(1, 0x60, "TxUnderRun"), +- MIB_DESC(1, 0x64, "Tx64Byte"), +- MIB_DESC(1, 0x68, "Tx128Byte"), +- MIB_DESC(1, 0x6c, "Tx256Byte"), +- MIB_DESC(1, 0x70, "Tx512Byte"), +- MIB_DESC(1, 0x74, "Tx1024Byte"), +- MIB_DESC(1, 0x78, "Tx1518Byte"), +- MIB_DESC(1, 0x7c, "TxMaxByte"), +- MIB_DESC(1, 0x80, "TxOverSize"), +- MIB_DESC(2, 0x84, "TxByte"), +- MIB_DESC(1, 0x8c, "TxCollision"), +- MIB_DESC(1, 0x90, "TxAbortCol"), +- MIB_DESC(1, 0x94, "TxMultiCol"), +- MIB_DESC(1, 0x98, "TxSingleCol"), +- MIB_DESC(1, 0x9c, "TxExcDefer"), +- MIB_DESC(1, 0xa0, "TxDefer"), +- MIB_DESC(1, 0xa4, "TxLateCol"), +- MIB_DESC(1, 0xa8, "RXUnicast"), +- MIB_DESC(1, 0xac, "TXUnicast"), +-}; +- +-static void +-qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +-{ +- regaddr >>= 1; +- *r1 = regaddr & 0x1e; +- +- regaddr >>= 5; +- *r2 = regaddr & 0x7; +- +- regaddr >>= 3; +- *page = regaddr & 0x3ff; +-} +- +-static int +-qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) +-{ +- u16 *cached_lo = &priv->mdio_cache.lo; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (lo == *cached_lo) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, lo); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit lo register\n"); +- +- *cached_lo = lo; +- return 0; +-} +- +-static int +-qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) +-{ +- u16 *cached_hi = &priv->mdio_cache.hi; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (hi == *cached_hi) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, hi); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit hi register\n"); +- +- *cached_hi = hi; +- return 0; +-} +- +-static int +-qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +-{ +- int ret; +- +- ret = bus->read(bus, phy_id, regnum); +- if (ret >= 0) { +- *val = ret; +- ret = bus->read(bus, phy_id, regnum + 1); +- *val |= ret << 16; +- } +- +- if (ret < 0) { +- dev_err_ratelimited(&bus->dev, +- "failed to read qca8k 32bit register\n"); +- *val = 0; +- return ret; +- } +- +- return 0; +-} +- +-static void +-qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) +-{ +- u16 lo, hi; +- int ret; +- +- lo = val & 0xffff; +- hi = (u16)(val >> 16); +- +- ret = qca8k_set_lo(priv, phy_id, regnum, lo); +- if (ret >= 0) +- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); +-} +- +-static int +-qca8k_set_page(struct qca8k_priv *priv, u16 page) +-{ +- u16 *cached_page = &priv->mdio_cache.page; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (page == *cached_page) +- return 0; +- +- ret = bus->write(bus, 0x18, 0, page); +- if (ret < 0) { +- dev_err_ratelimited(&bus->dev, +- "failed to set qca8k page\n"); +- return ret; +- } +- +- *cached_page = page; +- usleep_range(1000, 2000); +- return 0; +-} +- +-static int +-qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) +-{ +- return regmap_read(priv->regmap, reg, val); +-} +- +-static int +-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) +-{ +- return regmap_write(priv->regmap, reg, val); +-} +- +-static int +-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +-{ +- return regmap_update_bits(priv->regmap, reg, mask, write_val); +-} +- +-static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data; +- struct qca8k_priv *priv = ds->priv; +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- u8 len, cmd; +- +- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); +- mgmt_eth_data = &priv->mgmt_eth_data; +- +- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); +- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); +- +- /* Make sure the seq match the requested packet */ +- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) +- mgmt_eth_data->ack = true; +- +- if (cmd == MDIO_READ) { +- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; +- +- /* Get the rest of the 12 byte of data. +- * The read/write function will extract the requested data. +- */ +- if (len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(mgmt_eth_data->data + 1, skb->data, +- QCA_HDR_MGMT_DATA2_LEN); +- } +- +- complete(&mgmt_eth_data->rw_done); +-} +- +-static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, +- int priority, unsigned int len) +-{ +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- unsigned int real_len; +- struct sk_buff *skb; +- u32 *data2; +- u16 hdr; +- +- skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); +- if (!skb) +- return NULL; +- +- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte +- * Actually for some reason the steps are: +- * 0: nothing +- * 1-4: first 4 byte +- * 5-6: first 12 byte +- * 7-15: all 16 byte +- */ +- if (len == 16) +- real_len = 15; +- else +- real_len = len; +- +- skb_reset_mac_header(skb); +- skb_set_network_header(skb, skb->len); +- +- mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); +- +- hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); +- hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); +- hdr |= QCA_HDR_XMIT_FROM_CPU; +- hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); +- hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); +- +- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, +- QCA_HDR_MGMT_CHECK_CODE_VAL); +- +- if (cmd == MDIO_WRITE) +- mgmt_ethhdr->mdio_data = *val; +- +- mgmt_ethhdr->hdr = htons(hdr); +- +- data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); +- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); +- +- return skb; +-} +- +-static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) +-{ +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- +- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; +- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); +-} +- +-static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; +- struct sk_buff *skb; +- bool ack; +- int ret; +- +- skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, +- QCA8K_ETHERNET_MDIO_PRIORITY, len); +- if (!skb) +- return -ENOMEM; +- +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check mgmt_master if is operational */ +- if (!priv->mgmt_master) { +- kfree_skb(skb); +- mutex_unlock(&mgmt_eth_data->mutex); +- return -EINVAL; +- } +- +- skb->dev = priv->mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the mdio pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); +- +- *val = mgmt_eth_data->data[0]; +- if (len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); +- +- ack = mgmt_eth_data->ack; +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- return 0; +-} +- +-static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; +- struct sk_buff *skb; +- bool ack; +- int ret; +- +- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, +- QCA8K_ETHERNET_MDIO_PRIORITY, len); +- if (!skb) +- return -ENOMEM; +- +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check mgmt_master if is operational */ +- if (!priv->mgmt_master) { +- kfree_skb(skb); +- mutex_unlock(&mgmt_eth_data->mutex); +- return -EINVAL; +- } +- +- skb->dev = priv->mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the mdio pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); +- +- ack = mgmt_eth_data->ack; +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- return 0; +-} +- +-static int +-qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +-{ +- u32 val = 0; +- int ret; +- +- ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); +- if (ret) +- return ret; +- +- val &= ~mask; +- val |= write_val; +- +- return qca8k_write_eth(priv, reg, &val, sizeof(val)); +-} +- +-static int +-qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- +- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int +-qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- u32 tmp; +- +- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- tmp = val[i]; +- +- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int +-qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- int ret; +- +- if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- return ret; +-} +- +-static int +-qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- int ret; +- +- if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- return ret; +-} +- +-static int +-qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); +- if (ret < 0) +- goto exit; +- +- val &= ~mask; +- val |= write_val; +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- +- return ret; +-} +- +-static const struct regmap_range qca8k_readable_ranges[] = { +- regmap_reg_range(0x0000, 0x00e4), /* Global control */ +- regmap_reg_range(0x0100, 0x0168), /* EEE control */ +- regmap_reg_range(0x0200, 0x0270), /* Parser control */ +- regmap_reg_range(0x0400, 0x0454), /* ACL */ +- regmap_reg_range(0x0600, 0x0718), /* Lookup */ +- regmap_reg_range(0x0800, 0x0b70), /* QM */ +- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ +- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ +- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ +- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ +- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ +- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ +- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ +- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ +- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ +- +-}; +- +-static const struct regmap_access_table qca8k_readable_table = { +- .yes_ranges = qca8k_readable_ranges, +- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), +-}; +- +-static struct regmap_config qca8k_regmap_config = { +- .reg_bits = 16, +- .val_bits = 32, +- .reg_stride = 4, +- .max_register = 0x16ac, /* end MIB - Port6 range */ +- .reg_read = qca8k_regmap_read, +- .reg_write = qca8k_regmap_write, +- .reg_update_bits = qca8k_regmap_update_bits, +- .rd_table = &qca8k_readable_table, +- .disable_locking = true, /* Locking is handled by qca8k read/write */ +- .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ +-}; +- +-static int +-qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) +-{ +- u32 val; +- +- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); +-} +- +-static int +-qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) +-{ +- u32 reg[3]; +- int ret; +- +- /* load the ARL table into an array */ +- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +- if (ret) +- return ret; +- +- /* vid - 83:72 */ +- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); +- /* aging - 67:64 */ +- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); +- /* portmask - 54:48 */ +- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); +- /* mac - 47:0 */ +- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); +- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); +- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); +- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); +- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); +- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); +- +- return 0; +-} +- +-static void +-qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, +- u8 aging) +-{ +- u32 reg[3] = { 0 }; +- +- /* vid - 83:72 */ +- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); +- /* aging - 67:64 */ +- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); +- /* portmask - 54:48 */ +- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); +- /* mac - 47:0 */ +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); +- +- /* load the array into the ARL table */ +- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +-} +- +-static int +-qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and FDB index */ +- reg = QCA8K_ATU_FUNC_BUSY; +- reg |= cmd; +- if (port >= 0) { +- reg |= QCA8K_ATU_FUNC_PORT_EN; +- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); +- } +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_FDB_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_ATU_FUNC_FULL) +- return -1; +- } +- +- return 0; +-} +- +-static int +-qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) +-{ +- int ret; +- +- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); +- if (ret < 0) +- return ret; +- +- return qca8k_fdb_read(priv, fdb); +-} +- +-static int +-qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, +- u16 vid, u8 aging) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static void +-qca8k_fdb_flush(struct qca8k_priv *priv) +-{ +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_fdb_read(priv, &fdb); +- if (ret < 0) +- goto exit; +- +- /* Rule exist. Delete first */ +- if (!fdb.aging) { +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- } +- +- /* Add port to fdb portmask */ +- fdb.port_mask |= port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- /* Rule doesn't exist. Why delete? */ +- if (!fdb.aging) { +- ret = -EINVAL; +- goto exit; +- } +- +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- +- /* Only port in the rule is this port. Don't re insert */ +- if (fdb.port_mask == port_mask) +- goto exit; +- +- /* Remove port from port mask */ +- fdb.port_mask &= ~port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and VLAN index */ +- reg = QCA8K_VTU_FUNC1_BUSY; +- reg |= cmd; +- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_VLAN_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_VTU_FUNC1_FULL) +- return -ENOMEM; +- } +- +- return 0; +-} +- +-static int +-qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) +-{ +- u32 reg; +- int ret; +- +- /* +- We do the right thing with VLAN 0 and treat it as untagged while +- preserving the tag on egress. +- */ +- if (vid == 0) +- return 0; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- if (untagged) +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); +- else +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); +- +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) +-{ +- u32 reg, mask; +- int ret, i; +- bool del; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); +- +- /* Check if we're the last member to be removed */ +- del = true; +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); +- +- if ((reg & mask) != mask) { +- del = false; +- break; +- } +- } +- +- if (del) { +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); +- } else { +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- } +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_mib_init(struct qca8k_priv *priv) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, +- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, +- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | +- QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); +- if (ret) +- goto exit; +- +- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static void +-qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) +-{ +- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; +- +- /* Port 0 and 6 have no internal PHY */ +- if (port > 0 && port < 6) +- mask |= QCA8K_PORT_STATUS_LINK_AUTO; +- +- if (enable) +- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +- else +- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +-} +- +-static int +-qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, +- struct sk_buff *read_skb, u32 *val) +-{ +- struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); +- bool ack; +- int ret; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the copy pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- *val = mgmt_eth_data->data[0]; +- +- return 0; +-} +- +-static int +-qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, +- int regnum, u16 data) +-{ +- struct sk_buff *write_skb, *clear_skb, *read_skb; +- struct qca8k_mgmt_eth_data *mgmt_eth_data; +- u32 write_val, clear_val = 0, val; +- struct net_device *mgmt_master; +- int ret, ret1; +- bool ack; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- mgmt_eth_data = &priv->mgmt_eth_data; +- +- write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum); +- +- if (read) { +- write_val |= QCA8K_MDIO_MASTER_READ; +- } else { +- write_val |= QCA8K_MDIO_MASTER_WRITE; +- write_val |= QCA8K_MDIO_MASTER_DATA(data); +- } +- +- /* Prealloc all the needed skb before the lock */ +- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); +- if (!write_skb) +- return -ENOMEM; +- +- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); +- if (!clear_skb) { +- ret = -ENOMEM; +- goto err_clear_skb; +- } +- +- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); +- if (!read_skb) { +- ret = -ENOMEM; +- goto err_read_skb; +- } +- +- /* Actually start the request: +- * 1. Send mdio master packet +- * 2. Busy Wait for mdio master command +- * 3. Get the data if we are reading +- * 4. Reset the mdio master (even with error) +- */ +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check if mgmt_master is operational */ +- mgmt_master = priv->mgmt_master; +- if (!mgmt_master) { +- mutex_unlock(&mgmt_eth_data->mutex); +- ret = -EINVAL; +- goto err_mgmt_master; +- } +- +- read_skb->dev = mgmt_master; +- clear_skb->dev = mgmt_master; +- write_skb->dev = mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the write pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(write_skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) { +- ret = -ETIMEDOUT; +- kfree_skb(read_skb); +- goto exit; +- } +- +- if (!ack) { +- ret = -EINVAL; +- kfree_skb(read_skb); +- goto exit; +- } +- +- ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, +- !(val & QCA8K_MDIO_MASTER_BUSY), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- mgmt_eth_data, read_skb, &val); +- +- if (ret < 0 && ret1 < 0) { +- ret = ret1; +- goto exit; +- } +- +- if (read) { +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the read pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(read_skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) { +- ret = -ETIMEDOUT; +- goto exit; +- } +- +- if (!ack) { +- ret = -EINVAL; +- goto exit; +- } +- +- ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; +- } else { +- kfree_skb(read_skb); +- } +-exit: +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the clear pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(clear_skb); +- +- wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- return ret; +- +- /* Error handling before lock */ +-err_mgmt_master: +- kfree_skb(read_skb); +-err_read_skb: +- kfree_skb(clear_skb); +-err_clear_skb: +- kfree_skb(write_skb); +- +- return ret; +-} +- +-static u32 +-qca8k_port_to_phy(int port) +-{ +- /* From Andrew Lunn: +- * Port 0 has no internal phy. +- * Port 1 has an internal PHY at MDIO address 0. +- * Port 2 has an internal PHY at MDIO address 1. +- * ... +- * Port 5 has an internal PHY at MDIO address 4. +- * Port 6 has no internal PHY. +- */ +- +- return port - 1; +-} +- +-static int +-qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) +-{ +- u16 r1, r2, page; +- u32 val; +- int ret, ret1; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- bus, 0x10 | r2, r1, &val); +- +- /* Check if qca8k_read has failed for a different reason +- * before returnting -ETIMEDOUT +- */ +- if (ret < 0 && ret1 < 0) +- return ret1; +- +- return ret; +-} +- +-static int +-qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) +-{ +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum) | +- QCA8K_MDIO_MASTER_DATA(data); +- +- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_BUSY); +- +-exit: +- /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +- +- mutex_unlock(&bus->mdio_lock); +- +- return ret; +-} +- +-static int +-qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) +-{ +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum); +- +- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_BUSY); +- if (ret) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); +- +-exit: +- /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +- +- mutex_unlock(&bus->mdio_lock); +- +- if (ret >= 0) +- ret = val & QCA8K_MDIO_MASTER_DATA_MASK; +- +- return ret; +-} +- +-static int +-qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) +-{ +- struct qca8k_priv *priv = slave_bus->priv; +- int ret; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); +- if (!ret) +- return 0; +- +- return qca8k_mdio_write(priv, phy, regnum, data); +-} +- +-static int +-qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) +-{ +- struct qca8k_priv *priv = slave_bus->priv; +- int ret; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); +- if (ret >= 0) +- return ret; +- +- ret = qca8k_mdio_read(priv, phy, regnum); +- +- if (ret < 0) +- return 0xffff; +- +- return ret; +-} +- +-static int +-qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) +-{ +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- return qca8k_internal_mdio_write(slave_bus, port, regnum, data); +-} +- +-static int +-qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) +-{ +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- return qca8k_internal_mdio_read(slave_bus, port, regnum); +-} +- +-static int +-qca8k_mdio_register(struct qca8k_priv *priv) +-{ +- struct dsa_switch *ds = priv->ds; +- struct device_node *mdio; +- struct mii_bus *bus; +- +- bus = devm_mdiobus_alloc(ds->dev); +- if (!bus) +- return -ENOMEM; +- +- bus->priv = (void *)priv; +- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", +- ds->dst->index, ds->index); +- bus->parent = ds->dev; +- bus->phy_mask = ~ds->phys_mii_mask; +- ds->slave_mii_bus = bus; +- +- /* Check if the devicetree declare the port:phy mapping */ +- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); +- if (of_device_is_available(mdio)) { +- bus->name = "qca8k slave mii"; +- bus->read = qca8k_internal_mdio_read; +- bus->write = qca8k_internal_mdio_write; +- return devm_of_mdiobus_register(priv->dev, bus, mdio); +- } +- +- /* If a mapping can't be found the legacy mapping is used, +- * using the qca8k_port_to_phy function +- */ +- bus->name = "qca8k-legacy slave mii"; +- bus->read = qca8k_legacy_mdio_read; +- bus->write = qca8k_legacy_mdio_write; +- return devm_mdiobus_register(priv->dev, bus); +-} +- +-static int +-qca8k_setup_mdio_bus(struct qca8k_priv *priv) +-{ +- u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; +- struct device_node *ports, *port; +- phy_interface_t mode; +- int err; +- +- ports = of_get_child_by_name(priv->dev->of_node, "ports"); +- if (!ports) +- ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); +- +- if (!ports) +- return -EINVAL; +- +- for_each_available_child_of_node(ports, port) { +- err = of_property_read_u32(port, "reg", ®); +- if (err) { +- of_node_put(port); +- of_node_put(ports); +- return err; +- } +- +- if (!dsa_is_user_port(priv->ds, reg)) +- continue; +- +- of_get_phy_mode(port, &mode); +- +- if (of_property_read_bool(port, "phy-handle") && +- mode != PHY_INTERFACE_MODE_INTERNAL) +- external_mdio_mask |= BIT(reg); +- else +- internal_mdio_mask |= BIT(reg); +- } +- +- of_node_put(ports); +- if (!external_mdio_mask && !internal_mdio_mask) { +- dev_err(priv->dev, "no PHYs are defined.\n"); +- return -EINVAL; +- } +- +- /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through +- * the MDIO_MASTER register also _disconnects_ the external MDC +- * passthrough to the internal PHYs. It's not possible to use both +- * configurations at the same time! +- * +- * Because this came up during the review process: +- * If the external mdio-bus driver is capable magically disabling +- * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's +- * accessors for the time being, it would be possible to pull this +- * off. +- */ +- if (!!external_mdio_mask && !!internal_mdio_mask) { +- dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); +- return -EINVAL; +- } +- +- if (external_mdio_mask) { +- /* Make sure to disable the internal mdio bus in cases +- * a dt-overlay and driver reload changed the configuration +- */ +- +- return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_EN); +- } +- +- return qca8k_mdio_register(priv); +-} +- +-static int +-qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) +-{ +- u32 mask = 0; +- int ret = 0; +- +- /* SoC specific settings for ipq8064. +- * If more device require this consider adding +- * a dedicated binding. +- */ +- if (of_machine_is_compatible("qcom,ipq8064")) +- mask |= QCA8K_MAC_PWR_RGMII0_1_8V; +- +- /* SoC specific settings for ipq8065 */ +- if (of_machine_is_compatible("qcom,ipq8065")) +- mask |= QCA8K_MAC_PWR_RGMII1_1_8V; +- +- if (mask) { +- ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, +- QCA8K_MAC_PWR_RGMII0_1_8V | +- QCA8K_MAC_PWR_RGMII1_1_8V, +- mask); +- } +- +- return ret; +-} +- +-static int qca8k_find_cpu_port(struct dsa_switch *ds) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- /* Find the connected cpu port. Valid port are 0 or 6 */ +- if (dsa_is_cpu_port(ds, 0)) +- return 0; +- +- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); +- +- if (dsa_is_cpu_port(ds, 6)) +- return 6; +- +- return -EINVAL; +-} +- +-static int +-qca8k_setup_of_pws_reg(struct qca8k_priv *priv) +-{ +- struct device_node *node = priv->dev->of_node; +- const struct qca8k_match_data *data; +- u32 val = 0; +- int ret; +- +- /* QCA8327 require to set to the correct mode. +- * His bigger brother QCA8328 have the 172 pin layout. +- * Should be applied by default but we set this just to make sure. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- data = of_device_get_match_data(priv->dev); +- +- /* Set the correct package of 148 pin for QCA8327 */ +- if (data->reduced_package) +- val |= QCA8327_PWS_PACKAGE148_EN; +- +- ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, +- val); +- if (ret) +- return ret; +- } +- +- if (of_property_read_bool(node, "qca,ignore-power-on-sel")) +- val |= QCA8K_PWS_POWER_ON_SEL; +- +- if (of_property_read_bool(node, "qca,led-open-drain")) { +- if (!(val & QCA8K_PWS_POWER_ON_SEL)) { +- dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); +- return -EINVAL; +- } +- +- val |= QCA8K_PWS_LED_OPEN_EN_CSR; +- } +- +- return qca8k_rmw(priv, QCA8K_REG_PWS, +- QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, +- val); +-} +- +-static int +-qca8k_parse_port_config(struct qca8k_priv *priv) +-{ +- int port, cpu_port_index = -1, ret; +- struct device_node *port_dn; +- phy_interface_t mode; +- struct dsa_port *dp; +- u32 delay; +- +- /* We have 2 CPU port. Check them */ +- for (port = 0; port < QCA8K_NUM_PORTS; port++) { +- /* Skip every other port */ +- if (port != 0 && port != 6) +- continue; +- +- dp = dsa_to_port(priv->ds, port); +- port_dn = dp->dn; +- cpu_port_index++; +- +- if (!of_device_is_available(port_dn)) +- continue; +- +- ret = of_get_phy_mode(port_dn, &mode); +- if (ret) +- continue; +- +- switch (mode) { +- case PHY_INTERFACE_MODE_RGMII: +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_TXID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- case PHY_INTERFACE_MODE_SGMII: +- delay = 0; +- +- if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) +- /* Switch regs accept value in ns, convert ps to ns */ +- delay = delay / 1000; +- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_TXID) +- delay = 1; +- +- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { +- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); +- delay = 3; +- } +- +- priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; +- +- delay = 0; +- +- if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) +- /* Switch regs accept value in ns, convert ps to ns */ +- delay = delay / 1000; +- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_RXID) +- delay = 2; +- +- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { +- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); +- delay = 3; +- } +- +- priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; +- +- /* Skip sgmii parsing for rgmii* mode */ +- if (mode == PHY_INTERFACE_MODE_RGMII || +- mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_TXID || +- mode == PHY_INTERFACE_MODE_RGMII_RXID) +- break; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) +- priv->ports_config.sgmii_tx_clk_falling_edge = true; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) +- priv->ports_config.sgmii_rx_clk_falling_edge = true; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { +- priv->ports_config.sgmii_enable_pll = true; +- +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); +- priv->ports_config.sgmii_enable_pll = false; +- } +- +- if (priv->switch_revision < 2) +- dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); +- } +- +- break; +- default: +- continue; +- } +- } +- +- return 0; +-} +- +-static int +-qca8k_setup(struct dsa_switch *ds) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int cpu_port, ret, i; +- u32 mask; +- +- cpu_port = qca8k_find_cpu_port(ds); +- if (cpu_port < 0) { +- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); +- return cpu_port; +- } +- +- /* Parse CPU port config to be later used in phy_link mac_config */ +- ret = qca8k_parse_port_config(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_mdio_bus(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_of_pws_reg(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_mac_pwr_sel(priv); +- if (ret) +- return ret; +- +- /* Make sure MAC06 is disabled */ +- ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, +- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); +- if (ret) { +- dev_err(priv->dev, "failed disabling MAC06 exchange"); +- return ret; +- } +- +- /* Enable CPU Port */ +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); +- if (ret) { +- dev_err(priv->dev, "failed enabling CPU port"); +- return ret; +- } +- +- /* Enable MIB counters */ +- ret = qca8k_mib_init(priv); +- if (ret) +- dev_warn(priv->dev, "mib init failed"); +- +- /* Initial setup of all ports */ +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- /* Disable forwarding by default on all ports */ +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, 0); +- if (ret) +- return ret; +- +- /* Enable QCA header mode on all cpu ports */ +- if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), +- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | +- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); +- if (ret) { +- dev_err(priv->dev, "failed enabling QCA header mode"); +- return ret; +- } +- } +- +- /* Disable MAC by default on all user ports */ +- if (dsa_is_user_port(ds, i)) +- qca8k_port_set_status(priv, i, 0); +- } +- +- /* Forward all unknown frames to CPU port for Linux processing +- * Notice that in multi-cpu config only one port should be set +- * for igmp, unknown, multicast and broadcast packet +- */ +- ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); +- if (ret) +- return ret; +- +- /* Setup connection between CPU port & user ports +- * Configure specific switch configuration for ports +- */ +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- /* CPU port gets connected to all user ports of the switch */ +- if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); +- if (ret) +- return ret; +- } +- +- /* Individual user ports get connected to CPU port only */ +- if (dsa_is_user_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, +- BIT(cpu_port)); +- if (ret) +- return ret; +- +- /* Enable ARP Auto-learning by default */ +- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_LEARN); +- if (ret) +- return ret; +- +- /* For port based vlans to work we need to set the +- * default egress vid +- */ +- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), +- QCA8K_EGREES_VLAN_PORT_MASK(i), +- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); +- if (ret) +- return ret; +- +- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), +- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | +- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); +- if (ret) +- return ret; +- } +- +- /* The port 5 of the qca8337 have some problem in flood condition. The +- * original legacy driver had some specific buffer and priority settings +- * for the different port suggested by the QCA switch team. Add this +- * missing settings to improve switch stability under load condition. +- * This problem is limited to qca8337 and other qca8k switch are not affected. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8337) { +- switch (i) { +- /* The 2 CPU port and port 5 requires some different +- * priority than any other ports. +- */ +- case 0: +- case 5: +- case 6: +- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | +- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); +- break; +- default: +- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | +- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); +- } +- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); +- +- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | +- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_WRED_EN; +- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), +- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | +- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_WRED_EN, +- mask); +- } +- } +- +- /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | +- QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); +- qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, +- QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | +- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, +- mask); +- } +- +- /* Setup our port MTUs to match power on defaults */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); +- if (ret) +- dev_warn(priv->dev, "failed setting MTU settings"); +- +- /* Flush the FDB table */ +- qca8k_fdb_flush(priv); +- +- /* We don't have interrupts for link changes, so we need to poll */ +- ds->pcs_poll = true; +- +- /* Set min a max ageing value supported */ +- ds->ageing_time_min = 7000; +- ds->ageing_time_max = 458745000; +- +- /* Set max number of LAGs supported */ +- ds->num_lag_ids = QCA8K_NUM_LAGS; +- +- return 0; +-} +- +-static void +-qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, +- u32 reg) +-{ +- u32 delay, val = 0; +- int ret; +- +- /* Delay can be declared in 3 different way. +- * Mode to rgmii and internal-delay standard binding defined +- * rgmii-id or rgmii-tx/rx phy mode set. +- * The parse logic set a delay different than 0 only when one +- * of the 3 different way is used. In all other case delay is +- * not enabled. With ID or TX/RXID delay is enabled and set +- * to the default and recommended value. +- */ +- if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { +- delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; +- } +- +- if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { +- delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; +- } +- +- /* Set RGMII delay based on the selected values */ +- ret = qca8k_rmw(priv, reg, +- QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, +- val); +- if (ret) +- dev_err(priv->dev, "Failed to set internal delay for CPU port%d", +- cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); +-} +- +-static void +-qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, +- const struct phylink_link_state *state) +-{ +- struct qca8k_priv *priv = ds->priv; +- int cpu_port_index, ret; +- u32 reg, val; +- +- switch (port) { +- case 0: /* 1st CPU port */ +- if (state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII) +- return; +- +- reg = QCA8K_REG_PORT0_PAD_CTRL; +- cpu_port_index = QCA8K_CPU_PORT0; +- break; +- case 1: +- case 2: +- case 3: +- case 4: +- case 5: +- /* Internal PHY, nothing to do */ +- return; +- case 6: /* 2nd CPU port / external PHY */ +- if (state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII && +- state->interface != PHY_INTERFACE_MODE_1000BASEX) +- return; +- +- reg = QCA8K_REG_PORT6_PAD_CTRL; +- cpu_port_index = QCA8K_CPU_PORT6; +- break; +- default: +- dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); +- return; +- } +- +- if (port != 6 && phylink_autoneg_inband(mode)) { +- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", +- __func__); +- return; +- } +- +- switch (state->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_TXID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); +- +- /* Configure rgmii delay */ +- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +- +- /* QCA8337 requires to set rgmii rx delay for all ports. +- * This is enabled through PORT5_PAD_CTRL for all ports, +- * rather than individual port registers. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8337) +- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); +- break; +- case PHY_INTERFACE_MODE_SGMII: +- case PHY_INTERFACE_MODE_1000BASEX: +- /* Enable SGMII on the port */ +- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); +- +- /* Enable/disable SerDes auto-negotiation as necessary */ +- ret = qca8k_read(priv, QCA8K_REG_PWS, &val); +- if (ret) +- return; +- if (phylink_autoneg_inband(mode)) +- val &= ~QCA8K_PWS_SERDES_AEN_DIS; +- else +- val |= QCA8K_PWS_SERDES_AEN_DIS; +- qca8k_write(priv, QCA8K_REG_PWS, val); +- +- /* Configure the SGMII parameters */ +- ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); +- if (ret) +- return; +- +- val |= QCA8K_SGMII_EN_SD; +- +- if (priv->ports_config.sgmii_enable_pll) +- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | +- QCA8K_SGMII_EN_TX; +- +- if (dsa_is_cpu_port(ds, port)) { +- /* CPU port, we're talking to the CPU MAC, be a PHY */ +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_PHY; +- } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_MAC; +- } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_BASEX; +- } +- +- qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); +- +- /* From original code is reported port instability as SGMII also +- * require delay set. Apply advised values here or take them from DT. +- */ +- if (state->interface == PHY_INTERFACE_MODE_SGMII) +- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +- +- /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and +- * falling edge is set writing in the PORT0 PAD reg +- */ +- if (priv->switch_id == QCA8K_ID_QCA8327 || +- priv->switch_id == QCA8K_ID_QCA8337) +- reg = QCA8K_REG_PORT0_PAD_CTRL; +- +- val = 0; +- +- /* SGMII Clock phase configuration */ +- if (priv->ports_config.sgmii_rx_clk_falling_edge) +- val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; +- +- if (priv->ports_config.sgmii_tx_clk_falling_edge) +- val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; +- +- if (val) +- ret = qca8k_rmw(priv, reg, +- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | +- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, +- val); +- +- break; +- default: +- dev_err(ds->dev, "xMII mode %s not supported for port %d\n", +- phy_modes(state->interface), port); +- return; +- } +-} +- +-static void +-qca8k_phylink_validate(struct dsa_switch *ds, int port, +- unsigned long *supported, +- struct phylink_link_state *state) +-{ +- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- +- switch (port) { +- case 0: /* 1st CPU port */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII) +- goto unsupported; +- break; +- case 1: +- case 2: +- case 3: +- case 4: +- case 5: +- /* Internal PHY */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_GMII && +- state->interface != PHY_INTERFACE_MODE_INTERNAL) +- goto unsupported; +- break; +- case 6: /* 2nd CPU port / external PHY */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII && +- state->interface != PHY_INTERFACE_MODE_1000BASEX) +- goto unsupported; +- break; +- default: +-unsupported: +- linkmode_zero(supported); +- return; +- } +- +- phylink_set_port_modes(mask); +- phylink_set(mask, Autoneg); +- +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 10baseT_Half); +- phylink_set(mask, 10baseT_Full); +- phylink_set(mask, 100baseT_Half); +- phylink_set(mask, 100baseT_Full); +- +- if (state->interface == PHY_INTERFACE_MODE_1000BASEX) +- phylink_set(mask, 1000baseX_Full); +- +- phylink_set(mask, Pause); +- phylink_set(mask, Asym_Pause); +- +- linkmode_and(supported, supported, mask); +- linkmode_and(state->advertising, state->advertising, mask); +-} +- +-static int +-qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, +- struct phylink_link_state *state) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg; +- int ret; +- +- ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); +- if (ret < 0) +- return ret; +- +- state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); +- state->an_complete = state->link; +- state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); +- state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : +- DUPLEX_HALF; +- +- switch (reg & QCA8K_PORT_STATUS_SPEED) { +- case QCA8K_PORT_STATUS_SPEED_10: +- state->speed = SPEED_10; +- break; +- case QCA8K_PORT_STATUS_SPEED_100: +- state->speed = SPEED_100; +- break; +- case QCA8K_PORT_STATUS_SPEED_1000: +- state->speed = SPEED_1000; +- break; +- default: +- state->speed = SPEED_UNKNOWN; +- break; +- } +- +- state->pause = MLO_PAUSE_NONE; +- if (reg & QCA8K_PORT_STATUS_RXFLOW) +- state->pause |= MLO_PAUSE_RX; +- if (reg & QCA8K_PORT_STATUS_TXFLOW) +- state->pause |= MLO_PAUSE_TX; +- +- return 1; +-} +- +-static void +-qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, +- phy_interface_t interface) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- qca8k_port_set_status(priv, port, 0); +-} +- +-static void +-qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, +- phy_interface_t interface, struct phy_device *phydev, +- int speed, int duplex, bool tx_pause, bool rx_pause) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg; +- +- if (phylink_autoneg_inband(mode)) { +- reg = QCA8K_PORT_STATUS_LINK_AUTO; +- } else { +- switch (speed) { +- case SPEED_10: +- reg = QCA8K_PORT_STATUS_SPEED_10; +- break; +- case SPEED_100: +- reg = QCA8K_PORT_STATUS_SPEED_100; +- break; +- case SPEED_1000: +- reg = QCA8K_PORT_STATUS_SPEED_1000; +- break; +- default: +- reg = QCA8K_PORT_STATUS_LINK_AUTO; +- break; +- } +- +- if (duplex == DUPLEX_FULL) +- reg |= QCA8K_PORT_STATUS_DUPLEX; +- +- if (rx_pause || dsa_is_cpu_port(ds, port)) +- reg |= QCA8K_PORT_STATUS_RXFLOW; +- +- if (tx_pause || dsa_is_cpu_port(ds, port)) +- reg |= QCA8K_PORT_STATUS_TXFLOW; +- } +- +- reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; +- +- qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); +-} +- +-static void +-qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) +-{ +- const struct qca8k_match_data *match_data; +- struct qca8k_priv *priv = ds->priv; +- int i; +- +- if (stringset != ETH_SS_STATS) +- return; +- +- match_data = of_device_get_match_data(priv->dev); +- +- for (i = 0; i < match_data->mib_count; i++) +- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, +- ETH_GSTRING_LEN); +-} +- +-static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) +-{ +- const struct qca8k_match_data *match_data; +- struct qca8k_mib_eth_data *mib_eth_data; +- struct qca8k_priv *priv = ds->priv; +- const struct qca8k_mib_desc *mib; +- struct mib_ethhdr *mib_ethhdr; +- int i, mib_len, offset = 0; +- u64 *data; +- u8 port; +- +- mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); +- mib_eth_data = &priv->mib_eth_data; +- +- /* The switch autocast every port. Ignore other packet and +- * parse only the requested one. +- */ +- port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); +- if (port != mib_eth_data->req_port) +- goto exit; +- +- match_data = device_get_match_data(priv->dev); +- data = mib_eth_data->data; +- +- for (i = 0; i < match_data->mib_count; i++) { +- mib = &ar8327_mib[i]; +- +- /* First 3 mib are present in the skb head */ +- if (i < 3) { +- data[i] = mib_ethhdr->data[i]; +- continue; +- } +- +- mib_len = sizeof(uint32_t); +- +- /* Some mib are 64 bit wide */ +- if (mib->size == 2) +- mib_len = sizeof(uint64_t); +- +- /* Copy the mib value from packet to the */ +- memcpy(data + i, skb->data + offset, mib_len); +- +- /* Set the offset for the next mib */ +- offset += mib_len; +- } +- +-exit: +- /* Complete on receiving all the mib packet */ +- if (refcount_dec_and_test(&mib_eth_data->port_parsed)) +- complete(&mib_eth_data->rw_done); +-} +- +-static int +-qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) +-{ +- struct dsa_port *dp = dsa_to_port(ds, port); +- struct qca8k_mib_eth_data *mib_eth_data; +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- mib_eth_data = &priv->mib_eth_data; +- +- mutex_lock(&mib_eth_data->mutex); +- +- reinit_completion(&mib_eth_data->rw_done); +- +- mib_eth_data->req_port = dp->index; +- mib_eth_data->data = data; +- refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); +- +- mutex_lock(&priv->reg_mutex); +- +- /* Send mib autocast request */ +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, +- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, +- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | +- QCA8K_MIB_BUSY); +- +- mutex_unlock(&priv->reg_mutex); +- +- if (ret) +- goto exit; +- +- ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); +- +-exit: +- mutex_unlock(&mib_eth_data->mutex); +- +- return ret; +-} +- +-static void +-qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, +- uint64_t *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- const struct qca8k_match_data *match_data; +- const struct qca8k_mib_desc *mib; +- u32 reg, i, val; +- u32 hi = 0; +- int ret; +- +- if (priv->mgmt_master && +- qca8k_get_ethtool_stats_eth(ds, port, data) > 0) +- return; +- +- match_data = of_device_get_match_data(priv->dev); +- +- for (i = 0; i < match_data->mib_count; i++) { +- mib = &ar8327_mib[i]; +- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; +- +- ret = qca8k_read(priv, reg, &val); +- if (ret < 0) +- continue; +- +- if (mib->size == 2) { +- ret = qca8k_read(priv, reg + 4, &hi); +- if (ret < 0) +- continue; +- } +- +- data[i] = val; +- if (mib->size == 2) +- data[i] |= (u64)hi << 32; +- } +-} +- +-static int +-qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) +-{ +- const struct qca8k_match_data *match_data; +- struct qca8k_priv *priv = ds->priv; +- +- if (sset != ETH_SS_STATS) +- return 0; +- +- match_data = of_device_get_match_data(priv->dev); +- +- return match_data->mib_count; +-} +- +-static int +-qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); +- u32 reg; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); +- if (ret < 0) +- goto exit; +- +- if (eee->eee_enabled) +- reg |= lpi_en; +- else +- reg &= ~lpi_en; +- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +-{ +- /* Nothing to do on the port's MAC */ +- return 0; +-} +- +-static void +-qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 stp_state; +- +- switch (state) { +- case BR_STATE_DISABLED: +- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; +- break; +- case BR_STATE_BLOCKING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; +- break; +- case BR_STATE_LISTENING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; +- break; +- case BR_STATE_LEARNING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; +- break; +- case BR_STATE_FORWARDING: +- default: +- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; +- break; +- } +- +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); +-} +- +-static int +-qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int port_mask, cpu_port; +- int i, ret; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- port_mask = BIT(cpu_port); +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Add this port to the portvlan mask of the other ports +- * in the bridge +- */ +- ret = regmap_set_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- if (ret) +- return ret; +- if (i != port) +- port_mask |= BIT(i); +- } +- +- /* Add all other ports to this ports portvlan mask */ +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, port_mask); +- +- return ret; +-} +- +-static void +-qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int cpu_port, i; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Remove this port to the portvlan mask of the other ports +- * in the bridge +- */ +- regmap_clear_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- } +- +- /* Set the cpu port to be the only one in the portvlan mask of +- * this port +- */ +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); +-} +- +-static void +-qca8k_port_fast_age(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +-{ +- struct qca8k_priv *priv = ds->priv; +- unsigned int secs = msecs / 1000; +- u32 val; +- +- /* AGE_TIME reg is set in 7s step */ +- val = secs / 7; +- +- /* Handle case with 0 as val to NOT disable +- * learning +- */ +- if (!val) +- val = 1; +- +- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, +- QCA8K_ATU_AGE_TIME(val)); +-} +- +-static int +-qca8k_port_enable(struct dsa_switch *ds, int port, +- struct phy_device *phy) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 1); +- priv->port_enabled_map |= BIT(port); +- +- if (dsa_is_user_port(ds, port)) +- phy_support_asym_pause(phy); +- +- return 0; +-} +- +-static void +-qca8k_port_disable(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 0); +- priv->port_enabled_map &= ~BIT(port); +-} +- +-static int +-qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- /* We have only have a general MTU setting. +- * DSA always set the CPU port's MTU to the largest MTU of the slave +- * ports. +- * Setting MTU just for the CPU port is sufficient to correctly set a +- * value for every port. +- */ +- if (!dsa_is_cpu_port(ds, port)) +- return 0; +- +- /* To change the MAX_FRAME_SIZE the cpu ports must be off or +- * the switch panics. +- * Turn off both cpu ports before applying the new value to prevent +- * this. +- */ +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 0); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 0); +- +- /* Include L2 header / FCS length */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); +- +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 1); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 1); +- +- return ret; +-} +- +-static int +-qca8k_port_max_mtu(struct dsa_switch *ds, int port) +-{ +- return QCA8K_MAX_MTU; +-} +- +-static int +-qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, +- u16 port_mask, u16 vid) +-{ +- /* Set the vid to the port vlan id if no vid is set */ +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_add(priv, addr, port_mask, vid, +- QCA8K_ATU_STATUS_STATIC); +-} +- +-static int +-qca8k_port_fdb_add(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_del(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_del(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_dump(struct dsa_switch *ds, int port, +- dsa_fdb_dump_cb_t *cb, void *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- struct qca8k_fdb _fdb = { 0 }; +- int cnt = QCA8K_NUM_FDB_RECORDS; +- bool is_static; +- int ret = 0; +- +- mutex_lock(&priv->reg_mutex); +- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { +- if (!_fdb.aging) +- break; +- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); +- ret = cb(_fdb.mac, _fdb.vid, is_static, data); +- if (ret) +- break; +- } +- mutex_unlock(&priv->reg_mutex); +- +- return 0; +-} +- +-static int +-qca8k_port_mdb_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); +-} +- +-static int +-qca8k_port_mdb_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); +-} +- +-static int +-qca8k_port_mirror_add(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror, +- bool ingress) +-{ +- struct qca8k_priv *priv = ds->priv; +- int monitor_port, ret; +- u32 reg, val; +- +- /* Check for existent entry */ +- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) +- return -EEXIST; +- +- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); +- if (ret) +- return ret; +- +- /* QCA83xx can have only one port set to mirror mode. +- * Check that the correct port is requested and return error otherwise. +- * When no mirror port is set, the values is set to 0xF +- */ +- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) +- return -EEXIST; +- +- /* Set the monitor port */ +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, +- mirror->to_local_port); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- return ret; +- +- if (ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_update_bits(priv->regmap, reg, val, val); +- if (ret) +- return ret; +- +- /* Track mirror port for tx and rx to decide when the +- * mirror port has to be disabled. +- */ +- if (ingress) +- priv->mirror_rx |= BIT(port); +- else +- priv->mirror_tx |= BIT(port); +- +- return 0; +-} +- +-static void +-qca8k_port_mirror_del(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg, val; +- int ret; +- +- if (mirror->ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_clear_bits(priv->regmap, reg, val); +- if (ret) +- goto err; +- +- if (mirror->ingress) +- priv->mirror_rx &= ~BIT(port); +- else +- priv->mirror_tx &= ~BIT(port); +- +- /* No port set to send packet to mirror port. Disable mirror port */ +- if (!priv->mirror_rx && !priv->mirror_tx) { +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- goto err; +- } +-err: +- dev_err(priv->dev, "Failed to del mirror port from %d", port); +-} +- +-static int +-qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, +- struct netlink_ext_ack *extack) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- if (vlan_filtering) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); +- } else { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan, +- struct netlink_ext_ack *extack) +-{ +- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; +- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); +- if (ret) { +- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); +- return ret; +- } +- +- if (pvid) { +- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), +- QCA8K_EGREES_VLAN_PORT_MASK(port), +- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); +- if (ret) +- return ret; +- +- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), +- QCA8K_PORT_VLAN_CVID(vlan->vid) | +- QCA8K_PORT_VLAN_SVID(vlan->vid)); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_del(priv, port, vlan->vid); +- if (ret) +- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); +- +- return ret; +-} +- +-static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- /* Communicate to the phy internal driver the switch revision. +- * Based on the switch revision different values needs to be +- * set to the dbg and mmd reg on the phy. +- * The first 2 bit are used to communicate the switch revision +- * to the phy driver. +- */ +- if (port > 0 && port < 6) +- return priv->switch_revision; +- +- return 0; +-} +- +-static enum dsa_tag_protocol +-qca8k_get_tag_protocol(struct dsa_switch *ds, int port, +- enum dsa_tag_protocol mp) +-{ +- return DSA_TAG_PROTO_QCA; +-} +- +-static bool +-qca8k_lag_can_offload(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct dsa_port *dp; +- int id, members = 0; +- +- id = dsa_lag_id(ds->dst, lag); +- if (id < 0 || id >= ds->num_lag_ids) +- return false; +- +- dsa_lag_foreach_port(dp, ds->dst, lag) +- /* Includes the port joining the LAG */ +- members++; +- +- if (members > QCA8K_NUM_PORTS_FOR_LAG) +- return false; +- +- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) +- return false; +- +- if (info->hash_type != NETDEV_LAG_HASH_L2 && +- info->hash_type != NETDEV_LAG_HASH_L23) +- return false; +- +- return true; +-} +- +-static int +-qca8k_lag_setup_hash(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct qca8k_priv *priv = ds->priv; +- bool unique_lag = true; +- u32 hash = 0; +- int i, id; +- +- id = dsa_lag_id(ds->dst, lag); +- +- switch (info->hash_type) { +- case NETDEV_LAG_HASH_L23: +- hash |= QCA8K_TRUNK_HASH_SIP_EN; +- hash |= QCA8K_TRUNK_HASH_DIP_EN; +- fallthrough; +- case NETDEV_LAG_HASH_L2: +- hash |= QCA8K_TRUNK_HASH_SA_EN; +- hash |= QCA8K_TRUNK_HASH_DA_EN; +- break; +- default: /* We should NEVER reach this */ +- return -EOPNOTSUPP; +- } +- +- /* Check if we are the unique configured LAG */ +- dsa_lags_foreach_id(i, ds->dst) +- if (i != id && dsa_lag_dev(ds->dst, i)) { +- unique_lag = false; +- break; +- } +- +- /* Hash Mode is global. Make sure the same Hash Mode +- * is set to all the 4 possible lag. +- * If we are the unique LAG we can set whatever hash +- * mode we want. +- * To change hash mode it's needed to remove all LAG +- * and change the mode with the latest. +- */ +- if (unique_lag) { +- priv->lag_hash_mode = hash; +- } else if (priv->lag_hash_mode != hash) { +- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); +- return -EOPNOTSUPP; +- } +- +- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, +- QCA8K_TRUNK_HASH_MASK, hash); +-} +- +-static int +-qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, +- struct net_device *lag, bool delete) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret, id, i; +- u32 val; +- +- id = dsa_lag_id(ds->dst, lag); +- +- /* Read current port member */ +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); +- if (ret) +- return ret; +- +- /* Shift val to the correct trunk */ +- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); +- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; +- if (delete) +- val &= ~BIT(port); +- else +- val |= BIT(port); +- +- /* Update port member. With empty portmap disable trunk */ +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, +- QCA8K_REG_GOL_TRUNK_MEMBER(id) | +- QCA8K_REG_GOL_TRUNK_EN(id), +- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | +- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); +- +- /* Search empty member if adding or port on deleting */ +- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); +- if (ret) +- return ret; +- +- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; +- +- if (delete) { +- /* If port flagged to be disabled assume this member is +- * empty +- */ +- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; +- if (val != port) +- continue; +- } else { +- /* If port flagged to be enabled assume this member is +- * already set +- */ +- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- } +- +- /* We have found the member to add/remove */ +- break; +- } +- +- /* Set port in the correct port mask or disable port if in delete mode */ +- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), +- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | +- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); +-} +- +-static int +-qca8k_port_lag_join(struct dsa_switch *ds, int port, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- int ret; +- +- if (!qca8k_lag_can_offload(ds, lag, info)) +- return -EOPNOTSUPP; +- +- ret = qca8k_lag_setup_hash(ds, lag, info); +- if (ret) +- return ret; +- +- return qca8k_lag_refresh_portmap(ds, port, lag, false); +-} +- +-static int +-qca8k_port_lag_leave(struct dsa_switch *ds, int port, +- struct net_device *lag) +-{ +- return qca8k_lag_refresh_portmap(ds, port, lag, true); +-} +- +-static void +-qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, +- bool operational) +-{ +- struct dsa_port *dp = master->dsa_ptr; +- struct qca8k_priv *priv = ds->priv; +- +- /* Ethernet MIB/MDIO is only supported for CPU port 0 */ +- if (dp->index != 0) +- return; +- +- mutex_lock(&priv->mgmt_eth_data.mutex); +- mutex_lock(&priv->mib_eth_data.mutex); +- +- priv->mgmt_master = operational ? (struct net_device *)master : NULL; +- +- mutex_unlock(&priv->mib_eth_data.mutex); +- mutex_unlock(&priv->mgmt_eth_data.mutex); +-} +- +-static int qca8k_connect_tag_protocol(struct dsa_switch *ds, +- enum dsa_tag_protocol proto) +-{ +- struct qca_tagger_data *tagger_data; +- +- switch (proto) { +- case DSA_TAG_PROTO_QCA: +- tagger_data = ds->tagger_data; +- +- tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; +- tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; +- +- break; +- default: +- return -EOPNOTSUPP; +- } +- +- return 0; +-} +- +-static const struct dsa_switch_ops qca8k_switch_ops = { +- .get_tag_protocol = qca8k_get_tag_protocol, +- .setup = qca8k_setup, +- .get_strings = qca8k_get_strings, +- .get_ethtool_stats = qca8k_get_ethtool_stats, +- .get_sset_count = qca8k_get_sset_count, +- .set_ageing_time = qca8k_set_ageing_time, +- .get_mac_eee = qca8k_get_mac_eee, +- .set_mac_eee = qca8k_set_mac_eee, +- .port_enable = qca8k_port_enable, +- .port_disable = qca8k_port_disable, +- .port_change_mtu = qca8k_port_change_mtu, +- .port_max_mtu = qca8k_port_max_mtu, +- .port_stp_state_set = qca8k_port_stp_state_set, +- .port_bridge_join = qca8k_port_bridge_join, +- .port_bridge_leave = qca8k_port_bridge_leave, +- .port_fast_age = qca8k_port_fast_age, +- .port_fdb_add = qca8k_port_fdb_add, +- .port_fdb_del = qca8k_port_fdb_del, +- .port_fdb_dump = qca8k_port_fdb_dump, +- .port_mdb_add = qca8k_port_mdb_add, +- .port_mdb_del = qca8k_port_mdb_del, +- .port_mirror_add = qca8k_port_mirror_add, +- .port_mirror_del = qca8k_port_mirror_del, +- .port_vlan_filtering = qca8k_port_vlan_filtering, +- .port_vlan_add = qca8k_port_vlan_add, +- .port_vlan_del = qca8k_port_vlan_del, +- .phylink_validate = qca8k_phylink_validate, +- .phylink_mac_link_state = qca8k_phylink_mac_link_state, +- .phylink_mac_config = qca8k_phylink_mac_config, +- .phylink_mac_link_down = qca8k_phylink_mac_link_down, +- .phylink_mac_link_up = qca8k_phylink_mac_link_up, +- .get_phy_flags = qca8k_get_phy_flags, +- .port_lag_join = qca8k_port_lag_join, +- .port_lag_leave = qca8k_port_lag_leave, +- .master_state_change = qca8k_master_change, +- .connect_tag_protocol = qca8k_connect_tag_protocol, +-}; +- +-static int qca8k_read_switch_id(struct qca8k_priv *priv) +-{ +- const struct qca8k_match_data *data; +- u32 val; +- u8 id; +- int ret; +- +- /* get the switches ID from the compatible */ +- data = of_device_get_match_data(priv->dev); +- if (!data) +- return -ENODEV; +- +- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); +- if (ret < 0) +- return -ENODEV; +- +- id = QCA8K_MASK_CTRL_DEVICE_ID(val); +- if (id != data->id) { +- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); +- return -ENODEV; +- } +- +- priv->switch_id = id; +- +- /* Save revision to communicate to the internal PHY driver */ +- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); +- +- return 0; +-} +- +-static int +-qca8k_sw_probe(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv; +- int ret; +- +- /* allocate the private data struct so that we can probe the switches +- * ID register +- */ +- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->bus = mdiodev->bus; +- priv->dev = &mdiodev->dev; +- +- priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", +- GPIOD_ASIS); +- if (IS_ERR(priv->reset_gpio)) +- return PTR_ERR(priv->reset_gpio); +- +- if (priv->reset_gpio) { +- gpiod_set_value_cansleep(priv->reset_gpio, 1); +- /* The active low duration must be greater than 10 ms +- * and checkpatch.pl wants 20 ms. +- */ +- msleep(20); +- gpiod_set_value_cansleep(priv->reset_gpio, 0); +- } +- +- /* Start by setting up the register mapping */ +- priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, +- &qca8k_regmap_config); +- if (IS_ERR(priv->regmap)) { +- dev_err(priv->dev, "regmap initialization failed"); +- return PTR_ERR(priv->regmap); +- } +- +- priv->mdio_cache.page = 0xffff; +- priv->mdio_cache.lo = 0xffff; +- priv->mdio_cache.hi = 0xffff; +- +- /* Check the detected switch id */ +- ret = qca8k_read_switch_id(priv); +- if (ret) +- return ret; +- +- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); +- if (!priv->ds) +- return -ENOMEM; +- +- mutex_init(&priv->mgmt_eth_data.mutex); +- init_completion(&priv->mgmt_eth_data.rw_done); +- +- mutex_init(&priv->mib_eth_data.mutex); +- init_completion(&priv->mib_eth_data.rw_done); +- +- priv->ds->dev = &mdiodev->dev; +- priv->ds->num_ports = QCA8K_NUM_PORTS; +- priv->ds->priv = priv; +- priv->ds->ops = &qca8k_switch_ops; +- mutex_init(&priv->reg_mutex); +- dev_set_drvdata(&mdiodev->dev, priv); +- +- return dsa_register_switch(priv->ds); +-} +- +-static void +-qca8k_sw_remove(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); +- int i; +- +- if (!priv) +- return; +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) +- qca8k_port_set_status(priv, i, 0); +- +- dsa_unregister_switch(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-static void qca8k_sw_shutdown(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); +- +- if (!priv) +- return; +- +- dsa_switch_shutdown(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-#ifdef CONFIG_PM_SLEEP +-static void +-qca8k_set_pm(struct qca8k_priv *priv, int enable) +-{ +- int port; +- +- for (port = 0; port < QCA8K_NUM_PORTS; port++) { +- /* Do not enable on resume if the port was +- * disabled before. +- */ +- if (!(priv->port_enabled_map & BIT(port))) +- continue; +- +- qca8k_port_set_status(priv, port, enable); +- } +-} +- +-static int qca8k_suspend(struct device *dev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(dev); +- +- qca8k_set_pm(priv, 0); +- +- return dsa_switch_suspend(priv->ds); +-} +- +-static int qca8k_resume(struct device *dev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(dev); +- +- qca8k_set_pm(priv, 1); +- +- return dsa_switch_resume(priv->ds); +-} +-#endif /* CONFIG_PM_SLEEP */ +- +-static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, +- qca8k_suspend, qca8k_resume); +- +-static const struct qca8k_match_data qca8327 = { +- .id = QCA8K_ID_QCA8327, +- .reduced_package = true, +- .mib_count = QCA8K_QCA832X_MIB_COUNT, +-}; +- +-static const struct qca8k_match_data qca8328 = { +- .id = QCA8K_ID_QCA8327, +- .mib_count = QCA8K_QCA832X_MIB_COUNT, +-}; +- +-static const struct qca8k_match_data qca833x = { +- .id = QCA8K_ID_QCA8337, +- .mib_count = QCA8K_QCA833X_MIB_COUNT, +-}; +- +-static const struct of_device_id qca8k_of_match[] = { +- { .compatible = "qca,qca8327", .data = &qca8327 }, +- { .compatible = "qca,qca8328", .data = &qca8328 }, +- { .compatible = "qca,qca8334", .data = &qca833x }, +- { .compatible = "qca,qca8337", .data = &qca833x }, +- { /* sentinel */ }, +-}; +- +-static struct mdio_driver qca8kmdio_driver = { +- .probe = qca8k_sw_probe, +- .remove = qca8k_sw_remove, +- .shutdown = qca8k_sw_shutdown, +- .mdiodrv.driver = { +- .name = "qca8k", +- .of_match_table = qca8k_of_match, +- .pm = &qca8k_pm_ops, +- }, +-}; +- +-mdio_module_driver(qca8kmdio_driver); +- +-MODULE_AUTHOR("Mathieu Olivari, John Crispin "); +-MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); +-MODULE_LICENSE("GPL v2"); +-MODULE_ALIAS("platform:qca8k"); +--- a/drivers/net/dsa/qca8k.h ++++ /dev/null +@@ -1,411 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Copyright (C) 2009 Felix Fietkau +- * Copyright (C) 2011-2012 Gabor Juhos +- * Copyright (c) 2015, The Linux Foundation. All rights reserved. +- */ +- +-#ifndef __QCA8K_H +-#define __QCA8K_H +- +-#include +-#include +-#include +-#include +- +-#define QCA8K_ETHERNET_MDIO_PRIORITY 7 +-#define QCA8K_ETHERNET_PHY_PRIORITY 6 +-#define QCA8K_ETHERNET_TIMEOUT 100 +- +-#define QCA8K_NUM_PORTS 7 +-#define QCA8K_NUM_CPU_PORTS 2 +-#define QCA8K_MAX_MTU 9000 +-#define QCA8K_NUM_LAGS 4 +-#define QCA8K_NUM_PORTS_FOR_LAG 4 +- +-#define PHY_ID_QCA8327 0x004dd034 +-#define QCA8K_ID_QCA8327 0x12 +-#define PHY_ID_QCA8337 0x004dd036 +-#define QCA8K_ID_QCA8337 0x13 +- +-#define QCA8K_QCA832X_MIB_COUNT 39 +-#define QCA8K_QCA833X_MIB_COUNT 41 +- +-#define QCA8K_BUSY_WAIT_TIMEOUT 2000 +- +-#define QCA8K_NUM_FDB_RECORDS 2048 +- +-#define QCA8K_PORT_VID_DEF 1 +- +-/* Global control registers */ +-#define QCA8K_REG_MASK_CTRL 0x000 +-#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) +-#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) +-#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) +-#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) +-#define QCA8K_REG_PORT0_PAD_CTRL 0x004 +-#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) +-#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) +-#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) +-#define QCA8K_REG_PORT5_PAD_CTRL 0x008 +-#define QCA8K_REG_PORT6_PAD_CTRL 0x00c +-#define QCA8K_PORT_PAD_RGMII_EN BIT(26) +-#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) +-#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) +-#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) +-#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) +-#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) +-#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) +-#define QCA8K_PORT_PAD_SGMII_EN BIT(7) +-#define QCA8K_REG_PWS 0x010 +-#define QCA8K_PWS_POWER_ON_SEL BIT(31) +-/* This reg is only valid for QCA832x and toggle the package +- * type from 176 pin (by default) to 148 pin used on QCA8327 +- */ +-#define QCA8327_PWS_PACKAGE148_EN BIT(30) +-#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) +-#define QCA8K_PWS_SERDES_AEN_DIS BIT(7) +-#define QCA8K_REG_MODULE_EN 0x030 +-#define QCA8K_MODULE_EN_MIB BIT(0) +-#define QCA8K_REG_MIB 0x034 +-#define QCA8K_MIB_FUNC GENMASK(26, 24) +-#define QCA8K_MIB_CPU_KEEP BIT(20) +-#define QCA8K_MIB_BUSY BIT(17) +-#define QCA8K_MDIO_MASTER_CTRL 0x3c +-#define QCA8K_MDIO_MASTER_BUSY BIT(31) +-#define QCA8K_MDIO_MASTER_EN BIT(30) +-#define QCA8K_MDIO_MASTER_READ BIT(27) +-#define QCA8K_MDIO_MASTER_WRITE 0 +-#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) +-#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) +-#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) +-#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) +-#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) +-#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) +-#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) +-#define QCA8K_MDIO_MASTER_MAX_PORTS 5 +-#define QCA8K_MDIO_MASTER_MAX_REG 32 +-#define QCA8K_GOL_MAC_ADDR0 0x60 +-#define QCA8K_GOL_MAC_ADDR1 0x64 +-#define QCA8K_MAX_FRAME_SIZE 0x78 +-#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) +-#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) +-#define QCA8K_PORT_STATUS_SPEED_10 0 +-#define QCA8K_PORT_STATUS_SPEED_100 0x1 +-#define QCA8K_PORT_STATUS_SPEED_1000 0x2 +-#define QCA8K_PORT_STATUS_TXMAC BIT(2) +-#define QCA8K_PORT_STATUS_RXMAC BIT(3) +-#define QCA8K_PORT_STATUS_TXFLOW BIT(4) +-#define QCA8K_PORT_STATUS_RXFLOW BIT(5) +-#define QCA8K_PORT_STATUS_DUPLEX BIT(6) +-#define QCA8K_PORT_STATUS_LINK_UP BIT(8) +-#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) +-#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) +-#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) +-#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) +-#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) +-#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) +-#define QCA8K_PORT_HDR_CTRL_ALL 2 +-#define QCA8K_PORT_HDR_CTRL_MGMT 1 +-#define QCA8K_PORT_HDR_CTRL_NONE 0 +-#define QCA8K_REG_SGMII_CTRL 0x0e0 +-#define QCA8K_SGMII_EN_PLL BIT(1) +-#define QCA8K_SGMII_EN_RX BIT(2) +-#define QCA8K_SGMII_EN_TX BIT(3) +-#define QCA8K_SGMII_EN_SD BIT(4) +-#define QCA8K_SGMII_CLK125M_DELAY BIT(7) +-#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) +-#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) +-#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) +-#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) +-#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) +- +-/* MAC_PWR_SEL registers */ +-#define QCA8K_REG_MAC_PWR_SEL 0x0e4 +-#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) +-#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) +- +-/* EEE control registers */ +-#define QCA8K_REG_EEE_CTRL 0x100 +-#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) +- +-/* TRUNK_HASH_EN registers */ +-#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 +-#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) +-#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) +-#define QCA8K_TRUNK_HASH_SA_EN BIT(1) +-#define QCA8K_TRUNK_HASH_DA_EN BIT(0) +-#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) +- +-/* ACL registers */ +-#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) +-#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) +-#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) +-#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) +-#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) +-#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) +-#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 +-#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 +- +-/* Lookup registers */ +-#define QCA8K_REG_ATU_DATA0 0x600 +-#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) +-#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) +-#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) +-#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) +-#define QCA8K_REG_ATU_DATA1 0x604 +-#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) +-#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) +-#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) +-#define QCA8K_REG_ATU_DATA2 0x608 +-#define QCA8K_ATU_VID_MASK GENMASK(19, 8) +-#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) +-#define QCA8K_ATU_STATUS_STATIC 0xf +-#define QCA8K_REG_ATU_FUNC 0x60c +-#define QCA8K_ATU_FUNC_BUSY BIT(31) +-#define QCA8K_ATU_FUNC_PORT_EN BIT(14) +-#define QCA8K_ATU_FUNC_MULTI_EN BIT(13) +-#define QCA8K_ATU_FUNC_FULL BIT(12) +-#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) +-#define QCA8K_REG_VTU_FUNC0 0x610 +-#define QCA8K_VTU_FUNC0_VALID BIT(20) +-#define QCA8K_VTU_FUNC0_IVL_EN BIT(19) +-/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) +- * It does contain VLAN_MODE for each port [5:4] for port0, +- * [7:6] for port1 ... [17:16] for port6. Use virtual port +- * define to handle this. +- */ +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) +-#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +-#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +-#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +-#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +-#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) +-#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) +-#define QCA8K_REG_VTU_FUNC1 0x614 +-#define QCA8K_VTU_FUNC1_BUSY BIT(31) +-#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) +-#define QCA8K_VTU_FUNC1_FULL BIT(4) +-#define QCA8K_REG_ATU_CTRL 0x618 +-#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) +-#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) +-#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 +-#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) +-#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) +-#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 +-#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) +-#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) +-#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) +-#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) +-#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) +-#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) +-#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) +-#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) +-#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) +-#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) +-#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) +-#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) +-#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) +-#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) +-#define QCA8K_PORT_LOOKUP_LEARN BIT(20) +-#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) +- +-#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 +-/* 4 max trunk first +- * first 6 bit for member bitmap +- * 7th bit is to enable trunk port +- */ +-#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) +-#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) +-#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) +-#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) +-#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) +-/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ +-#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) +-#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) +-#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) +-/* Complex shift: FIRST shift for port THEN shift for trunk */ +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) +-#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) +- +-#define QCA8K_REG_GLOBAL_FC_THRESH 0x800 +-#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) +-#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) +-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) +-#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) +- +-#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) +-#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) +-#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) +- +-#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) +-#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) +-#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) +-#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) +-#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) +-#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) +-#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) +- +-/* Pkt edit registers */ +-#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) +-#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) +-#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) +-#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) +- +-/* L3 registers */ +-#define QCA8K_HROUTER_CONTROL 0xe00 +-#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16) +-#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16 +-#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1 +-#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08 +-#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c +-#define QCA8K_HNAT_CONTROL 0xe38 +- +-/* MIB registers */ +-#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100) +- +-/* QCA specific MII registers */ +-#define MII_ATH_MMD_ADDR 0x0d +-#define MII_ATH_MMD_DATA 0x0e +- +-enum { +- QCA8K_PORT_SPEED_10M = 0, +- QCA8K_PORT_SPEED_100M = 1, +- QCA8K_PORT_SPEED_1000M = 2, +- QCA8K_PORT_SPEED_ERR = 3, +-}; +- +-enum qca8k_fdb_cmd { +- QCA8K_FDB_FLUSH = 1, +- QCA8K_FDB_LOAD = 2, +- QCA8K_FDB_PURGE = 3, +- QCA8K_FDB_FLUSH_PORT = 5, +- QCA8K_FDB_NEXT = 6, +- QCA8K_FDB_SEARCH = 7, +-}; +- +-enum qca8k_vlan_cmd { +- QCA8K_VLAN_FLUSH = 1, +- QCA8K_VLAN_LOAD = 2, +- QCA8K_VLAN_PURGE = 3, +- QCA8K_VLAN_REMOVE_PORT = 4, +- QCA8K_VLAN_NEXT = 5, +- QCA8K_VLAN_READ = 6, +-}; +- +-enum qca8k_mid_cmd { +- QCA8K_MIB_FLUSH = 1, +- QCA8K_MIB_FLUSH_PORT = 2, +- QCA8K_MIB_CAST = 3, +-}; +- +-struct qca8k_match_data { +- u8 id; +- bool reduced_package; +- u8 mib_count; +-}; +- +-enum { +- QCA8K_CPU_PORT0, +- QCA8K_CPU_PORT6, +-}; +- +-struct qca8k_mgmt_eth_data { +- struct completion rw_done; +- struct mutex mutex; /* Enforce one mdio read/write at time */ +- bool ack; +- u32 seq; +- u32 data[4]; +-}; +- +-struct qca8k_mib_eth_data { +- struct completion rw_done; +- struct mutex mutex; /* Process one command at time */ +- refcount_t port_parsed; /* Counter to track parsed port */ +- u8 req_port; +- u64 *data; /* pointer to ethtool data */ +-}; +- +-struct qca8k_ports_config { +- bool sgmii_rx_clk_falling_edge; +- bool sgmii_tx_clk_falling_edge; +- bool sgmii_enable_pll; +- u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ +- u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ +-}; +- +-struct qca8k_mdio_cache { +-/* The 32bit switch registers are accessed indirectly. To achieve this we need +- * to set the page of the register. Track the last page that was set to reduce +- * mdio writes +- */ +- u16 page; +-/* lo and hi can also be cached and from Documentation we can skip one +- * extra mdio write if lo or hi is didn't change. +- */ +- u16 lo; +- u16 hi; +-}; +- +-struct qca8k_priv { +- u8 switch_id; +- u8 switch_revision; +- u8 mirror_rx; +- u8 mirror_tx; +- u8 lag_hash_mode; +- /* Each bit correspond to a port. This switch can support a max of 7 port. +- * Bit 1: port enabled. Bit 0: port disabled. +- */ +- u8 port_enabled_map; +- struct qca8k_ports_config ports_config; +- struct regmap *regmap; +- struct mii_bus *bus; +- struct dsa_switch *ds; +- struct mutex reg_mutex; +- struct device *dev; +- struct gpio_desc *reset_gpio; +- struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ +- struct qca8k_mgmt_eth_data mgmt_eth_data; +- struct qca8k_mib_eth_data mib_eth_data; +- struct qca8k_mdio_cache mdio_cache; +-}; +- +-struct qca8k_mib_desc { +- unsigned int size; +- unsigned int offset; +- const char *name; +-}; +- +-struct qca8k_fdb { +- u16 vid; +- u8 port_mask; +- u8 aging; +- u8 mac[6]; +-}; +- +-#endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch b/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch new file mode 100644 index 00000000000..77fe64632f4 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch @@ -0,0 +1,157 @@ +From 3bb0844e7bcd0fb0bcfab6202b5edd349ef5250a Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:10 +0200 +Subject: [PATCH 01/14] net: dsa: qca8k: cache match data to speed up access + +Using of_device_get_match_data is expensive. Cache match data to speed +up access and rework user of match data to use the new cached value. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k.c | 35 +++++++++++------------------------ + drivers/net/dsa/qca/qca8k.h | 1 + + 2 files changed, 12 insertions(+), 24 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k.c ++++ b/drivers/net/dsa/qca/qca8k.c +@@ -1462,8 +1462,8 @@ static int qca8k_find_cpu_port(struct ds + static int + qca8k_setup_of_pws_reg(struct qca8k_priv *priv) + { ++ const struct qca8k_match_data *data = priv->info; + struct device_node *node = priv->dev->of_node; +- const struct qca8k_match_data *data; + u32 val = 0; + int ret; + +@@ -1472,8 +1472,6 @@ qca8k_setup_of_pws_reg(struct qca8k_priv + * Should be applied by default but we set this just to make sure. + */ + if (priv->switch_id == QCA8K_ID_QCA8327) { +- data = of_device_get_match_data(priv->dev); +- + /* Set the correct package of 148 pin for QCA8327 */ + if (data->reduced_package) + val |= QCA8327_PWS_PACKAGE148_EN; +@@ -2146,23 +2144,19 @@ qca8k_phylink_mac_link_up(struct dsa_swi + static void + qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) + { +- const struct qca8k_match_data *match_data; + struct qca8k_priv *priv = ds->priv; + int i; + + if (stringset != ETH_SS_STATS) + return; + +- match_data = of_device_get_match_data(priv->dev); +- +- for (i = 0; i < match_data->mib_count; i++) ++ for (i = 0; i < priv->info->mib_count; i++) + strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, + ETH_GSTRING_LEN); + } + + static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) + { +- const struct qca8k_match_data *match_data; + struct qca8k_mib_eth_data *mib_eth_data; + struct qca8k_priv *priv = ds->priv; + const struct qca8k_mib_desc *mib; +@@ -2181,10 +2175,9 @@ static void qca8k_mib_autocast_handler(s + if (port != mib_eth_data->req_port) + goto exit; + +- match_data = device_get_match_data(priv->dev); + data = mib_eth_data->data; + +- for (i = 0; i < match_data->mib_count; i++) { ++ for (i = 0; i < priv->info->mib_count; i++) { + mib = &ar8327_mib[i]; + + /* First 3 mib are present in the skb head */ +@@ -2256,7 +2249,6 @@ qca8k_get_ethtool_stats(struct dsa_switc + uint64_t *data) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- const struct qca8k_match_data *match_data; + const struct qca8k_mib_desc *mib; + u32 reg, i, val; + u32 hi = 0; +@@ -2266,9 +2258,7 @@ qca8k_get_ethtool_stats(struct dsa_switc + qca8k_get_ethtool_stats_eth(ds, port, data) > 0) + return; + +- match_data = of_device_get_match_data(priv->dev); +- +- for (i = 0; i < match_data->mib_count; i++) { ++ for (i = 0; i < priv->info->mib_count; i++) { + mib = &ar8327_mib[i]; + reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; + +@@ -2291,15 +2281,12 @@ qca8k_get_ethtool_stats(struct dsa_switc + static int + qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) + { +- const struct qca8k_match_data *match_data; + struct qca8k_priv *priv = ds->priv; + + if (sset != ETH_SS_STATS) + return 0; + +- match_data = of_device_get_match_data(priv->dev); +- +- return match_data->mib_count; ++ return priv->info->mib_count; + } + + static int +@@ -3037,14 +3024,11 @@ static const struct dsa_switch_ops qca8k + + static int qca8k_read_switch_id(struct qca8k_priv *priv) + { +- const struct qca8k_match_data *data; + u32 val; + u8 id; + int ret; + +- /* get the switches ID from the compatible */ +- data = of_device_get_match_data(priv->dev); +- if (!data) ++ if (!priv->info) + return -ENODEV; + + ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); +@@ -3052,8 +3036,10 @@ static int qca8k_read_switch_id(struct q + return -ENODEV; + + id = QCA8K_MASK_CTRL_DEVICE_ID(val); +- if (id != data->id) { +- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); ++ if (id != priv->info->id) { ++ dev_err(priv->dev, ++ "Switch id detected %x but expected %x", ++ id, priv->info->id); + return -ENODEV; + } + +@@ -3078,6 +3064,7 @@ qca8k_sw_probe(struct mdio_device *mdiod + if (!priv) + return -ENOMEM; + ++ priv->info = of_device_get_match_data(priv->dev); + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; + +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -393,6 +393,7 @@ struct qca8k_priv { + struct qca8k_mgmt_eth_data mgmt_eth_data; + struct qca8k_mib_eth_data mib_eth_data; + struct qca8k_mdio_cache mdio_cache; ++ const struct qca8k_match_data *info; + }; + + struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch b/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch new file mode 100644 index 00000000000..5b2dce4c556 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch @@ -0,0 +1,77 @@ +From 533c64bca62a8654f00698bc893f639013e38c7b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:11 +0200 +Subject: [PATCH 02/14] net: dsa: qca8k: make mib autocast feature optional + +Some switch may not support mib autocast feature and require the legacy +way of reading the regs directly. +Make the mib autocast feature optional and permit to declare support for +it using match_data struct in a dedicated qca8k_info_ops struct. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k.c | 11 +++++++++-- + drivers/net/dsa/qca/qca8k.h | 5 +++++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k.c ++++ b/drivers/net/dsa/qca/qca8k.c +@@ -2254,8 +2254,8 @@ qca8k_get_ethtool_stats(struct dsa_switc + u32 hi = 0; + int ret; + +- if (priv->mgmt_master && +- qca8k_get_ethtool_stats_eth(ds, port, data) > 0) ++ if (priv->mgmt_master && priv->info->ops->autocast_mib && ++ priv->info->ops->autocast_mib(ds, port, data) > 0) + return; + + for (i = 0; i < priv->info->mib_count; i++) { +@@ -3187,20 +3187,27 @@ static int qca8k_resume(struct device *d + static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, + qca8k_suspend, qca8k_resume); + ++static const struct qca8k_info_ops qca8xxx_ops = { ++ .autocast_mib = qca8k_get_ethtool_stats_eth, ++}; ++ + static const struct qca8k_match_data qca8327 = { + .id = QCA8K_ID_QCA8327, + .reduced_package = true, + .mib_count = QCA8K_QCA832X_MIB_COUNT, ++ .ops = &qca8xxx_ops, + }; + + static const struct qca8k_match_data qca8328 = { + .id = QCA8K_ID_QCA8327, + .mib_count = QCA8K_QCA832X_MIB_COUNT, ++ .ops = &qca8xxx_ops, + }; + + static const struct qca8k_match_data qca833x = { + .id = QCA8K_ID_QCA8337, + .mib_count = QCA8K_QCA833X_MIB_COUNT, ++ .ops = &qca8xxx_ops, + }; + + static const struct of_device_id qca8k_of_match[] = { +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -324,10 +324,15 @@ enum qca8k_mid_cmd { + QCA8K_MIB_CAST = 3, + }; + ++struct qca8k_info_ops { ++ int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data); ++}; ++ + struct qca8k_match_data { + u8 id; + bool reduced_package; + u8 mib_count; ++ const struct qca8k_info_ops *ops; + }; + + enum { diff --git a/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch new file mode 100644 index 00000000000..afa466693a9 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch @@ -0,0 +1,6532 @@ +From 027152b830434e3632ad5dd678cc5d4740358dbb Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:12 +0200 +Subject: [PATCH 03/14] net: dsa: qca8k: move mib struct to common code + +The same MIB struct is used by drivers based on qca8k family switch. Move +it to common code to make it accessible also by other drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/Makefile | 1 + + drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} | 51 --------------- + drivers/net/dsa/qca/qca8k-common.c | 63 +++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 3 + + 4 files changed, 67 insertions(+), 51 deletions(-) + rename drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} (98%) + create mode 100644 drivers/net/dsa/qca/qca8k-common.c + +--- a/drivers/net/dsa/qca/Makefile ++++ b/drivers/net/dsa/qca/Makefile +@@ -1,3 +1,4 @@ + # SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o + obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o ++qca8k-y += qca8k-common.o qca8k-8xxx.o +--- a/drivers/net/dsa/qca/qca8k.c ++++ /dev/null +@@ -1,3237 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0 +-/* +- * Copyright (C) 2009 Felix Fietkau +- * Copyright (C) 2011-2012 Gabor Juhos +- * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. +- * Copyright (c) 2016 John Crispin +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "qca8k.h" +- +-#define MIB_DESC(_s, _o, _n) \ +- { \ +- .size = (_s), \ +- .offset = (_o), \ +- .name = (_n), \ +- } +- +-static const struct qca8k_mib_desc ar8327_mib[] = { +- MIB_DESC(1, 0x00, "RxBroad"), +- MIB_DESC(1, 0x04, "RxPause"), +- MIB_DESC(1, 0x08, "RxMulti"), +- MIB_DESC(1, 0x0c, "RxFcsErr"), +- MIB_DESC(1, 0x10, "RxAlignErr"), +- MIB_DESC(1, 0x14, "RxRunt"), +- MIB_DESC(1, 0x18, "RxFragment"), +- MIB_DESC(1, 0x1c, "Rx64Byte"), +- MIB_DESC(1, 0x20, "Rx128Byte"), +- MIB_DESC(1, 0x24, "Rx256Byte"), +- MIB_DESC(1, 0x28, "Rx512Byte"), +- MIB_DESC(1, 0x2c, "Rx1024Byte"), +- MIB_DESC(1, 0x30, "Rx1518Byte"), +- MIB_DESC(1, 0x34, "RxMaxByte"), +- MIB_DESC(1, 0x38, "RxTooLong"), +- MIB_DESC(2, 0x3c, "RxGoodByte"), +- MIB_DESC(2, 0x44, "RxBadByte"), +- MIB_DESC(1, 0x4c, "RxOverFlow"), +- MIB_DESC(1, 0x50, "Filtered"), +- MIB_DESC(1, 0x54, "TxBroad"), +- MIB_DESC(1, 0x58, "TxPause"), +- MIB_DESC(1, 0x5c, "TxMulti"), +- MIB_DESC(1, 0x60, "TxUnderRun"), +- MIB_DESC(1, 0x64, "Tx64Byte"), +- MIB_DESC(1, 0x68, "Tx128Byte"), +- MIB_DESC(1, 0x6c, "Tx256Byte"), +- MIB_DESC(1, 0x70, "Tx512Byte"), +- MIB_DESC(1, 0x74, "Tx1024Byte"), +- MIB_DESC(1, 0x78, "Tx1518Byte"), +- MIB_DESC(1, 0x7c, "TxMaxByte"), +- MIB_DESC(1, 0x80, "TxOverSize"), +- MIB_DESC(2, 0x84, "TxByte"), +- MIB_DESC(1, 0x8c, "TxCollision"), +- MIB_DESC(1, 0x90, "TxAbortCol"), +- MIB_DESC(1, 0x94, "TxMultiCol"), +- MIB_DESC(1, 0x98, "TxSingleCol"), +- MIB_DESC(1, 0x9c, "TxExcDefer"), +- MIB_DESC(1, 0xa0, "TxDefer"), +- MIB_DESC(1, 0xa4, "TxLateCol"), +- MIB_DESC(1, 0xa8, "RXUnicast"), +- MIB_DESC(1, 0xac, "TXUnicast"), +-}; +- +-static void +-qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) +-{ +- regaddr >>= 1; +- *r1 = regaddr & 0x1e; +- +- regaddr >>= 5; +- *r2 = regaddr & 0x7; +- +- regaddr >>= 3; +- *page = regaddr & 0x3ff; +-} +- +-static int +-qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) +-{ +- u16 *cached_lo = &priv->mdio_cache.lo; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (lo == *cached_lo) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, lo); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit lo register\n"); +- +- *cached_lo = lo; +- return 0; +-} +- +-static int +-qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) +-{ +- u16 *cached_hi = &priv->mdio_cache.hi; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (hi == *cached_hi) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, hi); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit hi register\n"); +- +- *cached_hi = hi; +- return 0; +-} +- +-static int +-qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) +-{ +- int ret; +- +- ret = bus->read(bus, phy_id, regnum); +- if (ret >= 0) { +- *val = ret; +- ret = bus->read(bus, phy_id, regnum + 1); +- *val |= ret << 16; +- } +- +- if (ret < 0) { +- dev_err_ratelimited(&bus->dev, +- "failed to read qca8k 32bit register\n"); +- *val = 0; +- return ret; +- } +- +- return 0; +-} +- +-static void +-qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) +-{ +- u16 lo, hi; +- int ret; +- +- lo = val & 0xffff; +- hi = (u16)(val >> 16); +- +- ret = qca8k_set_lo(priv, phy_id, regnum, lo); +- if (ret >= 0) +- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); +-} +- +-static int +-qca8k_set_page(struct qca8k_priv *priv, u16 page) +-{ +- u16 *cached_page = &priv->mdio_cache.page; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (page == *cached_page) +- return 0; +- +- ret = bus->write(bus, 0x18, 0, page); +- if (ret < 0) { +- dev_err_ratelimited(&bus->dev, +- "failed to set qca8k page\n"); +- return ret; +- } +- +- *cached_page = page; +- usleep_range(1000, 2000); +- return 0; +-} +- +-static int +-qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) +-{ +- return regmap_read(priv->regmap, reg, val); +-} +- +-static int +-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) +-{ +- return regmap_write(priv->regmap, reg, val); +-} +- +-static int +-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +-{ +- return regmap_update_bits(priv->regmap, reg, mask, write_val); +-} +- +-static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data; +- struct qca8k_priv *priv = ds->priv; +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- u8 len, cmd; +- +- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); +- mgmt_eth_data = &priv->mgmt_eth_data; +- +- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); +- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); +- +- /* Make sure the seq match the requested packet */ +- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) +- mgmt_eth_data->ack = true; +- +- if (cmd == MDIO_READ) { +- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; +- +- /* Get the rest of the 12 byte of data. +- * The read/write function will extract the requested data. +- */ +- if (len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(mgmt_eth_data->data + 1, skb->data, +- QCA_HDR_MGMT_DATA2_LEN); +- } +- +- complete(&mgmt_eth_data->rw_done); +-} +- +-static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, +- int priority, unsigned int len) +-{ +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- unsigned int real_len; +- struct sk_buff *skb; +- u32 *data2; +- u16 hdr; +- +- skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); +- if (!skb) +- return NULL; +- +- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte +- * Actually for some reason the steps are: +- * 0: nothing +- * 1-4: first 4 byte +- * 5-6: first 12 byte +- * 7-15: all 16 byte +- */ +- if (len == 16) +- real_len = 15; +- else +- real_len = len; +- +- skb_reset_mac_header(skb); +- skb_set_network_header(skb, skb->len); +- +- mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); +- +- hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); +- hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); +- hdr |= QCA_HDR_XMIT_FROM_CPU; +- hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); +- hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); +- +- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, +- QCA_HDR_MGMT_CHECK_CODE_VAL); +- +- if (cmd == MDIO_WRITE) +- mgmt_ethhdr->mdio_data = *val; +- +- mgmt_ethhdr->hdr = htons(hdr); +- +- data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); +- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); +- +- return skb; +-} +- +-static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) +-{ +- struct qca_mgmt_ethhdr *mgmt_ethhdr; +- +- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; +- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); +-} +- +-static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; +- struct sk_buff *skb; +- bool ack; +- int ret; +- +- skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, +- QCA8K_ETHERNET_MDIO_PRIORITY, len); +- if (!skb) +- return -ENOMEM; +- +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check mgmt_master if is operational */ +- if (!priv->mgmt_master) { +- kfree_skb(skb); +- mutex_unlock(&mgmt_eth_data->mutex); +- return -EINVAL; +- } +- +- skb->dev = priv->mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the mdio pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); +- +- *val = mgmt_eth_data->data[0]; +- if (len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); +- +- ack = mgmt_eth_data->ack; +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- return 0; +-} +- +-static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; +- struct sk_buff *skb; +- bool ack; +- int ret; +- +- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, +- QCA8K_ETHERNET_MDIO_PRIORITY, len); +- if (!skb) +- return -ENOMEM; +- +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check mgmt_master if is operational */ +- if (!priv->mgmt_master) { +- kfree_skb(skb); +- mutex_unlock(&mgmt_eth_data->mutex); +- return -EINVAL; +- } +- +- skb->dev = priv->mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the mdio pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); +- +- ack = mgmt_eth_data->ack; +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- return 0; +-} +- +-static int +-qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +-{ +- u32 val = 0; +- int ret; +- +- ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); +- if (ret) +- return ret; +- +- val &= ~mask; +- val |= write_val; +- +- return qca8k_write_eth(priv, reg, &val, sizeof(val)); +-} +- +-static int +-qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- +- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int +-qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- u32 tmp; +- +- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- tmp = val[i]; +- +- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int +-qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- int ret; +- +- if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- return ret; +-} +- +-static int +-qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- int ret; +- +- if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- return ret; +-} +- +-static int +-qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) +- return 0; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); +- if (ret < 0) +- goto exit; +- +- val &= ~mask; +- val |= write_val; +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +-exit: +- mutex_unlock(&bus->mdio_lock); +- +- return ret; +-} +- +-static const struct regmap_range qca8k_readable_ranges[] = { +- regmap_reg_range(0x0000, 0x00e4), /* Global control */ +- regmap_reg_range(0x0100, 0x0168), /* EEE control */ +- regmap_reg_range(0x0200, 0x0270), /* Parser control */ +- regmap_reg_range(0x0400, 0x0454), /* ACL */ +- regmap_reg_range(0x0600, 0x0718), /* Lookup */ +- regmap_reg_range(0x0800, 0x0b70), /* QM */ +- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ +- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ +- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ +- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ +- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ +- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ +- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ +- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ +- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ +- +-}; +- +-static const struct regmap_access_table qca8k_readable_table = { +- .yes_ranges = qca8k_readable_ranges, +- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), +-}; +- +-static struct regmap_config qca8k_regmap_config = { +- .reg_bits = 16, +- .val_bits = 32, +- .reg_stride = 4, +- .max_register = 0x16ac, /* end MIB - Port6 range */ +- .reg_read = qca8k_regmap_read, +- .reg_write = qca8k_regmap_write, +- .reg_update_bits = qca8k_regmap_update_bits, +- .rd_table = &qca8k_readable_table, +- .disable_locking = true, /* Locking is handled by qca8k read/write */ +- .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ +-}; +- +-static int +-qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) +-{ +- u32 val; +- +- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); +-} +- +-static int +-qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) +-{ +- u32 reg[3]; +- int ret; +- +- /* load the ARL table into an array */ +- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +- if (ret) +- return ret; +- +- /* vid - 83:72 */ +- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); +- /* aging - 67:64 */ +- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); +- /* portmask - 54:48 */ +- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); +- /* mac - 47:0 */ +- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); +- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); +- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); +- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); +- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); +- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); +- +- return 0; +-} +- +-static void +-qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, +- u8 aging) +-{ +- u32 reg[3] = { 0 }; +- +- /* vid - 83:72 */ +- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); +- /* aging - 67:64 */ +- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); +- /* portmask - 54:48 */ +- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); +- /* mac - 47:0 */ +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); +- +- /* load the array into the ARL table */ +- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +-} +- +-static int +-qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and FDB index */ +- reg = QCA8K_ATU_FUNC_BUSY; +- reg |= cmd; +- if (port >= 0) { +- reg |= QCA8K_ATU_FUNC_PORT_EN; +- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); +- } +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_FDB_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_ATU_FUNC_FULL) +- return -1; +- } +- +- return 0; +-} +- +-static int +-qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) +-{ +- int ret; +- +- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); +- if (ret < 0) +- return ret; +- +- return qca8k_fdb_read(priv, fdb); +-} +- +-static int +-qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, +- u16 vid, u8 aging) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static void +-qca8k_fdb_flush(struct qca8k_priv *priv) +-{ +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_fdb_read(priv, &fdb); +- if (ret < 0) +- goto exit; +- +- /* Rule exist. Delete first */ +- if (!fdb.aging) { +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- } +- +- /* Add port to fdb portmask */ +- fdb.port_mask |= port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- /* Rule doesn't exist. Why delete? */ +- if (!fdb.aging) { +- ret = -EINVAL; +- goto exit; +- } +- +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- +- /* Only port in the rule is this port. Don't re insert */ +- if (fdb.port_mask == port_mask) +- goto exit; +- +- /* Remove port from port mask */ +- fdb.port_mask &= ~port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and VLAN index */ +- reg = QCA8K_VTU_FUNC1_BUSY; +- reg |= cmd; +- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_VLAN_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_VTU_FUNC1_FULL) +- return -ENOMEM; +- } +- +- return 0; +-} +- +-static int +-qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) +-{ +- u32 reg; +- int ret; +- +- /* +- We do the right thing with VLAN 0 and treat it as untagged while +- preserving the tag on egress. +- */ +- if (vid == 0) +- return 0; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- if (untagged) +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); +- else +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); +- +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) +-{ +- u32 reg, mask; +- int ret, i; +- bool del; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); +- +- /* Check if we're the last member to be removed */ +- del = true; +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); +- +- if ((reg & mask) != mask) { +- del = false; +- break; +- } +- } +- +- if (del) { +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); +- } else { +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- } +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_mib_init(struct qca8k_priv *priv) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, +- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, +- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | +- QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); +- if (ret) +- goto exit; +- +- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static void +-qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) +-{ +- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; +- +- /* Port 0 and 6 have no internal PHY */ +- if (port > 0 && port < 6) +- mask |= QCA8K_PORT_STATUS_LINK_AUTO; +- +- if (enable) +- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +- else +- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +-} +- +-static int +-qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, +- struct sk_buff *read_skb, u32 *val) +-{ +- struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); +- bool ack; +- int ret; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the copy pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) +- return -ETIMEDOUT; +- +- if (!ack) +- return -EINVAL; +- +- *val = mgmt_eth_data->data[0]; +- +- return 0; +-} +- +-static int +-qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, +- int regnum, u16 data) +-{ +- struct sk_buff *write_skb, *clear_skb, *read_skb; +- struct qca8k_mgmt_eth_data *mgmt_eth_data; +- u32 write_val, clear_val = 0, val; +- struct net_device *mgmt_master; +- int ret, ret1; +- bool ack; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- mgmt_eth_data = &priv->mgmt_eth_data; +- +- write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum); +- +- if (read) { +- write_val |= QCA8K_MDIO_MASTER_READ; +- } else { +- write_val |= QCA8K_MDIO_MASTER_WRITE; +- write_val |= QCA8K_MDIO_MASTER_DATA(data); +- } +- +- /* Prealloc all the needed skb before the lock */ +- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); +- if (!write_skb) +- return -ENOMEM; +- +- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); +- if (!clear_skb) { +- ret = -ENOMEM; +- goto err_clear_skb; +- } +- +- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, +- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); +- if (!read_skb) { +- ret = -ENOMEM; +- goto err_read_skb; +- } +- +- /* Actually start the request: +- * 1. Send mdio master packet +- * 2. Busy Wait for mdio master command +- * 3. Get the data if we are reading +- * 4. Reset the mdio master (even with error) +- */ +- mutex_lock(&mgmt_eth_data->mutex); +- +- /* Check if mgmt_master is operational */ +- mgmt_master = priv->mgmt_master; +- if (!mgmt_master) { +- mutex_unlock(&mgmt_eth_data->mutex); +- ret = -EINVAL; +- goto err_mgmt_master; +- } +- +- read_skb->dev = mgmt_master; +- clear_skb->dev = mgmt_master; +- write_skb->dev = mgmt_master; +- +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the write pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(write_skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) { +- ret = -ETIMEDOUT; +- kfree_skb(read_skb); +- goto exit; +- } +- +- if (!ack) { +- ret = -EINVAL; +- kfree_skb(read_skb); +- goto exit; +- } +- +- ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, +- !(val & QCA8K_MDIO_MASTER_BUSY), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- mgmt_eth_data, read_skb, &val); +- +- if (ret < 0 && ret1 < 0) { +- ret = ret1; +- goto exit; +- } +- +- if (read) { +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the read pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(read_skb); +- +- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- ack = mgmt_eth_data->ack; +- +- if (ret <= 0) { +- ret = -ETIMEDOUT; +- goto exit; +- } +- +- if (!ack) { +- ret = -EINVAL; +- goto exit; +- } +- +- ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; +- } else { +- kfree_skb(read_skb); +- } +-exit: +- reinit_completion(&mgmt_eth_data->rw_done); +- +- /* Increment seq_num and set it in the clear pkt */ +- mgmt_eth_data->seq++; +- qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); +- mgmt_eth_data->ack = false; +- +- dev_queue_xmit(clear_skb); +- +- wait_for_completion_timeout(&mgmt_eth_data->rw_done, +- QCA8K_ETHERNET_TIMEOUT); +- +- mutex_unlock(&mgmt_eth_data->mutex); +- +- return ret; +- +- /* Error handling before lock */ +-err_mgmt_master: +- kfree_skb(read_skb); +-err_read_skb: +- kfree_skb(clear_skb); +-err_clear_skb: +- kfree_skb(write_skb); +- +- return ret; +-} +- +-static u32 +-qca8k_port_to_phy(int port) +-{ +- /* From Andrew Lunn: +- * Port 0 has no internal phy. +- * Port 1 has an internal PHY at MDIO address 0. +- * Port 2 has an internal PHY at MDIO address 1. +- * ... +- * Port 5 has an internal PHY at MDIO address 4. +- * Port 6 has no internal PHY. +- */ +- +- return port - 1; +-} +- +-static int +-qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) +-{ +- u16 r1, r2, page; +- u32 val; +- int ret, ret1; +- +- qca8k_split_addr(reg, &r1, &r2, &page); +- +- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- bus, 0x10 | r2, r1, &val); +- +- /* Check if qca8k_read has failed for a different reason +- * before returnting -ETIMEDOUT +- */ +- if (ret < 0 && ret1 < 0) +- return ret1; +- +- return ret; +-} +- +-static int +-qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) +-{ +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum) | +- QCA8K_MDIO_MASTER_DATA(data); +- +- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_BUSY); +- +-exit: +- /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +- +- mutex_unlock(&bus->mdio_lock); +- +- return ret; +-} +- +-static int +-qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) +-{ +- struct mii_bus *bus = priv->bus; +- u16 r1, r2, page; +- u32 val; +- int ret; +- +- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) +- return -EINVAL; +- +- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | +- QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | +- QCA8K_MDIO_MASTER_REG_ADDR(regnum); +- +- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); +- +- ret = qca8k_set_page(priv, page); +- if (ret) +- goto exit; +- +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); +- +- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_BUSY); +- if (ret) +- goto exit; +- +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); +- +-exit: +- /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); +- +- mutex_unlock(&bus->mdio_lock); +- +- if (ret >= 0) +- ret = val & QCA8K_MDIO_MASTER_DATA_MASK; +- +- return ret; +-} +- +-static int +-qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) +-{ +- struct qca8k_priv *priv = slave_bus->priv; +- int ret; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); +- if (!ret) +- return 0; +- +- return qca8k_mdio_write(priv, phy, regnum, data); +-} +- +-static int +-qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) +-{ +- struct qca8k_priv *priv = slave_bus->priv; +- int ret; +- +- /* Use mdio Ethernet when available, fallback to legacy one on error */ +- ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); +- if (ret >= 0) +- return ret; +- +- ret = qca8k_mdio_read(priv, phy, regnum); +- +- if (ret < 0) +- return 0xffff; +- +- return ret; +-} +- +-static int +-qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) +-{ +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- return qca8k_internal_mdio_write(slave_bus, port, regnum, data); +-} +- +-static int +-qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) +-{ +- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; +- +- return qca8k_internal_mdio_read(slave_bus, port, regnum); +-} +- +-static int +-qca8k_mdio_register(struct qca8k_priv *priv) +-{ +- struct dsa_switch *ds = priv->ds; +- struct device_node *mdio; +- struct mii_bus *bus; +- +- bus = devm_mdiobus_alloc(ds->dev); +- if (!bus) +- return -ENOMEM; +- +- bus->priv = (void *)priv; +- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", +- ds->dst->index, ds->index); +- bus->parent = ds->dev; +- bus->phy_mask = ~ds->phys_mii_mask; +- ds->slave_mii_bus = bus; +- +- /* Check if the devicetree declare the port:phy mapping */ +- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); +- if (of_device_is_available(mdio)) { +- bus->name = "qca8k slave mii"; +- bus->read = qca8k_internal_mdio_read; +- bus->write = qca8k_internal_mdio_write; +- return devm_of_mdiobus_register(priv->dev, bus, mdio); +- } +- +- /* If a mapping can't be found the legacy mapping is used, +- * using the qca8k_port_to_phy function +- */ +- bus->name = "qca8k-legacy slave mii"; +- bus->read = qca8k_legacy_mdio_read; +- bus->write = qca8k_legacy_mdio_write; +- return devm_mdiobus_register(priv->dev, bus); +-} +- +-static int +-qca8k_setup_mdio_bus(struct qca8k_priv *priv) +-{ +- u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; +- struct device_node *ports, *port; +- phy_interface_t mode; +- int err; +- +- ports = of_get_child_by_name(priv->dev->of_node, "ports"); +- if (!ports) +- ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); +- +- if (!ports) +- return -EINVAL; +- +- for_each_available_child_of_node(ports, port) { +- err = of_property_read_u32(port, "reg", ®); +- if (err) { +- of_node_put(port); +- of_node_put(ports); +- return err; +- } +- +- if (!dsa_is_user_port(priv->ds, reg)) +- continue; +- +- of_get_phy_mode(port, &mode); +- +- if (of_property_read_bool(port, "phy-handle") && +- mode != PHY_INTERFACE_MODE_INTERNAL) +- external_mdio_mask |= BIT(reg); +- else +- internal_mdio_mask |= BIT(reg); +- } +- +- of_node_put(ports); +- if (!external_mdio_mask && !internal_mdio_mask) { +- dev_err(priv->dev, "no PHYs are defined.\n"); +- return -EINVAL; +- } +- +- /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through +- * the MDIO_MASTER register also _disconnects_ the external MDC +- * passthrough to the internal PHYs. It's not possible to use both +- * configurations at the same time! +- * +- * Because this came up during the review process: +- * If the external mdio-bus driver is capable magically disabling +- * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's +- * accessors for the time being, it would be possible to pull this +- * off. +- */ +- if (!!external_mdio_mask && !!internal_mdio_mask) { +- dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); +- return -EINVAL; +- } +- +- if (external_mdio_mask) { +- /* Make sure to disable the internal mdio bus in cases +- * a dt-overlay and driver reload changed the configuration +- */ +- +- return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, +- QCA8K_MDIO_MASTER_EN); +- } +- +- return qca8k_mdio_register(priv); +-} +- +-static int +-qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) +-{ +- u32 mask = 0; +- int ret = 0; +- +- /* SoC specific settings for ipq8064. +- * If more device require this consider adding +- * a dedicated binding. +- */ +- if (of_machine_is_compatible("qcom,ipq8064")) +- mask |= QCA8K_MAC_PWR_RGMII0_1_8V; +- +- /* SoC specific settings for ipq8065 */ +- if (of_machine_is_compatible("qcom,ipq8065")) +- mask |= QCA8K_MAC_PWR_RGMII1_1_8V; +- +- if (mask) { +- ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, +- QCA8K_MAC_PWR_RGMII0_1_8V | +- QCA8K_MAC_PWR_RGMII1_1_8V, +- mask); +- } +- +- return ret; +-} +- +-static int qca8k_find_cpu_port(struct dsa_switch *ds) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- /* Find the connected cpu port. Valid port are 0 or 6 */ +- if (dsa_is_cpu_port(ds, 0)) +- return 0; +- +- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); +- +- if (dsa_is_cpu_port(ds, 6)) +- return 6; +- +- return -EINVAL; +-} +- +-static int +-qca8k_setup_of_pws_reg(struct qca8k_priv *priv) +-{ +- const struct qca8k_match_data *data = priv->info; +- struct device_node *node = priv->dev->of_node; +- u32 val = 0; +- int ret; +- +- /* QCA8327 require to set to the correct mode. +- * His bigger brother QCA8328 have the 172 pin layout. +- * Should be applied by default but we set this just to make sure. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- /* Set the correct package of 148 pin for QCA8327 */ +- if (data->reduced_package) +- val |= QCA8327_PWS_PACKAGE148_EN; +- +- ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, +- val); +- if (ret) +- return ret; +- } +- +- if (of_property_read_bool(node, "qca,ignore-power-on-sel")) +- val |= QCA8K_PWS_POWER_ON_SEL; +- +- if (of_property_read_bool(node, "qca,led-open-drain")) { +- if (!(val & QCA8K_PWS_POWER_ON_SEL)) { +- dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); +- return -EINVAL; +- } +- +- val |= QCA8K_PWS_LED_OPEN_EN_CSR; +- } +- +- return qca8k_rmw(priv, QCA8K_REG_PWS, +- QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, +- val); +-} +- +-static int +-qca8k_parse_port_config(struct qca8k_priv *priv) +-{ +- int port, cpu_port_index = -1, ret; +- struct device_node *port_dn; +- phy_interface_t mode; +- struct dsa_port *dp; +- u32 delay; +- +- /* We have 2 CPU port. Check them */ +- for (port = 0; port < QCA8K_NUM_PORTS; port++) { +- /* Skip every other port */ +- if (port != 0 && port != 6) +- continue; +- +- dp = dsa_to_port(priv->ds, port); +- port_dn = dp->dn; +- cpu_port_index++; +- +- if (!of_device_is_available(port_dn)) +- continue; +- +- ret = of_get_phy_mode(port_dn, &mode); +- if (ret) +- continue; +- +- switch (mode) { +- case PHY_INTERFACE_MODE_RGMII: +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_TXID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- case PHY_INTERFACE_MODE_SGMII: +- delay = 0; +- +- if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) +- /* Switch regs accept value in ns, convert ps to ns */ +- delay = delay / 1000; +- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_TXID) +- delay = 1; +- +- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { +- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); +- delay = 3; +- } +- +- priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; +- +- delay = 0; +- +- if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) +- /* Switch regs accept value in ns, convert ps to ns */ +- delay = delay / 1000; +- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_RXID) +- delay = 2; +- +- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { +- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); +- delay = 3; +- } +- +- priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; +- +- /* Skip sgmii parsing for rgmii* mode */ +- if (mode == PHY_INTERFACE_MODE_RGMII || +- mode == PHY_INTERFACE_MODE_RGMII_ID || +- mode == PHY_INTERFACE_MODE_RGMII_TXID || +- mode == PHY_INTERFACE_MODE_RGMII_RXID) +- break; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) +- priv->ports_config.sgmii_tx_clk_falling_edge = true; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) +- priv->ports_config.sgmii_rx_clk_falling_edge = true; +- +- if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { +- priv->ports_config.sgmii_enable_pll = true; +- +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); +- priv->ports_config.sgmii_enable_pll = false; +- } +- +- if (priv->switch_revision < 2) +- dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); +- } +- +- break; +- default: +- continue; +- } +- } +- +- return 0; +-} +- +-static int +-qca8k_setup(struct dsa_switch *ds) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int cpu_port, ret, i; +- u32 mask; +- +- cpu_port = qca8k_find_cpu_port(ds); +- if (cpu_port < 0) { +- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); +- return cpu_port; +- } +- +- /* Parse CPU port config to be later used in phy_link mac_config */ +- ret = qca8k_parse_port_config(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_mdio_bus(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_of_pws_reg(priv); +- if (ret) +- return ret; +- +- ret = qca8k_setup_mac_pwr_sel(priv); +- if (ret) +- return ret; +- +- /* Make sure MAC06 is disabled */ +- ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, +- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); +- if (ret) { +- dev_err(priv->dev, "failed disabling MAC06 exchange"); +- return ret; +- } +- +- /* Enable CPU Port */ +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); +- if (ret) { +- dev_err(priv->dev, "failed enabling CPU port"); +- return ret; +- } +- +- /* Enable MIB counters */ +- ret = qca8k_mib_init(priv); +- if (ret) +- dev_warn(priv->dev, "mib init failed"); +- +- /* Initial setup of all ports */ +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- /* Disable forwarding by default on all ports */ +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, 0); +- if (ret) +- return ret; +- +- /* Enable QCA header mode on all cpu ports */ +- if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), +- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | +- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); +- if (ret) { +- dev_err(priv->dev, "failed enabling QCA header mode"); +- return ret; +- } +- } +- +- /* Disable MAC by default on all user ports */ +- if (dsa_is_user_port(ds, i)) +- qca8k_port_set_status(priv, i, 0); +- } +- +- /* Forward all unknown frames to CPU port for Linux processing +- * Notice that in multi-cpu config only one port should be set +- * for igmp, unknown, multicast and broadcast packet +- */ +- ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | +- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); +- if (ret) +- return ret; +- +- /* Setup connection between CPU port & user ports +- * Configure specific switch configuration for ports +- */ +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- /* CPU port gets connected to all user ports of the switch */ +- if (dsa_is_cpu_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); +- if (ret) +- return ret; +- } +- +- /* Individual user ports get connected to CPU port only */ +- if (dsa_is_user_port(ds, i)) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_MEMBER, +- BIT(cpu_port)); +- if (ret) +- return ret; +- +- /* Enable ARP Auto-learning by default */ +- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), +- QCA8K_PORT_LOOKUP_LEARN); +- if (ret) +- return ret; +- +- /* For port based vlans to work we need to set the +- * default egress vid +- */ +- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), +- QCA8K_EGREES_VLAN_PORT_MASK(i), +- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); +- if (ret) +- return ret; +- +- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), +- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | +- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); +- if (ret) +- return ret; +- } +- +- /* The port 5 of the qca8337 have some problem in flood condition. The +- * original legacy driver had some specific buffer and priority settings +- * for the different port suggested by the QCA switch team. Add this +- * missing settings to improve switch stability under load condition. +- * This problem is limited to qca8337 and other qca8k switch are not affected. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8337) { +- switch (i) { +- /* The 2 CPU port and port 5 requires some different +- * priority than any other ports. +- */ +- case 0: +- case 5: +- case 6: +- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | +- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); +- break; +- default: +- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | +- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | +- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); +- } +- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); +- +- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | +- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_WRED_EN; +- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), +- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | +- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | +- QCA8K_PORT_HOL_CTRL1_WRED_EN, +- mask); +- } +- } +- +- /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ +- if (priv->switch_id == QCA8K_ID_QCA8327) { +- mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | +- QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); +- qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, +- QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | +- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, +- mask); +- } +- +- /* Setup our port MTUs to match power on defaults */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); +- if (ret) +- dev_warn(priv->dev, "failed setting MTU settings"); +- +- /* Flush the FDB table */ +- qca8k_fdb_flush(priv); +- +- /* We don't have interrupts for link changes, so we need to poll */ +- ds->pcs_poll = true; +- +- /* Set min a max ageing value supported */ +- ds->ageing_time_min = 7000; +- ds->ageing_time_max = 458745000; +- +- /* Set max number of LAGs supported */ +- ds->num_lag_ids = QCA8K_NUM_LAGS; +- +- return 0; +-} +- +-static void +-qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, +- u32 reg) +-{ +- u32 delay, val = 0; +- int ret; +- +- /* Delay can be declared in 3 different way. +- * Mode to rgmii and internal-delay standard binding defined +- * rgmii-id or rgmii-tx/rx phy mode set. +- * The parse logic set a delay different than 0 only when one +- * of the 3 different way is used. In all other case delay is +- * not enabled. With ID or TX/RXID delay is enabled and set +- * to the default and recommended value. +- */ +- if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { +- delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; +- } +- +- if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { +- delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; +- +- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; +- } +- +- /* Set RGMII delay based on the selected values */ +- ret = qca8k_rmw(priv, reg, +- QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | +- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, +- val); +- if (ret) +- dev_err(priv->dev, "Failed to set internal delay for CPU port%d", +- cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); +-} +- +-static void +-qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, +- const struct phylink_link_state *state) +-{ +- struct qca8k_priv *priv = ds->priv; +- int cpu_port_index, ret; +- u32 reg, val; +- +- switch (port) { +- case 0: /* 1st CPU port */ +- if (state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII) +- return; +- +- reg = QCA8K_REG_PORT0_PAD_CTRL; +- cpu_port_index = QCA8K_CPU_PORT0; +- break; +- case 1: +- case 2: +- case 3: +- case 4: +- case 5: +- /* Internal PHY, nothing to do */ +- return; +- case 6: /* 2nd CPU port / external PHY */ +- if (state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII && +- state->interface != PHY_INTERFACE_MODE_1000BASEX) +- return; +- +- reg = QCA8K_REG_PORT6_PAD_CTRL; +- cpu_port_index = QCA8K_CPU_PORT6; +- break; +- default: +- dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); +- return; +- } +- +- if (port != 6 && phylink_autoneg_inband(mode)) { +- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", +- __func__); +- return; +- } +- +- switch (state->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- case PHY_INTERFACE_MODE_RGMII_ID: +- case PHY_INTERFACE_MODE_RGMII_TXID: +- case PHY_INTERFACE_MODE_RGMII_RXID: +- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); +- +- /* Configure rgmii delay */ +- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +- +- /* QCA8337 requires to set rgmii rx delay for all ports. +- * This is enabled through PORT5_PAD_CTRL for all ports, +- * rather than individual port registers. +- */ +- if (priv->switch_id == QCA8K_ID_QCA8337) +- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, +- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); +- break; +- case PHY_INTERFACE_MODE_SGMII: +- case PHY_INTERFACE_MODE_1000BASEX: +- /* Enable SGMII on the port */ +- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); +- +- /* Enable/disable SerDes auto-negotiation as necessary */ +- ret = qca8k_read(priv, QCA8K_REG_PWS, &val); +- if (ret) +- return; +- if (phylink_autoneg_inband(mode)) +- val &= ~QCA8K_PWS_SERDES_AEN_DIS; +- else +- val |= QCA8K_PWS_SERDES_AEN_DIS; +- qca8k_write(priv, QCA8K_REG_PWS, val); +- +- /* Configure the SGMII parameters */ +- ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); +- if (ret) +- return; +- +- val |= QCA8K_SGMII_EN_SD; +- +- if (priv->ports_config.sgmii_enable_pll) +- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | +- QCA8K_SGMII_EN_TX; +- +- if (dsa_is_cpu_port(ds, port)) { +- /* CPU port, we're talking to the CPU MAC, be a PHY */ +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_PHY; +- } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_MAC; +- } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { +- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; +- val |= QCA8K_SGMII_MODE_CTRL_BASEX; +- } +- +- qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); +- +- /* From original code is reported port instability as SGMII also +- * require delay set. Apply advised values here or take them from DT. +- */ +- if (state->interface == PHY_INTERFACE_MODE_SGMII) +- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); +- +- /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and +- * falling edge is set writing in the PORT0 PAD reg +- */ +- if (priv->switch_id == QCA8K_ID_QCA8327 || +- priv->switch_id == QCA8K_ID_QCA8337) +- reg = QCA8K_REG_PORT0_PAD_CTRL; +- +- val = 0; +- +- /* SGMII Clock phase configuration */ +- if (priv->ports_config.sgmii_rx_clk_falling_edge) +- val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; +- +- if (priv->ports_config.sgmii_tx_clk_falling_edge) +- val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; +- +- if (val) +- ret = qca8k_rmw(priv, reg, +- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | +- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, +- val); +- +- break; +- default: +- dev_err(ds->dev, "xMII mode %s not supported for port %d\n", +- phy_modes(state->interface), port); +- return; +- } +-} +- +-static void +-qca8k_phylink_validate(struct dsa_switch *ds, int port, +- unsigned long *supported, +- struct phylink_link_state *state) +-{ +- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; +- +- switch (port) { +- case 0: /* 1st CPU port */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII) +- goto unsupported; +- break; +- case 1: +- case 2: +- case 3: +- case 4: +- case 5: +- /* Internal PHY */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_GMII && +- state->interface != PHY_INTERFACE_MODE_INTERNAL) +- goto unsupported; +- break; +- case 6: /* 2nd CPU port / external PHY */ +- if (state->interface != PHY_INTERFACE_MODE_NA && +- state->interface != PHY_INTERFACE_MODE_RGMII && +- state->interface != PHY_INTERFACE_MODE_RGMII_ID && +- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && +- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && +- state->interface != PHY_INTERFACE_MODE_SGMII && +- state->interface != PHY_INTERFACE_MODE_1000BASEX) +- goto unsupported; +- break; +- default: +-unsupported: +- linkmode_zero(supported); +- return; +- } +- +- phylink_set_port_modes(mask); +- phylink_set(mask, Autoneg); +- +- phylink_set(mask, 1000baseT_Full); +- phylink_set(mask, 10baseT_Half); +- phylink_set(mask, 10baseT_Full); +- phylink_set(mask, 100baseT_Half); +- phylink_set(mask, 100baseT_Full); +- +- if (state->interface == PHY_INTERFACE_MODE_1000BASEX) +- phylink_set(mask, 1000baseX_Full); +- +- phylink_set(mask, Pause); +- phylink_set(mask, Asym_Pause); +- +- linkmode_and(supported, supported, mask); +- linkmode_and(state->advertising, state->advertising, mask); +-} +- +-static int +-qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, +- struct phylink_link_state *state) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg; +- int ret; +- +- ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); +- if (ret < 0) +- return ret; +- +- state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); +- state->an_complete = state->link; +- state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); +- state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : +- DUPLEX_HALF; +- +- switch (reg & QCA8K_PORT_STATUS_SPEED) { +- case QCA8K_PORT_STATUS_SPEED_10: +- state->speed = SPEED_10; +- break; +- case QCA8K_PORT_STATUS_SPEED_100: +- state->speed = SPEED_100; +- break; +- case QCA8K_PORT_STATUS_SPEED_1000: +- state->speed = SPEED_1000; +- break; +- default: +- state->speed = SPEED_UNKNOWN; +- break; +- } +- +- state->pause = MLO_PAUSE_NONE; +- if (reg & QCA8K_PORT_STATUS_RXFLOW) +- state->pause |= MLO_PAUSE_RX; +- if (reg & QCA8K_PORT_STATUS_TXFLOW) +- state->pause |= MLO_PAUSE_TX; +- +- return 1; +-} +- +-static void +-qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, +- phy_interface_t interface) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- qca8k_port_set_status(priv, port, 0); +-} +- +-static void +-qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, +- phy_interface_t interface, struct phy_device *phydev, +- int speed, int duplex, bool tx_pause, bool rx_pause) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg; +- +- if (phylink_autoneg_inband(mode)) { +- reg = QCA8K_PORT_STATUS_LINK_AUTO; +- } else { +- switch (speed) { +- case SPEED_10: +- reg = QCA8K_PORT_STATUS_SPEED_10; +- break; +- case SPEED_100: +- reg = QCA8K_PORT_STATUS_SPEED_100; +- break; +- case SPEED_1000: +- reg = QCA8K_PORT_STATUS_SPEED_1000; +- break; +- default: +- reg = QCA8K_PORT_STATUS_LINK_AUTO; +- break; +- } +- +- if (duplex == DUPLEX_FULL) +- reg |= QCA8K_PORT_STATUS_DUPLEX; +- +- if (rx_pause || dsa_is_cpu_port(ds, port)) +- reg |= QCA8K_PORT_STATUS_RXFLOW; +- +- if (tx_pause || dsa_is_cpu_port(ds, port)) +- reg |= QCA8K_PORT_STATUS_TXFLOW; +- } +- +- reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; +- +- qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); +-} +- +-static void +-qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) +-{ +- struct qca8k_priv *priv = ds->priv; +- int i; +- +- if (stringset != ETH_SS_STATS) +- return; +- +- for (i = 0; i < priv->info->mib_count; i++) +- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, +- ETH_GSTRING_LEN); +-} +- +-static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) +-{ +- struct qca8k_mib_eth_data *mib_eth_data; +- struct qca8k_priv *priv = ds->priv; +- const struct qca8k_mib_desc *mib; +- struct mib_ethhdr *mib_ethhdr; +- int i, mib_len, offset = 0; +- u64 *data; +- u8 port; +- +- mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); +- mib_eth_data = &priv->mib_eth_data; +- +- /* The switch autocast every port. Ignore other packet and +- * parse only the requested one. +- */ +- port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); +- if (port != mib_eth_data->req_port) +- goto exit; +- +- data = mib_eth_data->data; +- +- for (i = 0; i < priv->info->mib_count; i++) { +- mib = &ar8327_mib[i]; +- +- /* First 3 mib are present in the skb head */ +- if (i < 3) { +- data[i] = mib_ethhdr->data[i]; +- continue; +- } +- +- mib_len = sizeof(uint32_t); +- +- /* Some mib are 64 bit wide */ +- if (mib->size == 2) +- mib_len = sizeof(uint64_t); +- +- /* Copy the mib value from packet to the */ +- memcpy(data + i, skb->data + offset, mib_len); +- +- /* Set the offset for the next mib */ +- offset += mib_len; +- } +- +-exit: +- /* Complete on receiving all the mib packet */ +- if (refcount_dec_and_test(&mib_eth_data->port_parsed)) +- complete(&mib_eth_data->rw_done); +-} +- +-static int +-qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) +-{ +- struct dsa_port *dp = dsa_to_port(ds, port); +- struct qca8k_mib_eth_data *mib_eth_data; +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- mib_eth_data = &priv->mib_eth_data; +- +- mutex_lock(&mib_eth_data->mutex); +- +- reinit_completion(&mib_eth_data->rw_done); +- +- mib_eth_data->req_port = dp->index; +- mib_eth_data->data = data; +- refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); +- +- mutex_lock(&priv->reg_mutex); +- +- /* Send mib autocast request */ +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, +- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, +- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | +- QCA8K_MIB_BUSY); +- +- mutex_unlock(&priv->reg_mutex); +- +- if (ret) +- goto exit; +- +- ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); +- +-exit: +- mutex_unlock(&mib_eth_data->mutex); +- +- return ret; +-} +- +-static void +-qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, +- uint64_t *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- const struct qca8k_mib_desc *mib; +- u32 reg, i, val; +- u32 hi = 0; +- int ret; +- +- if (priv->mgmt_master && priv->info->ops->autocast_mib && +- priv->info->ops->autocast_mib(ds, port, data) > 0) +- return; +- +- for (i = 0; i < priv->info->mib_count; i++) { +- mib = &ar8327_mib[i]; +- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; +- +- ret = qca8k_read(priv, reg, &val); +- if (ret < 0) +- continue; +- +- if (mib->size == 2) { +- ret = qca8k_read(priv, reg + 4, &hi); +- if (ret < 0) +- continue; +- } +- +- data[i] = val; +- if (mib->size == 2) +- data[i] |= (u64)hi << 32; +- } +-} +- +-static int +-qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- if (sset != ETH_SS_STATS) +- return 0; +- +- return priv->info->mib_count; +-} +- +-static int +-qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); +- u32 reg; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); +- if (ret < 0) +- goto exit; +- +- if (eee->eee_enabled) +- reg |= lpi_en; +- else +- reg &= ~lpi_en; +- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +-{ +- /* Nothing to do on the port's MAC */ +- return 0; +-} +- +-static void +-qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 stp_state; +- +- switch (state) { +- case BR_STATE_DISABLED: +- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; +- break; +- case BR_STATE_BLOCKING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; +- break; +- case BR_STATE_LISTENING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; +- break; +- case BR_STATE_LEARNING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; +- break; +- case BR_STATE_FORWARDING: +- default: +- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; +- break; +- } +- +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); +-} +- +-static int +-qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int port_mask, cpu_port; +- int i, ret; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- port_mask = BIT(cpu_port); +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Add this port to the portvlan mask of the other ports +- * in the bridge +- */ +- ret = regmap_set_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- if (ret) +- return ret; +- if (i != port) +- port_mask |= BIT(i); +- } +- +- /* Add all other ports to this ports portvlan mask */ +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, port_mask); +- +- return ret; +-} +- +-static void +-qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int cpu_port, i; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Remove this port to the portvlan mask of the other ports +- * in the bridge +- */ +- regmap_clear_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- } +- +- /* Set the cpu port to be the only one in the portvlan mask of +- * this port +- */ +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); +-} +- +-static void +-qca8k_port_fast_age(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +-{ +- struct qca8k_priv *priv = ds->priv; +- unsigned int secs = msecs / 1000; +- u32 val; +- +- /* AGE_TIME reg is set in 7s step */ +- val = secs / 7; +- +- /* Handle case with 0 as val to NOT disable +- * learning +- */ +- if (!val) +- val = 1; +- +- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, +- QCA8K_ATU_AGE_TIME(val)); +-} +- +-static int +-qca8k_port_enable(struct dsa_switch *ds, int port, +- struct phy_device *phy) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 1); +- priv->port_enabled_map |= BIT(port); +- +- if (dsa_is_user_port(ds, port)) +- phy_support_asym_pause(phy); +- +- return 0; +-} +- +-static void +-qca8k_port_disable(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 0); +- priv->port_enabled_map &= ~BIT(port); +-} +- +-static int +-qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- /* We have only have a general MTU setting. +- * DSA always set the CPU port's MTU to the largest MTU of the slave +- * ports. +- * Setting MTU just for the CPU port is sufficient to correctly set a +- * value for every port. +- */ +- if (!dsa_is_cpu_port(ds, port)) +- return 0; +- +- /* To change the MAX_FRAME_SIZE the cpu ports must be off or +- * the switch panics. +- * Turn off both cpu ports before applying the new value to prevent +- * this. +- */ +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 0); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 0); +- +- /* Include L2 header / FCS length */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); +- +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 1); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 1); +- +- return ret; +-} +- +-static int +-qca8k_port_max_mtu(struct dsa_switch *ds, int port) +-{ +- return QCA8K_MAX_MTU; +-} +- +-static int +-qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, +- u16 port_mask, u16 vid) +-{ +- /* Set the vid to the port vlan id if no vid is set */ +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_add(priv, addr, port_mask, vid, +- QCA8K_ATU_STATUS_STATIC); +-} +- +-static int +-qca8k_port_fdb_add(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_del(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_del(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_dump(struct dsa_switch *ds, int port, +- dsa_fdb_dump_cb_t *cb, void *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- struct qca8k_fdb _fdb = { 0 }; +- int cnt = QCA8K_NUM_FDB_RECORDS; +- bool is_static; +- int ret = 0; +- +- mutex_lock(&priv->reg_mutex); +- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { +- if (!_fdb.aging) +- break; +- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); +- ret = cb(_fdb.mac, _fdb.vid, is_static, data); +- if (ret) +- break; +- } +- mutex_unlock(&priv->reg_mutex); +- +- return 0; +-} +- +-static int +-qca8k_port_mdb_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); +-} +- +-static int +-qca8k_port_mdb_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); +-} +- +-static int +-qca8k_port_mirror_add(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror, +- bool ingress) +-{ +- struct qca8k_priv *priv = ds->priv; +- int monitor_port, ret; +- u32 reg, val; +- +- /* Check for existent entry */ +- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) +- return -EEXIST; +- +- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); +- if (ret) +- return ret; +- +- /* QCA83xx can have only one port set to mirror mode. +- * Check that the correct port is requested and return error otherwise. +- * When no mirror port is set, the values is set to 0xF +- */ +- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) +- return -EEXIST; +- +- /* Set the monitor port */ +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, +- mirror->to_local_port); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- return ret; +- +- if (ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_update_bits(priv->regmap, reg, val, val); +- if (ret) +- return ret; +- +- /* Track mirror port for tx and rx to decide when the +- * mirror port has to be disabled. +- */ +- if (ingress) +- priv->mirror_rx |= BIT(port); +- else +- priv->mirror_tx |= BIT(port); +- +- return 0; +-} +- +-static void +-qca8k_port_mirror_del(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg, val; +- int ret; +- +- if (mirror->ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_clear_bits(priv->regmap, reg, val); +- if (ret) +- goto err; +- +- if (mirror->ingress) +- priv->mirror_rx &= ~BIT(port); +- else +- priv->mirror_tx &= ~BIT(port); +- +- /* No port set to send packet to mirror port. Disable mirror port */ +- if (!priv->mirror_rx && !priv->mirror_tx) { +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- goto err; +- } +-err: +- dev_err(priv->dev, "Failed to del mirror port from %d", port); +-} +- +-static int +-qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, +- struct netlink_ext_ack *extack) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- if (vlan_filtering) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); +- } else { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan, +- struct netlink_ext_ack *extack) +-{ +- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; +- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); +- if (ret) { +- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); +- return ret; +- } +- +- if (pvid) { +- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), +- QCA8K_EGREES_VLAN_PORT_MASK(port), +- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); +- if (ret) +- return ret; +- +- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), +- QCA8K_PORT_VLAN_CVID(vlan->vid) | +- QCA8K_PORT_VLAN_SVID(vlan->vid)); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_del(priv, port, vlan->vid); +- if (ret) +- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); +- +- return ret; +-} +- +-static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- /* Communicate to the phy internal driver the switch revision. +- * Based on the switch revision different values needs to be +- * set to the dbg and mmd reg on the phy. +- * The first 2 bit are used to communicate the switch revision +- * to the phy driver. +- */ +- if (port > 0 && port < 6) +- return priv->switch_revision; +- +- return 0; +-} +- +-static enum dsa_tag_protocol +-qca8k_get_tag_protocol(struct dsa_switch *ds, int port, +- enum dsa_tag_protocol mp) +-{ +- return DSA_TAG_PROTO_QCA; +-} +- +-static bool +-qca8k_lag_can_offload(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct dsa_port *dp; +- int id, members = 0; +- +- id = dsa_lag_id(ds->dst, lag); +- if (id < 0 || id >= ds->num_lag_ids) +- return false; +- +- dsa_lag_foreach_port(dp, ds->dst, lag) +- /* Includes the port joining the LAG */ +- members++; +- +- if (members > QCA8K_NUM_PORTS_FOR_LAG) +- return false; +- +- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) +- return false; +- +- if (info->hash_type != NETDEV_LAG_HASH_L2 && +- info->hash_type != NETDEV_LAG_HASH_L23) +- return false; +- +- return true; +-} +- +-static int +-qca8k_lag_setup_hash(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct qca8k_priv *priv = ds->priv; +- bool unique_lag = true; +- u32 hash = 0; +- int i, id; +- +- id = dsa_lag_id(ds->dst, lag); +- +- switch (info->hash_type) { +- case NETDEV_LAG_HASH_L23: +- hash |= QCA8K_TRUNK_HASH_SIP_EN; +- hash |= QCA8K_TRUNK_HASH_DIP_EN; +- fallthrough; +- case NETDEV_LAG_HASH_L2: +- hash |= QCA8K_TRUNK_HASH_SA_EN; +- hash |= QCA8K_TRUNK_HASH_DA_EN; +- break; +- default: /* We should NEVER reach this */ +- return -EOPNOTSUPP; +- } +- +- /* Check if we are the unique configured LAG */ +- dsa_lags_foreach_id(i, ds->dst) +- if (i != id && dsa_lag_dev(ds->dst, i)) { +- unique_lag = false; +- break; +- } +- +- /* Hash Mode is global. Make sure the same Hash Mode +- * is set to all the 4 possible lag. +- * If we are the unique LAG we can set whatever hash +- * mode we want. +- * To change hash mode it's needed to remove all LAG +- * and change the mode with the latest. +- */ +- if (unique_lag) { +- priv->lag_hash_mode = hash; +- } else if (priv->lag_hash_mode != hash) { +- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); +- return -EOPNOTSUPP; +- } +- +- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, +- QCA8K_TRUNK_HASH_MASK, hash); +-} +- +-static int +-qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, +- struct net_device *lag, bool delete) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret, id, i; +- u32 val; +- +- id = dsa_lag_id(ds->dst, lag); +- +- /* Read current port member */ +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); +- if (ret) +- return ret; +- +- /* Shift val to the correct trunk */ +- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); +- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; +- if (delete) +- val &= ~BIT(port); +- else +- val |= BIT(port); +- +- /* Update port member. With empty portmap disable trunk */ +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, +- QCA8K_REG_GOL_TRUNK_MEMBER(id) | +- QCA8K_REG_GOL_TRUNK_EN(id), +- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | +- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); +- +- /* Search empty member if adding or port on deleting */ +- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); +- if (ret) +- return ret; +- +- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; +- +- if (delete) { +- /* If port flagged to be disabled assume this member is +- * empty +- */ +- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; +- if (val != port) +- continue; +- } else { +- /* If port flagged to be enabled assume this member is +- * already set +- */ +- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- } +- +- /* We have found the member to add/remove */ +- break; +- } +- +- /* Set port in the correct port mask or disable port if in delete mode */ +- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), +- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | +- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); +-} +- +-static int +-qca8k_port_lag_join(struct dsa_switch *ds, int port, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- int ret; +- +- if (!qca8k_lag_can_offload(ds, lag, info)) +- return -EOPNOTSUPP; +- +- ret = qca8k_lag_setup_hash(ds, lag, info); +- if (ret) +- return ret; +- +- return qca8k_lag_refresh_portmap(ds, port, lag, false); +-} +- +-static int +-qca8k_port_lag_leave(struct dsa_switch *ds, int port, +- struct net_device *lag) +-{ +- return qca8k_lag_refresh_portmap(ds, port, lag, true); +-} +- +-static void +-qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, +- bool operational) +-{ +- struct dsa_port *dp = master->dsa_ptr; +- struct qca8k_priv *priv = ds->priv; +- +- /* Ethernet MIB/MDIO is only supported for CPU port 0 */ +- if (dp->index != 0) +- return; +- +- mutex_lock(&priv->mgmt_eth_data.mutex); +- mutex_lock(&priv->mib_eth_data.mutex); +- +- priv->mgmt_master = operational ? (struct net_device *)master : NULL; +- +- mutex_unlock(&priv->mib_eth_data.mutex); +- mutex_unlock(&priv->mgmt_eth_data.mutex); +-} +- +-static int qca8k_connect_tag_protocol(struct dsa_switch *ds, +- enum dsa_tag_protocol proto) +-{ +- struct qca_tagger_data *tagger_data; +- +- switch (proto) { +- case DSA_TAG_PROTO_QCA: +- tagger_data = ds->tagger_data; +- +- tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; +- tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; +- +- break; +- default: +- return -EOPNOTSUPP; +- } +- +- return 0; +-} +- +-static const struct dsa_switch_ops qca8k_switch_ops = { +- .get_tag_protocol = qca8k_get_tag_protocol, +- .setup = qca8k_setup, +- .get_strings = qca8k_get_strings, +- .get_ethtool_stats = qca8k_get_ethtool_stats, +- .get_sset_count = qca8k_get_sset_count, +- .set_ageing_time = qca8k_set_ageing_time, +- .get_mac_eee = qca8k_get_mac_eee, +- .set_mac_eee = qca8k_set_mac_eee, +- .port_enable = qca8k_port_enable, +- .port_disable = qca8k_port_disable, +- .port_change_mtu = qca8k_port_change_mtu, +- .port_max_mtu = qca8k_port_max_mtu, +- .port_stp_state_set = qca8k_port_stp_state_set, +- .port_bridge_join = qca8k_port_bridge_join, +- .port_bridge_leave = qca8k_port_bridge_leave, +- .port_fast_age = qca8k_port_fast_age, +- .port_fdb_add = qca8k_port_fdb_add, +- .port_fdb_del = qca8k_port_fdb_del, +- .port_fdb_dump = qca8k_port_fdb_dump, +- .port_mdb_add = qca8k_port_mdb_add, +- .port_mdb_del = qca8k_port_mdb_del, +- .port_mirror_add = qca8k_port_mirror_add, +- .port_mirror_del = qca8k_port_mirror_del, +- .port_vlan_filtering = qca8k_port_vlan_filtering, +- .port_vlan_add = qca8k_port_vlan_add, +- .port_vlan_del = qca8k_port_vlan_del, +- .phylink_validate = qca8k_phylink_validate, +- .phylink_mac_link_state = qca8k_phylink_mac_link_state, +- .phylink_mac_config = qca8k_phylink_mac_config, +- .phylink_mac_link_down = qca8k_phylink_mac_link_down, +- .phylink_mac_link_up = qca8k_phylink_mac_link_up, +- .get_phy_flags = qca8k_get_phy_flags, +- .port_lag_join = qca8k_port_lag_join, +- .port_lag_leave = qca8k_port_lag_leave, +- .master_state_change = qca8k_master_change, +- .connect_tag_protocol = qca8k_connect_tag_protocol, +-}; +- +-static int qca8k_read_switch_id(struct qca8k_priv *priv) +-{ +- u32 val; +- u8 id; +- int ret; +- +- if (!priv->info) +- return -ENODEV; +- +- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); +- if (ret < 0) +- return -ENODEV; +- +- id = QCA8K_MASK_CTRL_DEVICE_ID(val); +- if (id != priv->info->id) { +- dev_err(priv->dev, +- "Switch id detected %x but expected %x", +- id, priv->info->id); +- return -ENODEV; +- } +- +- priv->switch_id = id; +- +- /* Save revision to communicate to the internal PHY driver */ +- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); +- +- return 0; +-} +- +-static int +-qca8k_sw_probe(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv; +- int ret; +- +- /* allocate the private data struct so that we can probe the switches +- * ID register +- */ +- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->info = of_device_get_match_data(priv->dev); +- priv->bus = mdiodev->bus; +- priv->dev = &mdiodev->dev; +- +- priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", +- GPIOD_ASIS); +- if (IS_ERR(priv->reset_gpio)) +- return PTR_ERR(priv->reset_gpio); +- +- if (priv->reset_gpio) { +- gpiod_set_value_cansleep(priv->reset_gpio, 1); +- /* The active low duration must be greater than 10 ms +- * and checkpatch.pl wants 20 ms. +- */ +- msleep(20); +- gpiod_set_value_cansleep(priv->reset_gpio, 0); +- } +- +- /* Start by setting up the register mapping */ +- priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, +- &qca8k_regmap_config); +- if (IS_ERR(priv->regmap)) { +- dev_err(priv->dev, "regmap initialization failed"); +- return PTR_ERR(priv->regmap); +- } +- +- priv->mdio_cache.page = 0xffff; +- priv->mdio_cache.lo = 0xffff; +- priv->mdio_cache.hi = 0xffff; +- +- /* Check the detected switch id */ +- ret = qca8k_read_switch_id(priv); +- if (ret) +- return ret; +- +- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); +- if (!priv->ds) +- return -ENOMEM; +- +- mutex_init(&priv->mgmt_eth_data.mutex); +- init_completion(&priv->mgmt_eth_data.rw_done); +- +- mutex_init(&priv->mib_eth_data.mutex); +- init_completion(&priv->mib_eth_data.rw_done); +- +- priv->ds->dev = &mdiodev->dev; +- priv->ds->num_ports = QCA8K_NUM_PORTS; +- priv->ds->priv = priv; +- priv->ds->ops = &qca8k_switch_ops; +- mutex_init(&priv->reg_mutex); +- dev_set_drvdata(&mdiodev->dev, priv); +- +- return dsa_register_switch(priv->ds); +-} +- +-static void +-qca8k_sw_remove(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); +- int i; +- +- if (!priv) +- return; +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) +- qca8k_port_set_status(priv, i, 0); +- +- dsa_unregister_switch(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-static void qca8k_sw_shutdown(struct mdio_device *mdiodev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); +- +- if (!priv) +- return; +- +- dsa_switch_shutdown(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-#ifdef CONFIG_PM_SLEEP +-static void +-qca8k_set_pm(struct qca8k_priv *priv, int enable) +-{ +- int port; +- +- for (port = 0; port < QCA8K_NUM_PORTS; port++) { +- /* Do not enable on resume if the port was +- * disabled before. +- */ +- if (!(priv->port_enabled_map & BIT(port))) +- continue; +- +- qca8k_port_set_status(priv, port, enable); +- } +-} +- +-static int qca8k_suspend(struct device *dev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(dev); +- +- qca8k_set_pm(priv, 0); +- +- return dsa_switch_suspend(priv->ds); +-} +- +-static int qca8k_resume(struct device *dev) +-{ +- struct qca8k_priv *priv = dev_get_drvdata(dev); +- +- qca8k_set_pm(priv, 1); +- +- return dsa_switch_resume(priv->ds); +-} +-#endif /* CONFIG_PM_SLEEP */ +- +-static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, +- qca8k_suspend, qca8k_resume); +- +-static const struct qca8k_info_ops qca8xxx_ops = { +- .autocast_mib = qca8k_get_ethtool_stats_eth, +-}; +- +-static const struct qca8k_match_data qca8327 = { +- .id = QCA8K_ID_QCA8327, +- .reduced_package = true, +- .mib_count = QCA8K_QCA832X_MIB_COUNT, +- .ops = &qca8xxx_ops, +-}; +- +-static const struct qca8k_match_data qca8328 = { +- .id = QCA8K_ID_QCA8327, +- .mib_count = QCA8K_QCA832X_MIB_COUNT, +- .ops = &qca8xxx_ops, +-}; +- +-static const struct qca8k_match_data qca833x = { +- .id = QCA8K_ID_QCA8337, +- .mib_count = QCA8K_QCA833X_MIB_COUNT, +- .ops = &qca8xxx_ops, +-}; +- +-static const struct of_device_id qca8k_of_match[] = { +- { .compatible = "qca,qca8327", .data = &qca8327 }, +- { .compatible = "qca,qca8328", .data = &qca8328 }, +- { .compatible = "qca,qca8334", .data = &qca833x }, +- { .compatible = "qca,qca8337", .data = &qca833x }, +- { /* sentinel */ }, +-}; +- +-static struct mdio_driver qca8kmdio_driver = { +- .probe = qca8k_sw_probe, +- .remove = qca8k_sw_remove, +- .shutdown = qca8k_sw_shutdown, +- .mdiodrv.driver = { +- .name = "qca8k", +- .of_match_table = qca8k_of_match, +- .pm = &qca8k_pm_ops, +- }, +-}; +- +-mdio_module_driver(qca8kmdio_driver); +- +-MODULE_AUTHOR("Mathieu Olivari, John Crispin "); +-MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); +-MODULE_LICENSE("GPL v2"); +-MODULE_ALIAS("platform:qca8k"); +--- /dev/null ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -0,0 +1,3186 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016 John Crispin ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "qca8k.h" ++ ++static void ++qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) ++{ ++ regaddr >>= 1; ++ *r1 = regaddr & 0x1e; ++ ++ regaddr >>= 5; ++ *r2 = regaddr & 0x7; ++ ++ regaddr >>= 3; ++ *page = regaddr & 0x3ff; ++} ++ ++static int ++qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) ++{ ++ u16 *cached_lo = &priv->mdio_cache.lo; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (lo == *cached_lo) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, lo); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit lo register\n"); ++ ++ *cached_lo = lo; ++ return 0; ++} ++ ++static int ++qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) ++{ ++ u16 *cached_hi = &priv->mdio_cache.hi; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (hi == *cached_hi) ++ return 0; ++ ++ ret = bus->write(bus, phy_id, regnum, hi); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit hi register\n"); ++ ++ *cached_hi = hi; ++ return 0; ++} ++ ++static int ++qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) ++{ ++ int ret; ++ ++ ret = bus->read(bus, phy_id, regnum); ++ if (ret >= 0) { ++ *val = ret; ++ ret = bus->read(bus, phy_id, regnum + 1); ++ *val |= ret << 16; ++ } ++ ++ if (ret < 0) { ++ dev_err_ratelimited(&bus->dev, ++ "failed to read qca8k 32bit register\n"); ++ *val = 0; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void ++qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) ++{ ++ u16 lo, hi; ++ int ret; ++ ++ lo = val & 0xffff; ++ hi = (u16)(val >> 16); ++ ++ ret = qca8k_set_lo(priv, phy_id, regnum, lo); ++ if (ret >= 0) ++ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); ++} ++ ++static int ++qca8k_set_page(struct qca8k_priv *priv, u16 page) ++{ ++ u16 *cached_page = &priv->mdio_cache.page; ++ struct mii_bus *bus = priv->bus; ++ int ret; ++ ++ if (page == *cached_page) ++ return 0; ++ ++ ret = bus->write(bus, 0x18, 0, page); ++ if (ret < 0) { ++ dev_err_ratelimited(&bus->dev, ++ "failed to set qca8k page\n"); ++ return ret; ++ } ++ ++ *cached_page = page; ++ usleep_range(1000, 2000); ++ return 0; ++} ++ ++static int ++qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) ++{ ++ return regmap_read(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) ++{ ++ return regmap_write(priv->regmap, reg, val); ++} ++ ++static int ++qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ return regmap_update_bits(priv->regmap, reg, mask, write_val); ++} ++ ++static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ u8 len, cmd; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); ++ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); ++ ++ /* Make sure the seq match the requested packet */ ++ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) ++ mgmt_eth_data->ack = true; ++ ++ if (cmd == MDIO_READ) { ++ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; ++ ++ /* Get the rest of the 12 byte of data. ++ * The read/write function will extract the requested data. ++ */ ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(mgmt_eth_data->data + 1, skb->data, ++ QCA_HDR_MGMT_DATA2_LEN); ++ } ++ ++ complete(&mgmt_eth_data->rw_done); ++} ++ ++static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, ++ int priority, unsigned int len) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ unsigned int real_len; ++ struct sk_buff *skb; ++ u32 *data2; ++ u16 hdr; ++ ++ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); ++ if (!skb) ++ return NULL; ++ ++ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte ++ * Actually for some reason the steps are: ++ * 0: nothing ++ * 1-4: first 4 byte ++ * 5-6: first 12 byte ++ * 7-15: all 16 byte ++ */ ++ if (len == 16) ++ real_len = 15; ++ else ++ real_len = len; ++ ++ skb_reset_mac_header(skb); ++ skb_set_network_header(skb, skb->len); ++ ++ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); ++ ++ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); ++ hdr |= QCA_HDR_XMIT_FROM_CPU; ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); ++ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); ++ ++ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); ++ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, ++ QCA_HDR_MGMT_CHECK_CODE_VAL); ++ ++ if (cmd == MDIO_WRITE) ++ mgmt_ethhdr->mdio_data = *val; ++ ++ mgmt_ethhdr->hdr = htons(hdr); ++ ++ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); ++ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ return skb; ++} ++ ++static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) ++{ ++ struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ ++ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; ++ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); ++} ++ ++static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ *val = mgmt_eth_data->data[0]; ++ if (len > QCA_HDR_MGMT_DATA1_LEN) ++ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; ++ struct sk_buff *skb; ++ bool ack; ++ int ret; ++ ++ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, ++ QCA8K_ETHERNET_MDIO_PRIORITY, len); ++ if (!skb) ++ return -ENOMEM; ++ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check mgmt_master if is operational */ ++ if (!priv->mgmt_master) { ++ kfree_skb(skb); ++ mutex_unlock(&mgmt_eth_data->mutex); ++ return -EINVAL; ++ } ++ ++ skb->dev = priv->mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the mdio pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); ++ ++ ack = mgmt_eth_data->ack; ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ++qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ u32 val = 0; ++ int ret; ++ ++ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); ++ if (ret) ++ return ret; ++ ++ val &= ~mask; ++ val |= write_val; ++ ++ return qca8k_write_eth(priv, reg, &val, sizeof(val)); ++} ++ ++static int ++qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ ++ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ u32 tmp; ++ ++ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ tmp = val[i]; ++ ++ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ int ret; ++ ++ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ return ret; ++} ++ ++static int ++qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ int ret; ++ ++ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ return ret; ++} ++ ++static int ++qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) ++ return 0; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); ++ if (ret < 0) ++ goto exit; ++ ++ val &= ~mask; ++ val |= write_val; ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++exit: ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret; ++} ++ ++static const struct regmap_range qca8k_readable_ranges[] = { ++ regmap_reg_range(0x0000, 0x00e4), /* Global control */ ++ regmap_reg_range(0x0100, 0x0168), /* EEE control */ ++ regmap_reg_range(0x0200, 0x0270), /* Parser control */ ++ regmap_reg_range(0x0400, 0x0454), /* ACL */ ++ regmap_reg_range(0x0600, 0x0718), /* Lookup */ ++ regmap_reg_range(0x0800, 0x0b70), /* QM */ ++ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ ++ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ ++ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ ++ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ ++ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ ++ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ ++ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ ++ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ ++ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ ++ ++}; ++ ++static const struct regmap_access_table qca8k_readable_table = { ++ .yes_ranges = qca8k_readable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), ++}; ++ ++static struct regmap_config qca8k_regmap_config = { ++ .reg_bits = 16, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = 0x16ac, /* end MIB - Port6 range */ ++ .reg_read = qca8k_regmap_read, ++ .reg_write = qca8k_regmap_write, ++ .reg_update_bits = qca8k_regmap_update_bits, ++ .rd_table = &qca8k_readable_table, ++ .disable_locking = true, /* Locking is handled by qca8k read/write */ ++ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ ++}; ++ ++static int ++qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) ++{ ++ u32 val; ++ ++ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); ++} ++ ++static int ++qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) ++{ ++ u32 reg[3]; ++ int ret; ++ ++ /* load the ARL table into an array */ ++ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++ if (ret) ++ return ret; ++ ++ /* vid - 83:72 */ ++ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); ++ /* aging - 67:64 */ ++ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); ++ /* portmask - 54:48 */ ++ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); ++ /* mac - 47:0 */ ++ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); ++ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); ++ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); ++ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); ++ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); ++ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); ++ ++ return 0; ++} ++ ++static void ++qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, ++ u8 aging) ++{ ++ u32 reg[3] = { 0 }; ++ ++ /* vid - 83:72 */ ++ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); ++ /* aging - 67:64 */ ++ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); ++ /* portmask - 54:48 */ ++ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); ++ /* mac - 47:0 */ ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); ++ ++ /* load the array into the ARL table */ ++ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++} ++ ++static int ++qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and FDB index */ ++ reg = QCA8K_ATU_FUNC_BUSY; ++ reg |= cmd; ++ if (port >= 0) { ++ reg |= QCA8K_ATU_FUNC_PORT_EN; ++ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); ++ } ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_FDB_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_ATU_FUNC_FULL) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) ++{ ++ int ret; ++ ++ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); ++ if (ret < 0) ++ return ret; ++ ++ return qca8k_fdb_read(priv, fdb); ++} ++ ++static int ++qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, ++ u16 vid, u8 aging) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static void ++qca8k_fdb_flush(struct qca8k_priv *priv) ++{ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_fdb_read(priv, &fdb); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule exist. Delete first */ ++ if (!fdb.aging) { ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ } ++ ++ /* Add port to fdb portmask */ ++ fdb.port_mask |= port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule doesn't exist. Why delete? */ ++ if (!fdb.aging) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ ++ /* Only port in the rule is this port. Don't re insert */ ++ if (fdb.port_mask == port_mask) ++ goto exit; ++ ++ /* Remove port from port mask */ ++ fdb.port_mask &= ~port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and VLAN index */ ++ reg = QCA8K_VTU_FUNC1_BUSY; ++ reg |= cmd; ++ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_VLAN_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_VTU_FUNC1_FULL) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) ++{ ++ u32 reg; ++ int ret; ++ ++ /* ++ We do the right thing with VLAN 0 and treat it as untagged while ++ preserving the tag on egress. ++ */ ++ if (vid == 0) ++ return 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ if (untagged) ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); ++ else ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); ++ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) ++{ ++ u32 reg, mask; ++ int ret, i; ++ bool del; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); ++ ++ /* Check if we're the last member to be removed */ ++ del = true; ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); ++ ++ if ((reg & mask) != mask) { ++ del = false; ++ break; ++ } ++ } ++ ++ if (del) { ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); ++ } else { ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ } ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int ++qca8k_mib_init(struct qca8k_priv *priv) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | ++ QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static void ++qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) ++{ ++ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; ++ ++ /* Port 0 and 6 have no internal PHY */ ++ if (port > 0 && port < 6) ++ mask |= QCA8K_PORT_STATUS_LINK_AUTO; ++ ++ if (enable) ++ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++ else ++ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++} ++ ++static int ++qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, ++ struct sk_buff *read_skb, u32 *val) ++{ ++ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); ++ bool ack; ++ int ret; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the copy pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) ++ return -ETIMEDOUT; ++ ++ if (!ack) ++ return -EINVAL; ++ ++ *val = mgmt_eth_data->data[0]; ++ ++ return 0; ++} ++ ++static int ++qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, ++ int regnum, u16 data) ++{ ++ struct sk_buff *write_skb, *clear_skb, *read_skb; ++ struct qca8k_mgmt_eth_data *mgmt_eth_data; ++ u32 write_val, clear_val = 0, val; ++ struct net_device *mgmt_master; ++ int ret, ret1; ++ bool ack; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ mgmt_eth_data = &priv->mgmt_eth_data; ++ ++ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum); ++ ++ if (read) { ++ write_val |= QCA8K_MDIO_MASTER_READ; ++ } else { ++ write_val |= QCA8K_MDIO_MASTER_WRITE; ++ write_val |= QCA8K_MDIO_MASTER_DATA(data); ++ } ++ ++ /* Prealloc all the needed skb before the lock */ ++ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); ++ if (!write_skb) ++ return -ENOMEM; ++ ++ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); ++ if (!clear_skb) { ++ ret = -ENOMEM; ++ goto err_clear_skb; ++ } ++ ++ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, ++ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); ++ if (!read_skb) { ++ ret = -ENOMEM; ++ goto err_read_skb; ++ } ++ ++ /* Actually start the request: ++ * 1. Send mdio master packet ++ * 2. Busy Wait for mdio master command ++ * 3. Get the data if we are reading ++ * 4. Reset the mdio master (even with error) ++ */ ++ mutex_lock(&mgmt_eth_data->mutex); ++ ++ /* Check if mgmt_master is operational */ ++ mgmt_master = priv->mgmt_master; ++ if (!mgmt_master) { ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ret = -EINVAL; ++ goto err_mgmt_master; ++ } ++ ++ read_skb->dev = mgmt_master; ++ clear_skb->dev = mgmt_master; ++ write_skb->dev = mgmt_master; ++ ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the write pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(write_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ kfree_skb(read_skb); ++ goto exit; ++ } ++ ++ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, ++ !(val & QCA8K_MDIO_MASTER_BUSY), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, ++ mgmt_eth_data, read_skb, &val); ++ ++ if (ret < 0 && ret1 < 0) { ++ ret = ret1; ++ goto exit; ++ } ++ ++ if (read) { ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the read pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(read_skb); ++ ++ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ ack = mgmt_eth_data->ack; ++ ++ if (ret <= 0) { ++ ret = -ETIMEDOUT; ++ goto exit; ++ } ++ ++ if (!ack) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; ++ } else { ++ kfree_skb(read_skb); ++ } ++exit: ++ reinit_completion(&mgmt_eth_data->rw_done); ++ ++ /* Increment seq_num and set it in the clear pkt */ ++ mgmt_eth_data->seq++; ++ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); ++ mgmt_eth_data->ack = false; ++ ++ dev_queue_xmit(clear_skb); ++ ++ wait_for_completion_timeout(&mgmt_eth_data->rw_done, ++ QCA8K_ETHERNET_TIMEOUT); ++ ++ mutex_unlock(&mgmt_eth_data->mutex); ++ ++ return ret; ++ ++ /* Error handling before lock */ ++err_mgmt_master: ++ kfree_skb(read_skb); ++err_read_skb: ++ kfree_skb(clear_skb); ++err_clear_skb: ++ kfree_skb(write_skb); ++ ++ return ret; ++} ++ ++static u32 ++qca8k_port_to_phy(int port) ++{ ++ /* From Andrew Lunn: ++ * Port 0 has no internal phy. ++ * Port 1 has an internal PHY at MDIO address 0. ++ * Port 2 has an internal PHY at MDIO address 1. ++ * ... ++ * Port 5 has an internal PHY at MDIO address 4. ++ * Port 6 has no internal PHY. ++ */ ++ ++ return port - 1; ++} ++ ++static int ++qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) ++{ ++ u16 r1, r2, page; ++ u32 val; ++ int ret, ret1; ++ ++ qca8k_split_addr(reg, &r1, &r2, &page); ++ ++ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, ++ bus, 0x10 | r2, r1, &val); ++ ++ /* Check if qca8k_read has failed for a different reason ++ * before returnting -ETIMEDOUT ++ */ ++ if (ret < 0 && ret1 < 0) ++ return ret1; ++ ++ return ret; ++} ++ ++static int ++qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum) | ++ QCA8K_MDIO_MASTER_DATA(data); ++ ++ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_BUSY); ++ ++exit: ++ /* even if the busy_wait timeouts try to clear the MASTER_EN */ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ return ret; ++} ++ ++static int ++qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) ++{ ++ struct mii_bus *bus = priv->bus; ++ u16 r1, r2, page; ++ u32 val; ++ int ret; ++ ++ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) ++ return -EINVAL; ++ ++ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | ++ QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | ++ QCA8K_MDIO_MASTER_REG_ADDR(regnum); ++ ++ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); ++ ++ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ ++ ret = qca8k_set_page(priv, page); ++ if (ret) ++ goto exit; ++ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ ++ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); ++ ++exit: ++ /* even if the busy_wait timeouts try to clear the MASTER_EN */ ++ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ ++ mutex_unlock(&bus->mdio_lock); ++ ++ if (ret >= 0) ++ ret = val & QCA8K_MDIO_MASTER_DATA_MASK; ++ ++ return ret; ++} ++ ++static int ++qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) ++{ ++ struct qca8k_priv *priv = slave_bus->priv; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); ++ if (!ret) ++ return 0; ++ ++ return qca8k_mdio_write(priv, phy, regnum, data); ++} ++ ++static int ++qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) ++{ ++ struct qca8k_priv *priv = slave_bus->priv; ++ int ret; ++ ++ /* Use mdio Ethernet when available, fallback to legacy one on error */ ++ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); ++ if (ret >= 0) ++ return ret; ++ ++ ret = qca8k_mdio_read(priv, phy, regnum); ++ ++ if (ret < 0) ++ return 0xffff; ++ ++ return ret; ++} ++ ++static int ++qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) ++{ ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; ++ ++ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); ++} ++ ++static int ++qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) ++{ ++ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; ++ ++ return qca8k_internal_mdio_read(slave_bus, port, regnum); ++} ++ ++static int ++qca8k_mdio_register(struct qca8k_priv *priv) ++{ ++ struct dsa_switch *ds = priv->ds; ++ struct device_node *mdio; ++ struct mii_bus *bus; ++ ++ bus = devm_mdiobus_alloc(ds->dev); ++ if (!bus) ++ return -ENOMEM; ++ ++ bus->priv = (void *)priv; ++ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", ++ ds->dst->index, ds->index); ++ bus->parent = ds->dev; ++ bus->phy_mask = ~ds->phys_mii_mask; ++ ds->slave_mii_bus = bus; ++ ++ /* Check if the devicetree declare the port:phy mapping */ ++ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); ++ if (of_device_is_available(mdio)) { ++ bus->name = "qca8k slave mii"; ++ bus->read = qca8k_internal_mdio_read; ++ bus->write = qca8k_internal_mdio_write; ++ return devm_of_mdiobus_register(priv->dev, bus, mdio); ++ } ++ ++ /* If a mapping can't be found the legacy mapping is used, ++ * using the qca8k_port_to_phy function ++ */ ++ bus->name = "qca8k-legacy slave mii"; ++ bus->read = qca8k_legacy_mdio_read; ++ bus->write = qca8k_legacy_mdio_write; ++ return devm_mdiobus_register(priv->dev, bus); ++} ++ ++static int ++qca8k_setup_mdio_bus(struct qca8k_priv *priv) ++{ ++ u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; ++ struct device_node *ports, *port; ++ phy_interface_t mode; ++ int err; ++ ++ ports = of_get_child_by_name(priv->dev->of_node, "ports"); ++ if (!ports) ++ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); ++ ++ if (!ports) ++ return -EINVAL; ++ ++ for_each_available_child_of_node(ports, port) { ++ err = of_property_read_u32(port, "reg", ®); ++ if (err) { ++ of_node_put(port); ++ of_node_put(ports); ++ return err; ++ } ++ ++ if (!dsa_is_user_port(priv->ds, reg)) ++ continue; ++ ++ of_get_phy_mode(port, &mode); ++ ++ if (of_property_read_bool(port, "phy-handle") && ++ mode != PHY_INTERFACE_MODE_INTERNAL) ++ external_mdio_mask |= BIT(reg); ++ else ++ internal_mdio_mask |= BIT(reg); ++ } ++ ++ of_node_put(ports); ++ if (!external_mdio_mask && !internal_mdio_mask) { ++ dev_err(priv->dev, "no PHYs are defined.\n"); ++ return -EINVAL; ++ } ++ ++ /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through ++ * the MDIO_MASTER register also _disconnects_ the external MDC ++ * passthrough to the internal PHYs. It's not possible to use both ++ * configurations at the same time! ++ * ++ * Because this came up during the review process: ++ * If the external mdio-bus driver is capable magically disabling ++ * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's ++ * accessors for the time being, it would be possible to pull this ++ * off. ++ */ ++ if (!!external_mdio_mask && !!internal_mdio_mask) { ++ dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); ++ return -EINVAL; ++ } ++ ++ if (external_mdio_mask) { ++ /* Make sure to disable the internal mdio bus in cases ++ * a dt-overlay and driver reload changed the configuration ++ */ ++ ++ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, ++ QCA8K_MDIO_MASTER_EN); ++ } ++ ++ return qca8k_mdio_register(priv); ++} ++ ++static int ++qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) ++{ ++ u32 mask = 0; ++ int ret = 0; ++ ++ /* SoC specific settings for ipq8064. ++ * If more device require this consider adding ++ * a dedicated binding. ++ */ ++ if (of_machine_is_compatible("qcom,ipq8064")) ++ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; ++ ++ /* SoC specific settings for ipq8065 */ ++ if (of_machine_is_compatible("qcom,ipq8065")) ++ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; ++ ++ if (mask) { ++ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, ++ QCA8K_MAC_PWR_RGMII0_1_8V | ++ QCA8K_MAC_PWR_RGMII1_1_8V, ++ mask); ++ } ++ ++ return ret; ++} ++ ++static int qca8k_find_cpu_port(struct dsa_switch *ds) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Find the connected cpu port. Valid port are 0 or 6 */ ++ if (dsa_is_cpu_port(ds, 0)) ++ return 0; ++ ++ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); ++ ++ if (dsa_is_cpu_port(ds, 6)) ++ return 6; ++ ++ return -EINVAL; ++} ++ ++static int ++qca8k_setup_of_pws_reg(struct qca8k_priv *priv) ++{ ++ const struct qca8k_match_data *data = priv->info; ++ struct device_node *node = priv->dev->of_node; ++ u32 val = 0; ++ int ret; ++ ++ /* QCA8327 require to set to the correct mode. ++ * His bigger brother QCA8328 have the 172 pin layout. ++ * Should be applied by default but we set this just to make sure. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ /* Set the correct package of 148 pin for QCA8327 */ ++ if (data->reduced_package) ++ val |= QCA8327_PWS_PACKAGE148_EN; ++ ++ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, ++ val); ++ if (ret) ++ return ret; ++ } ++ ++ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) ++ val |= QCA8K_PWS_POWER_ON_SEL; ++ ++ if (of_property_read_bool(node, "qca,led-open-drain")) { ++ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { ++ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); ++ return -EINVAL; ++ } ++ ++ val |= QCA8K_PWS_LED_OPEN_EN_CSR; ++ } ++ ++ return qca8k_rmw(priv, QCA8K_REG_PWS, ++ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, ++ val); ++} ++ ++static int ++qca8k_parse_port_config(struct qca8k_priv *priv) ++{ ++ int port, cpu_port_index = -1, ret; ++ struct device_node *port_dn; ++ phy_interface_t mode; ++ struct dsa_port *dp; ++ u32 delay; ++ ++ /* We have 2 CPU port. Check them */ ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Skip every other port */ ++ if (port != 0 && port != 6) ++ continue; ++ ++ dp = dsa_to_port(priv->ds, port); ++ port_dn = dp->dn; ++ cpu_port_index++; ++ ++ if (!of_device_is_available(port_dn)) ++ continue; ++ ++ ret = of_get_phy_mode(port_dn, &mode); ++ if (ret) ++ continue; ++ ++ switch (mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ case PHY_INTERFACE_MODE_SGMII: ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID) ++ delay = 1; ++ ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { ++ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; ++ ++ delay = 0; ++ ++ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) ++ /* Switch regs accept value in ns, convert ps to ns */ ++ delay = delay / 1000; ++ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ delay = 2; ++ ++ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { ++ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); ++ delay = 3; ++ } ++ ++ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; ++ ++ /* Skip sgmii parsing for rgmii* mode */ ++ if (mode == PHY_INTERFACE_MODE_RGMII || ++ mode == PHY_INTERFACE_MODE_RGMII_ID || ++ mode == PHY_INTERFACE_MODE_RGMII_TXID || ++ mode == PHY_INTERFACE_MODE_RGMII_RXID) ++ break; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) ++ priv->ports_config.sgmii_tx_clk_falling_edge = true; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) ++ priv->ports_config.sgmii_rx_clk_falling_edge = true; ++ ++ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { ++ priv->ports_config.sgmii_enable_pll = true; ++ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); ++ priv->ports_config.sgmii_enable_pll = false; ++ } ++ ++ if (priv->switch_revision < 2) ++ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); ++ } ++ ++ break; ++ default: ++ continue; ++ } ++ } ++ ++ return 0; ++} ++ ++static int ++qca8k_setup(struct dsa_switch *ds) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int cpu_port, ret, i; ++ u32 mask; ++ ++ cpu_port = qca8k_find_cpu_port(ds); ++ if (cpu_port < 0) { ++ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); ++ return cpu_port; ++ } ++ ++ /* Parse CPU port config to be later used in phy_link mac_config */ ++ ret = qca8k_parse_port_config(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_mdio_bus(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_of_pws_reg(priv); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_setup_mac_pwr_sel(priv); ++ if (ret) ++ return ret; ++ ++ /* Make sure MAC06 is disabled */ ++ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, ++ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); ++ if (ret) { ++ dev_err(priv->dev, "failed disabling MAC06 exchange"); ++ return ret; ++ } ++ ++ /* Enable CPU Port */ ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ++ if (ret) { ++ dev_err(priv->dev, "failed enabling CPU port"); ++ return ret; ++ } ++ ++ /* Enable MIB counters */ ++ ret = qca8k_mib_init(priv); ++ if (ret) ++ dev_warn(priv->dev, "mib init failed"); ++ ++ /* Initial setup of all ports */ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, 0); ++ if (ret) ++ return ret; ++ ++ /* Enable QCA header mode on all cpu ports */ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | ++ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); ++ if (ret) { ++ dev_err(priv->dev, "failed enabling QCA header mode"); ++ return ret; ++ } ++ } ++ ++ /* Disable MAC by default on all user ports */ ++ if (dsa_is_user_port(ds, i)) ++ qca8k_port_set_status(priv, i, 0); ++ } ++ ++ /* Forward all unknown frames to CPU port for Linux processing ++ * Notice that in multi-cpu config only one port should be set ++ * for igmp, unknown, multicast and broadcast packet ++ */ ++ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | ++ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); ++ if (ret) ++ return ret; ++ ++ /* Setup connection between CPU port & user ports ++ * Configure specific switch configuration for ports ++ */ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ /* CPU port gets connected to all user ports of the switch */ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); ++ if (ret) ++ return ret; ++ } ++ ++ /* Individual user ports get connected to CPU port only */ ++ if (dsa_is_user_port(ds, i)) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_MEMBER, ++ BIT(cpu_port)); ++ if (ret) ++ return ret; ++ ++ /* Enable ARP Auto-learning by default */ ++ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), ++ QCA8K_PORT_LOOKUP_LEARN); ++ if (ret) ++ return ret; ++ ++ /* For port based vlans to work we need to set the ++ * default egress vid ++ */ ++ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), ++ QCA8K_EGREES_VLAN_PORT_MASK(i), ++ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), ++ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | ++ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); ++ if (ret) ++ return ret; ++ } ++ ++ /* The port 5 of the qca8337 have some problem in flood condition. The ++ * original legacy driver had some specific buffer and priority settings ++ * for the different port suggested by the QCA switch team. Add this ++ * missing settings to improve switch stability under load condition. ++ * This problem is limited to qca8337 and other qca8k switch are not affected. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8337) { ++ switch (i) { ++ /* The 2 CPU port and port 5 requires some different ++ * priority than any other ports. ++ */ ++ case 0: ++ case 5: ++ case 6: ++ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | ++ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); ++ break; ++ default: ++ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | ++ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | ++ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); ++ } ++ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); ++ ++ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | ++ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_WRED_EN; ++ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), ++ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | ++ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | ++ QCA8K_PORT_HOL_CTRL1_WRED_EN, ++ mask); ++ } ++ } ++ ++ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ ++ if (priv->switch_id == QCA8K_ID_QCA8327) { ++ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | ++ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); ++ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, ++ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | ++ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, ++ mask); ++ } ++ ++ /* Setup our port MTUs to match power on defaults */ ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); ++ if (ret) ++ dev_warn(priv->dev, "failed setting MTU settings"); ++ ++ /* Flush the FDB table */ ++ qca8k_fdb_flush(priv); ++ ++ /* We don't have interrupts for link changes, so we need to poll */ ++ ds->pcs_poll = true; ++ ++ /* Set min a max ageing value supported */ ++ ds->ageing_time_min = 7000; ++ ds->ageing_time_max = 458745000; ++ ++ /* Set max number of LAGs supported */ ++ ds->num_lag_ids = QCA8K_NUM_LAGS; ++ ++ return 0; ++} ++ ++static void ++qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, ++ u32 reg) ++{ ++ u32 delay, val = 0; ++ int ret; ++ ++ /* Delay can be declared in 3 different way. ++ * Mode to rgmii and internal-delay standard binding defined ++ * rgmii-id or rgmii-tx/rx phy mode set. ++ * The parse logic set a delay different than 0 only when one ++ * of the 3 different way is used. In all other case delay is ++ * not enabled. With ID or TX/RXID delay is enabled and set ++ * to the default and recommended value. ++ */ ++ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; ++ } ++ ++ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { ++ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; ++ ++ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; ++ } ++ ++ /* Set RGMII delay based on the selected values */ ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | ++ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, ++ val); ++ if (ret) ++ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", ++ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); ++} ++ ++static void ++qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, ++ const struct phylink_link_state *state) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int cpu_port_index, ret; ++ u32 reg, val; ++ ++ switch (port) { ++ case 0: /* 1st CPU port */ ++ if (state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII) ++ return; ++ ++ reg = QCA8K_REG_PORT0_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT0; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ /* Internal PHY, nothing to do */ ++ return; ++ case 6: /* 2nd CPU port / external PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII && ++ state->interface != PHY_INTERFACE_MODE_1000BASEX) ++ return; ++ ++ reg = QCA8K_REG_PORT6_PAD_CTRL; ++ cpu_port_index = QCA8K_CPU_PORT6; ++ break; ++ default: ++ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); ++ return; ++ } ++ ++ if (port != 6 && phylink_autoneg_inband(mode)) { ++ dev_err(ds->dev, "%s: in-band negotiation unsupported\n", ++ __func__); ++ return; ++ } ++ ++ switch (state->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); ++ ++ /* Configure rgmii delay */ ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ ++ /* QCA8337 requires to set rgmii rx delay for all ports. ++ * This is enabled through PORT5_PAD_CTRL for all ports, ++ * rather than individual port registers. ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8337) ++ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, ++ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_1000BASEX: ++ /* Enable SGMII on the port */ ++ qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); ++ ++ /* Enable/disable SerDes auto-negotiation as necessary */ ++ ret = qca8k_read(priv, QCA8K_REG_PWS, &val); ++ if (ret) ++ return; ++ if (phylink_autoneg_inband(mode)) ++ val &= ~QCA8K_PWS_SERDES_AEN_DIS; ++ else ++ val |= QCA8K_PWS_SERDES_AEN_DIS; ++ qca8k_write(priv, QCA8K_REG_PWS, val); ++ ++ /* Configure the SGMII parameters */ ++ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); ++ if (ret) ++ return; ++ ++ val |= QCA8K_SGMII_EN_SD; ++ ++ if (priv->ports_config.sgmii_enable_pll) ++ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | ++ QCA8K_SGMII_EN_TX; ++ ++ if (dsa_is_cpu_port(ds, port)) { ++ /* CPU port, we're talking to the CPU MAC, be a PHY */ ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_PHY; ++ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_MAC; ++ } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { ++ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; ++ val |= QCA8K_SGMII_MODE_CTRL_BASEX; ++ } ++ ++ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); ++ ++ /* From original code is reported port instability as SGMII also ++ * require delay set. Apply advised values here or take them from DT. ++ */ ++ if (state->interface == PHY_INTERFACE_MODE_SGMII) ++ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); ++ ++ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and ++ * falling edge is set writing in the PORT0 PAD reg ++ */ ++ if (priv->switch_id == QCA8K_ID_QCA8327 || ++ priv->switch_id == QCA8K_ID_QCA8337) ++ reg = QCA8K_REG_PORT0_PAD_CTRL; ++ ++ val = 0; ++ ++ /* SGMII Clock phase configuration */ ++ if (priv->ports_config.sgmii_rx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; ++ ++ if (priv->ports_config.sgmii_tx_clk_falling_edge) ++ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; ++ ++ if (val) ++ ret = qca8k_rmw(priv, reg, ++ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | ++ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, ++ val); ++ ++ break; ++ default: ++ dev_err(ds->dev, "xMII mode %s not supported for port %d\n", ++ phy_modes(state->interface), port); ++ return; ++ } ++} ++ ++static void ++qca8k_phylink_validate(struct dsa_switch *ds, int port, ++ unsigned long *supported, ++ struct phylink_link_state *state) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; ++ ++ switch (port) { ++ case 0: /* 1st CPU port */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII) ++ goto unsupported; ++ break; ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ /* Internal PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_GMII && ++ state->interface != PHY_INTERFACE_MODE_INTERNAL) ++ goto unsupported; ++ break; ++ case 6: /* 2nd CPU port / external PHY */ ++ if (state->interface != PHY_INTERFACE_MODE_NA && ++ state->interface != PHY_INTERFACE_MODE_RGMII && ++ state->interface != PHY_INTERFACE_MODE_RGMII_ID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && ++ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && ++ state->interface != PHY_INTERFACE_MODE_SGMII && ++ state->interface != PHY_INTERFACE_MODE_1000BASEX) ++ goto unsupported; ++ break; ++ default: ++unsupported: ++ linkmode_zero(supported); ++ return; ++ } ++ ++ phylink_set_port_modes(mask); ++ phylink_set(mask, Autoneg); ++ ++ phylink_set(mask, 1000baseT_Full); ++ phylink_set(mask, 10baseT_Half); ++ phylink_set(mask, 10baseT_Full); ++ phylink_set(mask, 100baseT_Half); ++ phylink_set(mask, 100baseT_Full); ++ ++ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) ++ phylink_set(mask, 1000baseX_Full); ++ ++ phylink_set(mask, Pause); ++ phylink_set(mask, Asym_Pause); ++ ++ linkmode_and(supported, supported, mask); ++ linkmode_and(state->advertising, state->advertising, mask); ++} ++ ++static int ++qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, ++ struct phylink_link_state *state) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg; ++ int ret; ++ ++ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); ++ if (ret < 0) ++ return ret; ++ ++ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); ++ state->an_complete = state->link; ++ state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); ++ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : ++ DUPLEX_HALF; ++ ++ switch (reg & QCA8K_PORT_STATUS_SPEED) { ++ case QCA8K_PORT_STATUS_SPEED_10: ++ state->speed = SPEED_10; ++ break; ++ case QCA8K_PORT_STATUS_SPEED_100: ++ state->speed = SPEED_100; ++ break; ++ case QCA8K_PORT_STATUS_SPEED_1000: ++ state->speed = SPEED_1000; ++ break; ++ default: ++ state->speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ state->pause = MLO_PAUSE_NONE; ++ if (reg & QCA8K_PORT_STATUS_RXFLOW) ++ state->pause |= MLO_PAUSE_RX; ++ if (reg & QCA8K_PORT_STATUS_TXFLOW) ++ state->pause |= MLO_PAUSE_TX; ++ ++ return 1; ++} ++ ++static void ++qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, ++ phy_interface_t interface) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ qca8k_port_set_status(priv, port, 0); ++} ++ ++static void ++qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, ++ phy_interface_t interface, struct phy_device *phydev, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg; ++ ++ if (phylink_autoneg_inband(mode)) { ++ reg = QCA8K_PORT_STATUS_LINK_AUTO; ++ } else { ++ switch (speed) { ++ case SPEED_10: ++ reg = QCA8K_PORT_STATUS_SPEED_10; ++ break; ++ case SPEED_100: ++ reg = QCA8K_PORT_STATUS_SPEED_100; ++ break; ++ case SPEED_1000: ++ reg = QCA8K_PORT_STATUS_SPEED_1000; ++ break; ++ default: ++ reg = QCA8K_PORT_STATUS_LINK_AUTO; ++ break; ++ } ++ ++ if (duplex == DUPLEX_FULL) ++ reg |= QCA8K_PORT_STATUS_DUPLEX; ++ ++ if (rx_pause || dsa_is_cpu_port(ds, port)) ++ reg |= QCA8K_PORT_STATUS_RXFLOW; ++ ++ if (tx_pause || dsa_is_cpu_port(ds, port)) ++ reg |= QCA8K_PORT_STATUS_TXFLOW; ++ } ++ ++ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; ++ ++ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); ++} ++ ++static void ++qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int i; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ for (i = 0; i < priv->info->mib_count; i++) ++ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, ++ ETH_GSTRING_LEN); ++} ++ ++static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) ++{ ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ const struct qca8k_mib_desc *mib; ++ struct mib_ethhdr *mib_ethhdr; ++ int i, mib_len, offset = 0; ++ u64 *data; ++ u8 port; ++ ++ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); ++ mib_eth_data = &priv->mib_eth_data; ++ ++ /* The switch autocast every port. Ignore other packet and ++ * parse only the requested one. ++ */ ++ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); ++ if (port != mib_eth_data->req_port) ++ goto exit; ++ ++ data = mib_eth_data->data; ++ ++ for (i = 0; i < priv->info->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ ++ /* First 3 mib are present in the skb head */ ++ if (i < 3) { ++ data[i] = mib_ethhdr->data[i]; ++ continue; ++ } ++ ++ mib_len = sizeof(uint32_t); ++ ++ /* Some mib are 64 bit wide */ ++ if (mib->size == 2) ++ mib_len = sizeof(uint64_t); ++ ++ /* Copy the mib value from packet to the */ ++ memcpy(data + i, skb->data + offset, mib_len); ++ ++ /* Set the offset for the next mib */ ++ offset += mib_len; ++ } ++ ++exit: ++ /* Complete on receiving all the mib packet */ ++ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) ++ complete(&mib_eth_data->rw_done); ++} ++ ++static int ++qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) ++{ ++ struct dsa_port *dp = dsa_to_port(ds, port); ++ struct qca8k_mib_eth_data *mib_eth_data; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ mib_eth_data = &priv->mib_eth_data; ++ ++ mutex_lock(&mib_eth_data->mutex); ++ ++ reinit_completion(&mib_eth_data->rw_done); ++ ++ mib_eth_data->req_port = dp->index; ++ mib_eth_data->data = data; ++ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ /* Send mib autocast request */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | ++ QCA8K_MIB_BUSY); ++ ++ mutex_unlock(&priv->reg_mutex); ++ ++ if (ret) ++ goto exit; ++ ++ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); ++ ++exit: ++ mutex_unlock(&mib_eth_data->mutex); ++ ++ return ret; ++} ++ ++static void ++qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ const struct qca8k_mib_desc *mib; ++ u32 reg, i, val; ++ u32 hi = 0; ++ int ret; ++ ++ if (priv->mgmt_master && priv->info->ops->autocast_mib && ++ priv->info->ops->autocast_mib(ds, port, data) > 0) ++ return; ++ ++ for (i = 0; i < priv->info->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; ++ ++ ret = qca8k_read(priv, reg, &val); ++ if (ret < 0) ++ continue; ++ ++ if (mib->size == 2) { ++ ret = qca8k_read(priv, reg + 4, &hi); ++ if (ret < 0) ++ continue; ++ } ++ ++ data[i] = val; ++ if (mib->size == 2) ++ data[i] |= (u64)hi << 32; ++ } ++} ++ ++static int ++qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ if (sset != ETH_SS_STATS) ++ return 0; ++ ++ return priv->info->mib_count; ++} ++ ++static int ++qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); ++ u32 reg; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); ++ if (ret < 0) ++ goto exit; ++ ++ if (eee->eee_enabled) ++ reg |= lpi_en; ++ else ++ reg &= ~lpi_en; ++ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int ++qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) ++{ ++ /* Nothing to do on the port's MAC */ ++ return 0; ++} ++ ++static void ++qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ default: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; ++ break; ++ } ++ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); ++} ++ ++static int ++qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int port_mask, cpu_port; ++ int i, ret; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ port_mask = BIT(cpu_port); ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Add this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ ret = regmap_set_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ if (ret) ++ return ret; ++ if (i != port) ++ port_mask |= BIT(i); ++ } ++ ++ /* Add all other ports to this ports portvlan mask */ ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, port_mask); ++ ++ return ret; ++} ++ ++static void ++qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ int cpu_port, i; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Remove this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ regmap_clear_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ } ++ ++ /* Set the cpu port to be the only one in the portvlan mask of ++ * this port ++ */ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); ++} ++ ++static void ++qca8k_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int ++qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ unsigned int secs = msecs / 1000; ++ u32 val; ++ ++ /* AGE_TIME reg is set in 7s step */ ++ val = secs / 7; ++ ++ /* Handle case with 0 as val to NOT disable ++ * learning ++ */ ++ if (!val) ++ val = 1; ++ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, ++ QCA8K_ATU_AGE_TIME(val)); ++} ++ ++static int ++qca8k_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ ++ qca8k_port_set_status(priv, port, 1); ++ priv->port_enabled_map |= BIT(port); ++ ++ if (dsa_is_user_port(ds, port)) ++ phy_support_asym_pause(phy); ++ ++ return 0; ++} ++ ++static void ++qca8k_port_disable(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ ++ qca8k_port_set_status(priv, port, 0); ++ priv->port_enabled_map &= ~BIT(port); ++} ++ ++static int ++qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ /* We have only have a general MTU setting. ++ * DSA always set the CPU port's MTU to the largest MTU of the slave ++ * ports. ++ * Setting MTU just for the CPU port is sufficient to correctly set a ++ * value for every port. ++ */ ++ if (!dsa_is_cpu_port(ds, port)) ++ return 0; ++ ++ /* To change the MAX_FRAME_SIZE the cpu ports must be off or ++ * the switch panics. ++ * Turn off both cpu ports before applying the new value to prevent ++ * this. ++ */ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 0); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 0); ++ ++ /* Include L2 header / FCS length */ ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); ++ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 1); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 1); ++ ++ return ret; ++} ++ ++static int ++qca8k_port_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return QCA8K_MAX_MTU; ++} ++ ++static int ++qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, ++ u16 port_mask, u16 vid) ++{ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_add(priv, addr, port_mask, vid, ++ QCA8K_ATU_STATUS_STATIC); ++} ++ ++static int ++qca8k_port_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); ++} ++ ++static int ++qca8k_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_del(priv, addr, port_mask, vid); ++} ++ ++static int ++qca8k_port_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ struct qca8k_fdb _fdb = { 0 }; ++ int cnt = QCA8K_NUM_FDB_RECORDS; ++ bool is_static; ++ int ret = 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { ++ if (!_fdb.aging) ++ break; ++ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); ++ ret = cb(_fdb.mac, _fdb.vid, is_static, data); ++ if (ret) ++ break; ++ } ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++static int ++qca8k_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); ++} ++ ++static int ++qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); ++} ++ ++static int ++qca8k_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int monitor_port, ret; ++ u32 reg, val; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* QCA83xx can have only one port set to mirror mode. ++ * Check that the correct port is requested and return error otherwise. ++ * When no mirror port is set, the values is set to 0xF ++ */ ++ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) ++ return -EEXIST; ++ ++ /* Set the monitor port */ ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, ++ mirror->to_local_port); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ return ret; ++ ++ if (ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_update_bits(priv->regmap, reg, val, val); ++ if (ret) ++ return ret; ++ ++ /* Track mirror port for tx and rx to decide when the ++ * mirror port has to be disabled. ++ */ ++ if (ingress) ++ priv->mirror_rx |= BIT(port); ++ else ++ priv->mirror_tx |= BIT(port); ++ ++ return 0; ++} ++ ++static void ++qca8k_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg, val; ++ int ret; ++ ++ if (mirror->ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_clear_bits(priv->regmap, reg, val); ++ if (ret) ++ goto err; ++ ++ if (mirror->ingress) ++ priv->mirror_rx &= ~BIT(port); ++ else ++ priv->mirror_tx &= ~BIT(port); ++ ++ /* No port set to send packet to mirror port. Disable mirror port */ ++ if (!priv->mirror_rx && !priv->mirror_tx) { ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ goto err; ++ } ++err: ++ dev_err(priv->dev, "Failed to del mirror port from %d", port); ++} ++ ++static int ++qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, ++ struct netlink_ext_ack *extack) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ if (vlan_filtering) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); ++ } else { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); ++ } ++ ++ return ret; ++} ++ ++static int ++qca8k_port_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack) ++{ ++ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; ++ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); ++ if (ret) { ++ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); ++ return ret; ++ } ++ ++ if (pvid) { ++ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), ++ QCA8K_EGREES_VLAN_PORT_MASK(port), ++ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), ++ QCA8K_PORT_VLAN_CVID(vlan->vid) | ++ QCA8K_PORT_VLAN_SVID(vlan->vid)); ++ } ++ ++ return ret; ++} ++ ++static int ++qca8k_port_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_del(priv, port, vlan->vid); ++ if (ret) ++ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); ++ ++ return ret; ++} ++ ++static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Communicate to the phy internal driver the switch revision. ++ * Based on the switch revision different values needs to be ++ * set to the dbg and mmd reg on the phy. ++ * The first 2 bit are used to communicate the switch revision ++ * to the phy driver. ++ */ ++ if (port > 0 && port < 6) ++ return priv->switch_revision; ++ ++ return 0; ++} ++ ++static enum dsa_tag_protocol ++qca8k_get_tag_protocol(struct dsa_switch *ds, int port, ++ enum dsa_tag_protocol mp) ++{ ++ return DSA_TAG_PROTO_QCA; ++} ++ ++static bool ++qca8k_lag_can_offload(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct dsa_port *dp; ++ int id, members = 0; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ if (id < 0 || id >= ds->num_lag_ids) ++ return false; ++ ++ dsa_lag_foreach_port(dp, ds->dst, lag) ++ /* Includes the port joining the LAG */ ++ members++; ++ ++ if (members > QCA8K_NUM_PORTS_FOR_LAG) ++ return false; ++ ++ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) ++ return false; ++ ++ if (info->hash_type != NETDEV_LAG_HASH_L2 && ++ info->hash_type != NETDEV_LAG_HASH_L23) ++ return false; ++ ++ return true; ++} ++ ++static int ++qca8k_lag_setup_hash(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ bool unique_lag = true; ++ u32 hash = 0; ++ int i, id; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ switch (info->hash_type) { ++ case NETDEV_LAG_HASH_L23: ++ hash |= QCA8K_TRUNK_HASH_SIP_EN; ++ hash |= QCA8K_TRUNK_HASH_DIP_EN; ++ fallthrough; ++ case NETDEV_LAG_HASH_L2: ++ hash |= QCA8K_TRUNK_HASH_SA_EN; ++ hash |= QCA8K_TRUNK_HASH_DA_EN; ++ break; ++ default: /* We should NEVER reach this */ ++ return -EOPNOTSUPP; ++ } ++ ++ /* Check if we are the unique configured LAG */ ++ dsa_lags_foreach_id(i, ds->dst) ++ if (i != id && dsa_lag_dev(ds->dst, i)) { ++ unique_lag = false; ++ break; ++ } ++ ++ /* Hash Mode is global. Make sure the same Hash Mode ++ * is set to all the 4 possible lag. ++ * If we are the unique LAG we can set whatever hash ++ * mode we want. ++ * To change hash mode it's needed to remove all LAG ++ * and change the mode with the latest. ++ */ ++ if (unique_lag) { ++ priv->lag_hash_mode = hash; ++ } else if (priv->lag_hash_mode != hash) { ++ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, ++ QCA8K_TRUNK_HASH_MASK, hash); ++} ++ ++static int ++qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, ++ struct net_device *lag, bool delete) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret, id, i; ++ u32 val; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ /* Read current port member */ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* Shift val to the correct trunk */ ++ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); ++ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; ++ if (delete) ++ val &= ~BIT(port); ++ else ++ val |= BIT(port); ++ ++ /* Update port member. With empty portmap disable trunk */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, ++ QCA8K_REG_GOL_TRUNK_MEMBER(id) | ++ QCA8K_REG_GOL_TRUNK_EN(id), ++ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | ++ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); ++ ++ /* Search empty member if adding or port on deleting */ ++ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); ++ if (ret) ++ return ret; ++ ++ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; ++ ++ if (delete) { ++ /* If port flagged to be disabled assume this member is ++ * empty ++ */ ++ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; ++ if (val != port) ++ continue; ++ } else { ++ /* If port flagged to be enabled assume this member is ++ * already set ++ */ ++ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ } ++ ++ /* We have found the member to add/remove */ ++ break; ++ } ++ ++ /* Set port in the correct port mask or disable port if in delete mode */ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), ++ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | ++ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); ++} ++ ++static int ++qca8k_port_lag_join(struct dsa_switch *ds, int port, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ int ret; ++ ++ if (!qca8k_lag_can_offload(ds, lag, info)) ++ return -EOPNOTSUPP; ++ ++ ret = qca8k_lag_setup_hash(ds, lag, info); ++ if (ret) ++ return ret; ++ ++ return qca8k_lag_refresh_portmap(ds, port, lag, false); ++} ++ ++static int ++qca8k_port_lag_leave(struct dsa_switch *ds, int port, ++ struct net_device *lag) ++{ ++ return qca8k_lag_refresh_portmap(ds, port, lag, true); ++} ++ ++static void ++qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, ++ bool operational) ++{ ++ struct dsa_port *dp = master->dsa_ptr; ++ struct qca8k_priv *priv = ds->priv; ++ ++ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ ++ if (dp->index != 0) ++ return; ++ ++ mutex_lock(&priv->mgmt_eth_data.mutex); ++ mutex_lock(&priv->mib_eth_data.mutex); ++ ++ priv->mgmt_master = operational ? (struct net_device *)master : NULL; ++ ++ mutex_unlock(&priv->mib_eth_data.mutex); ++ mutex_unlock(&priv->mgmt_eth_data.mutex); ++} ++ ++static int qca8k_connect_tag_protocol(struct dsa_switch *ds, ++ enum dsa_tag_protocol proto) ++{ ++ struct qca_tagger_data *tagger_data; ++ ++ switch (proto) { ++ case DSA_TAG_PROTO_QCA: ++ tagger_data = ds->tagger_data; ++ ++ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; ++ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; ++ ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static const struct dsa_switch_ops qca8k_switch_ops = { ++ .get_tag_protocol = qca8k_get_tag_protocol, ++ .setup = qca8k_setup, ++ .get_strings = qca8k_get_strings, ++ .get_ethtool_stats = qca8k_get_ethtool_stats, ++ .get_sset_count = qca8k_get_sset_count, ++ .set_ageing_time = qca8k_set_ageing_time, ++ .get_mac_eee = qca8k_get_mac_eee, ++ .set_mac_eee = qca8k_set_mac_eee, ++ .port_enable = qca8k_port_enable, ++ .port_disable = qca8k_port_disable, ++ .port_change_mtu = qca8k_port_change_mtu, ++ .port_max_mtu = qca8k_port_max_mtu, ++ .port_stp_state_set = qca8k_port_stp_state_set, ++ .port_bridge_join = qca8k_port_bridge_join, ++ .port_bridge_leave = qca8k_port_bridge_leave, ++ .port_fast_age = qca8k_port_fast_age, ++ .port_fdb_add = qca8k_port_fdb_add, ++ .port_fdb_del = qca8k_port_fdb_del, ++ .port_fdb_dump = qca8k_port_fdb_dump, ++ .port_mdb_add = qca8k_port_mdb_add, ++ .port_mdb_del = qca8k_port_mdb_del, ++ .port_mirror_add = qca8k_port_mirror_add, ++ .port_mirror_del = qca8k_port_mirror_del, ++ .port_vlan_filtering = qca8k_port_vlan_filtering, ++ .port_vlan_add = qca8k_port_vlan_add, ++ .port_vlan_del = qca8k_port_vlan_del, ++ .phylink_validate = qca8k_phylink_validate, ++ .phylink_mac_link_state = qca8k_phylink_mac_link_state, ++ .phylink_mac_config = qca8k_phylink_mac_config, ++ .phylink_mac_link_down = qca8k_phylink_mac_link_down, ++ .phylink_mac_link_up = qca8k_phylink_mac_link_up, ++ .get_phy_flags = qca8k_get_phy_flags, ++ .port_lag_join = qca8k_port_lag_join, ++ .port_lag_leave = qca8k_port_lag_leave, ++ .master_state_change = qca8k_master_change, ++ .connect_tag_protocol = qca8k_connect_tag_protocol, ++}; ++ ++static int qca8k_read_switch_id(struct qca8k_priv *priv) ++{ ++ u32 val; ++ u8 id; ++ int ret; ++ ++ if (!priv->info) ++ return -ENODEV; ++ ++ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); ++ if (ret < 0) ++ return -ENODEV; ++ ++ id = QCA8K_MASK_CTRL_DEVICE_ID(val); ++ if (id != priv->info->id) { ++ dev_err(priv->dev, ++ "Switch id detected %x but expected %x", ++ id, priv->info->id); ++ return -ENODEV; ++ } ++ ++ priv->switch_id = id; ++ ++ /* Save revision to communicate to the internal PHY driver */ ++ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); ++ ++ return 0; ++} ++ ++static int ++qca8k_sw_probe(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv; ++ int ret; ++ ++ /* allocate the private data struct so that we can probe the switches ++ * ID register ++ */ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->info = of_device_get_match_data(priv->dev); ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ ++ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", ++ GPIOD_ASIS); ++ if (IS_ERR(priv->reset_gpio)) ++ return PTR_ERR(priv->reset_gpio); ++ ++ if (priv->reset_gpio) { ++ gpiod_set_value_cansleep(priv->reset_gpio, 1); ++ /* The active low duration must be greater than 10 ms ++ * and checkpatch.pl wants 20 ms. ++ */ ++ msleep(20); ++ gpiod_set_value_cansleep(priv->reset_gpio, 0); ++ } ++ ++ /* Start by setting up the register mapping */ ++ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, ++ &qca8k_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ dev_err(priv->dev, "regmap initialization failed"); ++ return PTR_ERR(priv->regmap); ++ } ++ ++ priv->mdio_cache.page = 0xffff; ++ priv->mdio_cache.lo = 0xffff; ++ priv->mdio_cache.hi = 0xffff; ++ ++ /* Check the detected switch id */ ++ ret = qca8k_read_switch_id(priv); ++ if (ret) ++ return ret; ++ ++ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); ++ if (!priv->ds) ++ return -ENOMEM; ++ ++ mutex_init(&priv->mgmt_eth_data.mutex); ++ init_completion(&priv->mgmt_eth_data.rw_done); ++ ++ mutex_init(&priv->mib_eth_data.mutex); ++ init_completion(&priv->mib_eth_data.rw_done); ++ ++ priv->ds->dev = &mdiodev->dev; ++ priv->ds->num_ports = QCA8K_NUM_PORTS; ++ priv->ds->priv = priv; ++ priv->ds->ops = &qca8k_switch_ops; ++ mutex_init(&priv->reg_mutex); ++ dev_set_drvdata(&mdiodev->dev, priv); ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static void ++qca8k_sw_remove(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ int i; ++ ++ if (!priv) ++ return; ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) ++ qca8k_port_set_status(priv, i, 0); ++ ++ dsa_unregister_switch(priv->ds); ++ ++ dev_set_drvdata(&mdiodev->dev, NULL); ++} ++ ++static void qca8k_sw_shutdown(struct mdio_device *mdiodev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ ++ if (!priv) ++ return; ++ ++ dsa_switch_shutdown(priv->ds); ++ ++ dev_set_drvdata(&mdiodev->dev, NULL); ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static void ++qca8k_set_pm(struct qca8k_priv *priv, int enable) ++{ ++ int port; ++ ++ for (port = 0; port < QCA8K_NUM_PORTS; port++) { ++ /* Do not enable on resume if the port was ++ * disabled before. ++ */ ++ if (!(priv->port_enabled_map & BIT(port))) ++ continue; ++ ++ qca8k_port_set_status(priv, port, enable); ++ } ++} ++ ++static int qca8k_suspend(struct device *dev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(dev); ++ ++ qca8k_set_pm(priv, 0); ++ ++ return dsa_switch_suspend(priv->ds); ++} ++ ++static int qca8k_resume(struct device *dev) ++{ ++ struct qca8k_priv *priv = dev_get_drvdata(dev); ++ ++ qca8k_set_pm(priv, 1); ++ ++ return dsa_switch_resume(priv->ds); ++} ++#endif /* CONFIG_PM_SLEEP */ ++ ++static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, ++ qca8k_suspend, qca8k_resume); ++ ++static const struct qca8k_info_ops qca8xxx_ops = { ++ .autocast_mib = qca8k_get_ethtool_stats_eth, ++}; ++ ++static const struct qca8k_match_data qca8327 = { ++ .id = QCA8K_ID_QCA8327, ++ .reduced_package = true, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, ++ .ops = &qca8xxx_ops, ++}; ++ ++static const struct qca8k_match_data qca8328 = { ++ .id = QCA8K_ID_QCA8327, ++ .mib_count = QCA8K_QCA832X_MIB_COUNT, ++ .ops = &qca8xxx_ops, ++}; ++ ++static const struct qca8k_match_data qca833x = { ++ .id = QCA8K_ID_QCA8337, ++ .mib_count = QCA8K_QCA833X_MIB_COUNT, ++ .ops = &qca8xxx_ops, ++}; ++ ++static const struct of_device_id qca8k_of_match[] = { ++ { .compatible = "qca,qca8327", .data = &qca8327 }, ++ { .compatible = "qca,qca8328", .data = &qca8328 }, ++ { .compatible = "qca,qca8334", .data = &qca833x }, ++ { .compatible = "qca,qca8337", .data = &qca833x }, ++ { /* sentinel */ }, ++}; ++ ++static struct mdio_driver qca8kmdio_driver = { ++ .probe = qca8k_sw_probe, ++ .remove = qca8k_sw_remove, ++ .shutdown = qca8k_sw_shutdown, ++ .mdiodrv.driver = { ++ .name = "qca8k", ++ .of_match_table = qca8k_of_match, ++ .pm = &qca8k_pm_ops, ++ }, ++}; ++ ++mdio_module_driver(qca8kmdio_driver); ++ ++MODULE_AUTHOR("Mathieu Olivari, John Crispin "); ++MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:qca8k"); +--- /dev/null ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -0,0 +1,63 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2009 Felix Fietkau ++ * Copyright (C) 2011-2012 Gabor Juhos ++ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. ++ * Copyright (c) 2016 John Crispin ++ */ ++ ++#include ++#include ++ ++#include "qca8k.h" ++ ++#define MIB_DESC(_s, _o, _n) \ ++ { \ ++ .size = (_s), \ ++ .offset = (_o), \ ++ .name = (_n), \ ++ } ++ ++const struct qca8k_mib_desc ar8327_mib[] = { ++ MIB_DESC(1, 0x00, "RxBroad"), ++ MIB_DESC(1, 0x04, "RxPause"), ++ MIB_DESC(1, 0x08, "RxMulti"), ++ MIB_DESC(1, 0x0c, "RxFcsErr"), ++ MIB_DESC(1, 0x10, "RxAlignErr"), ++ MIB_DESC(1, 0x14, "RxRunt"), ++ MIB_DESC(1, 0x18, "RxFragment"), ++ MIB_DESC(1, 0x1c, "Rx64Byte"), ++ MIB_DESC(1, 0x20, "Rx128Byte"), ++ MIB_DESC(1, 0x24, "Rx256Byte"), ++ MIB_DESC(1, 0x28, "Rx512Byte"), ++ MIB_DESC(1, 0x2c, "Rx1024Byte"), ++ MIB_DESC(1, 0x30, "Rx1518Byte"), ++ MIB_DESC(1, 0x34, "RxMaxByte"), ++ MIB_DESC(1, 0x38, "RxTooLong"), ++ MIB_DESC(2, 0x3c, "RxGoodByte"), ++ MIB_DESC(2, 0x44, "RxBadByte"), ++ MIB_DESC(1, 0x4c, "RxOverFlow"), ++ MIB_DESC(1, 0x50, "Filtered"), ++ MIB_DESC(1, 0x54, "TxBroad"), ++ MIB_DESC(1, 0x58, "TxPause"), ++ MIB_DESC(1, 0x5c, "TxMulti"), ++ MIB_DESC(1, 0x60, "TxUnderRun"), ++ MIB_DESC(1, 0x64, "Tx64Byte"), ++ MIB_DESC(1, 0x68, "Tx128Byte"), ++ MIB_DESC(1, 0x6c, "Tx256Byte"), ++ MIB_DESC(1, 0x70, "Tx512Byte"), ++ MIB_DESC(1, 0x74, "Tx1024Byte"), ++ MIB_DESC(1, 0x78, "Tx1518Byte"), ++ MIB_DESC(1, 0x7c, "TxMaxByte"), ++ MIB_DESC(1, 0x80, "TxOverSize"), ++ MIB_DESC(2, 0x84, "TxByte"), ++ MIB_DESC(1, 0x8c, "TxCollision"), ++ MIB_DESC(1, 0x90, "TxAbortCol"), ++ MIB_DESC(1, 0x94, "TxMultiCol"), ++ MIB_DESC(1, 0x98, "TxSingleCol"), ++ MIB_DESC(1, 0x9c, "TxExcDefer"), ++ MIB_DESC(1, 0xa0, "TxDefer"), ++ MIB_DESC(1, 0xa4, "TxLateCol"), ++ MIB_DESC(1, 0xa8, "RXUnicast"), ++ MIB_DESC(1, 0xac, "TXUnicast"), ++}; +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -414,4 +414,7 @@ struct qca8k_fdb { + u8 mac[6]; + }; + ++/* Common setup function */ ++extern const struct qca8k_mib_desc ar8327_mib[]; ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch b/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch new file mode 100644 index 00000000000..012ab854742 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch @@ -0,0 +1,135 @@ +From d5f901eab2e9dfed1095995dfc98f231f4fd2971 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:13 +0200 +Subject: [PATCH 04/14] net: dsa: qca8k: move qca8k read/write/rmw and reg + table to common code + +The same reg table and read/write/rmw function are used by drivers +based on qca8k family switch. +Move them to common code to make it accessible also by other drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 42 ------------------------------ + drivers/net/dsa/qca/qca8k-common.c | 38 +++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 6 +++++ + 3 files changed, 44 insertions(+), 42 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -133,24 +133,6 @@ qca8k_set_page(struct qca8k_priv *priv, + return 0; + } + +-static int +-qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) +-{ +- return regmap_read(priv->regmap, reg, val); +-} +- +-static int +-qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) +-{ +- return regmap_write(priv->regmap, reg, val); +-} +- +-static int +-qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) +-{ +- return regmap_update_bits(priv->regmap, reg, mask, write_val); +-} +- + static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) + { + struct qca8k_mgmt_eth_data *mgmt_eth_data; +@@ -483,30 +465,6 @@ exit: + return ret; + } + +-static const struct regmap_range qca8k_readable_ranges[] = { +- regmap_reg_range(0x0000, 0x00e4), /* Global control */ +- regmap_reg_range(0x0100, 0x0168), /* EEE control */ +- regmap_reg_range(0x0200, 0x0270), /* Parser control */ +- regmap_reg_range(0x0400, 0x0454), /* ACL */ +- regmap_reg_range(0x0600, 0x0718), /* Lookup */ +- regmap_reg_range(0x0800, 0x0b70), /* QM */ +- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ +- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ +- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ +- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ +- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ +- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ +- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ +- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ +- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ +- +-}; +- +-static const struct regmap_access_table qca8k_readable_table = { +- .yes_ranges = qca8k_readable_ranges, +- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), +-}; +- + static struct regmap_config qca8k_regmap_config = { + .reg_bits = 16, + .val_bits = 32, +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -61,3 +61,41 @@ const struct qca8k_mib_desc ar8327_mib[] + MIB_DESC(1, 0xa8, "RXUnicast"), + MIB_DESC(1, 0xac, "TXUnicast"), + }; ++ ++int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) ++{ ++ return regmap_read(priv->regmap, reg, val); ++} ++ ++int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) ++{ ++ return regmap_write(priv->regmap, reg, val); ++} ++ ++int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) ++{ ++ return regmap_update_bits(priv->regmap, reg, mask, write_val); ++} ++ ++static const struct regmap_range qca8k_readable_ranges[] = { ++ regmap_reg_range(0x0000, 0x00e4), /* Global control */ ++ regmap_reg_range(0x0100, 0x0168), /* EEE control */ ++ regmap_reg_range(0x0200, 0x0270), /* Parser control */ ++ regmap_reg_range(0x0400, 0x0454), /* ACL */ ++ regmap_reg_range(0x0600, 0x0718), /* Lookup */ ++ regmap_reg_range(0x0800, 0x0b70), /* QM */ ++ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ ++ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ ++ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ ++ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ ++ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ ++ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ ++ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ ++ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ ++ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ ++}; ++ ++const struct regmap_access_table qca8k_readable_table = { ++ .yes_ranges = qca8k_readable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), ++}; +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -416,5 +416,11 @@ struct qca8k_fdb { + + /* Common setup function */ + extern const struct qca8k_mib_desc ar8327_mib[]; ++extern const struct regmap_access_table qca8k_readable_table; ++ ++/* Common read/write/rmw function */ ++int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); ++int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); ++int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); + + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch b/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch new file mode 100644 index 00000000000..0ed7ed41fbe --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch @@ -0,0 +1,145 @@ +From 910746444313dc463396cd63024cdf54ef04ef39 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:14 +0200 +Subject: [PATCH 05/14] net: dsa: qca8k: move qca8k bulk read/write helper to + common code + +The same ATU function are used by drivers based on qca8k family switch. +Move the bulk read/write helper to common code to declare these shared +ATU functions in common code. +These helper will be dropped when regmap correctly support bulk +read/write. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 39 ++---------------------------- + drivers/net/dsa/qca/qca8k-common.c | 39 ++++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 8 ++++++ + 3 files changed, 49 insertions(+), 37 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -343,43 +343,6 @@ qca8k_regmap_update_bits_eth(struct qca8 + } + + static int +-qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- +- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int +-qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +-{ +- int i, count = len / sizeof(u32), ret; +- u32 tmp; +- +- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) +- return 0; +- +- for (i = 0; i < count; i++) { +- tmp = val[i]; +- +- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); +- if (ret < 0) +- return ret; +- } +- +- return 0; +-} +- +-static int + qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ctx; +@@ -3096,6 +3059,8 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, + + static const struct qca8k_info_ops qca8xxx_ops = { + .autocast_mib = qca8k_get_ethtool_stats_eth, ++ .read_eth = qca8k_read_eth, ++ .write_eth = qca8k_write_eth, + }; + + static const struct qca8k_match_data qca8327 = { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -99,3 +99,42 @@ const struct regmap_access_table qca8k_r + .yes_ranges = qca8k_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), + }; ++ ++/* TODO: remove these extra ops when we can support regmap bulk read/write */ ++int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ ++ if (priv->mgmt_master && priv->info->ops->read_eth && ++ !priv->info->ops->read_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/* TODO: remove these extra ops when we can support regmap bulk read/write */ ++int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++{ ++ int i, count = len / sizeof(u32), ret; ++ u32 tmp; ++ ++ if (priv->mgmt_master && priv->info->ops->write_eth && ++ !priv->info->ops->write_eth(priv, reg, val, len)) ++ return 0; ++ ++ for (i = 0; i < count; i++) { ++ tmp = val[i]; ++ ++ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -324,8 +324,13 @@ enum qca8k_mid_cmd { + QCA8K_MIB_CAST = 3, + }; + ++struct qca8k_priv; ++ + struct qca8k_info_ops { + int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data); ++ /* TODO: remove these extra ops when we can support regmap bulk read/write */ ++ int (*read_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len); ++ int (*write_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len); + }; + + struct qca8k_match_data { +@@ -423,4 +428,7 @@ int qca8k_read(struct qca8k_priv *priv, + int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); + int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); + ++int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); ++int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch new file mode 100644 index 00000000000..a39a55b89b4 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch @@ -0,0 +1,137 @@ +From fce1ec0c4e2d03d9c62ffc615a42bdba78eb4c14 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:15 +0200 +Subject: [PATCH 06/14] net: dsa: qca8k: move mib init function to common code + +The same mib function is used by drivers based on qca8k family switch. +Move it to common code to make it accessible also by other drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 37 ------------------------------ + drivers/net/dsa/qca/qca8k-common.c | 35 ++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 4 ++++ + 3 files changed, 39 insertions(+), 37 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -442,15 +442,6 @@ static struct regmap_config qca8k_regmap + }; + + static int +-qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) +-{ +- u32 val; +- +- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, +- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); +-} +- +-static int + qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) + { + u32 reg[3]; +@@ -777,34 +768,6 @@ out: + return ret; + } + +-static int +-qca8k_mib_init(struct qca8k_priv *priv) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, +- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, +- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | +- QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); +- if (ret) +- goto exit; +- +- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); +- if (ret) +- goto exit; +- +- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- + static void + qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) + { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + + #include "qca8k.h" +@@ -138,3 +139,38 @@ int qca8k_bulk_write(struct qca8k_priv * + + return 0; + } ++ ++int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) ++{ ++ u32 val; ++ ++ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, ++ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); ++} ++ ++int qca8k_mib_init(struct qca8k_priv *priv) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, ++ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, ++ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | ++ QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); ++ if (ret) ++ goto exit; ++ ++ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); ++ if (ret) ++ goto exit; ++ ++ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -422,6 +422,7 @@ struct qca8k_fdb { + /* Common setup function */ + extern const struct qca8k_mib_desc ar8327_mib[]; + extern const struct regmap_access_table qca8k_readable_table; ++int qca8k_mib_init(struct qca8k_priv *priv); + + /* Common read/write/rmw function */ + int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); +@@ -431,4 +432,7 @@ int qca8k_rmw(struct qca8k_priv *priv, u + int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); + int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); + ++/* Common ops function */ ++int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch b/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch new file mode 100644 index 00000000000..6fd1c66b0ae --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch @@ -0,0 +1,281 @@ +From 472fcea160f27a5d9b7526093d9d8d89ba0b6137 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:16 +0200 +Subject: [PATCH 07/14] net: dsa: qca8k: move port set status/eee/ethtool stats + function to common code + +The same logic to disable/enable port, set eee and get ethtool stats is +used by drivers based on qca8k family switch. +Move it to common code to make it accessible also by other drivers. +While at it also drop unnecessary qca8k_priv cast for void pointers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 105 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 102 ++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 11 +++ + 3 files changed, 113 insertions(+), 105 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -768,21 +768,6 @@ out: + return ret; + } + +-static void +-qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) +-{ +- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; +- +- /* Port 0 and 6 have no internal PHY */ +- if (port > 0 && port < 6) +- mask |= QCA8K_PORT_STATUS_LINK_AUTO; +- +- if (enable) +- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +- else +- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); +-} +- + static int + qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, + struct sk_buff *read_skb, u32 *val) +@@ -1974,20 +1959,6 @@ qca8k_phylink_mac_link_up(struct dsa_swi + qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); + } + +-static void +-qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) +-{ +- struct qca8k_priv *priv = ds->priv; +- int i; +- +- if (stringset != ETH_SS_STATS) +- return; +- +- for (i = 0; i < priv->info->mib_count; i++) +- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, +- ETH_GSTRING_LEN); +-} +- + static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) + { + struct qca8k_mib_eth_data *mib_eth_data; +@@ -2078,82 +2049,6 @@ exit: + } + + static void +-qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, +- uint64_t *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- const struct qca8k_mib_desc *mib; +- u32 reg, i, val; +- u32 hi = 0; +- int ret; +- +- if (priv->mgmt_master && priv->info->ops->autocast_mib && +- priv->info->ops->autocast_mib(ds, port, data) > 0) +- return; +- +- for (i = 0; i < priv->info->mib_count; i++) { +- mib = &ar8327_mib[i]; +- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; +- +- ret = qca8k_read(priv, reg, &val); +- if (ret < 0) +- continue; +- +- if (mib->size == 2) { +- ret = qca8k_read(priv, reg + 4, &hi); +- if (ret < 0) +- continue; +- } +- +- data[i] = val; +- if (mib->size == 2) +- data[i] |= (u64)hi << 32; +- } +-} +- +-static int +-qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- if (sset != ETH_SS_STATS) +- return 0; +- +- return priv->info->mib_count; +-} +- +-static int +-qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); +- u32 reg; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); +- if (ret < 0) +- goto exit; +- +- if (eee->eee_enabled) +- reg |= lpi_en; +- else +- reg &= ~lpi_en; +- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +-{ +- /* Nothing to do on the port's MAC */ +- return 0; +-} +- +-static void + qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) + { + struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -174,3 +174,105 @@ exit: + mutex_unlock(&priv->reg_mutex); + return ret; + } ++ ++void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) ++{ ++ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; ++ ++ /* Port 0 and 6 have no internal PHY */ ++ if (port > 0 && port < 6) ++ mask |= QCA8K_PORT_STATUS_LINK_AUTO; ++ ++ if (enable) ++ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++ else ++ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); ++} ++ ++void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, ++ uint8_t *data) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int i; ++ ++ if (stringset != ETH_SS_STATS) ++ return; ++ ++ for (i = 0; i < priv->info->mib_count; i++) ++ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, ++ ETH_GSTRING_LEN); ++} ++ ++void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const struct qca8k_mib_desc *mib; ++ u32 reg, i, val; ++ u32 hi = 0; ++ int ret; ++ ++ if (priv->mgmt_master && priv->info->ops->autocast_mib && ++ priv->info->ops->autocast_mib(ds, port, data) > 0) ++ return; ++ ++ for (i = 0; i < priv->info->mib_count; i++) { ++ mib = &ar8327_mib[i]; ++ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; ++ ++ ret = qca8k_read(priv, reg, &val); ++ if (ret < 0) ++ continue; ++ ++ if (mib->size == 2) { ++ ret = qca8k_read(priv, reg + 4, &hi); ++ if (ret < 0) ++ continue; ++ } ++ ++ data[i] = val; ++ if (mib->size == 2) ++ data[i] |= (u64)hi << 32; ++ } ++} ++ ++int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ if (sset != ETH_SS_STATS) ++ return 0; ++ ++ return priv->info->mib_count; ++} ++ ++int qca8k_set_mac_eee(struct dsa_switch *ds, int port, ++ struct ethtool_eee *eee) ++{ ++ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); ++ if (ret < 0) ++ goto exit; ++ ++ if (eee->eee_enabled) ++ reg |= lpi_en; ++ else ++ reg &= ~lpi_en; ++ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++int qca8k_get_mac_eee(struct dsa_switch *ds, int port, ++ struct ethtool_eee *e) ++{ ++ /* Nothing to do on the port's MAC */ ++ return 0; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -423,6 +423,7 @@ struct qca8k_fdb { + extern const struct qca8k_mib_desc ar8327_mib[]; + extern const struct regmap_access_table qca8k_readable_table; + int qca8k_mib_init(struct qca8k_priv *priv); ++void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable); + + /* Common read/write/rmw function */ + int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); +@@ -435,4 +436,14 @@ int qca8k_bulk_write(struct qca8k_priv * + /* Common ops function */ + int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); + ++/* Common ethtool stats function */ ++void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); ++void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, ++ uint64_t *data); ++int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset); ++ ++/* Common eee function */ ++int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); ++int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch new file mode 100644 index 00000000000..3ca682d72cc --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch @@ -0,0 +1,237 @@ +From fd3cae2f3ac190d06e48f43739237e02f9dc51ff Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:17 +0200 +Subject: [PATCH 08/14] net: dsa: qca8k: move bridge functions to common code + +The same bridge functions are used by drivers based on qca8k family +switch. Move them to common code to make them accessible also by other +drivers. +While at it also drop unnecessary qca8k_priv cast for void pointers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------ + drivers/net/dsa/qca/qca8k-common.c | 93 ++++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 9 +++ + 3 files changed, 102 insertions(+), 93 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -2049,97 +2049,6 @@ exit: + } + + static void +-qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u32 stp_state; +- +- switch (state) { +- case BR_STATE_DISABLED: +- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; +- break; +- case BR_STATE_BLOCKING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; +- break; +- case BR_STATE_LISTENING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; +- break; +- case BR_STATE_LEARNING: +- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; +- break; +- case BR_STATE_FORWARDING: +- default: +- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; +- break; +- } +- +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); +-} +- +-static int +-qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int port_mask, cpu_port; +- int i, ret; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- port_mask = BIT(cpu_port); +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Add this port to the portvlan mask of the other ports +- * in the bridge +- */ +- ret = regmap_set_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- if (ret) +- return ret; +- if (i != port) +- port_mask |= BIT(i); +- } +- +- /* Add all other ports to this ports portvlan mask */ +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, port_mask); +- +- return ret; +-} +- +-static void +-qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- int cpu_port, i; +- +- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; +- +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- if (dsa_is_cpu_port(ds, i)) +- continue; +- if (dsa_to_port(ds, i)->bridge_dev != br) +- continue; +- /* Remove this port to the portvlan mask of the other ports +- * in the bridge +- */ +- regmap_clear_bits(priv->regmap, +- QCA8K_PORT_LOOKUP_CTRL(i), +- BIT(port)); +- } +- +- /* Set the cpu port to be the only one in the portvlan mask of +- * this port +- */ +- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); +-} +- +-static void + qca8k_port_fast_age(struct dsa_switch *ds, int port) + { + struct qca8k_priv *priv = ds->priv; +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include "qca8k.h" + +@@ -276,3 +277,93 @@ int qca8k_get_mac_eee(struct dsa_switch + /* Nothing to do on the port's MAC */ + return 0; + } ++ ++void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 stp_state; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; ++ break; ++ case BR_STATE_LISTENING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; ++ break; ++ case BR_STATE_LEARNING: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ default: ++ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; ++ break; ++ } ++ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); ++} ++ ++int qca8k_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *br) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int port_mask, cpu_port; ++ int i, ret; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ port_mask = BIT(cpu_port); ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Add this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ ret = regmap_set_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ if (ret) ++ return ret; ++ if (i != port) ++ port_mask |= BIT(i); ++ } ++ ++ /* Add all other ports to this ports portvlan mask */ ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, port_mask); ++ ++ return ret; ++} ++ ++void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *br) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int cpu_port, i; ++ ++ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; ++ ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ if (dsa_is_cpu_port(ds, i)) ++ continue; ++ if (dsa_to_port(ds, i)->bridge_dev != br) ++ continue; ++ /* Remove this port to the portvlan mask of the other ports ++ * in the bridge ++ */ ++ regmap_clear_bits(priv->regmap, ++ QCA8K_PORT_LOOKUP_CTRL(i), ++ BIT(port)); ++ } ++ ++ /* Set the cpu port to be the only one in the portvlan mask of ++ * this port ++ */ ++ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -446,4 +446,11 @@ int qca8k_get_sset_count(struct dsa_swit + int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); + int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); + ++/* Common bridge function */ ++void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); ++int qca8k_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *br); ++void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *br); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch b/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch new file mode 100644 index 00000000000..e3414408d64 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch @@ -0,0 +1,227 @@ +From b3a302b171f73425b41de8d3357fae3fa7057322 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:18 +0200 +Subject: [PATCH 09/14] net: dsa: qca8k: move set age/MTU/port enable/disable + functions to common code + +The same set age, MTU and port enable/disable function are used by +driver based on qca8k family switch. +Move them to common code to make them accessible also by other drivers. +While at it also drop unnecessary qca8k_priv cast for void pointers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 88 ------------------------------ + drivers/net/dsa/qca/qca8k-common.c | 85 +++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 12 ++++ + 3 files changed, 97 insertions(+), 88 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -2059,94 +2059,6 @@ qca8k_port_fast_age(struct dsa_switch *d + } + + static int +-qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) +-{ +- struct qca8k_priv *priv = ds->priv; +- unsigned int secs = msecs / 1000; +- u32 val; +- +- /* AGE_TIME reg is set in 7s step */ +- val = secs / 7; +- +- /* Handle case with 0 as val to NOT disable +- * learning +- */ +- if (!val) +- val = 1; +- +- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, +- QCA8K_ATU_AGE_TIME(val)); +-} +- +-static int +-qca8k_port_enable(struct dsa_switch *ds, int port, +- struct phy_device *phy) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 1); +- priv->port_enabled_map |= BIT(port); +- +- if (dsa_is_user_port(ds, port)) +- phy_support_asym_pause(phy); +- +- return 0; +-} +- +-static void +-qca8k_port_disable(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- +- qca8k_port_set_status(priv, port, 0); +- priv->port_enabled_map &= ~BIT(port); +-} +- +-static int +-qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- /* We have only have a general MTU setting. +- * DSA always set the CPU port's MTU to the largest MTU of the slave +- * ports. +- * Setting MTU just for the CPU port is sufficient to correctly set a +- * value for every port. +- */ +- if (!dsa_is_cpu_port(ds, port)) +- return 0; +- +- /* To change the MAX_FRAME_SIZE the cpu ports must be off or +- * the switch panics. +- * Turn off both cpu ports before applying the new value to prevent +- * this. +- */ +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 0); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 0); +- +- /* Include L2 header / FCS length */ +- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); +- +- if (priv->port_enabled_map & BIT(0)) +- qca8k_port_set_status(priv, 0, 1); +- +- if (priv->port_enabled_map & BIT(6)) +- qca8k_port_set_status(priv, 6, 1); +- +- return ret; +-} +- +-static int +-qca8k_port_max_mtu(struct dsa_switch *ds, int port) +-{ +- return QCA8K_MAX_MTU; +-} +- +-static int + qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, + u16 port_mask, u16 vid) + { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -367,3 +367,88 @@ void qca8k_port_bridge_leave(struct dsa_ + qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), + QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); + } ++ ++int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ unsigned int secs = msecs / 1000; ++ u32 val; ++ ++ /* AGE_TIME reg is set in 7s step */ ++ val = secs / 7; ++ ++ /* Handle case with 0 as val to NOT disable ++ * learning ++ */ ++ if (!val) ++ val = 1; ++ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, ++ QCA8K_ATU_AGE_TIME_MASK, ++ QCA8K_ATU_AGE_TIME(val)); ++} ++ ++int qca8k_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ qca8k_port_set_status(priv, port, 1); ++ priv->port_enabled_map |= BIT(port); ++ ++ if (dsa_is_user_port(ds, port)) ++ phy_support_asym_pause(phy); ++ ++ return 0; ++} ++ ++void qca8k_port_disable(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ qca8k_port_set_status(priv, port, 0); ++ priv->port_enabled_map &= ~BIT(port); ++} ++ ++int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ /* We have only have a general MTU setting. ++ * DSA always set the CPU port's MTU to the largest MTU of the slave ++ * ports. ++ * Setting MTU just for the CPU port is sufficient to correctly set a ++ * value for every port. ++ */ ++ if (!dsa_is_cpu_port(ds, port)) ++ return 0; ++ ++ /* To change the MAX_FRAME_SIZE the cpu ports must be off or ++ * the switch panics. ++ * Turn off both cpu ports before applying the new value to prevent ++ * this. ++ */ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 0); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 0); ++ ++ /* Include L2 header / FCS length */ ++ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ++ ETH_HLEN + ETH_FCS_LEN); ++ ++ if (priv->port_enabled_map & BIT(0)) ++ qca8k_port_set_status(priv, 0, 1); ++ ++ if (priv->port_enabled_map & BIT(6)) ++ qca8k_port_set_status(priv, 6, 1); ++ ++ return ret; ++} ++ ++int qca8k_port_max_mtu(struct dsa_switch *ds, int port) ++{ ++ return QCA8K_MAX_MTU; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -453,4 +453,16 @@ int qca8k_port_bridge_join(struct dsa_sw + void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, + struct net_device *br); + ++/* Common port enable/disable function */ ++int qca8k_port_enable(struct dsa_switch *ds, int port, ++ struct phy_device *phy); ++void qca8k_port_disable(struct dsa_switch *ds, int port); ++ ++/* Common MTU function */ ++int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu); ++int qca8k_port_max_mtu(struct dsa_switch *ds, int port); ++ ++/* Common fast age function */ ++int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch b/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch new file mode 100644 index 00000000000..96468ae74e9 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch @@ -0,0 +1,704 @@ +From 2e5bd96eea86a246b4de3bf756f7a11b43e6187d Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:19 +0200 +Subject: [PATCH 10/14] net: dsa: qca8k: move port FDB/MDB function to common + code + +The same port FDB/MDB function are used by drivers based on qca8k family +switch. Move them to common code to make them accessible also by other +drivers. +Also drop bulk read/write functions and make them static + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 306 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 297 +++++++++++++++++++++++++++- + drivers/net/dsa/qca/qca8k.h | 25 ++- + 3 files changed, 317 insertions(+), 311 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -442,217 +442,6 @@ static struct regmap_config qca8k_regmap + }; + + static int +-qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) +-{ +- u32 reg[3]; +- int ret; +- +- /* load the ARL table into an array */ +- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +- if (ret) +- return ret; +- +- /* vid - 83:72 */ +- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); +- /* aging - 67:64 */ +- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); +- /* portmask - 54:48 */ +- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); +- /* mac - 47:0 */ +- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); +- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); +- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); +- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); +- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); +- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); +- +- return 0; +-} +- +-static void +-qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, +- u8 aging) +-{ +- u32 reg[3] = { 0 }; +- +- /* vid - 83:72 */ +- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); +- /* aging - 67:64 */ +- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); +- /* portmask - 54:48 */ +- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); +- /* mac - 47:0 */ +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); +- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); +- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); +- +- /* load the array into the ARL table */ +- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); +-} +- +-static int +-qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and FDB index */ +- reg = QCA8K_ATU_FUNC_BUSY; +- reg |= cmd; +- if (port >= 0) { +- reg |= QCA8K_ATU_FUNC_PORT_EN; +- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); +- } +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_FDB_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_ATU_FUNC_FULL) +- return -1; +- } +- +- return 0; +-} +- +-static int +-qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) +-{ +- int ret; +- +- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); +- if (ret < 0) +- return ret; +- +- return qca8k_fdb_read(priv, fdb); +-} +- +-static int +-qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, +- u16 vid, u8 aging) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) +-{ +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_write(priv, vid, port_mask, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static void +-qca8k_fdb_flush(struct qca8k_priv *priv) +-{ +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- ret = qca8k_fdb_read(priv, &fdb); +- if (ret < 0) +- goto exit; +- +- /* Rule exist. Delete first */ +- if (!fdb.aging) { +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- } +- +- /* Add port to fdb portmask */ +- fdb.port_mask |= port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int +-qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, +- const u8 *mac, u16 vid) +-{ +- struct qca8k_fdb fdb = { 0 }; +- int ret; +- +- mutex_lock(&priv->reg_mutex); +- +- qca8k_fdb_write(priv, vid, 0, mac, 0); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); +- if (ret < 0) +- goto exit; +- +- /* Rule doesn't exist. Why delete? */ +- if (!fdb.aging) { +- ret = -EINVAL; +- goto exit; +- } +- +- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); +- if (ret) +- goto exit; +- +- /* Only port in the rule is this port. Don't re insert */ +- if (fdb.port_mask == port_mask) +- goto exit; +- +- /* Remove port from port mask */ +- fdb.port_mask &= ~port_mask; +- +- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); +- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); +- +-exit: +- mutex_unlock(&priv->reg_mutex); +- return ret; +-} +- +-static int + qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) + { + u32 reg; +@@ -2048,97 +1837,6 @@ exit: + return ret; + } + +-static void +-qca8k_port_fast_age(struct dsa_switch *ds, int port) +-{ +- struct qca8k_priv *priv = ds->priv; +- +- mutex_lock(&priv->reg_mutex); +- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); +- mutex_unlock(&priv->reg_mutex); +-} +- +-static int +-qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, +- u16 port_mask, u16 vid) +-{ +- /* Set the vid to the port vlan id if no vid is set */ +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_add(priv, addr, port_mask, vid, +- QCA8K_ATU_STATUS_STATIC); +-} +- +-static int +-qca8k_port_fdb_add(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_del(struct dsa_switch *ds, int port, +- const unsigned char *addr, u16 vid) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- u16 port_mask = BIT(port); +- +- if (!vid) +- vid = QCA8K_PORT_VID_DEF; +- +- return qca8k_fdb_del(priv, addr, port_mask, vid); +-} +- +-static int +-qca8k_port_fdb_dump(struct dsa_switch *ds, int port, +- dsa_fdb_dump_cb_t *cb, void *data) +-{ +- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; +- struct qca8k_fdb _fdb = { 0 }; +- int cnt = QCA8K_NUM_FDB_RECORDS; +- bool is_static; +- int ret = 0; +- +- mutex_lock(&priv->reg_mutex); +- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { +- if (!_fdb.aging) +- break; +- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); +- ret = cb(_fdb.mac, _fdb.vid, is_static, data); +- if (ret) +- break; +- } +- mutex_unlock(&priv->reg_mutex); +- +- return 0; +-} +- +-static int +-qca8k_port_mdb_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); +-} +- +-static int +-qca8k_port_mdb_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_mdb *mdb) +-{ +- struct qca8k_priv *priv = ds->priv; +- const u8 *addr = mdb->addr; +- u16 vid = mdb->vid; +- +- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); +-} +- + static int + qca8k_port_mirror_add(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror, +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -103,7 +103,7 @@ const struct regmap_access_table qca8k_r + }; + + /* TODO: remove these extra ops when we can support regmap bulk read/write */ +-int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) + { + int i, count = len / sizeof(u32), ret; + +@@ -121,7 +121,7 @@ int qca8k_bulk_read(struct qca8k_priv *p + } + + /* TODO: remove these extra ops when we can support regmap bulk read/write */ +-int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ++static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) + { + int i, count = len / sizeof(u32), ret; + u32 tmp; +@@ -149,6 +149,211 @@ int qca8k_busy_wait(struct qca8k_priv *p + QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); + } + ++static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) ++{ ++ u32 reg[3]; ++ int ret; ++ ++ /* load the ARL table into an array */ ++ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++ if (ret) ++ return ret; ++ ++ /* vid - 83:72 */ ++ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); ++ /* aging - 67:64 */ ++ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); ++ /* portmask - 54:48 */ ++ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); ++ /* mac - 47:0 */ ++ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); ++ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); ++ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); ++ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); ++ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); ++ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); ++ ++ return 0; ++} ++ ++static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, ++ const u8 *mac, u8 aging) ++{ ++ u32 reg[3] = { 0 }; ++ ++ /* vid - 83:72 */ ++ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); ++ /* aging - 67:64 */ ++ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); ++ /* portmask - 54:48 */ ++ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); ++ /* mac - 47:0 */ ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); ++ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); ++ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); ++ ++ /* load the array into the ARL table */ ++ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); ++} ++ ++static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, ++ int port) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and FDB index */ ++ reg = QCA8K_ATU_FUNC_BUSY; ++ reg |= cmd; ++ if (port >= 0) { ++ reg |= QCA8K_ATU_FUNC_PORT_EN; ++ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); ++ } ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_FDB_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_ATU_FUNC_FULL) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, ++ int port) ++{ ++ int ret; ++ ++ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); ++ if (ret < 0) ++ return ret; ++ ++ return qca8k_fdb_read(priv, fdb); ++} ++ ++static int qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, ++ u16 port_mask, u16 vid, u8 aging) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, ++ u16 port_mask, u16 vid) ++{ ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_write(priv, vid, port_mask, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++void qca8k_fdb_flush(struct qca8k_priv *priv) ++{ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); ++ mutex_unlock(&priv->reg_mutex); ++} ++ ++static int qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ ret = qca8k_fdb_read(priv, &fdb); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule exist. Delete first */ ++ if (!fdb.aging) { ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ } ++ ++ /* Add port to fdb portmask */ ++ fdb.port_mask |= port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ ++static int qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, ++ const u8 *mac, u16 vid) ++{ ++ struct qca8k_fdb fdb = { 0 }; ++ int ret; ++ ++ mutex_lock(&priv->reg_mutex); ++ ++ qca8k_fdb_write(priv, vid, 0, mac, 0); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); ++ if (ret < 0) ++ goto exit; ++ ++ /* Rule doesn't exist. Why delete? */ ++ if (!fdb.aging) { ++ ret = -EINVAL; ++ goto exit; ++ } ++ ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); ++ if (ret) ++ goto exit; ++ ++ /* Only port in the rule is this port. Don't re insert */ ++ if (fdb.port_mask == port_mask) ++ goto exit; ++ ++ /* Remove port from port mask */ ++ fdb.port_mask &= ~port_mask; ++ ++ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); ++ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); ++ ++exit: ++ mutex_unlock(&priv->reg_mutex); ++ return ret; ++} ++ + int qca8k_mib_init(struct qca8k_priv *priv) + { + int ret; +@@ -368,6 +573,15 @@ void qca8k_port_bridge_leave(struct dsa_ + QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); + } + ++void qca8k_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ ++ mutex_lock(&priv->reg_mutex); ++ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); ++ mutex_unlock(&priv->reg_mutex); ++} ++ + int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) + { + struct qca8k_priv *priv = ds->priv; +@@ -452,3 +666,78 @@ int qca8k_port_max_mtu(struct dsa_switch + { + return QCA8K_MAX_MTU; + } ++ ++int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, ++ u16 port_mask, u16 vid) ++{ ++ /* Set the vid to the port vlan id if no vid is set */ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_add(priv, addr, port_mask, vid, ++ QCA8K_ATU_STATUS_STATIC); ++} ++ ++int qca8k_port_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); ++} ++ ++int qca8k_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ u16 port_mask = BIT(port); ++ ++ if (!vid) ++ vid = QCA8K_PORT_VID_DEF; ++ ++ return qca8k_fdb_del(priv, addr, port_mask, vid); ++} ++ ++int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data) ++{ ++ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ++ struct qca8k_fdb _fdb = { 0 }; ++ int cnt = QCA8K_NUM_FDB_RECORDS; ++ bool is_static; ++ int ret = 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { ++ if (!_fdb.aging) ++ break; ++ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); ++ ret = cb(_fdb.mac, _fdb.vid, is_static, data); ++ if (ret) ++ break; ++ } ++ mutex_unlock(&priv->reg_mutex); ++ ++ return 0; ++} ++ ++int qca8k_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); ++} ++ ++int qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ const u8 *addr = mdb->addr; ++ u16 vid = mdb->vid; ++ ++ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -430,11 +430,9 @@ int qca8k_read(struct qca8k_priv *priv, + int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); + int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); + +-int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); +-int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); +- + /* Common ops function */ + int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); ++void qca8k_fdb_flush(struct qca8k_priv *priv); + + /* Common ethtool stats function */ + void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); +@@ -463,6 +461,23 @@ int qca8k_port_change_mtu(struct dsa_swi + int qca8k_port_max_mtu(struct dsa_switch *ds, int port); + + /* Common fast age function */ ++void qca8k_port_fast_age(struct dsa_switch *ds, int port); + int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); + ++/* Common FDB function */ ++int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, ++ u16 port_mask, u16 vid); ++int qca8k_port_fdb_add(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid); ++int qca8k_port_fdb_del(struct dsa_switch *ds, int port, ++ const unsigned char *addr, u16 vid); ++int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, ++ dsa_fdb_dump_cb_t *cb, void *data); ++ ++/* Common MDB function */ ++int qca8k_port_mdb_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb); ++int qca8k_port_mdb_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_mdb *mdb); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch b/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch new file mode 100644 index 00000000000..c1336d4a921 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch @@ -0,0 +1,232 @@ +From 742d37a84d3f7bb60d9b2d9ada9ad4e599f65ebf Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:20 +0200 +Subject: [PATCH 11/14] net: dsa: qca8k: move port mirror functions to common + code + +The same port mirror functions are used by drivers based on qca8k family +switch. Move them to common code to make them accessible also by other +drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------ + drivers/net/dsa/qca/qca8k-common.c | 91 +++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 7 +++ + 3 files changed, 98 insertions(+), 93 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1838,99 +1838,6 @@ exit: + } + + static int +-qca8k_port_mirror_add(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror, +- bool ingress) +-{ +- struct qca8k_priv *priv = ds->priv; +- int monitor_port, ret; +- u32 reg, val; +- +- /* Check for existent entry */ +- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) +- return -EEXIST; +- +- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); +- if (ret) +- return ret; +- +- /* QCA83xx can have only one port set to mirror mode. +- * Check that the correct port is requested and return error otherwise. +- * When no mirror port is set, the values is set to 0xF +- */ +- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) +- return -EEXIST; +- +- /* Set the monitor port */ +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, +- mirror->to_local_port); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- return ret; +- +- if (ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_update_bits(priv->regmap, reg, val, val); +- if (ret) +- return ret; +- +- /* Track mirror port for tx and rx to decide when the +- * mirror port has to be disabled. +- */ +- if (ingress) +- priv->mirror_rx |= BIT(port); +- else +- priv->mirror_tx |= BIT(port); +- +- return 0; +-} +- +-static void +-qca8k_port_mirror_del(struct dsa_switch *ds, int port, +- struct dsa_mall_mirror_tc_entry *mirror) +-{ +- struct qca8k_priv *priv = ds->priv; +- u32 reg, val; +- int ret; +- +- if (mirror->ingress) { +- reg = QCA8K_PORT_LOOKUP_CTRL(port); +- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; +- } else { +- reg = QCA8K_REG_PORT_HOL_CTRL1(port); +- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; +- } +- +- ret = regmap_clear_bits(priv->regmap, reg, val); +- if (ret) +- goto err; +- +- if (mirror->ingress) +- priv->mirror_rx &= ~BIT(port); +- else +- priv->mirror_tx &= ~BIT(port); +- +- /* No port set to send packet to mirror port. Disable mirror port */ +- if (!priv->mirror_rx && !priv->mirror_tx) { +- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, +- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); +- if (ret) +- goto err; +- } +-err: +- dev_err(priv->dev, "Failed to del mirror port from %d", port); +-} +- +-static int + qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack) + { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -741,3 +741,94 @@ int qca8k_port_mdb_del(struct dsa_switch + + return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); + } ++ ++int qca8k_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int monitor_port, ret; ++ u32 reg, val; ++ ++ /* Check for existent entry */ ++ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) ++ return -EEXIST; ++ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* QCA83xx can have only one port set to mirror mode. ++ * Check that the correct port is requested and return error otherwise. ++ * When no mirror port is set, the values is set to 0xF ++ */ ++ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) ++ return -EEXIST; ++ ++ /* Set the monitor port */ ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, ++ mirror->to_local_port); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ return ret; ++ ++ if (ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_update_bits(priv->regmap, reg, val, val); ++ if (ret) ++ return ret; ++ ++ /* Track mirror port for tx and rx to decide when the ++ * mirror port has to be disabled. ++ */ ++ if (ingress) ++ priv->mirror_rx |= BIT(port); ++ else ++ priv->mirror_tx |= BIT(port); ++ ++ return 0; ++} ++ ++void qca8k_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ u32 reg, val; ++ int ret; ++ ++ if (mirror->ingress) { ++ reg = QCA8K_PORT_LOOKUP_CTRL(port); ++ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; ++ } else { ++ reg = QCA8K_REG_PORT_HOL_CTRL1(port); ++ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; ++ } ++ ++ ret = regmap_clear_bits(priv->regmap, reg, val); ++ if (ret) ++ goto err; ++ ++ if (mirror->ingress) ++ priv->mirror_rx &= ~BIT(port); ++ else ++ priv->mirror_tx &= ~BIT(port); ++ ++ /* No port set to send packet to mirror port. Disable mirror port */ ++ if (!priv->mirror_rx && !priv->mirror_tx) { ++ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, ++ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); ++ if (ret) ++ goto err; ++ } ++err: ++ dev_err(priv->dev, "Failed to del mirror port from %d", port); ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -480,4 +480,11 @@ int qca8k_port_mdb_add(struct dsa_switch + int qca8k_port_mdb_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_mdb *mdb); + ++/* Common port mirror function */ ++int qca8k_port_mirror_add(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror, ++ bool ingress); ++void qca8k_port_mirror_del(struct dsa_switch *ds, int port, ++ struct dsa_mall_mirror_tc_entry *mirror); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch b/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch new file mode 100644 index 00000000000..898010f9509 --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch @@ -0,0 +1,448 @@ +From c5290f636624b98e76a82bd63ffec0a8a9daa620 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:21 +0200 +Subject: [PATCH 12/14] net: dsa: qca8k: move port VLAN functions to common + code + +The same port VLAN functions are used by drivers based on qca8k family +switch. Move them to common code to make them accessible also by other +drivers. +Also drop exposing busy_wait and make it static. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 182 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 179 +++++++++++++++++++++++++++- + drivers/net/dsa/qca/qca8k.h | 10 +- + 3 files changed, 187 insertions(+), 184 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -15,7 +15,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -442,122 +441,6 @@ static struct regmap_config qca8k_regmap + }; + + static int +-qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) +-{ +- u32 reg; +- int ret; +- +- /* Set the command and VLAN index */ +- reg = QCA8K_VTU_FUNC1_BUSY; +- reg |= cmd; +- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); +- +- /* Write the function register triggering the table access */ +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); +- if (ret) +- return ret; +- +- /* wait for completion */ +- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); +- if (ret) +- return ret; +- +- /* Check for table full violation when adding an entry */ +- if (cmd == QCA8K_VLAN_LOAD) { +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); +- if (ret < 0) +- return ret; +- if (reg & QCA8K_VTU_FUNC1_FULL) +- return -ENOMEM; +- } +- +- return 0; +-} +- +-static int +-qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) +-{ +- u32 reg; +- int ret; +- +- /* +- We do the right thing with VLAN 0 and treat it as untagged while +- preserving the tag on egress. +- */ +- if (vid == 0) +- return 0; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- if (untagged) +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); +- else +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); +- +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int +-qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) +-{ +- u32 reg, mask; +- int ret, i; +- bool del; +- +- mutex_lock(&priv->reg_mutex); +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); +- if (ret < 0) +- goto out; +- +- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); +- if (ret < 0) +- goto out; +- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); +- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); +- +- /* Check if we're the last member to be removed */ +- del = true; +- for (i = 0; i < QCA8K_NUM_PORTS; i++) { +- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); +- +- if ((reg & mask) != mask) { +- del = false; +- break; +- } +- } +- +- if (del) { +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); +- } else { +- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); +- if (ret) +- goto out; +- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); +- } +- +-out: +- mutex_unlock(&priv->reg_mutex); +- +- return ret; +-} +- +-static int + qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, + struct sk_buff *read_skb, u32 *val) + { +@@ -1836,71 +1719,6 @@ exit: + + return ret; + } +- +-static int +-qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, +- struct netlink_ext_ack *extack) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- if (vlan_filtering) { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); +- } else { +- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), +- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, +- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_add(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan, +- struct netlink_ext_ack *extack) +-{ +- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; +- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); +- if (ret) { +- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); +- return ret; +- } +- +- if (pvid) { +- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), +- QCA8K_EGREES_VLAN_PORT_MASK(port), +- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); +- if (ret) +- return ret; +- +- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), +- QCA8K_PORT_VLAN_CVID(vlan->vid) | +- QCA8K_PORT_VLAN_SVID(vlan->vid)); +- } +- +- return ret; +-} +- +-static int +-qca8k_port_vlan_del(struct dsa_switch *ds, int port, +- const struct switchdev_obj_port_vlan *vlan) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret; +- +- ret = qca8k_vlan_del(priv, port, vlan->vid); +- if (ret) +- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); +- +- return ret; +-} + + static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) + { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -141,7 +141,7 @@ static int qca8k_bulk_write(struct qca8k + return 0; + } + +-int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) ++static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) + { + u32 val; + +@@ -354,6 +354,120 @@ exit: + return ret; + } + ++static int qca8k_vlan_access(struct qca8k_priv *priv, ++ enum qca8k_vlan_cmd cmd, u16 vid) ++{ ++ u32 reg; ++ int ret; ++ ++ /* Set the command and VLAN index */ ++ reg = QCA8K_VTU_FUNC1_BUSY; ++ reg |= cmd; ++ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); ++ ++ /* Write the function register triggering the table access */ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); ++ if (ret) ++ return ret; ++ ++ /* wait for completion */ ++ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); ++ if (ret) ++ return ret; ++ ++ /* Check for table full violation when adding an entry */ ++ if (cmd == QCA8K_VLAN_LOAD) { ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); ++ if (ret < 0) ++ return ret; ++ if (reg & QCA8K_VTU_FUNC1_FULL) ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, ++ bool untagged) ++{ ++ u32 reg; ++ int ret; ++ ++ /* We do the right thing with VLAN 0 and treat it as untagged while ++ * preserving the tag on egress. ++ */ ++ if (vid == 0) ++ return 0; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ if (untagged) ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); ++ else ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); ++ ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ ++static int qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) ++{ ++ u32 reg, mask; ++ int ret, i; ++ bool del; ++ ++ mutex_lock(&priv->reg_mutex); ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); ++ if (ret < 0) ++ goto out; ++ ++ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); ++ if (ret < 0) ++ goto out; ++ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); ++ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); ++ ++ /* Check if we're the last member to be removed */ ++ del = true; ++ for (i = 0; i < QCA8K_NUM_PORTS; i++) { ++ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); ++ ++ if ((reg & mask) != mask) { ++ del = false; ++ break; ++ } ++ } ++ ++ if (del) { ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); ++ } else { ++ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); ++ if (ret) ++ goto out; ++ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); ++ } ++ ++out: ++ mutex_unlock(&priv->reg_mutex); ++ ++ return ret; ++} ++ + int qca8k_mib_init(struct qca8k_priv *priv) + { + int ret; +@@ -832,3 +946,66 @@ void qca8k_port_mirror_del(struct dsa_sw + err: + dev_err(priv->dev, "Failed to del mirror port from %d", port); + } ++ ++int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, ++ bool vlan_filtering, ++ struct netlink_ext_ack *extack) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ if (vlan_filtering) { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); ++ } else { ++ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), ++ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, ++ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); ++ } ++ ++ return ret; ++} ++ ++int qca8k_port_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack) ++{ ++ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; ++ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); ++ if (ret) { ++ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); ++ return ret; ++ } ++ ++ if (pvid) { ++ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), ++ QCA8K_EGREES_VLAN_PORT_MASK(port), ++ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); ++ if (ret) ++ return ret; ++ ++ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), ++ QCA8K_PORT_VLAN_CVID(vlan->vid) | ++ QCA8K_PORT_VLAN_SVID(vlan->vid)); ++ } ++ ++ return ret; ++} ++ ++int qca8k_port_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret; ++ ++ ret = qca8k_vlan_del(priv, port, vlan->vid); ++ if (ret) ++ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); ++ ++ return ret; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -431,7 +431,6 @@ int qca8k_write(struct qca8k_priv *priv, + int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); + + /* Common ops function */ +-int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); + void qca8k_fdb_flush(struct qca8k_priv *priv); + + /* Common ethtool stats function */ +@@ -487,4 +486,13 @@ int qca8k_port_mirror_add(struct dsa_swi + void qca8k_port_mirror_del(struct dsa_switch *ds, int port, + struct dsa_mall_mirror_tc_entry *mirror); + ++/* Common port VLAN function */ ++int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, ++ struct netlink_ext_ack *extack); ++int qca8k_port_vlan_add(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan, ++ struct netlink_ext_ack *extack); ++int qca8k_port_vlan_del(struct dsa_switch *ds, int port, ++ const struct switchdev_obj_port_vlan *vlan); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch new file mode 100644 index 00000000000..1802b17eaad --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch @@ -0,0 +1,384 @@ +From e9bbf019af44b204b71ef8edf224002550aab641 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:22 +0200 +Subject: [PATCH 13/14] net: dsa: qca8k: move port LAG functions to common code + +The same port LAG functions are used by drivers based on qca8k family +switch. Move them to common code to make them accessible also by other +drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 168 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 165 ++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 6 ++ + 3 files changed, 171 insertions(+), 168 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1743,178 +1743,6 @@ qca8k_get_tag_protocol(struct dsa_switch + return DSA_TAG_PROTO_QCA; + } + +-static bool +-qca8k_lag_can_offload(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct dsa_port *dp; +- int id, members = 0; +- +- id = dsa_lag_id(ds->dst, lag); +- if (id < 0 || id >= ds->num_lag_ids) +- return false; +- +- dsa_lag_foreach_port(dp, ds->dst, lag) +- /* Includes the port joining the LAG */ +- members++; +- +- if (members > QCA8K_NUM_PORTS_FOR_LAG) +- return false; +- +- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) +- return false; +- +- if (info->hash_type != NETDEV_LAG_HASH_L2 && +- info->hash_type != NETDEV_LAG_HASH_L23) +- return false; +- +- return true; +-} +- +-static int +-qca8k_lag_setup_hash(struct dsa_switch *ds, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- struct qca8k_priv *priv = ds->priv; +- bool unique_lag = true; +- u32 hash = 0; +- int i, id; +- +- id = dsa_lag_id(ds->dst, lag); +- +- switch (info->hash_type) { +- case NETDEV_LAG_HASH_L23: +- hash |= QCA8K_TRUNK_HASH_SIP_EN; +- hash |= QCA8K_TRUNK_HASH_DIP_EN; +- fallthrough; +- case NETDEV_LAG_HASH_L2: +- hash |= QCA8K_TRUNK_HASH_SA_EN; +- hash |= QCA8K_TRUNK_HASH_DA_EN; +- break; +- default: /* We should NEVER reach this */ +- return -EOPNOTSUPP; +- } +- +- /* Check if we are the unique configured LAG */ +- dsa_lags_foreach_id(i, ds->dst) +- if (i != id && dsa_lag_dev(ds->dst, i)) { +- unique_lag = false; +- break; +- } +- +- /* Hash Mode is global. Make sure the same Hash Mode +- * is set to all the 4 possible lag. +- * If we are the unique LAG we can set whatever hash +- * mode we want. +- * To change hash mode it's needed to remove all LAG +- * and change the mode with the latest. +- */ +- if (unique_lag) { +- priv->lag_hash_mode = hash; +- } else if (priv->lag_hash_mode != hash) { +- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); +- return -EOPNOTSUPP; +- } +- +- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, +- QCA8K_TRUNK_HASH_MASK, hash); +-} +- +-static int +-qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, +- struct net_device *lag, bool delete) +-{ +- struct qca8k_priv *priv = ds->priv; +- int ret, id, i; +- u32 val; +- +- id = dsa_lag_id(ds->dst, lag); +- +- /* Read current port member */ +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); +- if (ret) +- return ret; +- +- /* Shift val to the correct trunk */ +- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); +- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; +- if (delete) +- val &= ~BIT(port); +- else +- val |= BIT(port); +- +- /* Update port member. With empty portmap disable trunk */ +- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, +- QCA8K_REG_GOL_TRUNK_MEMBER(id) | +- QCA8K_REG_GOL_TRUNK_EN(id), +- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | +- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); +- +- /* Search empty member if adding or port on deleting */ +- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { +- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); +- if (ret) +- return ret; +- +- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; +- +- if (delete) { +- /* If port flagged to be disabled assume this member is +- * empty +- */ +- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- +- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; +- if (val != port) +- continue; +- } else { +- /* If port flagged to be enabled assume this member is +- * already set +- */ +- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) +- continue; +- } +- +- /* We have found the member to add/remove */ +- break; +- } +- +- /* Set port in the correct port mask or disable port if in delete mode */ +- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | +- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), +- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | +- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); +-} +- +-static int +-qca8k_port_lag_join(struct dsa_switch *ds, int port, +- struct net_device *lag, +- struct netdev_lag_upper_info *info) +-{ +- int ret; +- +- if (!qca8k_lag_can_offload(ds, lag, info)) +- return -EOPNOTSUPP; +- +- ret = qca8k_lag_setup_hash(ds, lag, info); +- if (ret) +- return ret; +- +- return qca8k_lag_refresh_portmap(ds, port, lag, false); +-} +- +-static int +-qca8k_port_lag_leave(struct dsa_switch *ds, int port, +- struct net_device *lag) +-{ +- return qca8k_lag_refresh_portmap(ds, port, lag, true); +-} +- + static void + qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, + bool operational) +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -1009,3 +1009,169 @@ int qca8k_port_vlan_del(struct dsa_switc + + return ret; + } ++ ++static bool qca8k_lag_can_offload(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct dsa_port *dp; ++ int id, members = 0; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ if (id < 0 || id >= ds->num_lag_ids) ++ return false; ++ ++ dsa_lag_foreach_port(dp, ds->dst, lag) ++ /* Includes the port joining the LAG */ ++ members++; ++ ++ if (members > QCA8K_NUM_PORTS_FOR_LAG) ++ return false; ++ ++ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) ++ return false; ++ ++ if (info->hash_type != NETDEV_LAG_HASH_L2 && ++ info->hash_type != NETDEV_LAG_HASH_L23) ++ return false; ++ ++ return true; ++} ++ ++static int qca8k_lag_setup_hash(struct dsa_switch *ds, ++ struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ bool unique_lag = true; ++ u32 hash = 0; ++ int i, id; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ switch (info->hash_type) { ++ case NETDEV_LAG_HASH_L23: ++ hash |= QCA8K_TRUNK_HASH_SIP_EN; ++ hash |= QCA8K_TRUNK_HASH_DIP_EN; ++ fallthrough; ++ case NETDEV_LAG_HASH_L2: ++ hash |= QCA8K_TRUNK_HASH_SA_EN; ++ hash |= QCA8K_TRUNK_HASH_DA_EN; ++ break; ++ default: /* We should NEVER reach this */ ++ return -EOPNOTSUPP; ++ } ++ ++ /* Check if we are the unique configured LAG */ ++ dsa_lags_foreach_id(i, ds->dst) ++ if (i != id && dsa_lag_dev(ds->dst, i)) { ++ unique_lag = false; ++ break; ++ } ++ ++ /* Hash Mode is global. Make sure the same Hash Mode ++ * is set to all the 4 possible lag. ++ * If we are the unique LAG we can set whatever hash ++ * mode we want. ++ * To change hash mode it's needed to remove all LAG ++ * and change the mode with the latest. ++ */ ++ if (unique_lag) { ++ priv->lag_hash_mode = hash; ++ } else if (priv->lag_hash_mode != hash) { ++ netdev_err(lag, "Error: Mismatched Hash Mode across different lag is not supported\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, ++ QCA8K_TRUNK_HASH_MASK, hash); ++} ++ ++static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, ++ struct net_device *lag, bool delete) ++{ ++ struct qca8k_priv *priv = ds->priv; ++ int ret, id, i; ++ u32 val; ++ ++ id = dsa_lag_id(ds->dst, lag); ++ ++ /* Read current port member */ ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); ++ if (ret) ++ return ret; ++ ++ /* Shift val to the correct trunk */ ++ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); ++ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; ++ if (delete) ++ val &= ~BIT(port); ++ else ++ val |= BIT(port); ++ ++ /* Update port member. With empty portmap disable trunk */ ++ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, ++ QCA8K_REG_GOL_TRUNK_MEMBER(id) | ++ QCA8K_REG_GOL_TRUNK_EN(id), ++ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | ++ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); ++ ++ /* Search empty member if adding or port on deleting */ ++ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { ++ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); ++ if (ret) ++ return ret; ++ ++ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; ++ ++ if (delete) { ++ /* If port flagged to be disabled assume this member is ++ * empty ++ */ ++ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ ++ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; ++ if (val != port) ++ continue; ++ } else { ++ /* If port flagged to be enabled assume this member is ++ * already set ++ */ ++ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) ++ continue; ++ } ++ ++ /* We have found the member to add/remove */ ++ break; ++ } ++ ++ /* Set port in the correct port mask or disable port if in delete mode */ ++ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | ++ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), ++ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | ++ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); ++} ++ ++int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag, ++ struct netdev_lag_upper_info *info) ++{ ++ int ret; ++ ++ if (!qca8k_lag_can_offload(ds, lag, info)) ++ return -EOPNOTSUPP; ++ ++ ret = qca8k_lag_setup_hash(ds, lag, info); ++ if (ret) ++ return ret; ++ ++ return qca8k_lag_refresh_portmap(ds, port, lag, false); ++} ++ ++int qca8k_port_lag_leave(struct dsa_switch *ds, int port, ++ struct net_device *lag) ++{ ++ return qca8k_lag_refresh_portmap(ds, port, lag, true); ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -495,4 +495,10 @@ int qca8k_port_vlan_add(struct dsa_switc + int qca8k_port_vlan_del(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan); + ++/* Common port LAG function */ ++int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag, ++ struct netdev_lag_upper_info *info); ++int qca8k_port_lag_leave(struct dsa_switch *ds, int port, ++ struct net_device *lag); ++ + #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch b/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch new file mode 100644 index 00000000000..d6ec8b77e0c --- /dev/null +++ b/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch @@ -0,0 +1,102 @@ +From 9d1bcb1f293f1391302a109c9819c3705c804700 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 27 Jul 2022 13:35:23 +0200 +Subject: [PATCH 14/14] net: dsa: qca8k: move read_switch_id function to common + code + +The same function to read the switch id is used by drivers based on +qca8k family switch. Move them to common code to make them accessible +also by other drivers. + +Signed-off-by: Christian Marangi +Reviewed-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 29 ----------------------------- + drivers/net/dsa/qca/qca8k-common.c | 29 +++++++++++++++++++++++++++++ + drivers/net/dsa/qca/qca8k.h | 1 + + 3 files changed, 30 insertions(+), 29 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1822,35 +1822,6 @@ static const struct dsa_switch_ops qca8k + .connect_tag_protocol = qca8k_connect_tag_protocol, + }; + +-static int qca8k_read_switch_id(struct qca8k_priv *priv) +-{ +- u32 val; +- u8 id; +- int ret; +- +- if (!priv->info) +- return -ENODEV; +- +- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); +- if (ret < 0) +- return -ENODEV; +- +- id = QCA8K_MASK_CTRL_DEVICE_ID(val); +- if (id != priv->info->id) { +- dev_err(priv->dev, +- "Switch id detected %x but expected %x", +- id, priv->info->id); +- return -ENODEV; +- } +- +- priv->switch_id = id; +- +- /* Save revision to communicate to the internal PHY driver */ +- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); +- +- return 0; +-} +- + static int + qca8k_sw_probe(struct mdio_device *mdiodev) + { +--- a/drivers/net/dsa/qca/qca8k-common.c ++++ b/drivers/net/dsa/qca/qca8k-common.c +@@ -1175,3 +1175,32 @@ int qca8k_port_lag_leave(struct dsa_swit + { + return qca8k_lag_refresh_portmap(ds, port, lag, true); + } ++ ++int qca8k_read_switch_id(struct qca8k_priv *priv) ++{ ++ u32 val; ++ u8 id; ++ int ret; ++ ++ if (!priv->info) ++ return -ENODEV; ++ ++ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); ++ if (ret < 0) ++ return -ENODEV; ++ ++ id = QCA8K_MASK_CTRL_DEVICE_ID(val); ++ if (id != priv->info->id) { ++ dev_err(priv->dev, ++ "Switch id detected %x but expected %x", ++ id, priv->info->id); ++ return -ENODEV; ++ } ++ ++ priv->switch_id = id; ++ ++ /* Save revision to communicate to the internal PHY driver */ ++ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); ++ ++ return 0; ++} +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -424,6 +424,7 @@ extern const struct qca8k_mib_desc ar832 + extern const struct regmap_access_table qca8k_readable_table; + int qca8k_mib_init(struct qca8k_priv *priv); + void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable); ++int qca8k_read_switch_id(struct qca8k_priv *priv); + + /* Common read/write/rmw function */ + int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); diff --git a/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch b/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch new file mode 100644 index 00000000000..0cca2788f6d --- /dev/null +++ b/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch @@ -0,0 +1,29 @@ +From 057bcf15db8e625276ddf02b2b7c668a3cb43f81 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sun, 4 Sep 2022 23:46:24 +0200 +Subject: [net PATCH] net: dsa: qca8k: fix NULL pointer dereference for + of_device_get_match_data + +of_device_get_match_data is called on priv->dev before priv->dev is +actually set. Move of_device_get_match_data after priv->dev is correctly +set to fix this kernel panic. + +Fixes: 3bb0844e7bcd ("net: dsa: qca8k: cache match data to speed up access") +Signed-off-by: Christian Marangi +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1835,9 +1835,9 @@ qca8k_sw_probe(struct mdio_device *mdiod + if (!priv) + return -ENOMEM; + +- priv->info = of_device_get_match_data(priv->dev); + priv->bus = mdiodev->bus; + priv->dev = &mdiodev->dev; ++ priv->info = of_device_get_match_data(priv->dev); + + priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", + GPIOD_ASIS); diff --git a/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch b/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch new file mode 100644 index 00000000000..44093eab95b --- /dev/null +++ b/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch @@ -0,0 +1,77 @@ +From 381a730182f1d174e1950cd4e63e885b1c302051 Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Mon, 24 Jan 2022 22:09:43 +0100 +Subject: net: dsa: Move VLAN filtering syncing out of dsa_switch_bridge_leave + +Most of dsa_switch_bridge_leave was, in fact, dealing with the syncing +of VLAN filtering for switches on which that is a global +setting. Separate the two phases to prepare for the cross-chip related +bugfix in the following commit. + +Signed-off-by: Tobias Waldekranz +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + net/dsa/switch.c | 38 +++++++++++++++++++++++++------------- + 1 file changed, 25 insertions(+), 13 deletions(-) + +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -113,25 +113,14 @@ static int dsa_switch_bridge_join(struct + return dsa_tag_8021q_bridge_join(ds, info); + } + +-static int dsa_switch_bridge_leave(struct dsa_switch *ds, +- struct dsa_notifier_bridge_info *info) ++static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds, ++ struct dsa_notifier_bridge_info *info) + { +- struct dsa_switch_tree *dst = ds->dst; + struct netlink_ext_ack extack = {0}; + bool change_vlan_filtering = false; + bool vlan_filtering; + int err, port; + +- if (dst->index == info->tree_index && ds->index == info->sw_index && +- ds->ops->port_bridge_leave) +- ds->ops->port_bridge_leave(ds, info->port, info->br); +- +- if ((dst->index != info->tree_index || ds->index != info->sw_index) && +- ds->ops->crosschip_bridge_leave) +- ds->ops->crosschip_bridge_leave(ds, info->tree_index, +- info->sw_index, info->port, +- info->br); +- + if (ds->needs_standalone_vlan_filtering && !br_vlan_enabled(info->br)) { + change_vlan_filtering = true; + vlan_filtering = true; +@@ -172,6 +161,29 @@ static int dsa_switch_bridge_leave(struc + return err; + } + ++ return 0; ++} ++ ++static int dsa_switch_bridge_leave(struct dsa_switch *ds, ++ struct dsa_notifier_bridge_info *info) ++{ ++ struct dsa_switch_tree *dst = ds->dst; ++ int err; ++ ++ if (dst->index == info->tree_index && ds->index == info->sw_index && ++ ds->ops->port_bridge_leave) ++ ds->ops->port_bridge_leave(ds, info->port, info->br); ++ ++ if ((dst->index != info->tree_index || ds->index != info->sw_index) && ++ ds->ops->crosschip_bridge_leave) ++ ds->ops->crosschip_bridge_leave(ds, info->tree_index, ++ info->sw_index, info->port, ++ info->br); ++ ++ err = dsa_switch_sync_vlan_filtering(ds, info); ++ if (err) ++ return err; ++ + return dsa_tag_8021q_bridge_leave(ds, info); + } + diff --git a/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch b/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch new file mode 100644 index 00000000000..cdddbcf14ee --- /dev/null +++ b/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch @@ -0,0 +1,52 @@ +From 108dc8741c203e9d6ce4e973367f1bac20c7192b Mon Sep 17 00:00:00 2001 +From: Tobias Waldekranz +Date: Mon, 24 Jan 2022 22:09:44 +0100 +Subject: net: dsa: Avoid cross-chip syncing of VLAN filtering + +Changes to VLAN filtering are not applicable to cross-chip +notifications. + +On a system like this: + +.-----. .-----. .-----. +| sw1 +---+ sw2 +---+ sw3 | +'-1-2-' '-1-2-' '-1-2-' + +Before this change, upon sw1p1 leaving a bridge, a call to +dsa_port_vlan_filtering would also be made to sw2p1 and sw3p1. + +In this scenario: + +.---------. .-----. .-----. +| sw1 +---+ sw2 +---+ sw3 | +'-1-2-3-4-' '-1-2-' '-1-2-' + +When sw1p4 would leave a bridge, dsa_port_vlan_filtering would be +called for sw2 and sw3 with a non-existing port - leading to array +out-of-bounds accesses and crashes on mv88e6xxx. + +Fixes: d371b7c92d19 ("net: dsa: Unset vlan_filtering when ports leave the bridge") +Signed-off-by: Tobias Waldekranz +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + net/dsa/switch.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/net/dsa/switch.c ++++ b/net/dsa/switch.c +@@ -180,9 +180,11 @@ static int dsa_switch_bridge_leave(struc + info->sw_index, info->port, + info->br); + +- err = dsa_switch_sync_vlan_filtering(ds, info); +- if (err) +- return err; ++ if (ds->dst->index == info->tree_index && ds->index == info->sw_index) { ++ err = dsa_switch_sync_vlan_filtering(ds, info); ++ if (err) ++ return err; ++ } + + return dsa_tag_8021q_bridge_leave(ds, info); + } diff --git a/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch b/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch new file mode 100644 index 00000000000..78570c5e6e3 --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch @@ -0,0 +1,141 @@ +From c9111895fd38dadf125e07be627778a9950d8d77 Mon Sep 17 00:00:00 2001 +From: DENG Qingfang +Date: Sun, 26 Sep 2021 00:59:24 +0200 +Subject: [PATCH 01/11] net: dsa: rtl8366rb: Support bridge offloading +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use port isolation registers to configure bridge offloading. + +Tested on the D-Link DIR-685, switching between ports and +sniffing ports to make sure no packets leak. + +Cc: Vladimir Oltean +Cc: Mauri Sandberg +Reviewed-by: Vladimir Oltean +Reviewed-by: Alvin Šipraga +Reviewed-by: Florian Fainelli +Signed-off-by: DENG Qingfang +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366rb.c | 86 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 86 insertions(+) + +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -300,6 +300,13 @@ + #define RTL8366RB_INTERRUPT_STATUS_REG 0x0442 + #define RTL8366RB_NUM_INTERRUPT 14 /* 0..13 */ + ++/* Port isolation registers */ ++#define RTL8366RB_PORT_ISO_BASE 0x0F08 ++#define RTL8366RB_PORT_ISO(pnum) (RTL8366RB_PORT_ISO_BASE + (pnum)) ++#define RTL8366RB_PORT_ISO_EN BIT(0) ++#define RTL8366RB_PORT_ISO_PORTS_MASK GENMASK(7, 1) ++#define RTL8366RB_PORT_ISO_PORTS(pmask) ((pmask) << 1) ++ + /* bits 0..5 enable force when cleared */ + #define RTL8366RB_MAC_FORCE_CTRL_REG 0x0F11 + +@@ -835,6 +842,21 @@ static int rtl8366rb_setup(struct dsa_sw + if (ret) + return ret; + ++ /* Isolate all user ports so they can only send packets to itself and the CPU port */ ++ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { ++ ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(i), ++ RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) | ++ RTL8366RB_PORT_ISO_EN); ++ if (ret) ++ return ret; ++ } ++ /* CPU port can send packets to all ports */ ++ ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU), ++ RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) | ++ RTL8366RB_PORT_ISO_EN); ++ if (ret) ++ return ret; ++ + /* Set up the "green ethernet" feature */ + ret = rtl8366rb_jam_table(rtl8366rb_green_jam, + ARRAY_SIZE(rtl8366rb_green_jam), smi, false); +@@ -1127,6 +1149,68 @@ rtl8366rb_port_disable(struct dsa_switch + rb8366rb_set_port_led(smi, port, false); + } + ++static int ++rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct realtek_smi *smi = ds->priv; ++ unsigned int port_bitmap = 0; ++ int ret, i; ++ ++ /* Loop over all other ports than the current one */ ++ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { ++ /* Current port handled last */ ++ if (i == port) ++ continue; ++ /* Not on this bridge */ ++ if (dsa_to_port(ds, i)->bridge_dev != bridge) ++ continue; ++ /* Join this port to each other port on the bridge */ ++ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), ++ RTL8366RB_PORT_ISO_PORTS(BIT(port)), ++ RTL8366RB_PORT_ISO_PORTS(BIT(port))); ++ if (ret) ++ dev_err(smi->dev, "failed to join port %d\n", port); ++ ++ port_bitmap |= BIT(i); ++ } ++ ++ /* Set the bits for the ports we can access */ ++ return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), ++ RTL8366RB_PORT_ISO_PORTS(port_bitmap), ++ RTL8366RB_PORT_ISO_PORTS(port_bitmap)); ++} ++ ++static void ++rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port, ++ struct net_device *bridge) ++{ ++ struct realtek_smi *smi = ds->priv; ++ unsigned int port_bitmap = 0; ++ int ret, i; ++ ++ /* Loop over all other ports than this one */ ++ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { ++ /* Current port handled last */ ++ if (i == port) ++ continue; ++ /* Not on this bridge */ ++ if (dsa_to_port(ds, i)->bridge_dev != bridge) ++ continue; ++ /* Remove this port from any other port on the bridge */ ++ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), ++ RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0); ++ if (ret) ++ dev_err(smi->dev, "failed to leave port %d\n", port); ++ ++ port_bitmap |= BIT(i); ++ } ++ ++ /* Clear the bits for the ports we can not access, leave ourselves */ ++ regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), ++ RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); ++} ++ + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct realtek_smi *smi = ds->priv; +@@ -1510,6 +1594,8 @@ static const struct dsa_switch_ops rtl83 + .get_strings = rtl8366_get_strings, + .get_ethtool_stats = rtl8366_get_ethtool_stats, + .get_sset_count = rtl8366_get_sset_count, ++ .port_bridge_join = rtl8366rb_port_bridge_join, ++ .port_bridge_leave = rtl8366rb_port_bridge_leave, + .port_vlan_filtering = rtl8366_vlan_filtering, + .port_vlan_add = rtl8366_vlan_add, + .port_vlan_del = rtl8366_vlan_del, diff --git a/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch b/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch new file mode 100644 index 00000000000..e61349a32ca --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch @@ -0,0 +1,118 @@ +From 96cf10a8e7297065459473c081a6fb6432a22312 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Sun, 26 Sep 2021 00:59:25 +0200 +Subject: [PATCH 02/11] net: dsa: rtl8366: Drop custom VLAN set-up +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This hacky default VLAN setup was done in order to direct +packets to the right ports and provide port isolation, both +which we now support properly using custom tags and proper +bridge port isolation. + +We can drop the custom VLAN code and leave all VLAN handling +alone, as users expect things to be. We can also drop +ds->configure_vlan_while_not_filtering = false; and let +the core deal with any VLANs it wants. + +Cc: Mauri Sandberg +Cc: DENG Qingfang +Reviewed-by: Vladimir Oltean +Reviewed-by: Alvin Šipraga +Reviewed-by: Florian Fainelli +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek-smi-core.h | 1 - + drivers/net/dsa/rtl8366.c | 48 ------------------------------ + drivers/net/dsa/rtl8366rb.c | 4 +-- + 3 files changed, 1 insertion(+), 52 deletions(-) + +--- a/drivers/net/dsa/realtek-smi-core.h ++++ b/drivers/net/dsa/realtek-smi-core.h +@@ -129,7 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi + int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); + int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); + int rtl8366_reset_vlan(struct realtek_smi *smi); +-int rtl8366_init_vlan(struct realtek_smi *smi); + int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack); + int rtl8366_vlan_add(struct dsa_switch *ds, int port, +--- a/drivers/net/dsa/rtl8366.c ++++ b/drivers/net/dsa/rtl8366.c +@@ -292,54 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm + } + EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +-int rtl8366_init_vlan(struct realtek_smi *smi) +-{ +- int port; +- int ret; +- +- ret = rtl8366_reset_vlan(smi); +- if (ret) +- return ret; +- +- /* Loop over the available ports, for each port, associate +- * it with the VLAN (port+1) +- */ +- for (port = 0; port < smi->num_ports; port++) { +- u32 mask; +- +- if (port == smi->cpu_port) +- /* For the CPU port, make all ports members of this +- * VLAN. +- */ +- mask = GENMASK((int)smi->num_ports - 1, 0); +- else +- /* For all other ports, enable itself plus the +- * CPU port. +- */ +- mask = BIT(port) | BIT(smi->cpu_port); +- +- /* For each port, set the port as member of VLAN (port+1) +- * and untagged, except for the CPU port: the CPU port (5) is +- * member of VLAN 6 and so are ALL the other ports as well. +- * Use filter 0 (no filter). +- */ +- dev_info(smi->dev, "VLAN%d port mask for port %d, %08x\n", +- (port + 1), port, mask); +- ret = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); +- if (ret) +- return ret; +- +- dev_info(smi->dev, "VLAN%d port %d, PVID set to %d\n", +- (port + 1), port, (port + 1)); +- ret = rtl8366_set_pvid(smi, port, (port + 1)); +- if (ret) +- return ret; +- } +- +- return rtl8366_enable_vlan(smi, true); +-} +-EXPORT_SYMBOL_GPL(rtl8366_init_vlan); +- + int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, + struct netlink_ext_ack *extack) + { +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -985,7 +985,7 @@ static int rtl8366rb_setup(struct dsa_sw + return ret; + } + +- ret = rtl8366_init_vlan(smi); ++ ret = rtl8366_reset_vlan(smi); + if (ret) + return ret; + +@@ -999,8 +999,6 @@ static int rtl8366rb_setup(struct dsa_sw + return -ENODEV; + } + +- ds->configure_vlan_while_not_filtering = false; +- + return 0; + } + diff --git a/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch b/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch new file mode 100644 index 00000000000..2b197523994 --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch @@ -0,0 +1,270 @@ +From 7028f54b620f8df344b18e46e4a78e266091ab45 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Sun, 26 Sep 2021 00:59:26 +0200 +Subject: [PATCH 03/11] net: dsa: rtl8366rb: Rewrite weird VLAN filering + enablement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +While we were defining one VLAN per port for isolating the ports +the port_vlan_filtering() callback was implemented to enable a +VLAN on the port + 1. This function makes no sense, not only is +it incomplete as it only enables the VLAN, it doesn't do what +the callback is supposed to do, which is to selectively enable +and disable filtering on a certain port. + +Implement the correct callback: we have two registers dealing +with filtering on the RTL9366RB, so we implement an ASIC-specific +callback and implement filering using the register bit that makes +the switch drop frames if the port is not in the VLAN member set. + +The DSA documentation Documentation/networking/switchdev.rst states: + + When the bridge has VLAN filtering enabled and a PVID is not + configured on the ingress port, untagged and 802.1p tagged + packets must be dropped. When the bridge has VLAN filtering + enabled and a PVID exists on the ingress port, untagged and + priority-tagged packets must be accepted and forwarded according + to the bridge's port membership of the PVID VLAN. When the + bridge has VLAN filtering disabled, the presence/lack of a + PVID should not influence the packet forwarding decision. + +To comply with this, we add two arrays of bool in the RTL8366RB +state that keeps track of if filtering and PVID is enabled or +not for each port. We then add code such that whenever filtering +or PVID changes, we update the filter according to the +specification. + +Cc: Vladimir Oltean +Cc: Mauri Sandberg +Cc: Alvin Šipraga +Cc: Florian Fainelli +Cc: DENG Qingfang +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/realtek-smi-core.h | 2 - + drivers/net/dsa/rtl8366.c | 35 ---------- + drivers/net/dsa/rtl8366rb.c | 102 +++++++++++++++++++++++++++-- + 3 files changed, 95 insertions(+), 44 deletions(-) + +--- a/drivers/net/dsa/realtek-smi-core.h ++++ b/drivers/net/dsa/realtek-smi-core.h +@@ -129,8 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi + int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); + int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); + int rtl8366_reset_vlan(struct realtek_smi *smi); +-int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, +- struct netlink_ext_ack *extack); + int rtl8366_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack); +--- a/drivers/net/dsa/rtl8366.c ++++ b/drivers/net/dsa/rtl8366.c +@@ -292,41 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm + } + EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +-int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, +- struct netlink_ext_ack *extack) +-{ +- struct realtek_smi *smi = ds->priv; +- struct rtl8366_vlan_4k vlan4k; +- int ret; +- +- /* Use VLAN nr port + 1 since VLAN0 is not valid */ +- if (!smi->ops->is_vlan_valid(smi, port + 1)) +- return -EINVAL; +- +- dev_info(smi->dev, "%s filtering on port %d\n", +- vlan_filtering ? "enable" : "disable", +- port); +- +- /* TODO: +- * The hardware support filter ID (FID) 0..7, I have no clue how to +- * support this in the driver when the callback only says on/off. +- */ +- ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k); +- if (ret) +- return ret; +- +- /* Just set the filter to FID 1 for now then */ +- ret = rtl8366_set_vlan(smi, port + 1, +- vlan4k.member, +- vlan4k.untag, +- 1); +- if (ret) +- return ret; +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering); +- + int rtl8366_vlan_add(struct dsa_switch *ds, int port, + const struct switchdev_obj_port_vlan *vlan, + struct netlink_ext_ack *extack) +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -143,6 +143,21 @@ + #define RTL8366RB_PHY_NO_OFFSET 9 + #define RTL8366RB_PHY_NO_MASK (0x1f << 9) + ++/* VLAN Ingress Control Register 1, one bit per port. ++ * bit 0 .. 5 will make the switch drop ingress frames without ++ * VID such as untagged or priority-tagged frames for respective ++ * port. ++ * bit 6 .. 11 will make the switch drop ingress frames carrying ++ * a C-tag with VID != 0 for respective port. ++ */ ++#define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E ++#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) + 6)) ++ ++/* VLAN Ingress Control Register 2, one bit per port. ++ * bit0 .. bit5 will make the switch drop all ingress frames with ++ * a VLAN classification that does not include the port is in its ++ * member set. ++ */ + #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f + + /* LED control registers */ +@@ -321,9 +336,13 @@ + /** + * struct rtl8366rb - RTL8366RB-specific data + * @max_mtu: per-port max MTU setting ++ * @pvid_enabled: if PVID is set for respective port ++ * @vlan_filtering: if VLAN filtering is enabled for respective port + */ + struct rtl8366rb { + unsigned int max_mtu[RTL8366RB_NUM_PORTS]; ++ bool pvid_enabled[RTL8366RB_NUM_PORTS]; ++ bool vlan_filtering[RTL8366RB_NUM_PORTS]; + }; + + static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { +@@ -933,11 +952,13 @@ static int rtl8366rb_setup(struct dsa_sw + if (ret) + return ret; + +- /* Discard VLAN tagged packets if the port is not a member of +- * the VLAN with which the packets is associated. +- */ ++ /* Accept all packets by default, we enable filtering on-demand */ ++ ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, ++ 0); ++ if (ret) ++ return ret; + ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, +- RTL8366RB_PORT_ALL); ++ 0); + if (ret) + return ret; + +@@ -1209,6 +1230,53 @@ rtl8366rb_port_bridge_leave(struct dsa_s + RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); + } + ++/** ++ * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames ++ * @smi: SMI state container ++ * @port: the port to drop untagged and C-tagged frames on ++ * @drop: whether to drop or pass untagged and C-tagged frames ++ */ ++static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool drop) ++{ ++ return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, ++ RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port), ++ drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0); ++} ++ ++static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, ++ bool vlan_filtering, ++ struct netlink_ext_ack *extack) ++{ ++ struct realtek_smi *smi = ds->priv; ++ struct rtl8366rb *rb; ++ int ret; ++ ++ rb = smi->chip_data; ++ ++ dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port, ++ vlan_filtering ? "enable" : "disable"); ++ ++ /* If the port is not in the member set, the frame will be dropped */ ++ ret = regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, ++ BIT(port), vlan_filtering ? BIT(port) : 0); ++ if (ret) ++ return ret; ++ ++ /* Keep track if filtering is enabled on each port */ ++ rb->vlan_filtering[port] = vlan_filtering; ++ ++ /* If VLAN filtering is enabled and PVID is also enabled, we must ++ * not drop any untagged or C-tagged frames. If we turn off VLAN ++ * filtering on a port, we need ti accept any frames. ++ */ ++ if (vlan_filtering) ++ ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); ++ else ++ ret = rtl8366rb_drop_untagged(smi, port, false); ++ ++ return ret; ++} ++ + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct realtek_smi *smi = ds->priv; +@@ -1420,14 +1488,34 @@ static int rtl8366rb_get_mc_index(struct + + static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index) + { ++ struct rtl8366rb *rb; ++ bool pvid_enabled; ++ int ret; ++ ++ rb = smi->chip_data; ++ pvid_enabled = !!index; ++ + if (port >= smi->num_ports || index >= RTL8366RB_NUM_VLANS) + return -EINVAL; + +- return regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), ++ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), + RTL8366RB_PORT_VLAN_CTRL_MASK << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), + (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << + RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); ++ if (ret) ++ return ret; ++ ++ rb->pvid_enabled[port] = pvid_enabled; ++ ++ /* If VLAN filtering is enabled and PVID is also enabled, we must ++ * not drop any untagged or C-tagged frames. Make sure to update the ++ * filtering setting. ++ */ ++ if (rb->vlan_filtering[port]) ++ ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled); ++ ++ return ret; + } + + static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan) +@@ -1437,7 +1525,7 @@ static bool rtl8366rb_is_vlan_valid(stru + if (smi->vlan4k_enabled) + max = RTL8366RB_NUM_VIDS - 1; + +- if (vlan == 0 || vlan > max) ++ if (vlan > max) + return false; + + return true; +@@ -1594,7 +1682,7 @@ static const struct dsa_switch_ops rtl83 + .get_sset_count = rtl8366_get_sset_count, + .port_bridge_join = rtl8366rb_port_bridge_join, + .port_bridge_leave = rtl8366rb_port_bridge_leave, +- .port_vlan_filtering = rtl8366_vlan_filtering, ++ .port_vlan_filtering = rtl8366rb_vlan_filtering, + .port_vlan_add = rtl8366_vlan_add, + .port_vlan_del = rtl8366_vlan_del, + .port_enable = rtl8366rb_port_enable, diff --git a/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch b/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch new file mode 100644 index 00000000000..b56032c366b --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch @@ -0,0 +1,51 @@ +From ddb59a5dc42714999c335dab4bf256125ba3120c Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Sun, 26 Sep 2021 00:59:29 +0200 +Subject: [PATCH 06/11] net: dsa: rtl8366: Drop and depromote pointless prints +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We don't need a message for every VLAN association, dbg +is fine. The message about adding the DSA or CPU +port to a VLAN is directly misleading, this is perfectly +fine. + +Cc: Vladimir Oltean +Cc: Mauri Sandberg +Cc: DENG Qingfang +Reviewed-by: Alvin Šipraga +Reviewed-by: Florian Fainelli +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +--- a/drivers/net/dsa/rtl8366.c ++++ b/drivers/net/dsa/rtl8366.c +@@ -318,12 +318,9 @@ int rtl8366_vlan_add(struct dsa_switch * + return ret; + } + +- dev_info(smi->dev, "add VLAN %d on port %d, %s, %s\n", +- vlan->vid, port, untagged ? "untagged" : "tagged", +- pvid ? " PVID" : "no PVID"); +- +- if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) +- dev_err(smi->dev, "port is DSA or CPU port\n"); ++ dev_dbg(smi->dev, "add VLAN %d on port %d, %s, %s\n", ++ vlan->vid, port, untagged ? "untagged" : "tagged", ++ pvid ? "PVID" : "no PVID"); + + member |= BIT(port); + +@@ -356,7 +353,7 @@ int rtl8366_vlan_del(struct dsa_switch * + struct realtek_smi *smi = ds->priv; + int ret, i; + +- dev_info(smi->dev, "del VLAN %04x on port %d\n", vlan->vid, port); ++ dev_dbg(smi->dev, "del VLAN %d on port %d\n", vlan->vid, port); + + for (i = 0; i < smi->num_vlan_mc; i++) { + struct rtl8366_vlan_mc vlanmc; diff --git a/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch b/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch new file mode 100644 index 00000000000..8cd1df97f24 --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch @@ -0,0 +1,61 @@ +From 5c9b66f3c8a3f72fa2a58e89a57c6d7afd550bf0 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 29 Sep 2021 13:23:22 +0200 +Subject: [PATCH 07/11] net: dsa: rtl8366rb: Use core filtering tracking +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We added a state variable to track whether a certain port +was VLAN filtering or not, but we can just inquire the DSA +core about this. + +Cc: Vladimir Oltean +Cc: Mauri Sandberg +Cc: DENG Qingfang +Cc: Alvin Šipraga +Cc: Reviewed-by: Florian Fainelli +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366rb.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -337,12 +337,10 @@ + * struct rtl8366rb - RTL8366RB-specific data + * @max_mtu: per-port max MTU setting + * @pvid_enabled: if PVID is set for respective port +- * @vlan_filtering: if VLAN filtering is enabled for respective port + */ + struct rtl8366rb { + unsigned int max_mtu[RTL8366RB_NUM_PORTS]; + bool pvid_enabled[RTL8366RB_NUM_PORTS]; +- bool vlan_filtering[RTL8366RB_NUM_PORTS]; + }; + + static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { +@@ -1262,12 +1260,9 @@ static int rtl8366rb_vlan_filtering(stru + if (ret) + return ret; + +- /* Keep track if filtering is enabled on each port */ +- rb->vlan_filtering[port] = vlan_filtering; +- + /* If VLAN filtering is enabled and PVID is also enabled, we must + * not drop any untagged or C-tagged frames. If we turn off VLAN +- * filtering on a port, we need ti accept any frames. ++ * filtering on a port, we need to accept any frames. + */ + if (vlan_filtering) + ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); +@@ -1512,7 +1507,7 @@ static int rtl8366rb_set_mc_index(struct + * not drop any untagged or C-tagged frames. Make sure to update the + * filtering setting. + */ +- if (rb->vlan_filtering[port]) ++ if (dsa_port_is_vlan_filtering(dsa_to_port(smi->ds, port))) + ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled); + + return ret; diff --git a/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch b/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch new file mode 100644 index 00000000000..8306eb5aefa --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch @@ -0,0 +1,115 @@ +From 831a3d26bea0d14f8563eecf96def660a74a3000 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Tue, 5 Oct 2021 21:47:02 +0200 +Subject: [PATCH 08/11] net: dsa: rtl8366rb: Support disabling learning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The RTL8366RB hardware supports disabling learning per-port +so let's make use of this feature. Rename some unfortunately +named registers in the process. + +Suggested-by: Vladimir Oltean +Cc: Alvin Šipraga +Cc: Mauri Sandberg +Cc: Florian Fainelli +Cc: DENG Qingfang +Reviewed-by: Vladimir Oltean +Signed-off-by: Linus Walleij +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366rb.c | 50 ++++++++++++++++++++++++++++++++----- + 1 file changed, 44 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -14,6 +14,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -42,9 +43,12 @@ + /* Port Enable Control register */ + #define RTL8366RB_PECR 0x0001 + +-/* Switch Security Control registers */ +-#define RTL8366RB_SSCR0 0x0002 +-#define RTL8366RB_SSCR1 0x0003 ++/* Switch per-port learning disablement register */ ++#define RTL8366RB_PORT_LEARNDIS_CTRL 0x0002 ++ ++/* Security control, actually aging register */ ++#define RTL8366RB_SECURITY_CTRL 0x0003 ++ + #define RTL8366RB_SSCR2 0x0004 + #define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) + +@@ -927,13 +931,14 @@ static int rtl8366rb_setup(struct dsa_sw + /* layer 2 size, see rtl8366rb_change_mtu() */ + rb->max_mtu[i] = 1532; + +- /* Enable learning for all ports */ +- ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0); ++ /* Disable learning for all ports */ ++ ret = regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, ++ RTL8366RB_PORT_ALL); + if (ret) + return ret; + + /* Enable auto ageing for all ports */ +- ret = regmap_write(smi->map, RTL8366RB_SSCR1, 0); ++ ret = regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0); + if (ret) + return ret; + +@@ -1272,6 +1277,37 @@ static int rtl8366rb_vlan_filtering(stru + return ret; + } + ++static int ++rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ /* We support enabling/disabling learning */ ++ if (flags.mask & ~(BR_LEARNING)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int ++rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, ++ struct switchdev_brport_flags flags, ++ struct netlink_ext_ack *extack) ++{ ++ struct realtek_smi *smi = ds->priv; ++ int ret; ++ ++ if (flags.mask & BR_LEARNING) { ++ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, ++ BIT(port), ++ (flags.val & BR_LEARNING) ? 0 : BIT(port)); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct realtek_smi *smi = ds->priv; +@@ -1682,6 +1718,8 @@ static const struct dsa_switch_ops rtl83 + .port_vlan_del = rtl8366_vlan_del, + .port_enable = rtl8366rb_port_enable, + .port_disable = rtl8366rb_port_disable, ++ .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, ++ .port_bridge_flags = rtl8366rb_port_bridge_flags, + .port_change_mtu = rtl8366rb_change_mtu, + .port_max_mtu = rtl8366rb_max_mtu, + }; diff --git a/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch b/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch new file mode 100644 index 00000000000..a74108e23db --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch @@ -0,0 +1,57 @@ +From 8eb13420eb9ab4a4e2ebd612bf5dc9dba0039236 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Tue, 5 Oct 2021 21:47:03 +0200 +Subject: [PATCH 09/11] net: dsa: rtl8366rb: Support fast aging +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This implements fast aging per-port using the special "security" +register, which will flush any learned L2 LUT entries on a port. + +The vendor API just enabled setting and clearing this bit, so +we set it to age out any entries on the port and then we clear +it again. + +Suggested-by: Vladimir Oltean +Cc: Mauri Sandberg +Cc: DENG Qingfang +Cc: Florian Fainelli +Reviewed-by: Alvin Šipraga +Signed-off-by: Linus Walleij +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366rb.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -1308,6 +1308,19 @@ rtl8366rb_port_bridge_flags(struct dsa_s + return 0; + } + ++static void ++rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) ++{ ++ struct realtek_smi *smi = ds->priv; ++ ++ /* This will age out any learned L2 entries */ ++ regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, ++ BIT(port), BIT(port)); ++ /* Restore the normal state of things */ ++ regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, ++ BIT(port), 0); ++} ++ + static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct realtek_smi *smi = ds->priv; +@@ -1720,6 +1733,7 @@ static const struct dsa_switch_ops rtl83 + .port_disable = rtl8366rb_port_disable, + .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, + .port_bridge_flags = rtl8366rb_port_bridge_flags, ++ .port_fast_age = rtl8366rb_port_fast_age, + .port_change_mtu = rtl8366rb_change_mtu, + .port_max_mtu = rtl8366rb_max_mtu, + }; diff --git a/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch b/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch new file mode 100644 index 00000000000..e787ce94811 --- /dev/null +++ b/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch @@ -0,0 +1,107 @@ +From 90c855471a89d3e05ecf5b6464bd04abf2c83b70 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Tue, 5 Oct 2021 21:47:04 +0200 +Subject: [PATCH 10/11] net: dsa: rtl8366rb: Support setting STP state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds support for setting the STP state to the RTL8366RB +DSA switch. This rids the following message from the kernel on +e.g. OpenWrt: + +DSA: failed to set STP state 3 (-95) + +Since the RTL8366RB has one STP state register per FID with +two bit per port in each, we simply loop over all the FIDs +and set the state on all of them. + +Cc: Vladimir Oltean +Cc: Alvin Šipraga +Cc: Mauri Sandberg +Cc: DENG Qingfang +Signed-off-by: Linus Walleij +Reviewed-by: Vladimir Oltean +Signed-off-by: David S. Miller +--- + drivers/net/dsa/rtl8366rb.c | 48 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/drivers/net/dsa/rtl8366rb.c ++++ b/drivers/net/dsa/rtl8366rb.c +@@ -110,6 +110,18 @@ + + #define RTL8366RB_POWER_SAVING_REG 0x0021 + ++/* Spanning tree status (STP) control, two bits per port per FID */ ++#define RTL8366RB_STP_STATE_BASE 0x0050 /* 0x0050..0x0057 */ ++#define RTL8366RB_STP_STATE_DISABLED 0x0 ++#define RTL8366RB_STP_STATE_BLOCKING 0x1 ++#define RTL8366RB_STP_STATE_LEARNING 0x2 ++#define RTL8366RB_STP_STATE_FORWARDING 0x3 ++#define RTL8366RB_STP_MASK GENMASK(1, 0) ++#define RTL8366RB_STP_STATE(port, state) \ ++ ((state) << ((port) * 2)) ++#define RTL8366RB_STP_STATE_MASK(port) \ ++ RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK) ++ + /* CPU port control reg */ + #define RTL8368RB_CPU_CTRL_REG 0x0061 + #define RTL8368RB_CPU_PORTS_MSK 0x00FF +@@ -234,6 +246,7 @@ + #define RTL8366RB_NUM_LEDGROUPS 4 + #define RTL8366RB_NUM_VIDS 4096 + #define RTL8366RB_PRIORITYMAX 7 ++#define RTL8366RB_NUM_FIDS 8 + #define RTL8366RB_FIDMAX 7 + + #define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ +@@ -1309,6 +1322,40 @@ rtl8366rb_port_bridge_flags(struct dsa_s + } + + static void ++rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) ++{ ++ struct realtek_smi *smi = ds->priv; ++ u32 val; ++ int i; ++ ++ switch (state) { ++ case BR_STATE_DISABLED: ++ val = RTL8366RB_STP_STATE_DISABLED; ++ break; ++ case BR_STATE_BLOCKING: ++ case BR_STATE_LISTENING: ++ val = RTL8366RB_STP_STATE_BLOCKING; ++ break; ++ case BR_STATE_LEARNING: ++ val = RTL8366RB_STP_STATE_LEARNING; ++ break; ++ case BR_STATE_FORWARDING: ++ val = RTL8366RB_STP_STATE_FORWARDING; ++ break; ++ default: ++ dev_err(smi->dev, "unknown bridge state requested\n"); ++ return; ++ }; ++ ++ /* Set the same status for the port on all the FIDs */ ++ for (i = 0; i < RTL8366RB_NUM_FIDS; i++) { ++ regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i, ++ RTL8366RB_STP_STATE_MASK(port), ++ RTL8366RB_STP_STATE(port, val)); ++ } ++} ++ ++static void + rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) + { + struct realtek_smi *smi = ds->priv; +@@ -1733,6 +1780,7 @@ static const struct dsa_switch_ops rtl83 + .port_disable = rtl8366rb_port_disable, + .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, + .port_bridge_flags = rtl8366rb_port_bridge_flags, ++ .port_stp_state_set = rtl8366rb_port_stp_state_set, + .port_fast_age = rtl8366rb_port_fast_age, + .port_change_mtu = rtl8366rb_change_mtu, + .port_max_mtu = rtl8366rb_max_mtu, diff --git a/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch b/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch new file mode 100644 index 00000000000..9b9ab04af6c --- /dev/null +++ b/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch @@ -0,0 +1,142 @@ +From f9ec5723c3dbfcede9c7b0dcdf85e401ce16316c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 23 Jul 2022 16:29:29 +0200 +Subject: [PATCH 1/5] net: ethernet: stmicro: stmmac: move queue reset to + dedicated functions + +Move queue reset to dedicated functions. This aside from a simple +cleanup is also required to allocate a dma conf without resetting the tx +queue while the device is temporarily detached as now the reset is not +part of the dma init function and can be done later in the code flow. + +Signed-off-by: Christian Marangi +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 59 ++++++++++--------- + 1 file changed, 31 insertions(+), 28 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -130,6 +130,9 @@ static irqreturn_t stmmac_mac_interrupt( + static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id); + static irqreturn_t stmmac_msi_intr_tx(int irq, void *data); + static irqreturn_t stmmac_msi_intr_rx(int irq, void *data); ++static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue); ++static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue); ++static void stmmac_reset_queues_param(struct stmmac_priv *priv); + static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue); + static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue); + +@@ -1712,9 +1715,6 @@ static int __init_dma_rx_desc_rings(stru + return -ENOMEM; + } + +- rx_q->cur_rx = 0; +- rx_q->dirty_rx = 0; +- + /* Setup the chained descriptor addresses */ + if (priv->mode == STMMAC_CHAIN_MODE) { + if (priv->extend_desc) +@@ -1820,12 +1820,6 @@ static int __init_dma_tx_desc_rings(stru + tx_q->tx_skbuff[i] = NULL; + } + +- tx_q->dirty_tx = 0; +- tx_q->cur_tx = 0; +- tx_q->mss = 0; +- +- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); +- + return 0; + } + +@@ -2694,10 +2688,7 @@ static void stmmac_tx_err(struct stmmac_ + stmmac_stop_tx_dma(priv, chan); + dma_free_tx_skbufs(priv, chan); + stmmac_clear_tx_descriptors(priv, chan); +- tx_q->dirty_tx = 0; +- tx_q->cur_tx = 0; +- tx_q->mss = 0; +- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, chan)); ++ stmmac_reset_tx_queue(priv, chan); + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + tx_q->dma_tx_phy, chan); + stmmac_start_tx_dma(priv, chan); +@@ -3781,6 +3772,8 @@ static int stmmac_open(struct net_device + } + } + ++ stmmac_reset_queues_param(priv); ++ + ret = stmmac_hw_setup(dev, true); + if (ret < 0) { + netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); +@@ -6430,6 +6423,7 @@ void stmmac_enable_rx_queue(struct stmma + return; + } + ++ stmmac_reset_rx_queue(priv, queue); + stmmac_clear_rx_descriptors(priv, queue); + + stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, +@@ -6491,6 +6485,7 @@ void stmmac_enable_tx_queue(struct stmma + return; + } + ++ stmmac_reset_tx_queue(priv, queue); + stmmac_clear_tx_descriptors(priv, queue); + + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, +@@ -7417,6 +7412,25 @@ int stmmac_suspend(struct device *dev) + } + EXPORT_SYMBOL_GPL(stmmac_suspend); + ++static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue) ++{ ++ struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ ++ rx_q->cur_rx = 0; ++ rx_q->dirty_rx = 0; ++} ++ ++static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue) ++{ ++ struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ ++ tx_q->cur_tx = 0; ++ tx_q->dirty_tx = 0; ++ tx_q->mss = 0; ++ ++ netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); ++} ++ + /** + * stmmac_reset_queues_param - reset queue parameters + * @priv: device pointer +@@ -7427,22 +7441,11 @@ static void stmmac_reset_queues_param(st + u32 tx_cnt = priv->plat->tx_queues_to_use; + u32 queue; + +- for (queue = 0; queue < rx_cnt; queue++) { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ for (queue = 0; queue < rx_cnt; queue++) ++ stmmac_reset_rx_queue(priv, queue); + +- rx_q->cur_rx = 0; +- rx_q->dirty_rx = 0; +- } +- +- for (queue = 0; queue < tx_cnt; queue++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; +- +- tx_q->cur_tx = 0; +- tx_q->dirty_tx = 0; +- tx_q->mss = 0; +- +- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); +- } ++ for (queue = 0; queue < tx_cnt; queue++) ++ stmmac_reset_tx_queue(priv, queue); + } + + /** diff --git a/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch b/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch new file mode 100644 index 00000000000..8eca92a5c54 --- /dev/null +++ b/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch @@ -0,0 +1,37 @@ +From 7028471edb646bfc532fec0973e50e784cdcb7c6 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 23 Jul 2022 16:29:30 +0200 +Subject: [PATCH 2/5] net: ethernet: stmicro: stmmac: first disable all queues + and disconnect in release + +Disable all queues and disconnect before tx_disable in stmmac_release to +prevent a corner case where packet may be still queued at the same time +tx_disable is called resulting in kernel panic if some packet still has +to be processed. + +Signed-off-by: Christian Marangi +Signed-off-by: Jakub Kicinski +--- + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -3833,8 +3833,6 @@ static int stmmac_release(struct net_dev + struct stmmac_priv *priv = netdev_priv(dev); + u32 chan; + +- netif_tx_disable(dev); +- + if (device_may_wakeup(priv->device)) + phylink_speed_down(priv->phylink, false); + /* Stop and disconnect the PHY */ +@@ -3846,6 +3844,8 @@ static int stmmac_release(struct net_dev + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) + hrtimer_cancel(&priv->tx_queue[chan].txtimer); + ++ netif_tx_disable(dev); ++ + /* Free the IRQ lines */ + stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); + diff --git a/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch b/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch new file mode 100644 index 00000000000..d4c2567a1fd --- /dev/null +++ b/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch @@ -0,0 +1,1289 @@ +From 8531c80800c10e8ef7952022326c2f983e1314bf Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 23 Jul 2022 16:29:31 +0200 +Subject: [PATCH 3/5] net: ethernet: stmicro: stmmac: move dma conf to + dedicated struct + +Move dma buf conf to dedicated struct. This in preparation for code +rework that will permit to allocate separate dma_conf without affecting +the priv struct. + +Signed-off-by: Christian Marangi +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/stmicro/stmmac/chain_mode.c | 6 +- + .../net/ethernet/stmicro/stmmac/ring_mode.c | 4 +- + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 21 +- + .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 4 +- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 286 +++++++++--------- + .../stmicro/stmmac/stmmac_selftests.c | 8 +- + .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 +- + 7 files changed, 172 insertions(+), 163 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c +@@ -46,7 +46,7 @@ static int jumbo_frm(void *p, struct sk_ + + while (len != 0) { + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + desc = tx_q->dma_tx + entry; + + if (len > bmax) { +@@ -137,7 +137,7 @@ static void refill_desc3(void *priv_ptr, + */ + p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy + + (((rx_q->dirty_rx) + 1) % +- priv->dma_rx_size) * ++ priv->dma_conf.dma_rx_size) * + sizeof(struct dma_desc))); + } + +@@ -155,7 +155,7 @@ static void clean_desc3(void *priv_ptr, + */ + p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy + + ((tx_q->dirty_tx + 1) % +- priv->dma_tx_size)) ++ priv->dma_conf.dma_tx_size)) + * sizeof(struct dma_desc))); + } + +--- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c ++++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +@@ -51,7 +51,7 @@ static int jumbo_frm(void *p, struct sk_ + stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, + STMMAC_RING_MODE, 0, false, skb->len); + tx_q->tx_skbuff[entry] = NULL; +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + + if (priv->extend_desc) + desc = (struct dma_desc *)(tx_q->dma_etx + entry); +@@ -107,7 +107,7 @@ static void refill_desc3(void *priv_ptr, + struct stmmac_priv *priv = rx_q->priv_data; + + /* Fill DES3 in case of RING mode */ +- if (priv->dma_buf_sz == BUF_SIZE_16KiB) ++ if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) + p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB); + } + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -185,6 +185,18 @@ struct stmmac_rfs_entry { + int tc; + }; + ++struct stmmac_dma_conf { ++ unsigned int dma_buf_sz; ++ ++ /* RX Queue */ ++ struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES]; ++ unsigned int dma_rx_size; ++ ++ /* TX Queue */ ++ struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; ++ unsigned int dma_tx_size; ++}; ++ + struct stmmac_priv { + /* Frequently used values are kept adjacent for cache effect */ + u32 tx_coal_frames[MTL_MAX_TX_QUEUES]; +@@ -199,7 +211,6 @@ struct stmmac_priv { + int sph_cap; + u32 sarc_type; + +- unsigned int dma_buf_sz; + unsigned int rx_copybreak; + u32 rx_riwt[MTL_MAX_TX_QUEUES]; + int hwts_rx_en; +@@ -211,13 +222,7 @@ struct stmmac_priv { + int (*hwif_quirks)(struct stmmac_priv *priv); + struct mutex lock; + +- /* RX Queue */ +- struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES]; +- unsigned int dma_rx_size; +- +- /* TX Queue */ +- struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; +- unsigned int dma_tx_size; ++ struct stmmac_dma_conf dma_conf; + + /* Generic channel for NAPI */ + struct stmmac_channel channel[STMMAC_CH_MAX]; +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +@@ -484,8 +484,8 @@ static void stmmac_get_ringparam(struct + + ring->rx_max_pending = DMA_MAX_RX_SIZE; + ring->tx_max_pending = DMA_MAX_TX_SIZE; +- ring->rx_pending = priv->dma_rx_size; +- ring->tx_pending = priv->dma_tx_size; ++ ring->rx_pending = priv->dma_conf.dma_rx_size; ++ ring->tx_pending = priv->dma_conf.dma_tx_size; + } + + static int stmmac_set_ringparam(struct net_device *netdev, +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -74,8 +74,8 @@ static int phyaddr = -1; + module_param(phyaddr, int, 0444); + MODULE_PARM_DESC(phyaddr, "Physical device address"); + +-#define STMMAC_TX_THRESH(x) ((x)->dma_tx_size / 4) +-#define STMMAC_RX_THRESH(x) ((x)->dma_rx_size / 4) ++#define STMMAC_TX_THRESH(x) ((x)->dma_conf.dma_tx_size / 4) ++#define STMMAC_RX_THRESH(x) ((x)->dma_conf.dma_rx_size / 4) + + /* Limit to make sure XDP TX and slow path can coexist */ + #define STMMAC_XSK_TX_BUDGET_MAX 256 +@@ -232,7 +232,7 @@ static void stmmac_disable_all_queues(st + + /* synchronize_rcu() needed for pending XDP buffers to drain */ + for (queue = 0; queue < rx_queues_cnt; queue++) { +- rx_q = &priv->rx_queue[queue]; ++ rx_q = &priv->dma_conf.rx_queue[queue]; + if (rx_q->xsk_pool) { + synchronize_rcu(); + break; +@@ -358,13 +358,13 @@ static void print_pkt(unsigned char *buf + + static inline u32 stmmac_tx_avail(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + u32 avail; + + if (tx_q->dirty_tx > tx_q->cur_tx) + avail = tx_q->dirty_tx - tx_q->cur_tx - 1; + else +- avail = priv->dma_tx_size - tx_q->cur_tx + tx_q->dirty_tx - 1; ++ avail = priv->dma_conf.dma_tx_size - tx_q->cur_tx + tx_q->dirty_tx - 1; + + return avail; + } +@@ -376,13 +376,13 @@ static inline u32 stmmac_tx_avail(struct + */ + static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + u32 dirty; + + if (rx_q->dirty_rx <= rx_q->cur_rx) + dirty = rx_q->cur_rx - rx_q->dirty_rx; + else +- dirty = priv->dma_rx_size - rx_q->dirty_rx + rx_q->cur_rx; ++ dirty = priv->dma_conf.dma_rx_size - rx_q->dirty_rx + rx_q->cur_rx; + + return dirty; + } +@@ -410,7 +410,7 @@ static int stmmac_enable_eee_mode(struct + + /* check if all TX queues have the work finished */ + for (queue = 0; queue < tx_cnt; queue++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + if (tx_q->dirty_tx != tx_q->cur_tx) + return -EBUSY; /* still unfinished work */ +@@ -1309,7 +1309,7 @@ static void stmmac_display_rx_rings(stru + + /* Display RX rings */ + for (queue = 0; queue < rx_cnt; queue++) { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + + pr_info("\tRX Queue %u rings\n", queue); + +@@ -1322,7 +1322,7 @@ static void stmmac_display_rx_rings(stru + } + + /* Display RX ring */ +- stmmac_display_ring(priv, head_rx, priv->dma_rx_size, true, ++ stmmac_display_ring(priv, head_rx, priv->dma_conf.dma_rx_size, true, + rx_q->dma_rx_phy, desc_size); + } + } +@@ -1336,7 +1336,7 @@ static void stmmac_display_tx_rings(stru + + /* Display TX rings */ + for (queue = 0; queue < tx_cnt; queue++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + pr_info("\tTX Queue %d rings\n", queue); + +@@ -1351,7 +1351,7 @@ static void stmmac_display_tx_rings(stru + desc_size = sizeof(struct dma_desc); + } + +- stmmac_display_ring(priv, head_tx, priv->dma_tx_size, false, ++ stmmac_display_ring(priv, head_tx, priv->dma_conf.dma_tx_size, false, + tx_q->dma_tx_phy, desc_size); + } + } +@@ -1392,21 +1392,21 @@ static int stmmac_set_bfsize(int mtu, in + */ + static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int i; + + /* Clear the RX descriptors */ +- for (i = 0; i < priv->dma_rx_size; i++) ++ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) + if (priv->extend_desc) + stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic, + priv->use_riwt, priv->mode, +- (i == priv->dma_rx_size - 1), +- priv->dma_buf_sz); ++ (i == priv->dma_conf.dma_rx_size - 1), ++ priv->dma_conf.dma_buf_sz); + else + stmmac_init_rx_desc(priv, &rx_q->dma_rx[i], + priv->use_riwt, priv->mode, +- (i == priv->dma_rx_size - 1), +- priv->dma_buf_sz); ++ (i == priv->dma_conf.dma_rx_size - 1), ++ priv->dma_conf.dma_buf_sz); + } + + /** +@@ -1418,12 +1418,12 @@ static void stmmac_clear_rx_descriptors( + */ + static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + int i; + + /* Clear the TX descriptors */ +- for (i = 0; i < priv->dma_tx_size; i++) { +- int last = (i == (priv->dma_tx_size - 1)); ++ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { ++ int last = (i == (priv->dma_conf.dma_tx_size - 1)); + struct dma_desc *p; + + if (priv->extend_desc) +@@ -1471,7 +1471,7 @@ static void stmmac_clear_descriptors(str + static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, + int i, gfp_t flags, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (!buf->page) { +@@ -1496,7 +1496,7 @@ static int stmmac_init_rx_buffers(struct + buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; + + stmmac_set_desc_addr(priv, p, buf->addr); +- if (priv->dma_buf_sz == BUF_SIZE_16KiB) ++ if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) + stmmac_init_desc3(priv, p); + + return 0; +@@ -1510,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct + */ + static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (buf->page) +@@ -1530,7 +1530,7 @@ static void stmmac_free_rx_buffer(struct + */ + static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + if (tx_q->tx_skbuff_dma[i].buf && + tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { +@@ -1575,17 +1575,17 @@ static void dma_free_rx_skbufs(struct st + { + int i; + +- for (i = 0; i < priv->dma_rx_size; i++) ++ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) + stmmac_free_rx_buffer(priv, queue, i); + } + + static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, u32 queue, + gfp_t flags) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_rx_size; i++) { ++ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { + struct dma_desc *p; + int ret; + +@@ -1612,10 +1612,10 @@ static int stmmac_alloc_rx_buffers(struc + */ + static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_rx_size; i++) { ++ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (!buf->xdp) +@@ -1628,10 +1628,10 @@ static void dma_free_rx_xskbufs(struct s + + static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_rx_size; i++) { ++ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { + struct stmmac_rx_buffer *buf; + dma_addr_t dma_addr; + struct dma_desc *p; +@@ -1674,7 +1674,7 @@ static struct xsk_buff_pool *stmmac_get_ + */ + static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int ret; + + netif_dbg(priv, probe, priv->dev, +@@ -1720,11 +1720,11 @@ static int __init_dma_rx_desc_rings(stru + if (priv->extend_desc) + stmmac_mode_init(priv, rx_q->dma_erx, + rx_q->dma_rx_phy, +- priv->dma_rx_size, 1); ++ priv->dma_conf.dma_rx_size, 1); + else + stmmac_mode_init(priv, rx_q->dma_rx, + rx_q->dma_rx_phy, +- priv->dma_rx_size, 0); ++ priv->dma_conf.dma_rx_size, 0); + } + + return 0; +@@ -1751,7 +1751,7 @@ static int init_dma_rx_desc_rings(struct + + err_init_rx_buffers: + while (queue >= 0) { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + + if (rx_q->xsk_pool) + dma_free_rx_xskbufs(priv, queue); +@@ -1780,7 +1780,7 @@ err_init_rx_buffers: + */ + static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + int i; + + netif_dbg(priv, probe, priv->dev, +@@ -1792,16 +1792,16 @@ static int __init_dma_tx_desc_rings(stru + if (priv->extend_desc) + stmmac_mode_init(priv, tx_q->dma_etx, + tx_q->dma_tx_phy, +- priv->dma_tx_size, 1); ++ priv->dma_conf.dma_tx_size, 1); + else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) + stmmac_mode_init(priv, tx_q->dma_tx, + tx_q->dma_tx_phy, +- priv->dma_tx_size, 0); ++ priv->dma_conf.dma_tx_size, 0); + } + + tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue); + +- for (i = 0; i < priv->dma_tx_size; i++) { ++ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { + struct dma_desc *p; + + if (priv->extend_desc) +@@ -1871,12 +1871,12 @@ static int init_dma_desc_rings(struct ne + */ + static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + int i; + + tx_q->xsk_frames_done = 0; + +- for (i = 0; i < priv->dma_tx_size; i++) ++ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) + stmmac_free_tx_buffer(priv, queue, i); + + if (tx_q->xsk_pool && tx_q->xsk_frames_done) { +@@ -1906,7 +1906,7 @@ static void stmmac_free_tx_skbufs(struct + */ + static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + + /* Release the DMA RX socket buffers */ + if (rx_q->xsk_pool) +@@ -1919,11 +1919,11 @@ static void __free_dma_rx_desc_resources + + /* Free DMA regions of consistent memory previously allocated */ + if (!priv->extend_desc) +- dma_free_coherent(priv->device, priv->dma_rx_size * ++ dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * + sizeof(struct dma_desc), + rx_q->dma_rx, rx_q->dma_rx_phy); + else +- dma_free_coherent(priv->device, priv->dma_rx_size * ++ dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * + sizeof(struct dma_extended_desc), + rx_q->dma_erx, rx_q->dma_rx_phy); + +@@ -1952,7 +1952,7 @@ static void free_dma_rx_desc_resources(s + */ + static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + size_t size; + void *addr; + +@@ -1970,7 +1970,7 @@ static void __free_dma_tx_desc_resources + addr = tx_q->dma_tx; + } + +- size *= priv->dma_tx_size; ++ size *= priv->dma_conf.dma_tx_size; + + dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); + +@@ -1999,7 +1999,7 @@ static void free_dma_tx_desc_resources(s + */ + static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_channel *ch = &priv->channel[queue]; + bool xdp_prog = stmmac_xdp_is_enabled(priv); + struct page_pool_params pp_params = { 0 }; +@@ -2011,8 +2011,8 @@ static int __alloc_dma_rx_desc_resources + rx_q->priv_data = priv; + + pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; +- pp_params.pool_size = priv->dma_rx_size; +- num_pages = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE); ++ pp_params.pool_size = priv->dma_conf.dma_rx_size; ++ num_pages = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE); + pp_params.order = ilog2(num_pages); + pp_params.nid = dev_to_node(priv->device); + pp_params.dev = priv->device; +@@ -2027,7 +2027,7 @@ static int __alloc_dma_rx_desc_resources + return ret; + } + +- rx_q->buf_pool = kcalloc(priv->dma_rx_size, ++ rx_q->buf_pool = kcalloc(priv->dma_conf.dma_rx_size, + sizeof(*rx_q->buf_pool), + GFP_KERNEL); + if (!rx_q->buf_pool) +@@ -2035,7 +2035,7 @@ static int __alloc_dma_rx_desc_resources + + if (priv->extend_desc) { + rx_q->dma_erx = dma_alloc_coherent(priv->device, +- priv->dma_rx_size * ++ priv->dma_conf.dma_rx_size * + sizeof(struct dma_extended_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); +@@ -2044,7 +2044,7 @@ static int __alloc_dma_rx_desc_resources + + } else { + rx_q->dma_rx = dma_alloc_coherent(priv->device, +- priv->dma_rx_size * ++ priv->dma_conf.dma_rx_size * + sizeof(struct dma_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); +@@ -2101,20 +2101,20 @@ err_dma: + */ + static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + size_t size; + void *addr; + + tx_q->queue_index = queue; + tx_q->priv_data = priv; + +- tx_q->tx_skbuff_dma = kcalloc(priv->dma_tx_size, ++ tx_q->tx_skbuff_dma = kcalloc(priv->dma_conf.dma_tx_size, + sizeof(*tx_q->tx_skbuff_dma), + GFP_KERNEL); + if (!tx_q->tx_skbuff_dma) + return -ENOMEM; + +- tx_q->tx_skbuff = kcalloc(priv->dma_tx_size, ++ tx_q->tx_skbuff = kcalloc(priv->dma_conf.dma_tx_size, + sizeof(struct sk_buff *), + GFP_KERNEL); + if (!tx_q->tx_skbuff) +@@ -2127,7 +2127,7 @@ static int __alloc_dma_tx_desc_resources + else + size = sizeof(struct dma_desc); + +- size *= priv->dma_tx_size; ++ size *= priv->dma_conf.dma_tx_size; + + addr = dma_alloc_coherent(priv->device, size, + &tx_q->dma_tx_phy, GFP_KERNEL); +@@ -2371,7 +2371,7 @@ static void stmmac_dma_operation_mode(st + + /* configure all channels */ + for (chan = 0; chan < rx_channels_count; chan++) { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; + u32 buf_size; + + qmode = priv->plat->rx_queues_cfg[chan].mode_to_use; +@@ -2386,7 +2386,7 @@ static void stmmac_dma_operation_mode(st + chan); + } else { + stmmac_set_dma_bfsize(priv, priv->ioaddr, +- priv->dma_buf_sz, ++ priv->dma_conf.dma_buf_sz, + chan); + } + } +@@ -2402,7 +2402,7 @@ static void stmmac_dma_operation_mode(st + static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + { + struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct xsk_buff_pool *pool = tx_q->xsk_pool; + unsigned int entry = tx_q->cur_tx; + struct dma_desc *tx_desc = NULL; +@@ -2477,7 +2477,7 @@ static bool stmmac_xdp_xmit_zc(struct st + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); ++ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + entry = tx_q->cur_tx; + } + +@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct st + */ + static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + unsigned int bytes_compl = 0, pkts_compl = 0; + unsigned int entry, xmits = 0, count = 0; + +@@ -2516,7 +2516,7 @@ static int stmmac_tx_clean(struct stmmac + entry = tx_q->dirty_tx; + + /* Try to clean all TX complete frame in 1 shot */ +- while ((entry != tx_q->cur_tx) && count < priv->dma_tx_size) { ++ while ((entry != tx_q->cur_tx) && count < priv->dma_conf.dma_tx_size) { + struct xdp_frame *xdpf; + struct sk_buff *skb; + struct dma_desc *p; +@@ -2616,7 +2616,7 @@ static int stmmac_tx_clean(struct stmmac + + stmmac_release_tx_desc(priv, p, priv->mode); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + } + tx_q->dirty_tx = entry; + +@@ -2681,7 +2681,7 @@ static int stmmac_tx_clean(struct stmmac + */ + static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + + netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); + +@@ -2748,8 +2748,8 @@ static int stmmac_napi_check(struct stmm + { + int status = stmmac_dma_interrupt_status(priv, priv->ioaddr, + &priv->xstats, chan, dir); +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan]; +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + struct stmmac_channel *ch = &priv->channel[chan]; + struct napi_struct *rx_napi; + struct napi_struct *tx_napi; +@@ -2925,7 +2925,7 @@ static int stmmac_init_dma_engine(struct + + /* DMA RX Channel Configuration */ + for (chan = 0; chan < rx_channels_count; chan++) { +- rx_q = &priv->rx_queue[chan]; ++ rx_q = &priv->dma_conf.rx_queue[chan]; + + stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + rx_q->dma_rx_phy, chan); +@@ -2939,7 +2939,7 @@ static int stmmac_init_dma_engine(struct + + /* DMA TX Channel Configuration */ + for (chan = 0; chan < tx_channels_count; chan++) { +- tx_q = &priv->tx_queue[chan]; ++ tx_q = &priv->dma_conf.tx_queue[chan]; + + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + tx_q->dma_tx_phy, chan); +@@ -2954,7 +2954,7 @@ static int stmmac_init_dma_engine(struct + + static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + hrtimer_start(&tx_q->txtimer, + STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), +@@ -3004,7 +3004,7 @@ static void stmmac_init_coalesce(struct + u32 chan; + + for (chan = 0; chan < tx_channel_count; chan++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + + priv->tx_coal_frames[chan] = STMMAC_TX_FRAMES; + priv->tx_coal_timer[chan] = STMMAC_COAL_TX_TIMER; +@@ -3026,12 +3026,12 @@ static void stmmac_set_rings_length(stru + /* set TX ring length */ + for (chan = 0; chan < tx_channels_count; chan++) + stmmac_set_tx_ring_len(priv, priv->ioaddr, +- (priv->dma_tx_size - 1), chan); ++ (priv->dma_conf.dma_tx_size - 1), chan); + + /* set RX ring length */ + for (chan = 0; chan < rx_channels_count; chan++) + stmmac_set_rx_ring_len(priv, priv->ioaddr, +- (priv->dma_rx_size - 1), chan); ++ (priv->dma_conf.dma_rx_size - 1), chan); + } + + /** +@@ -3366,7 +3366,7 @@ static int stmmac_hw_setup(struct net_de + /* Enable TSO */ + if (priv->tso) { + for (chan = 0; chan < tx_cnt; chan++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + + /* TSO and TBS cannot co-exist */ + if (tx_q->tbs & STMMAC_TBS_AVAIL) +@@ -3388,7 +3388,7 @@ static int stmmac_hw_setup(struct net_de + + /* TBS */ + for (chan = 0; chan < tx_cnt; chan++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + int enable = tx_q->tbs & STMMAC_TBS_AVAIL; + + stmmac_enable_tbs(priv, priv->ioaddr, enable, chan); +@@ -3432,7 +3432,7 @@ static void stmmac_free_irq(struct net_d + for (j = irq_idx - 1; j >= 0; j--) { + if (priv->tx_irq[j] > 0) { + irq_set_affinity_hint(priv->tx_irq[j], NULL); +- free_irq(priv->tx_irq[j], &priv->tx_queue[j]); ++ free_irq(priv->tx_irq[j], &priv->dma_conf.tx_queue[j]); + } + } + irq_idx = priv->plat->rx_queues_to_use; +@@ -3441,7 +3441,7 @@ static void stmmac_free_irq(struct net_d + for (j = irq_idx - 1; j >= 0; j--) { + if (priv->rx_irq[j] > 0) { + irq_set_affinity_hint(priv->rx_irq[j], NULL); +- free_irq(priv->rx_irq[j], &priv->rx_queue[j]); ++ free_irq(priv->rx_irq[j], &priv->dma_conf.rx_queue[j]); + } + } + +@@ -3574,7 +3574,7 @@ static int stmmac_request_irq_multi_msi( + sprintf(int_name, "%s:%s-%d", dev->name, "rx", i); + ret = request_irq(priv->rx_irq[i], + stmmac_msi_intr_rx, +- 0, int_name, &priv->rx_queue[i]); ++ 0, int_name, &priv->dma_conf.rx_queue[i]); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: alloc rx-%d MSI %d (error: %d)\n", +@@ -3597,7 +3597,7 @@ static int stmmac_request_irq_multi_msi( + sprintf(int_name, "%s:%s-%d", dev->name, "tx", i); + ret = request_irq(priv->tx_irq[i], + stmmac_msi_intr_tx, +- 0, int_name, &priv->tx_queue[i]); ++ 0, int_name, &priv->dma_conf.tx_queue[i]); + if (unlikely(ret < 0)) { + netdev_err(priv->dev, + "%s: alloc tx-%d MSI %d (error: %d)\n", +@@ -3728,21 +3728,21 @@ static int stmmac_open(struct net_device + bfsize = 0; + + if (bfsize < BUF_SIZE_16KiB) +- bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); ++ bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_conf.dma_buf_sz); + +- priv->dma_buf_sz = bfsize; ++ priv->dma_conf.dma_buf_sz = bfsize; + buf_sz = bfsize; + + priv->rx_copybreak = STMMAC_RX_COPYBREAK; + +- if (!priv->dma_tx_size) +- priv->dma_tx_size = DMA_DEFAULT_TX_SIZE; +- if (!priv->dma_rx_size) +- priv->dma_rx_size = DMA_DEFAULT_RX_SIZE; ++ if (!priv->dma_conf.dma_tx_size) ++ priv->dma_conf.dma_tx_size = DMA_DEFAULT_TX_SIZE; ++ if (!priv->dma_conf.dma_rx_size) ++ priv->dma_conf.dma_rx_size = DMA_DEFAULT_RX_SIZE; + + /* Earlier check for TBS */ + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; + + /* Setup per-TXQ tbs flag before TX descriptor alloc */ +@@ -3800,7 +3800,7 @@ irq_error: + phylink_stop(priv->phylink); + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) +- hrtimer_cancel(&priv->tx_queue[chan].txtimer); ++ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + stmmac_hw_teardown(dev); + init_error: +@@ -3842,7 +3842,7 @@ static int stmmac_release(struct net_dev + stmmac_disable_all_queues(priv); + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) +- hrtimer_cancel(&priv->tx_queue[chan].txtimer); ++ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + netif_tx_disable(dev); + +@@ -3906,7 +3906,7 @@ static bool stmmac_vlan_insert(struct st + return false; + + stmmac_set_tx_owner(priv, p); +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); ++ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + return true; + } + +@@ -3924,7 +3924,7 @@ static bool stmmac_vlan_insert(struct st + static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des, + int total_len, bool last_segment, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct dma_desc *desc; + u32 buff_size; + int tmp_len; +@@ -3935,7 +3935,7 @@ static void stmmac_tso_allocator(struct + dma_addr_t curr_addr; + + tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, +- priv->dma_tx_size); ++ priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + + if (tx_q->tbs & STMMAC_TBS_AVAIL) +@@ -3963,7 +3963,7 @@ static void stmmac_tso_allocator(struct + + static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + int desc_size; + + if (likely(priv->extend_desc)) +@@ -4025,7 +4025,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + dma_addr_t des; + int i; + +- tx_q = &priv->tx_queue[queue]; ++ tx_q = &priv->dma_conf.tx_queue[queue]; + first_tx = tx_q->cur_tx; + + /* Compute header lengths */ +@@ -4065,7 +4065,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + stmmac_set_mss(priv, mss_desc, mss); + tx_q->mss = mss; + tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, +- priv->dma_tx_size); ++ priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); + } + +@@ -4177,7 +4177,7 @@ static netdev_tx_t stmmac_tso_xmit(struc + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); ++ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); + + if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) { + netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n", +@@ -4265,7 +4265,7 @@ static netdev_tx_t stmmac_xmit(struct sk + int entry, first_tx; + dma_addr_t des; + +- tx_q = &priv->tx_queue[queue]; ++ tx_q = &priv->dma_conf.tx_queue[queue]; + first_tx = tx_q->cur_tx; + + if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) +@@ -4328,7 +4328,7 @@ static netdev_tx_t stmmac_xmit(struct sk + int len = skb_frag_size(frag); + bool last_segment = (i == (nfrags - 1)); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + WARN_ON(tx_q->tx_skbuff[entry]); + + if (likely(priv->extend_desc)) +@@ -4399,7 +4399,7 @@ static netdev_tx_t stmmac_xmit(struct sk + * ndo_start_xmit will fill this descriptor the next time it's + * called and stmmac_tx_clean may clean up to this descriptor. + */ +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + if (netif_msg_pktdata(priv)) { +@@ -4514,7 +4514,7 @@ static void stmmac_rx_vlan(struct net_de + */ + static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + int dirty = stmmac_rx_dirty(priv, queue); + unsigned int entry = rx_q->dirty_rx; + +@@ -4564,7 +4564,7 @@ static inline void stmmac_rx_refill(stru + dma_wmb(); + stmmac_set_rx_owner(priv, p, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_rx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + rx_q->dirty_rx = entry; + rx_q->rx_tail_addr = rx_q->dma_rx_phy + +@@ -4592,12 +4592,12 @@ static unsigned int stmmac_rx_buf1_len(s + + /* First descriptor, not last descriptor and not split header */ + if (status & rx_not_ls) +- return priv->dma_buf_sz; ++ return priv->dma_conf.dma_buf_sz; + + plen = stmmac_get_rx_frame_len(priv, p, coe); + + /* First descriptor and last descriptor and not split header */ +- return min_t(unsigned int, priv->dma_buf_sz, plen); ++ return min_t(unsigned int, priv->dma_conf.dma_buf_sz, plen); + } + + static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, +@@ -4613,7 +4613,7 @@ static unsigned int stmmac_rx_buf2_len(s + + /* Not last descriptor */ + if (status & rx_not_ls) +- return priv->dma_buf_sz; ++ return priv->dma_conf.dma_buf_sz; + + plen = stmmac_get_rx_frame_len(priv, p, coe); + +@@ -4624,7 +4624,7 @@ static unsigned int stmmac_rx_buf2_len(s + static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, + struct xdp_frame *xdpf, bool dma_map) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + unsigned int entry = tx_q->cur_tx; + struct dma_desc *tx_desc; + dma_addr_t dma_addr; +@@ -4687,7 +4687,7 @@ static int stmmac_xdp_xmit_xdpf(struct s + + stmmac_enable_dma_transmission(priv, priv->ioaddr); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); + tx_q->cur_tx = entry; + + return STMMAC_XDP_TX; +@@ -4861,7 +4861,7 @@ static void stmmac_dispatch_skb_zc(struc + + static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + unsigned int entry = rx_q->dirty_rx; + struct dma_desc *rx_desc = NULL; + bool ret = true; +@@ -4904,7 +4904,7 @@ static bool stmmac_rx_refill_zc(struct s + dma_wmb(); + stmmac_set_rx_owner(priv, rx_desc, use_rx_wd); + +- entry = STMMAC_GET_ENTRY(entry, priv->dma_rx_size); ++ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); + } + + if (rx_desc) { +@@ -4919,7 +4919,7 @@ static bool stmmac_rx_refill_zc(struct s + + static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + unsigned int count = 0, error = 0, len = 0; + int dirty = stmmac_rx_dirty(priv, queue); + unsigned int next_entry = rx_q->cur_rx; +@@ -4941,7 +4941,7 @@ static int stmmac_rx_zc(struct stmmac_pr + desc_size = sizeof(struct dma_desc); + } + +- stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true, ++ stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true, + rx_q->dma_rx_phy, desc_size); + } + while (count < limit) { +@@ -4988,7 +4988,7 @@ read_again: + + /* Prefetch the next RX descriptor */ + rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, +- priv->dma_rx_size); ++ priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + + if (priv->extend_desc) +@@ -5109,7 +5109,7 @@ read_again: + */ + static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_channel *ch = &priv->channel[queue]; + unsigned int count = 0, error = 0, len = 0; + int status = 0, coe = priv->hw->rx_csum; +@@ -5122,7 +5122,7 @@ static int stmmac_rx(struct stmmac_priv + int buf_sz; + + dma_dir = page_pool_get_dma_dir(rx_q->page_pool); +- buf_sz = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; ++ buf_sz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; + + if (netif_msg_rx_status(priv)) { + void *rx_head; +@@ -5136,7 +5136,7 @@ static int stmmac_rx(struct stmmac_priv + desc_size = sizeof(struct dma_desc); + } + +- stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true, ++ stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true, + rx_q->dma_rx_phy, desc_size); + } + while (count < limit) { +@@ -5180,7 +5180,7 @@ read_again: + break; + + rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, +- priv->dma_rx_size); ++ priv->dma_conf.dma_rx_size); + next_entry = rx_q->cur_rx; + + if (priv->extend_desc) +@@ -5314,7 +5314,7 @@ read_again: + buf1_len, dma_dir); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + buf->page, buf->page_offset, buf1_len, +- priv->dma_buf_sz); ++ priv->dma_conf.dma_buf_sz); + + /* Data payload appended into SKB */ + page_pool_release_page(rx_q->page_pool, buf->page); +@@ -5326,7 +5326,7 @@ read_again: + buf2_len, dma_dir); + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + buf->sec_page, 0, buf2_len, +- priv->dma_buf_sz); ++ priv->dma_conf.dma_buf_sz); + + /* Data payload appended into SKB */ + page_pool_release_page(rx_q->page_pool, buf->sec_page); +@@ -5768,11 +5768,13 @@ static irqreturn_t stmmac_safety_interru + static irqreturn_t stmmac_msi_intr_tx(int irq, void *data) + { + struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)data; ++ struct stmmac_dma_conf *dma_conf; + int chan = tx_q->queue_index; + struct stmmac_priv *priv; + int status; + +- priv = container_of(tx_q, struct stmmac_priv, tx_queue[chan]); ++ dma_conf = container_of(tx_q, struct stmmac_dma_conf, tx_queue[chan]); ++ priv = container_of(dma_conf, struct stmmac_priv, dma_conf); + + if (unlikely(!data)) { + netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); +@@ -5812,10 +5814,12 @@ static irqreturn_t stmmac_msi_intr_tx(in + static irqreturn_t stmmac_msi_intr_rx(int irq, void *data) + { + struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)data; ++ struct stmmac_dma_conf *dma_conf; + int chan = rx_q->queue_index; + struct stmmac_priv *priv; + +- priv = container_of(rx_q, struct stmmac_priv, rx_queue[chan]); ++ dma_conf = container_of(rx_q, struct stmmac_dma_conf, rx_queue[chan]); ++ priv = container_of(dma_conf, struct stmmac_priv, dma_conf); + + if (unlikely(!data)) { + netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); +@@ -5846,10 +5850,10 @@ static void stmmac_poll_controller(struc + + if (priv->plat->multi_msi_en) { + for (i = 0; i < priv->plat->rx_queues_to_use; i++) +- stmmac_msi_intr_rx(0, &priv->rx_queue[i]); ++ stmmac_msi_intr_rx(0, &priv->dma_conf.rx_queue[i]); + + for (i = 0; i < priv->plat->tx_queues_to_use; i++) +- stmmac_msi_intr_tx(0, &priv->tx_queue[i]); ++ stmmac_msi_intr_tx(0, &priv->dma_conf.tx_queue[i]); + } else { + disable_irq(dev->irq); + stmmac_interrupt(dev->irq, dev); +@@ -6030,34 +6034,34 @@ static int stmmac_rings_status_show(stru + return 0; + + for (queue = 0; queue < rx_count; queue++) { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + + seq_printf(seq, "RX Queue %d:\n", queue); + + if (priv->extend_desc) { + seq_printf(seq, "Extended descriptor ring:\n"); + sysfs_display_ring((void *)rx_q->dma_erx, +- priv->dma_rx_size, 1, seq, rx_q->dma_rx_phy); ++ priv->dma_conf.dma_rx_size, 1, seq, rx_q->dma_rx_phy); + } else { + seq_printf(seq, "Descriptor ring:\n"); + sysfs_display_ring((void *)rx_q->dma_rx, +- priv->dma_rx_size, 0, seq, rx_q->dma_rx_phy); ++ priv->dma_conf.dma_rx_size, 0, seq, rx_q->dma_rx_phy); + } + } + + for (queue = 0; queue < tx_count; queue++) { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + seq_printf(seq, "TX Queue %d:\n", queue); + + if (priv->extend_desc) { + seq_printf(seq, "Extended descriptor ring:\n"); + sysfs_display_ring((void *)tx_q->dma_etx, +- priv->dma_tx_size, 1, seq, tx_q->dma_tx_phy); ++ priv->dma_conf.dma_tx_size, 1, seq, tx_q->dma_tx_phy); + } else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) { + seq_printf(seq, "Descriptor ring:\n"); + sysfs_display_ring((void *)tx_q->dma_tx, +- priv->dma_tx_size, 0, seq, tx_q->dma_tx_phy); ++ priv->dma_conf.dma_tx_size, 0, seq, tx_q->dma_tx_phy); + } + } + +@@ -6404,7 +6408,7 @@ void stmmac_disable_rx_queue(struct stmm + + void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_channel *ch = &priv->channel[queue]; + unsigned long flags; + u32 buf_size; +@@ -6441,7 +6445,7 @@ void stmmac_enable_rx_queue(struct stmma + rx_q->queue_index); + } else { + stmmac_set_dma_bfsize(priv, priv->ioaddr, +- priv->dma_buf_sz, ++ priv->dma_conf.dma_buf_sz, + rx_q->queue_index); + } + +@@ -6467,7 +6471,7 @@ void stmmac_disable_tx_queue(struct stmm + + void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct stmmac_channel *ch = &priv->channel[queue]; + unsigned long flags; + int ret; +@@ -6517,7 +6521,7 @@ void stmmac_xdp_release(struct net_devic + stmmac_disable_all_queues(priv); + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) +- hrtimer_cancel(&priv->tx_queue[chan].txtimer); ++ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + /* Free the IRQ lines */ + stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); +@@ -6576,7 +6580,7 @@ int stmmac_xdp_open(struct net_device *d + + /* DMA RX Channel Configuration */ + for (chan = 0; chan < rx_cnt; chan++) { +- rx_q = &priv->rx_queue[chan]; ++ rx_q = &priv->dma_conf.rx_queue[chan]; + + stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + rx_q->dma_rx_phy, chan); +@@ -6594,7 +6598,7 @@ int stmmac_xdp_open(struct net_device *d + rx_q->queue_index); + } else { + stmmac_set_dma_bfsize(priv, priv->ioaddr, +- priv->dma_buf_sz, ++ priv->dma_conf.dma_buf_sz, + rx_q->queue_index); + } + +@@ -6603,7 +6607,7 @@ int stmmac_xdp_open(struct net_device *d + + /* DMA TX Channel Configuration */ + for (chan = 0; chan < tx_cnt; chan++) { +- tx_q = &priv->tx_queue[chan]; ++ tx_q = &priv->dma_conf.tx_queue[chan]; + + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + tx_q->dma_tx_phy, chan); +@@ -6636,7 +6640,7 @@ int stmmac_xdp_open(struct net_device *d + + irq_error: + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) +- hrtimer_cancel(&priv->tx_queue[chan].txtimer); ++ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + stmmac_hw_teardown(dev); + init_error: +@@ -6663,8 +6667,8 @@ int stmmac_xsk_wakeup(struct net_device + queue >= priv->plat->tx_queues_to_use) + return -EINVAL; + +- rx_q = &priv->rx_queue[queue]; +- tx_q = &priv->tx_queue[queue]; ++ rx_q = &priv->dma_conf.rx_queue[queue]; ++ tx_q = &priv->dma_conf.tx_queue[queue]; + ch = &priv->channel[queue]; + + if (!rx_q->xsk_pool && !tx_q->xsk_pool) +@@ -6924,8 +6928,8 @@ int stmmac_reinit_ringparam(struct net_d + if (netif_running(dev)) + stmmac_release(dev); + +- priv->dma_rx_size = rx_size; +- priv->dma_tx_size = tx_size; ++ priv->dma_conf.dma_rx_size = rx_size; ++ priv->dma_conf.dma_tx_size = tx_size; + + if (netif_running(dev)) + ret = stmmac_open(dev); +@@ -7363,7 +7367,7 @@ int stmmac_suspend(struct device *dev) + stmmac_disable_all_queues(priv); + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) +- hrtimer_cancel(&priv->tx_queue[chan].txtimer); ++ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + if (priv->eee_enabled) { + priv->tx_path_in_lpi_mode = false; +@@ -7414,7 +7418,7 @@ EXPORT_SYMBOL_GPL(stmmac_suspend); + + static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + + rx_q->cur_rx = 0; + rx_q->dirty_rx = 0; +@@ -7422,7 +7426,7 @@ static void stmmac_reset_rx_queue(struct + + static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + + tx_q->cur_tx = 0; + tx_q->dirty_tx = 0; +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +@@ -795,8 +795,8 @@ static int stmmac_test_flowctrl(struct s + struct stmmac_channel *ch = &priv->channel[i]; + u32 tail; + +- tail = priv->rx_queue[i].dma_rx_phy + +- (priv->dma_rx_size * sizeof(struct dma_desc)); ++ tail = priv->dma_conf.rx_queue[i].dma_rx_phy + ++ (priv->dma_conf.dma_rx_size * sizeof(struct dma_desc)); + + stmmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i); + stmmac_start_rx(priv, priv->ioaddr, i); +@@ -1684,7 +1684,7 @@ cleanup: + static int __stmmac_test_jumbo(struct stmmac_priv *priv, u16 queue) + { + struct stmmac_packet_attrs attr = { }; +- int size = priv->dma_buf_sz; ++ int size = priv->dma_conf.dma_buf_sz; + + attr.dst = priv->dev->dev_addr; + attr.max_size = size - ETH_FCS_LEN; +@@ -1767,7 +1767,7 @@ static int stmmac_test_tbs(struct stmmac + + /* Find first TBS enabled Queue, if any */ + for (i = 0; i < priv->plat->tx_queues_to_use; i++) +- if (priv->tx_queue[i].tbs & STMMAC_TBS_AVAIL) ++ if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_AVAIL) + break; + + if (i >= priv->plat->tx_queues_to_use) +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +@@ -970,13 +970,13 @@ static int tc_setup_etf(struct stmmac_pr + return -EOPNOTSUPP; + if (qopt->queue >= priv->plat->tx_queues_to_use) + return -EINVAL; +- if (!(priv->tx_queue[qopt->queue].tbs & STMMAC_TBS_AVAIL)) ++ if (!(priv->dma_conf.tx_queue[qopt->queue].tbs & STMMAC_TBS_AVAIL)) + return -EINVAL; + + if (qopt->enable) +- priv->tx_queue[qopt->queue].tbs |= STMMAC_TBS_EN; ++ priv->dma_conf.tx_queue[qopt->queue].tbs |= STMMAC_TBS_EN; + else +- priv->tx_queue[qopt->queue].tbs &= ~STMMAC_TBS_EN; ++ priv->dma_conf.tx_queue[qopt->queue].tbs &= ~STMMAC_TBS_EN; + + netdev_info(priv->dev, "%s ETF for Queue %d\n", + qopt->enable ? "enabled" : "disabled", qopt->queue); diff --git a/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch b/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch new file mode 100644 index 00000000000..e84373b4718 --- /dev/null +++ b/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch @@ -0,0 +1,1161 @@ +From ba39b344e9240a4a5fd4ab8178200b85cd1809da Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 23 Jul 2022 16:29:32 +0200 +Subject: [PATCH 4/5] net: ethernet: stmicro: stmmac: generate stmmac dma conf + before open + +Rework the driver to generate the stmmac dma_conf before stmmac_open. +This permits a function to first check if it's possible to allocate a +new dma_config and then pass it directly to __stmmac_open and "open" the +interface with the new configuration. + +Signed-off-by: Christian Marangi +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 462 +++++++++++------- + 1 file changed, 289 insertions(+), 173 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -1300,7 +1300,8 @@ static int stmmac_phy_setup(struct stmma + return 0; + } + +-static void stmmac_display_rx_rings(struct stmmac_priv *priv) ++static void stmmac_display_rx_rings(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 rx_cnt = priv->plat->rx_queues_to_use; + unsigned int desc_size; +@@ -1309,7 +1310,7 @@ static void stmmac_display_rx_rings(stru + + /* Display RX rings */ + for (queue = 0; queue < rx_cnt; queue++) { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + + pr_info("\tRX Queue %u rings\n", queue); + +@@ -1322,12 +1323,13 @@ static void stmmac_display_rx_rings(stru + } + + /* Display RX ring */ +- stmmac_display_ring(priv, head_rx, priv->dma_conf.dma_rx_size, true, ++ stmmac_display_ring(priv, head_rx, dma_conf->dma_rx_size, true, + rx_q->dma_rx_phy, desc_size); + } + } + +-static void stmmac_display_tx_rings(struct stmmac_priv *priv) ++static void stmmac_display_tx_rings(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 tx_cnt = priv->plat->tx_queues_to_use; + unsigned int desc_size; +@@ -1336,7 +1338,7 @@ static void stmmac_display_tx_rings(stru + + /* Display TX rings */ + for (queue = 0; queue < tx_cnt; queue++) { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + + pr_info("\tTX Queue %d rings\n", queue); + +@@ -1351,18 +1353,19 @@ static void stmmac_display_tx_rings(stru + desc_size = sizeof(struct dma_desc); + } + +- stmmac_display_ring(priv, head_tx, priv->dma_conf.dma_tx_size, false, ++ stmmac_display_ring(priv, head_tx, dma_conf->dma_tx_size, false, + tx_q->dma_tx_phy, desc_size); + } + } + +-static void stmmac_display_rings(struct stmmac_priv *priv) ++static void stmmac_display_rings(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + /* Display RX ring */ +- stmmac_display_rx_rings(priv); ++ stmmac_display_rx_rings(priv, dma_conf); + + /* Display TX ring */ +- stmmac_display_tx_rings(priv); ++ stmmac_display_tx_rings(priv, dma_conf); + } + + static int stmmac_set_bfsize(int mtu, int bufsize) +@@ -1386,44 +1389,50 @@ static int stmmac_set_bfsize(int mtu, in + /** + * stmmac_clear_rx_descriptors - clear RX descriptors + * @priv: driver private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + * Description: this function is called to clear the RX descriptors + * in case of both basic and extended descriptors are used. + */ +-static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue) ++static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int i; + + /* Clear the RX descriptors */ +- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) ++ for (i = 0; i < dma_conf->dma_rx_size; i++) + if (priv->extend_desc) + stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic, + priv->use_riwt, priv->mode, +- (i == priv->dma_conf.dma_rx_size - 1), +- priv->dma_conf.dma_buf_sz); ++ (i == dma_conf->dma_rx_size - 1), ++ dma_conf->dma_buf_sz); + else + stmmac_init_rx_desc(priv, &rx_q->dma_rx[i], + priv->use_riwt, priv->mode, +- (i == priv->dma_conf.dma_rx_size - 1), +- priv->dma_conf.dma_buf_sz); ++ (i == dma_conf->dma_rx_size - 1), ++ dma_conf->dma_buf_sz); + } + + /** + * stmmac_clear_tx_descriptors - clear tx descriptors + * @priv: driver private structure ++ * @dma_conf: structure to take the dma data + * @queue: TX queue index. + * Description: this function is called to clear the TX descriptors + * in case of both basic and extended descriptors are used. + */ +-static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, u32 queue) ++static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + int i; + + /* Clear the TX descriptors */ +- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { +- int last = (i == (priv->dma_conf.dma_tx_size - 1)); ++ for (i = 0; i < dma_conf->dma_tx_size; i++) { ++ int last = (i == (dma_conf->dma_tx_size - 1)); + struct dma_desc *p; + + if (priv->extend_desc) +@@ -1440,10 +1449,12 @@ static void stmmac_clear_tx_descriptors( + /** + * stmmac_clear_descriptors - clear descriptors + * @priv: driver private structure ++ * @dma_conf: structure to take the dma data + * Description: this function is called to clear the TX and RX descriptors + * in case of both basic and extended descriptors are used. + */ +-static void stmmac_clear_descriptors(struct stmmac_priv *priv) ++static void stmmac_clear_descriptors(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 rx_queue_cnt = priv->plat->rx_queues_to_use; + u32 tx_queue_cnt = priv->plat->tx_queues_to_use; +@@ -1451,16 +1462,17 @@ static void stmmac_clear_descriptors(str + + /* Clear the RX descriptors */ + for (queue = 0; queue < rx_queue_cnt; queue++) +- stmmac_clear_rx_descriptors(priv, queue); ++ stmmac_clear_rx_descriptors(priv, dma_conf, queue); + + /* Clear the TX descriptors */ + for (queue = 0; queue < tx_queue_cnt; queue++) +- stmmac_clear_tx_descriptors(priv, queue); ++ stmmac_clear_tx_descriptors(priv, dma_conf, queue); + } + + /** + * stmmac_init_rx_buffers - init the RX descriptor buffer. + * @priv: driver private structure ++ * @dma_conf: structure to take the dma data + * @p: descriptor pointer + * @i: descriptor index + * @flags: gfp flag +@@ -1468,10 +1480,12 @@ static void stmmac_clear_descriptors(str + * Description: this function is called to allocate a receive buffer, perform + * the DMA mapping and init the descriptor. + */ +-static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, ++static int stmmac_init_rx_buffers(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ struct dma_desc *p, + int i, gfp_t flags, u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (!buf->page) { +@@ -1496,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct + buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; + + stmmac_set_desc_addr(priv, p, buf->addr); +- if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) ++ if (dma_conf->dma_buf_sz == BUF_SIZE_16KiB) + stmmac_init_desc3(priv, p); + + return 0; +@@ -1505,12 +1519,13 @@ static int stmmac_init_rx_buffers(struct + /** + * stmmac_free_rx_buffer - free RX dma buffers + * @priv: private structure +- * @queue: RX queue index ++ * @rx_q: RX queue + * @i: buffer index. + */ +-static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) ++static void stmmac_free_rx_buffer(struct stmmac_priv *priv, ++ struct stmmac_rx_queue *rx_q, ++ int i) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (buf->page) +@@ -1525,12 +1540,15 @@ static void stmmac_free_rx_buffer(struct + /** + * stmmac_free_tx_buffer - free RX dma buffers + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + * @i: buffer index. + */ +-static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i) ++static void stmmac_free_tx_buffer(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue, int i) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + + if (tx_q->tx_skbuff_dma[i].buf && + tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { +@@ -1569,23 +1587,28 @@ static void stmmac_free_tx_buffer(struct + /** + * dma_free_rx_skbufs - free RX dma buffers + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + */ +-static void dma_free_rx_skbufs(struct stmmac_priv *priv, u32 queue) ++static void dma_free_rx_skbufs(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) +- stmmac_free_rx_buffer(priv, queue, i); ++ for (i = 0; i < dma_conf->dma_rx_size; i++) ++ stmmac_free_rx_buffer(priv, rx_q, i); + } + +-static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, u32 queue, +- gfp_t flags) ++static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue, gfp_t flags) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { ++ for (i = 0; i < dma_conf->dma_rx_size; i++) { + struct dma_desc *p; + int ret; + +@@ -1594,7 +1617,7 @@ static int stmmac_alloc_rx_buffers(struc + else + p = rx_q->dma_rx + i; + +- ret = stmmac_init_rx_buffers(priv, p, i, flags, ++ ret = stmmac_init_rx_buffers(priv, dma_conf, p, i, flags, + queue); + if (ret) + return ret; +@@ -1608,14 +1631,17 @@ static int stmmac_alloc_rx_buffers(struc + /** + * dma_free_rx_xskbufs - free RX dma buffers from XSK pool + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + */ +-static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue) ++static void dma_free_rx_xskbufs(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { ++ for (i = 0; i < dma_conf->dma_rx_size; i++) { + struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; + + if (!buf->xdp) +@@ -1626,12 +1652,14 @@ static void dma_free_rx_xskbufs(struct s + } + } + +-static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue) ++static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int i; + +- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { ++ for (i = 0; i < dma_conf->dma_rx_size; i++) { + struct stmmac_rx_buffer *buf; + dma_addr_t dma_addr; + struct dma_desc *p; +@@ -1666,22 +1694,25 @@ static struct xsk_buff_pool *stmmac_get_ + /** + * __init_dma_rx_desc_rings - init the RX descriptor ring (per queue) + * @priv: driver private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + * @flags: gfp flag. + * Description: this function initializes the DMA RX descriptors + * and allocates the socket buffers. It supports the chained and ring + * modes. + */ +-static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags) ++static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue, gfp_t flags) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + int ret; + + netif_dbg(priv, probe, priv->dev, + "(%s) dma_rx_phy=0x%08x\n", __func__, + (u32)rx_q->dma_rx_phy); + +- stmmac_clear_rx_descriptors(priv, queue); ++ stmmac_clear_rx_descriptors(priv, dma_conf, queue); + + xdp_rxq_info_unreg_mem_model(&rx_q->xdp_rxq); + +@@ -1708,9 +1739,9 @@ static int __init_dma_rx_desc_rings(stru + /* RX XDP ZC buffer pool may not be populated, e.g. + * xdpsock TX-only. + */ +- stmmac_alloc_rx_buffers_zc(priv, queue); ++ stmmac_alloc_rx_buffers_zc(priv, dma_conf, queue); + } else { +- ret = stmmac_alloc_rx_buffers(priv, queue, flags); ++ ret = stmmac_alloc_rx_buffers(priv, dma_conf, queue, flags); + if (ret < 0) + return -ENOMEM; + } +@@ -1720,17 +1751,19 @@ static int __init_dma_rx_desc_rings(stru + if (priv->extend_desc) + stmmac_mode_init(priv, rx_q->dma_erx, + rx_q->dma_rx_phy, +- priv->dma_conf.dma_rx_size, 1); ++ dma_conf->dma_rx_size, 1); + else + stmmac_mode_init(priv, rx_q->dma_rx, + rx_q->dma_rx_phy, +- priv->dma_conf.dma_rx_size, 0); ++ dma_conf->dma_rx_size, 0); + } + + return 0; + } + +-static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) ++static int init_dma_rx_desc_rings(struct net_device *dev, ++ struct stmmac_dma_conf *dma_conf, ++ gfp_t flags) + { + struct stmmac_priv *priv = netdev_priv(dev); + u32 rx_count = priv->plat->rx_queues_to_use; +@@ -1742,7 +1775,7 @@ static int init_dma_rx_desc_rings(struct + "SKB addresses:\nskb\t\tskb data\tdma data\n"); + + for (queue = 0; queue < rx_count; queue++) { +- ret = __init_dma_rx_desc_rings(priv, queue, flags); ++ ret = __init_dma_rx_desc_rings(priv, dma_conf, queue, flags); + if (ret) + goto err_init_rx_buffers; + } +@@ -1751,12 +1784,12 @@ static int init_dma_rx_desc_rings(struct + + err_init_rx_buffers: + while (queue >= 0) { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + + if (rx_q->xsk_pool) +- dma_free_rx_xskbufs(priv, queue); ++ dma_free_rx_xskbufs(priv, dma_conf, queue); + else +- dma_free_rx_skbufs(priv, queue); ++ dma_free_rx_skbufs(priv, dma_conf, queue); + + rx_q->buf_alloc_num = 0; + rx_q->xsk_pool = NULL; +@@ -1773,14 +1806,17 @@ err_init_rx_buffers: + /** + * __init_dma_tx_desc_rings - init the TX descriptor ring (per queue) + * @priv: driver private structure +- * @queue : TX queue index ++ * @dma_conf: structure to take the dma data ++ * @queue: TX queue index + * Description: this function initializes the DMA TX descriptors + * and allocates the socket buffers. It supports the chained and ring + * modes. + */ +-static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue) ++static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + int i; + + netif_dbg(priv, probe, priv->dev, +@@ -1792,16 +1828,16 @@ static int __init_dma_tx_desc_rings(stru + if (priv->extend_desc) + stmmac_mode_init(priv, tx_q->dma_etx, + tx_q->dma_tx_phy, +- priv->dma_conf.dma_tx_size, 1); ++ dma_conf->dma_tx_size, 1); + else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) + stmmac_mode_init(priv, tx_q->dma_tx, + tx_q->dma_tx_phy, +- priv->dma_conf.dma_tx_size, 0); ++ dma_conf->dma_tx_size, 0); + } + + tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue); + +- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { ++ for (i = 0; i < dma_conf->dma_tx_size; i++) { + struct dma_desc *p; + + if (priv->extend_desc) +@@ -1823,7 +1859,8 @@ static int __init_dma_tx_desc_rings(stru + return 0; + } + +-static int init_dma_tx_desc_rings(struct net_device *dev) ++static int init_dma_tx_desc_rings(struct net_device *dev, ++ struct stmmac_dma_conf *dma_conf) + { + struct stmmac_priv *priv = netdev_priv(dev); + u32 tx_queue_cnt; +@@ -1832,7 +1869,7 @@ static int init_dma_tx_desc_rings(struct + tx_queue_cnt = priv->plat->tx_queues_to_use; + + for (queue = 0; queue < tx_queue_cnt; queue++) +- __init_dma_tx_desc_rings(priv, queue); ++ __init_dma_tx_desc_rings(priv, dma_conf, queue); + + return 0; + } +@@ -1840,26 +1877,29 @@ static int init_dma_tx_desc_rings(struct + /** + * init_dma_desc_rings - init the RX/TX descriptor rings + * @dev: net device structure ++ * @dma_conf: structure to take the dma data + * @flags: gfp flag. + * Description: this function initializes the DMA RX/TX descriptors + * and allocates the socket buffers. It supports the chained and ring + * modes. + */ +-static int init_dma_desc_rings(struct net_device *dev, gfp_t flags) ++static int init_dma_desc_rings(struct net_device *dev, ++ struct stmmac_dma_conf *dma_conf, ++ gfp_t flags) + { + struct stmmac_priv *priv = netdev_priv(dev); + int ret; + +- ret = init_dma_rx_desc_rings(dev, flags); ++ ret = init_dma_rx_desc_rings(dev, dma_conf, flags); + if (ret) + return ret; + +- ret = init_dma_tx_desc_rings(dev); ++ ret = init_dma_tx_desc_rings(dev, dma_conf); + +- stmmac_clear_descriptors(priv); ++ stmmac_clear_descriptors(priv, dma_conf); + + if (netif_msg_hw(priv)) +- stmmac_display_rings(priv); ++ stmmac_display_rings(priv, dma_conf); + + return ret; + } +@@ -1867,17 +1907,20 @@ static int init_dma_desc_rings(struct ne + /** + * dma_free_tx_skbufs - free TX dma buffers + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: TX queue index + */ +-static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) ++static void dma_free_tx_skbufs(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + int i; + + tx_q->xsk_frames_done = 0; + +- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) +- stmmac_free_tx_buffer(priv, queue, i); ++ for (i = 0; i < dma_conf->dma_tx_size; i++) ++ stmmac_free_tx_buffer(priv, dma_conf, queue, i); + + if (tx_q->xsk_pool && tx_q->xsk_frames_done) { + xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done); +@@ -1896,34 +1939,37 @@ static void stmmac_free_tx_skbufs(struct + u32 queue; + + for (queue = 0; queue < tx_queue_cnt; queue++) +- dma_free_tx_skbufs(priv, queue); ++ dma_free_tx_skbufs(priv, &priv->dma_conf, queue); + } + + /** + * __free_dma_rx_desc_resources - free RX dma desc resources (per queue) + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + */ +-static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) ++static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + + /* Release the DMA RX socket buffers */ + if (rx_q->xsk_pool) +- dma_free_rx_xskbufs(priv, queue); ++ dma_free_rx_xskbufs(priv, dma_conf, queue); + else +- dma_free_rx_skbufs(priv, queue); ++ dma_free_rx_skbufs(priv, dma_conf, queue); + + rx_q->buf_alloc_num = 0; + rx_q->xsk_pool = NULL; + + /* Free DMA regions of consistent memory previously allocated */ + if (!priv->extend_desc) +- dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * ++ dma_free_coherent(priv->device, dma_conf->dma_rx_size * + sizeof(struct dma_desc), + rx_q->dma_rx, rx_q->dma_rx_phy); + else +- dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * ++ dma_free_coherent(priv->device, dma_conf->dma_rx_size * + sizeof(struct dma_extended_desc), + rx_q->dma_erx, rx_q->dma_rx_phy); + +@@ -1935,29 +1981,33 @@ static void __free_dma_rx_desc_resources + page_pool_destroy(rx_q->page_pool); + } + +-static void free_dma_rx_desc_resources(struct stmmac_priv *priv) ++static void free_dma_rx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 rx_count = priv->plat->rx_queues_to_use; + u32 queue; + + /* Free RX queue resources */ + for (queue = 0; queue < rx_count; queue++) +- __free_dma_rx_desc_resources(priv, queue); ++ __free_dma_rx_desc_resources(priv, dma_conf, queue); + } + + /** + * __free_dma_tx_desc_resources - free TX dma desc resources (per queue) + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: TX queue index + */ +-static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) ++static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + size_t size; + void *addr; + + /* Release the DMA TX socket buffers */ +- dma_free_tx_skbufs(priv, queue); ++ dma_free_tx_skbufs(priv, dma_conf, queue); + + if (priv->extend_desc) { + size = sizeof(struct dma_extended_desc); +@@ -1970,7 +2020,7 @@ static void __free_dma_tx_desc_resources + addr = tx_q->dma_tx; + } + +- size *= priv->dma_conf.dma_tx_size; ++ size *= dma_conf->dma_tx_size; + + dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); + +@@ -1978,28 +2028,32 @@ static void __free_dma_tx_desc_resources + kfree(tx_q->tx_skbuff); + } + +-static void free_dma_tx_desc_resources(struct stmmac_priv *priv) ++static void free_dma_tx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 tx_count = priv->plat->tx_queues_to_use; + u32 queue; + + /* Free TX queue resources */ + for (queue = 0; queue < tx_count; queue++) +- __free_dma_tx_desc_resources(priv, queue); ++ __free_dma_tx_desc_resources(priv, dma_conf, queue); + } + + /** + * __alloc_dma_rx_desc_resources - alloc RX resources (per queue). + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: RX queue index + * Description: according to which descriptor can be used (extend or basic) + * this function allocates the resources for TX and RX paths. In case of + * reception, for example, it pre-allocated the RX socket buffer in order to + * allow zero-copy mechanism. + */ +-static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) ++static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; ++ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; + struct stmmac_channel *ch = &priv->channel[queue]; + bool xdp_prog = stmmac_xdp_is_enabled(priv); + struct page_pool_params pp_params = { 0 }; +@@ -2011,8 +2065,8 @@ static int __alloc_dma_rx_desc_resources + rx_q->priv_data = priv; + + pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; +- pp_params.pool_size = priv->dma_conf.dma_rx_size; +- num_pages = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE); ++ pp_params.pool_size = dma_conf->dma_rx_size; ++ num_pages = DIV_ROUND_UP(dma_conf->dma_buf_sz, PAGE_SIZE); + pp_params.order = ilog2(num_pages); + pp_params.nid = dev_to_node(priv->device); + pp_params.dev = priv->device; +@@ -2027,7 +2081,7 @@ static int __alloc_dma_rx_desc_resources + return ret; + } + +- rx_q->buf_pool = kcalloc(priv->dma_conf.dma_rx_size, ++ rx_q->buf_pool = kcalloc(dma_conf->dma_rx_size, + sizeof(*rx_q->buf_pool), + GFP_KERNEL); + if (!rx_q->buf_pool) +@@ -2035,7 +2089,7 @@ static int __alloc_dma_rx_desc_resources + + if (priv->extend_desc) { + rx_q->dma_erx = dma_alloc_coherent(priv->device, +- priv->dma_conf.dma_rx_size * ++ dma_conf->dma_rx_size * + sizeof(struct dma_extended_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); +@@ -2044,7 +2098,7 @@ static int __alloc_dma_rx_desc_resources + + } else { + rx_q->dma_rx = dma_alloc_coherent(priv->device, +- priv->dma_conf.dma_rx_size * ++ dma_conf->dma_rx_size * + sizeof(struct dma_desc), + &rx_q->dma_rx_phy, + GFP_KERNEL); +@@ -2069,7 +2123,8 @@ static int __alloc_dma_rx_desc_resources + return 0; + } + +-static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv) ++static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 rx_count = priv->plat->rx_queues_to_use; + u32 queue; +@@ -2077,7 +2132,7 @@ static int alloc_dma_rx_desc_resources(s + + /* RX queues buffers and DMA */ + for (queue = 0; queue < rx_count; queue++) { +- ret = __alloc_dma_rx_desc_resources(priv, queue); ++ ret = __alloc_dma_rx_desc_resources(priv, dma_conf, queue); + if (ret) + goto err_dma; + } +@@ -2085,7 +2140,7 @@ static int alloc_dma_rx_desc_resources(s + return 0; + + err_dma: +- free_dma_rx_desc_resources(priv); ++ free_dma_rx_desc_resources(priv, dma_conf); + + return ret; + } +@@ -2093,28 +2148,31 @@ err_dma: + /** + * __alloc_dma_tx_desc_resources - alloc TX resources (per queue). + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * @queue: TX queue index + * Description: according to which descriptor can be used (extend or basic) + * this function allocates the resources for TX and RX paths. In case of + * reception, for example, it pre-allocated the RX socket buffer in order to + * allow zero-copy mechanism. + */ +-static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) ++static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf, ++ u32 queue) + { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; + size_t size; + void *addr; + + tx_q->queue_index = queue; + tx_q->priv_data = priv; + +- tx_q->tx_skbuff_dma = kcalloc(priv->dma_conf.dma_tx_size, ++ tx_q->tx_skbuff_dma = kcalloc(dma_conf->dma_tx_size, + sizeof(*tx_q->tx_skbuff_dma), + GFP_KERNEL); + if (!tx_q->tx_skbuff_dma) + return -ENOMEM; + +- tx_q->tx_skbuff = kcalloc(priv->dma_conf.dma_tx_size, ++ tx_q->tx_skbuff = kcalloc(dma_conf->dma_tx_size, + sizeof(struct sk_buff *), + GFP_KERNEL); + if (!tx_q->tx_skbuff) +@@ -2127,7 +2185,7 @@ static int __alloc_dma_tx_desc_resources + else + size = sizeof(struct dma_desc); + +- size *= priv->dma_conf.dma_tx_size; ++ size *= dma_conf->dma_tx_size; + + addr = dma_alloc_coherent(priv->device, size, + &tx_q->dma_tx_phy, GFP_KERNEL); +@@ -2144,7 +2202,8 @@ static int __alloc_dma_tx_desc_resources + return 0; + } + +-static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv) ++static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + u32 tx_count = priv->plat->tx_queues_to_use; + u32 queue; +@@ -2152,7 +2211,7 @@ static int alloc_dma_tx_desc_resources(s + + /* TX queues buffers and DMA */ + for (queue = 0; queue < tx_count; queue++) { +- ret = __alloc_dma_tx_desc_resources(priv, queue); ++ ret = __alloc_dma_tx_desc_resources(priv, dma_conf, queue); + if (ret) + goto err_dma; + } +@@ -2160,27 +2219,29 @@ static int alloc_dma_tx_desc_resources(s + return 0; + + err_dma: +- free_dma_tx_desc_resources(priv); ++ free_dma_tx_desc_resources(priv, dma_conf); + return ret; + } + + /** + * alloc_dma_desc_resources - alloc TX/RX resources. + * @priv: private structure ++ * @dma_conf: structure to take the dma data + * Description: according to which descriptor can be used (extend or basic) + * this function allocates the resources for TX and RX paths. In case of + * reception, for example, it pre-allocated the RX socket buffer in order to + * allow zero-copy mechanism. + */ +-static int alloc_dma_desc_resources(struct stmmac_priv *priv) ++static int alloc_dma_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + /* RX Allocation */ +- int ret = alloc_dma_rx_desc_resources(priv); ++ int ret = alloc_dma_rx_desc_resources(priv, dma_conf); + + if (ret) + return ret; + +- ret = alloc_dma_tx_desc_resources(priv); ++ ret = alloc_dma_tx_desc_resources(priv, dma_conf); + + return ret; + } +@@ -2188,16 +2249,18 @@ static int alloc_dma_desc_resources(stru + /** + * free_dma_desc_resources - free dma desc resources + * @priv: private structure ++ * @dma_conf: structure to take the dma data + */ +-static void free_dma_desc_resources(struct stmmac_priv *priv) ++static void free_dma_desc_resources(struct stmmac_priv *priv, ++ struct stmmac_dma_conf *dma_conf) + { + /* Release the DMA TX socket buffers */ +- free_dma_tx_desc_resources(priv); ++ free_dma_tx_desc_resources(priv, dma_conf); + + /* Release the DMA RX socket buffers later + * to ensure all pending XDP_TX buffers are returned. + */ +- free_dma_rx_desc_resources(priv); ++ free_dma_rx_desc_resources(priv, dma_conf); + } + + /** +@@ -2686,8 +2749,8 @@ static void stmmac_tx_err(struct stmmac_ + netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); + + stmmac_stop_tx_dma(priv, chan); +- dma_free_tx_skbufs(priv, chan); +- stmmac_clear_tx_descriptors(priv, chan); ++ dma_free_tx_skbufs(priv, &priv->dma_conf, chan); ++ stmmac_clear_tx_descriptors(priv, &priv->dma_conf, chan); + stmmac_reset_tx_queue(priv, chan); + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + tx_q->dma_tx_phy, chan); +@@ -3684,19 +3747,93 @@ static int stmmac_request_irq(struct net + } + + /** +- * stmmac_open - open entry point of the driver ++ * stmmac_setup_dma_desc - Generate a dma_conf and allocate DMA queue ++ * @priv: driver private structure ++ * @mtu: MTU to setup the dma queue and buf with ++ * Description: Allocate and generate a dma_conf based on the provided MTU. ++ * Allocate the Tx/Rx DMA queue and init them. ++ * Return value: ++ * the dma_conf allocated struct on success and an appropriate ERR_PTR on failure. ++ */ ++static struct stmmac_dma_conf * ++stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu) ++{ ++ struct stmmac_dma_conf *dma_conf; ++ int chan, bfsize, ret; ++ ++ dma_conf = kzalloc(sizeof(*dma_conf), GFP_KERNEL); ++ if (!dma_conf) { ++ netdev_err(priv->dev, "%s: DMA conf allocation failed\n", ++ __func__); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ bfsize = stmmac_set_16kib_bfsize(priv, mtu); ++ if (bfsize < 0) ++ bfsize = 0; ++ ++ if (bfsize < BUF_SIZE_16KiB) ++ bfsize = stmmac_set_bfsize(mtu, 0); ++ ++ dma_conf->dma_buf_sz = bfsize; ++ /* Chose the tx/rx size from the already defined one in the ++ * priv struct. (if defined) ++ */ ++ dma_conf->dma_tx_size = priv->dma_conf.dma_tx_size; ++ dma_conf->dma_rx_size = priv->dma_conf.dma_rx_size; ++ ++ if (!dma_conf->dma_tx_size) ++ dma_conf->dma_tx_size = DMA_DEFAULT_TX_SIZE; ++ if (!dma_conf->dma_rx_size) ++ dma_conf->dma_rx_size = DMA_DEFAULT_RX_SIZE; ++ ++ /* Earlier check for TBS */ ++ for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { ++ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[chan]; ++ int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; ++ ++ /* Setup per-TXQ tbs flag before TX descriptor alloc */ ++ tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0; ++ } ++ ++ ret = alloc_dma_desc_resources(priv, dma_conf); ++ if (ret < 0) { ++ netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", ++ __func__); ++ goto alloc_error; ++ } ++ ++ ret = init_dma_desc_rings(priv->dev, dma_conf, GFP_KERNEL); ++ if (ret < 0) { ++ netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", ++ __func__); ++ goto init_error; ++ } ++ ++ return dma_conf; ++ ++init_error: ++ free_dma_desc_resources(priv, dma_conf); ++alloc_error: ++ kfree(dma_conf); ++ return ERR_PTR(ret); ++} ++ ++/** ++ * __stmmac_open - open entry point of the driver + * @dev : pointer to the device structure. ++ * @dma_conf : structure to take the dma data + * Description: + * This function is the open entry point of the driver. + * Return value: + * 0 on success and an appropriate (-)ve integer as defined in errno.h + * file on failure. + */ +-static int stmmac_open(struct net_device *dev) ++static int __stmmac_open(struct net_device *dev, ++ struct stmmac_dma_conf *dma_conf) + { + struct stmmac_priv *priv = netdev_priv(dev); + int mode = priv->plat->phy_interface; +- int bfsize = 0; + u32 chan; + int ret; + +@@ -3723,45 +3860,10 @@ static int stmmac_open(struct net_device + memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); + priv->xstats.threshold = tc; + +- bfsize = stmmac_set_16kib_bfsize(priv, dev->mtu); +- if (bfsize < 0) +- bfsize = 0; +- +- if (bfsize < BUF_SIZE_16KiB) +- bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_conf.dma_buf_sz); +- +- priv->dma_conf.dma_buf_sz = bfsize; +- buf_sz = bfsize; +- + priv->rx_copybreak = STMMAC_RX_COPYBREAK; + +- if (!priv->dma_conf.dma_tx_size) +- priv->dma_conf.dma_tx_size = DMA_DEFAULT_TX_SIZE; +- if (!priv->dma_conf.dma_rx_size) +- priv->dma_conf.dma_rx_size = DMA_DEFAULT_RX_SIZE; +- +- /* Earlier check for TBS */ +- for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { +- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; +- int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; +- +- /* Setup per-TXQ tbs flag before TX descriptor alloc */ +- tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0; +- } +- +- ret = alloc_dma_desc_resources(priv); +- if (ret < 0) { +- netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", +- __func__); +- goto dma_desc_error; +- } +- +- ret = init_dma_desc_rings(dev, GFP_KERNEL); +- if (ret < 0) { +- netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", +- __func__); +- goto init_error; +- } ++ buf_sz = dma_conf->dma_buf_sz; ++ memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf)); + + if (priv->plat->serdes_powerup) { + ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv); +@@ -3804,14 +3906,28 @@ irq_error: + + stmmac_hw_teardown(dev); + init_error: +- free_dma_desc_resources(priv); +-dma_desc_error: ++ free_dma_desc_resources(priv, &priv->dma_conf); + phylink_disconnect_phy(priv->phylink); + init_phy_error: + pm_runtime_put(priv->device); + return ret; + } + ++static int stmmac_open(struct net_device *dev) ++{ ++ struct stmmac_priv *priv = netdev_priv(dev); ++ struct stmmac_dma_conf *dma_conf; ++ int ret; ++ ++ dma_conf = stmmac_setup_dma_desc(priv, dev->mtu); ++ if (IS_ERR(dma_conf)) ++ return PTR_ERR(dma_conf); ++ ++ ret = __stmmac_open(dev, dma_conf); ++ kfree(dma_conf); ++ return ret; ++} ++ + static void stmmac_fpe_stop_wq(struct stmmac_priv *priv) + { + set_bit(__FPE_REMOVING, &priv->fpe_task_state); +@@ -3858,7 +3974,7 @@ static int stmmac_release(struct net_dev + stmmac_stop_all_dma(priv); + + /* Release and free the Rx/Tx resources */ +- free_dma_desc_resources(priv); ++ free_dma_desc_resources(priv, &priv->dma_conf); + + /* Disable the MAC Rx/Tx */ + stmmac_mac_set(priv, priv->ioaddr, false); +@@ -6403,7 +6519,7 @@ void stmmac_disable_rx_queue(struct stmm + spin_unlock_irqrestore(&ch->lock, flags); + + stmmac_stop_rx_dma(priv, queue); +- __free_dma_rx_desc_resources(priv, queue); ++ __free_dma_rx_desc_resources(priv, &priv->dma_conf, queue); + } + + void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) +@@ -6414,21 +6530,21 @@ void stmmac_enable_rx_queue(struct stmma + u32 buf_size; + int ret; + +- ret = __alloc_dma_rx_desc_resources(priv, queue); ++ ret = __alloc_dma_rx_desc_resources(priv, &priv->dma_conf, queue); + if (ret) { + netdev_err(priv->dev, "Failed to alloc RX desc.\n"); + return; + } + +- ret = __init_dma_rx_desc_rings(priv, queue, GFP_KERNEL); ++ ret = __init_dma_rx_desc_rings(priv, &priv->dma_conf, queue, GFP_KERNEL); + if (ret) { +- __free_dma_rx_desc_resources(priv, queue); ++ __free_dma_rx_desc_resources(priv, &priv->dma_conf, queue); + netdev_err(priv->dev, "Failed to init RX desc.\n"); + return; + } + + stmmac_reset_rx_queue(priv, queue); +- stmmac_clear_rx_descriptors(priv, queue); ++ stmmac_clear_rx_descriptors(priv, &priv->dma_conf, queue); + + stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + rx_q->dma_rx_phy, rx_q->queue_index); +@@ -6466,7 +6582,7 @@ void stmmac_disable_tx_queue(struct stmm + spin_unlock_irqrestore(&ch->lock, flags); + + stmmac_stop_tx_dma(priv, queue); +- __free_dma_tx_desc_resources(priv, queue); ++ __free_dma_tx_desc_resources(priv, &priv->dma_conf, queue); + } + + void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) +@@ -6476,21 +6592,21 @@ void stmmac_enable_tx_queue(struct stmma + unsigned long flags; + int ret; + +- ret = __alloc_dma_tx_desc_resources(priv, queue); ++ ret = __alloc_dma_tx_desc_resources(priv, &priv->dma_conf, queue); + if (ret) { + netdev_err(priv->dev, "Failed to alloc TX desc.\n"); + return; + } + +- ret = __init_dma_tx_desc_rings(priv, queue); ++ ret = __init_dma_tx_desc_rings(priv, &priv->dma_conf, queue); + if (ret) { +- __free_dma_tx_desc_resources(priv, queue); ++ __free_dma_tx_desc_resources(priv, &priv->dma_conf, queue); + netdev_err(priv->dev, "Failed to init TX desc.\n"); + return; + } + + stmmac_reset_tx_queue(priv, queue); +- stmmac_clear_tx_descriptors(priv, queue); ++ stmmac_clear_tx_descriptors(priv, &priv->dma_conf, queue); + + stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, + tx_q->dma_tx_phy, tx_q->queue_index); +@@ -6530,7 +6646,7 @@ void stmmac_xdp_release(struct net_devic + stmmac_stop_all_dma(priv); + + /* Release and free the Rx/Tx resources */ +- free_dma_desc_resources(priv); ++ free_dma_desc_resources(priv, &priv->dma_conf); + + /* Disable the MAC Rx/Tx */ + stmmac_mac_set(priv, priv->ioaddr, false); +@@ -6555,14 +6671,14 @@ int stmmac_xdp_open(struct net_device *d + u32 chan; + int ret; + +- ret = alloc_dma_desc_resources(priv); ++ ret = alloc_dma_desc_resources(priv, &priv->dma_conf); + if (ret < 0) { + netdev_err(dev, "%s: DMA descriptors allocation failed\n", + __func__); + goto dma_desc_error; + } + +- ret = init_dma_desc_rings(dev, GFP_KERNEL); ++ ret = init_dma_desc_rings(dev, &priv->dma_conf, GFP_KERNEL); + if (ret < 0) { + netdev_err(dev, "%s: DMA descriptors initialization failed\n", + __func__); +@@ -6644,7 +6760,7 @@ irq_error: + + stmmac_hw_teardown(dev); + init_error: +- free_dma_desc_resources(priv); ++ free_dma_desc_resources(priv, &priv->dma_conf); + dma_desc_error: + return ret; + } +@@ -7509,7 +7625,7 @@ int stmmac_resume(struct device *dev) + stmmac_reset_queues_param(priv); + + stmmac_free_tx_skbufs(priv); +- stmmac_clear_descriptors(priv); ++ stmmac_clear_descriptors(priv, &priv->dma_conf); + + stmmac_hw_setup(ndev, false); + stmmac_init_coalesce(priv); diff --git a/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch b/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch new file mode 100644 index 00000000000..8fccc716597 --- /dev/null +++ b/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch @@ -0,0 +1,73 @@ +From 3470079687448abac42deb62774253be1d6bdef3 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 23 Jul 2022 16:29:33 +0200 +Subject: [PATCH 5/5] net: ethernet: stmicro: stmmac: permit MTU change with + interface up + +Remove the limitation where the interface needs to be down to change +MTU by releasing and opening the stmmac driver to set the new MTU. +Also call the set_filter function to correctly init the port. +This permits to remove the EBUSY error while the ethernet port is +running permitting a correct MTU change if for example a DSA request +a MTU change for a switch CPU port. + +Signed-off-by: Christian Marangi +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 30 +++++++++++++++---- + 1 file changed, 24 insertions(+), 6 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -5626,18 +5626,15 @@ static int stmmac_change_mtu(struct net_ + { + struct stmmac_priv *priv = netdev_priv(dev); + int txfifosz = priv->plat->tx_fifo_size; ++ struct stmmac_dma_conf *dma_conf; + const int mtu = new_mtu; ++ int ret; + + if (txfifosz == 0) + txfifosz = priv->dma_cap.tx_fifo_size; + + txfifosz /= priv->plat->tx_queues_to_use; + +- if (netif_running(dev)) { +- netdev_err(priv->dev, "must be stopped to change its MTU\n"); +- return -EBUSY; +- } +- + if (stmmac_xdp_is_enabled(priv) && new_mtu > ETH_DATA_LEN) { + netdev_dbg(priv->dev, "Jumbo frames not supported for XDP\n"); + return -EINVAL; +@@ -5649,8 +5646,29 @@ static int stmmac_change_mtu(struct net_ + if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB)) + return -EINVAL; + +- dev->mtu = mtu; ++ if (netif_running(dev)) { ++ netdev_dbg(priv->dev, "restarting interface to change its MTU\n"); ++ /* Try to allocate the new DMA conf with the new mtu */ ++ dma_conf = stmmac_setup_dma_desc(priv, mtu); ++ if (IS_ERR(dma_conf)) { ++ netdev_err(priv->dev, "failed allocating new dma conf for new MTU %d\n", ++ mtu); ++ return PTR_ERR(dma_conf); ++ } ++ ++ stmmac_release(dev); ++ ++ ret = __stmmac_open(dev, dma_conf); ++ kfree(dma_conf); ++ if (ret) { ++ netdev_err(priv->dev, "failed reopening the interface after MTU change\n"); ++ return ret; ++ } ++ ++ stmmac_set_rx_mode(dev); ++ } + ++ dev->mtu = mtu; + netdev_update_features(dev); + + return 0; diff --git a/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch b/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch new file mode 100644 index 00000000000..4f0d95f4561 --- /dev/null +++ b/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch @@ -0,0 +1,156 @@ +From a2550d3ce53c68f54042bc5e468c4d07491ffe0e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 12 Oct 2022 19:18:36 +0200 +Subject: [PATCH 1/2] net: dsa: qca8k: fix inband mgmt for big-endian systems + +The header and the data of the skb for the inband mgmt requires +to be in little-endian. This is problematic for big-endian system +as the mgmt header is written in the cpu byte order. + +Fix this by converting each value for the mgmt header and data to +little-endian, and convert to cpu byte order the mgmt header and +data sent by the switch. + +Fixes: 5950c7c0a68c ("net: dsa: qca8k: add support for mgmt read/write in Ethernet packet") +Tested-by: Pawel Dembicki +Tested-by: Lech Perczak +Signed-off-by: Christian Marangi +Reviewed-by: Lech Perczak +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 63 ++++++++++++++++++++++++-------- + include/linux/dsa/tag_qca.h | 6 +-- + 2 files changed, 50 insertions(+), 19 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -137,27 +137,42 @@ static void qca8k_rw_reg_ack_handler(str + struct qca8k_mgmt_eth_data *mgmt_eth_data; + struct qca8k_priv *priv = ds->priv; + struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ u32 command; + u8 len, cmd; ++ int i; + + mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); + mgmt_eth_data = &priv->mgmt_eth_data; + +- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); +- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); ++ command = get_unaligned_le32(&mgmt_ethhdr->command); ++ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); ++ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); + + /* Make sure the seq match the requested packet */ +- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) ++ if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) + mgmt_eth_data->ack = true; + + if (cmd == MDIO_READ) { +- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; ++ u32 *val = mgmt_eth_data->data; ++ ++ *val = get_unaligned_le32(&mgmt_ethhdr->mdio_data); + + /* Get the rest of the 12 byte of data. + * The read/write function will extract the requested data. + */ +- if (len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(mgmt_eth_data->data + 1, skb->data, +- QCA_HDR_MGMT_DATA2_LEN); ++ if (len > QCA_HDR_MGMT_DATA1_LEN) { ++ __le32 *data2 = (__le32 *)skb->data; ++ int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, ++ len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ val++; ++ ++ for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { ++ *val = get_unaligned_le32(data2); ++ val++; ++ data2++; ++ } ++ } + } + + complete(&mgmt_eth_data->rw_done); +@@ -169,8 +184,10 @@ static struct sk_buff *qca8k_alloc_mdio_ + struct qca_mgmt_ethhdr *mgmt_ethhdr; + unsigned int real_len; + struct sk_buff *skb; +- u32 *data2; ++ __le32 *data2; ++ u32 command; + u16 hdr; ++ int i; + + skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); + if (!skb) +@@ -199,20 +216,32 @@ static struct sk_buff *qca8k_alloc_mdio_ + hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); + hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); + +- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); +- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, ++ command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); ++ command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); ++ command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); ++ command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, + QCA_HDR_MGMT_CHECK_CODE_VAL); + ++ put_unaligned_le32(command, &mgmt_ethhdr->command); ++ + if (cmd == MDIO_WRITE) +- mgmt_ethhdr->mdio_data = *val; ++ put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data); + + mgmt_ethhdr->hdr = htons(hdr); + + data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); +- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) +- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); ++ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) { ++ int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, ++ len - QCA_HDR_MGMT_DATA1_LEN); ++ ++ val++; ++ ++ for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { ++ put_unaligned_le32(*val, data2); ++ data2++; ++ val++; ++ } ++ } + + return skb; + } +@@ -220,9 +249,11 @@ static struct sk_buff *qca8k_alloc_mdio_ + static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) + { + struct qca_mgmt_ethhdr *mgmt_ethhdr; ++ u32 seq; + ++ seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); + mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; +- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); ++ put_unaligned_le32(seq, &mgmt_ethhdr->seq); + } + + static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -56,9 +56,9 @@ + + /* Special struct emulating a Ethernet header */ + struct qca_mgmt_ethhdr { +- u32 command; /* command bit 31:0 */ +- u32 seq; /* seq 63:32 */ +- u32 mdio_data; /* first 4byte mdio */ ++ __le32 command; /* command bit 31:0 */ ++ __le32 seq; /* seq 63:32 */ ++ __le32 mdio_data; /* first 4byte mdio */ + __be16 hdr; /* qca hdr */ + } __packed; + diff --git a/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch b/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch new file mode 100644 index 00000000000..d13014bf93b --- /dev/null +++ b/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch @@ -0,0 +1,81 @@ +From 0d4636f7d72df3179b20a2d32b647881917a5e2a Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 12 Oct 2022 19:18:37 +0200 +Subject: [PATCH 2/2] net: dsa: qca8k: fix ethtool autocast mib for big-endian + systems + +The switch sends autocast mib in little-endian. This is problematic for +big-endian system as the values needs to be converted. + +Fix this by converting each mib value to cpu byte order. + +Fixes: 5c957c7ca78c ("net: dsa: qca8k: add support for mib autocast in Ethernet packet") +Tested-by: Pawel Dembicki +Tested-by: Lech Perczak +Signed-off-by: Christian Marangi +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 20 ++++++++------------ + include/linux/dsa/tag_qca.h | 2 +- + 2 files changed, 9 insertions(+), 13 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -1668,9 +1668,9 @@ static void qca8k_mib_autocast_handler(s + struct qca8k_priv *priv = ds->priv; + const struct qca8k_mib_desc *mib; + struct mib_ethhdr *mib_ethhdr; +- int i, mib_len, offset = 0; +- u64 *data; ++ __le32 *data2; + u8 port; ++ int i; + + mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); + mib_eth_data = &priv->mib_eth_data; +@@ -1682,28 +1682,24 @@ static void qca8k_mib_autocast_handler(s + if (port != mib_eth_data->req_port) + goto exit; + +- data = mib_eth_data->data; ++ data2 = (__le32 *)skb->data; + + for (i = 0; i < priv->info->mib_count; i++) { + mib = &ar8327_mib[i]; + + /* First 3 mib are present in the skb head */ + if (i < 3) { +- data[i] = mib_ethhdr->data[i]; ++ mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i); + continue; + } + +- mib_len = sizeof(uint32_t); +- + /* Some mib are 64 bit wide */ + if (mib->size == 2) +- mib_len = sizeof(uint64_t); +- +- /* Copy the mib value from packet to the */ +- memcpy(data + i, skb->data + offset, mib_len); ++ mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2); ++ else ++ mib_eth_data->data[i] = get_unaligned_le32(data2); + +- /* Set the offset for the next mib */ +- offset += mib_len; ++ data2 += mib->size; + } + + exit: +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -68,7 +68,7 @@ enum mdio_cmd { + }; + + struct mib_ethhdr { +- u32 data[3]; /* first 3 mib counter */ ++ __le32 data[3]; /* first 3 mib counter */ + __be16 hdr; /* qca hdr */ + } __packed; + diff --git a/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch b/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch new file mode 100644 index 00000000000..b61e7ede494 --- /dev/null +++ b/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch @@ -0,0 +1,102 @@ +From 9807ae69746196ee4bbffe7d22d22ab2b61c6ed0 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 29 Dec 2022 17:33:32 +0100 +Subject: [PATCH 1/5] net: dsa: qca8k: fix wrong length value for mgmt eth + packet + +The assumption that Documentation was right about how this value work was +wrong. It was discovered that the length value of the mgmt header is in +step of word size. + +As an example to process 4 byte of data the correct length to set is 2. +To process 8 byte 4, 12 byte 6, 16 byte 8... + +Odd values will always return the next size on the ack packet. +(length of 3 (6 byte) will always return 8 bytes of data) + +This means that a value of 15 (0xf) actually means reading/writing 32 bytes +of data instead of 16 bytes. This behaviour is totally absent and not +documented in the switch Documentation. + +In fact from Documentation the max value that mgmt eth can process is +16 byte of data while in reality it can process 32 bytes at once. + +To handle this we always round up the length after deviding it for word +size. We check if the result is odd and we round another time to align +to what the switch will provide in the ack packet. +The workaround for the length limit of 15 is still needed as the length +reg max value is 0xf(15) + +Reported-by: Ronald Wahl +Tested-by: Ronald Wahl +Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet") +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org # v5.18+ +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 45 +++++++++++++++++++++++++------- + 1 file changed, 35 insertions(+), 10 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -146,7 +146,16 @@ static void qca8k_rw_reg_ack_handler(str + + command = get_unaligned_le32(&mgmt_ethhdr->command); + cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); ++ + len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); ++ /* Special case for len of 15 as this is the max value for len and needs to ++ * be increased before converting it from word to dword. ++ */ ++ if (len == 15) ++ len++; ++ ++ /* We can ignore odd value, we always round up them in the alloc function. */ ++ len *= sizeof(u16); + + /* Make sure the seq match the requested packet */ + if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) +@@ -193,17 +202,33 @@ static struct sk_buff *qca8k_alloc_mdio_ + if (!skb) + return NULL; + +- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte +- * Actually for some reason the steps are: +- * 0: nothing +- * 1-4: first 4 byte +- * 5-6: first 12 byte +- * 7-15: all 16 byte ++ /* Hdr mgmt length value is in step of word size. ++ * As an example to process 4 byte of data the correct length to set is 2. ++ * To process 8 byte 4, 12 byte 6, 16 byte 8... ++ * ++ * Odd values will always return the next size on the ack packet. ++ * (length of 3 (6 byte) will always return 8 bytes of data) ++ * ++ * This means that a value of 15 (0xf) actually means reading/writing 32 bytes ++ * of data. ++ * ++ * To correctly calculate the length we devide the requested len by word and ++ * round up. ++ * On the ack function we can skip the odd check as we already handle the ++ * case here. + */ +- if (len == 16) +- real_len = 15; +- else +- real_len = len; ++ real_len = DIV_ROUND_UP(len, sizeof(u16)); ++ ++ /* We check if the result len is odd and we round up another time to ++ * the next size. (length of 3 will be increased to 4 as switch will always ++ * return 8 bytes) ++ */ ++ if (real_len % sizeof(u16) != 0) ++ real_len++; ++ ++ /* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ ++ if (real_len == 16) ++ real_len--; + + skb_reset_mac_header(skb); + skb_set_network_header(skb, skb->len); diff --git a/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch b/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch new file mode 100644 index 00000000000..55ecb1eb42e --- /dev/null +++ b/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch @@ -0,0 +1,34 @@ +From d9dba91be71f03cc75bcf39fc0d5d99ff33f1ae0 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 29 Dec 2022 17:33:33 +0100 +Subject: [PATCH 2/5] net: dsa: tag_qca: fix wrong MGMT_DATA2 size + +It was discovered that MGMT_DATA2 can contain up to 28 bytes of data +instead of the 12 bytes written in the Documentation by accounting the +limit of 16 bytes declared in Documentation subtracting the first 4 byte +in the packet header. + +Update the define with the real world value. + +Tested-by: Ronald Wahl +Fixes: c2ee8181fddb ("net: dsa: tag_qca: add define for handling mgmt Ethernet packet") +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org # v5.18+ +Signed-off-by: David S. Miller +--- + include/linux/dsa/tag_qca.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/include/linux/dsa/tag_qca.h ++++ b/include/linux/dsa/tag_qca.h +@@ -40,8 +40,8 @@ + QCA_HDR_MGMT_COMMAND_LEN + \ + QCA_HDR_MGMT_DATA1_LEN) + +-#define QCA_HDR_MGMT_DATA2_LEN 12 /* Other 12 byte for the mdio data */ +-#define QCA_HDR_MGMT_PADDING_LEN 34 /* Padding to reach the min Ethernet packet */ ++#define QCA_HDR_MGMT_DATA2_LEN 28 /* Other 28 byte for the mdio data */ ++#define QCA_HDR_MGMT_PADDING_LEN 18 /* Padding to reach the min Ethernet packet */ + + #define QCA_HDR_MGMT_PKT_LEN (QCA_HDR_MGMT_HEADER_LEN + \ + QCA_HDR_LEN + \ diff --git a/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch b/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch new file mode 100644 index 00000000000..c8e22fd1b81 --- /dev/null +++ b/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch @@ -0,0 +1,172 @@ +From 03cb9e6d0b32b768e3d9d473c5c4ca1100877664 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 29 Dec 2022 17:33:34 +0100 +Subject: [PATCH 3/5] Revert "net: dsa: qca8k: cache lo and hi for mdio write" + +This reverts commit 2481d206fae7884cd07014fd1318e63af35e99eb. + +The Documentation is very confusing about the topic. +The cache logic for hi and lo is wrong and actually miss some regs to be +actually written. + +What the Documentation actually intended was that it's possible to skip +writing hi OR lo if half of the reg is not needed to be written or read. + +Revert the change in favor of a better and correct implementation. + +Reported-by: Ronald Wahl +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org # v5.18+ +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 61 +++++++------------------------- + drivers/net/dsa/qca/qca8k.h | 5 --- + 2 files changed, 12 insertions(+), 54 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -37,44 +37,6 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u + } + + static int +-qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) +-{ +- u16 *cached_lo = &priv->mdio_cache.lo; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (lo == *cached_lo) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, lo); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit lo register\n"); +- +- *cached_lo = lo; +- return 0; +-} +- +-static int +-qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) +-{ +- u16 *cached_hi = &priv->mdio_cache.hi; +- struct mii_bus *bus = priv->bus; +- int ret; +- +- if (hi == *cached_hi) +- return 0; +- +- ret = bus->write(bus, phy_id, regnum, hi); +- if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit hi register\n"); +- +- *cached_hi = hi; +- return 0; +-} +- +-static int + qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) + { + int ret; +@@ -97,7 +59,7 @@ qca8k_mii_read32(struct mii_bus *bus, in + } + + static void +-qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) ++qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) + { + u16 lo, hi; + int ret; +@@ -105,9 +67,12 @@ qca8k_mii_write32(struct qca8k_priv *pri + lo = val & 0xffff; + hi = (u16)(val >> 16); + +- ret = qca8k_set_lo(priv, phy_id, regnum, lo); ++ ret = bus->write(bus, phy_id, regnum, lo); + if (ret >= 0) +- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); ++ ret = bus->write(bus, phy_id, regnum + 1, hi); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit register\n"); + } + + static int +@@ -442,7 +407,7 @@ qca8k_regmap_write(void *ctx, uint32_t r + if (ret < 0) + goto exit; + +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, val); + + exit: + mutex_unlock(&bus->mdio_lock); +@@ -475,7 +440,7 @@ qca8k_regmap_update_bits(void *ctx, uint + + val &= ~mask; + val |= write_val; +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, val); + + exit: + mutex_unlock(&bus->mdio_lock); +@@ -750,14 +715,14 @@ qca8k_mdio_write(struct qca8k_priv *priv + if (ret) + goto exit; + +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, val); + + ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_BUSY); + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); + + mutex_unlock(&bus->mdio_lock); + +@@ -787,7 +752,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, + if (ret) + goto exit; + +- qca8k_mii_write32(priv, 0x10 | r2, r1, val); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, val); + + ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_BUSY); +@@ -798,7 +763,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); ++ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); + + mutex_unlock(&bus->mdio_lock); + +@@ -1914,8 +1879,6 @@ qca8k_sw_probe(struct mdio_device *mdiod + } + + priv->mdio_cache.page = 0xffff; +- priv->mdio_cache.lo = 0xffff; +- priv->mdio_cache.hi = 0xffff; + + /* Check the detected switch id */ + ret = qca8k_read_switch_id(priv); +--- a/drivers/net/dsa/qca/qca8k.h ++++ b/drivers/net/dsa/qca/qca8k.h +@@ -375,11 +375,6 @@ struct qca8k_mdio_cache { + * mdio writes + */ + u16 page; +-/* lo and hi can also be cached and from Documentation we can skip one +- * extra mdio write if lo or hi is didn't change. +- */ +- u16 lo; +- u16 hi; + }; + + struct qca8k_priv { diff --git a/target/linux/generic/backport-6.1/777-v6.2-04-net-dsa-qca8k-introduce-single-mii-read-write-lo-hi.patch b/target/linux/generic/backport-6.1/777-v6.2-04-net-dsa-qca8k-introduce-single-mii-read-write-lo-hi.patch new file mode 100644 index 00000000000..c0320ad6f9d --- /dev/null +++ b/target/linux/generic/backport-6.1/777-v6.2-04-net-dsa-qca8k-introduce-single-mii-read-write-lo-hi.patch @@ -0,0 +1,150 @@ +From cfbd6de588ef659c198083205dc954a6d3ed2aec Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 29 Dec 2022 17:33:35 +0100 +Subject: [PATCH 4/5] net: dsa: qca8k: introduce single mii read/write lo/hi + +It may be useful to read/write just the lo or hi half of a reg. + +This is especially useful for phy poll with the use of mdio master. +The mdio master reg is composed by the first 16 bit related to setup and +the other half with the returned data or data to write. + +Refactor the mii function to permit single mii read/write of lo or hi +half of the reg. + +Tested-by: Ronald Wahl +Signed-off-by: Christian Marangi +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 106 ++++++++++++++++++++++++------- + 1 file changed, 84 insertions(+), 22 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -37,42 +37,104 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u + } + + static int +-qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) ++qca8k_mii_write_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) + { + int ret; ++ u16 lo; + +- ret = bus->read(bus, phy_id, regnum); +- if (ret >= 0) { +- *val = ret; +- ret = bus->read(bus, phy_id, regnum + 1); +- *val |= ret << 16; +- } ++ lo = val & 0xffff; ++ ret = bus->write(bus, phy_id, regnum, lo); ++ if (ret < 0) ++ dev_err_ratelimited(&bus->dev, ++ "failed to write qca8k 32bit lo register\n"); ++ ++ return ret; ++} + +- if (ret < 0) { ++static int ++qca8k_mii_write_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) ++{ ++ int ret; ++ u16 hi; ++ ++ hi = (u16)(val >> 16); ++ ret = bus->write(bus, phy_id, regnum, hi); ++ if (ret < 0) + dev_err_ratelimited(&bus->dev, +- "failed to read qca8k 32bit register\n"); +- *val = 0; +- return ret; +- } ++ "failed to write qca8k 32bit hi register\n"); + ++ return ret; ++} ++ ++static int ++qca8k_mii_read_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) ++{ ++ int ret; ++ ++ ret = bus->read(bus, phy_id, regnum); ++ if (ret < 0) ++ goto err; ++ ++ *val = ret & 0xffff; + return 0; ++ ++err: ++ dev_err_ratelimited(&bus->dev, ++ "failed to read qca8k 32bit lo register\n"); ++ *val = 0; ++ ++ return ret; + } + +-static void +-qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) ++static int ++qca8k_mii_read_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) + { +- u16 lo, hi; + int ret; + +- lo = val & 0xffff; +- hi = (u16)(val >> 16); ++ ret = bus->read(bus, phy_id, regnum); ++ if (ret < 0) ++ goto err; + +- ret = bus->write(bus, phy_id, regnum, lo); +- if (ret >= 0) +- ret = bus->write(bus, phy_id, regnum + 1, hi); ++ *val = ret << 16; ++ return 0; ++ ++err: ++ dev_err_ratelimited(&bus->dev, ++ "failed to read qca8k 32bit hi register\n"); ++ *val = 0; ++ ++ return ret; ++} ++ ++static int ++qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) ++{ ++ u32 hi, lo; ++ int ret; ++ ++ *val = 0; ++ ++ ret = qca8k_mii_read_lo(bus, phy_id, regnum, &lo); + if (ret < 0) +- dev_err_ratelimited(&bus->dev, +- "failed to write qca8k 32bit register\n"); ++ goto err; ++ ++ ret = qca8k_mii_read_hi(bus, phy_id, regnum + 1, &hi); ++ if (ret < 0) ++ goto err; ++ ++ *val = lo | hi; ++ ++err: ++ return ret; ++} ++ ++static void ++qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) ++{ ++ if (qca8k_mii_write_lo(bus, phy_id, regnum, val) < 0) ++ return; ++ ++ qca8k_mii_write_hi(bus, phy_id, regnum + 1, val); + } + + static int diff --git a/target/linux/generic/backport-6.1/777-v6.2-05-net-dsa-qca8k-improve-mdio-master-read-write-by-usin.patch b/target/linux/generic/backport-6.1/777-v6.2-05-net-dsa-qca8k-improve-mdio-master-read-write-by-usin.patch new file mode 100644 index 00000000000..4cbb66cf35f --- /dev/null +++ b/target/linux/generic/backport-6.1/777-v6.2-05-net-dsa-qca8k-improve-mdio-master-read-write-by-usin.patch @@ -0,0 +1,73 @@ +From a4165830ca237f2b3318faf62562bce8ce12a389 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 29 Dec 2022 17:33:36 +0100 +Subject: [PATCH 5/5] net: dsa: qca8k: improve mdio master read/write by using + single lo/hi + +Improve mdio master read/write by using singe mii read/write lo/hi. + +In a read and write we need to poll the mdio master regs in a busy loop +to check for a specific bit present in the upper half of the reg. We can +ignore the other half since it won't contain useful data. This will save +an additional useless read for each read and write operation. + +In a read operation the returned data is present in the mdio master reg +lower half. We can ignore the other half since it won't contain useful +data. This will save an additional useless read for each read operation. + +In a read operation it's needed to just set the hi half of the mdio +master reg as the lo half will be replaced by the result. This will save +an additional useless write for each read operation. + +Tested-by: Ronald Wahl +Signed-off-by: Christian Marangi +Signed-off-by: David S. Miller +--- + drivers/net/dsa/qca/qca8k-8xxx.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/qca/qca8k-8xxx.c ++++ b/drivers/net/dsa/qca/qca8k-8xxx.c +@@ -740,9 +740,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus + + qca8k_split_addr(reg, &r1, &r2, &page); + +- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, ++ ret = read_poll_timeout(qca8k_mii_read_hi, ret1, !(val & mask), 0, + QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, +- bus, 0x10 | r2, r1, &val); ++ bus, 0x10 | r2, r1 + 1, &val); + + /* Check if qca8k_read has failed for a different reason + * before returnting -ETIMEDOUT +@@ -784,7 +784,7 @@ qca8k_mdio_write(struct qca8k_priv *priv + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); ++ qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); + + mutex_unlock(&bus->mdio_lock); + +@@ -814,18 +814,18 @@ qca8k_mdio_read(struct qca8k_priv *priv, + if (ret) + goto exit; + +- qca8k_mii_write32(bus, 0x10 | r2, r1, val); ++ qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, val); + + ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, + QCA8K_MDIO_MASTER_BUSY); + if (ret) + goto exit; + +- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); ++ ret = qca8k_mii_read_lo(bus, 0x10 | r2, r1, &val); + + exit: + /* even if the busy_wait timeouts try to clear the MASTER_EN */ +- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); ++ qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); + + mutex_unlock(&bus->mdio_lock); + diff --git a/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch b/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch new file mode 100644 index 00000000000..7cb21ed00d6 --- /dev/null +++ b/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch @@ -0,0 +1,193 @@ +From 3265f421887847db9ae2c01a00645e33608556d8 Mon Sep 17 00:00:00 2001 +From: Robert Hancock +Date: Tue, 25 Jan 2022 10:54:09 -0600 +Subject: [PATCH] net: phy: at803x: add fiber support + +Previously this driver always forced the copper page to be selected, +however for AR8031 in 100Base-FX or 1000Base-X modes, the fiber page +needs to be selected. Set the appropriate mode based on the hardware +mode_cfg strap selection. + +Enable the appropriate interrupt bits to detect fiber-side link up +or down events. + +Update config_aneg and read_status methods to use the appropriate +Clause 37 calls when fiber mode is in use. + +Signed-off-by: Robert Hancock +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 76 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 67 insertions(+), 9 deletions(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -48,6 +48,8 @@ + #define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) + #define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) + #define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) ++#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) ++#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) + #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) + #define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) + #define AT803X_INTR_ENABLE_WOL BIT(0) +@@ -82,6 +84,17 @@ + + #define AT803X_MODE_CFG_MASK 0x0F + #define AT803X_MODE_CFG_SGMII 0x01 ++#define AT803X_MODE_CFG_BASET_RGMII 0x00 ++#define AT803X_MODE_CFG_BASET_SGMII 0x01 ++#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 ++#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 ++#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 ++#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 ++#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 ++#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 ++#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B ++#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E ++#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F + + #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ + #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 +@@ -199,6 +212,8 @@ struct at803x_priv { + u16 clk_25m_mask; + u8 smarteee_lpi_tw_1g; + u8 smarteee_lpi_tw_100m; ++ bool is_fiber; ++ bool is_1000basex; + struct regulator_dev *vddio_rdev; + struct regulator_dev *vddh_rdev; + struct regulator *vddio; +@@ -674,7 +689,33 @@ static int at803x_probe(struct phy_devic + return ret; + } + ++ if (phydev->drv->phy_id == ATH8031_PHY_ID) { ++ int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); ++ int mode_cfg; ++ ++ if (ccr < 0) ++ goto err; ++ mode_cfg = ccr & AT803X_MODE_CFG_MASK; ++ ++ switch (mode_cfg) { ++ case AT803X_MODE_CFG_BX1000_RGMII_50OHM: ++ case AT803X_MODE_CFG_BX1000_RGMII_75OHM: ++ priv->is_1000basex = true; ++ fallthrough; ++ case AT803X_MODE_CFG_FX100_RGMII_50OHM: ++ case AT803X_MODE_CFG_FX100_RGMII_75OHM: ++ priv->is_fiber = true; ++ break; ++ } ++ } ++ + return 0; ++ ++err: ++ if (priv->vddio) ++ regulator_disable(priv->vddio); ++ ++ return ret; + } + + static void at803x_remove(struct phy_device *phydev) +@@ -687,6 +728,7 @@ static void at803x_remove(struct phy_dev + + static int at803x_get_features(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int err; + + err = genphy_read_abilities(phydev); +@@ -704,12 +746,13 @@ static int at803x_get_features(struct ph + * As a result of that, ESTATUS_1000_XFULL is set + * to 1 even when operating in copper TP mode. + * +- * Remove this mode from the supported link modes, +- * as this driver currently only supports copper +- * operation. ++ * Remove this mode from the supported link modes ++ * when not operating in 1000BaseX mode. + */ +- linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, +- phydev->supported); ++ if (!priv->is_1000basex) ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->supported); ++ + return 0; + } + +@@ -773,15 +816,18 @@ static int at8031_pll_config(struct phy_ + + static int at803x_config_init(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ret; + + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + /* Some bootloaders leave the fiber page selected. +- * Switch to the copper page, as otherwise we read +- * the PHY capabilities from the fiber side. ++ * Switch to the appropriate page (fiber or copper), as otherwise we ++ * read the PHY capabilities from the wrong page. + */ + phy_lock_mdio_bus(phydev); +- ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); ++ ret = at803x_write_page(phydev, ++ priv->is_fiber ? AT803X_PAGE_FIBER : ++ AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; +@@ -840,6 +886,7 @@ static int at803x_ack_interrupt(struct p + + static int at803x_config_intr(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int err; + int value; + +@@ -856,6 +903,10 @@ static int at803x_config_intr(struct phy + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; ++ if (priv->is_fiber) { ++ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; ++ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; ++ } + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } else { +@@ -923,8 +974,12 @@ static void at803x_link_change_notify(st + + static int at803x_read_status(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ss, err, old_link = phydev->link; + ++ if (priv->is_1000basex) ++ return genphy_c37_read_status(phydev); ++ + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) +@@ -1023,6 +1078,7 @@ static int at803x_config_mdix(struct phy + + static int at803x_config_aneg(struct phy_device *phydev) + { ++ struct at803x_priv *priv = phydev->priv; + int ret; + + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); +@@ -1039,6 +1095,9 @@ static int at803x_config_aneg(struct phy + return ret; + } + ++ if (priv->is_1000basex) ++ return genphy_c37_config_aneg(phydev); ++ + return genphy_config_aneg(phydev); + } + diff --git a/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch b/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch new file mode 100644 index 00000000000..8393cb32e89 --- /dev/null +++ b/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch @@ -0,0 +1,95 @@ +From dc4d5fcc5d365c9f70ea3f5c09bdf70e988fad50 Mon Sep 17 00:00:00 2001 +From: Robert Hancock +Date: Tue, 25 Jan 2022 10:54:10 -0600 +Subject: [PATCH] net: phy: at803x: Support downstream SFP cage + +Add support for downstream SFP cages for AR8031 and AR8033. This is +primarily intended for fiber modules or direct-attach cables, however +copper modules which work in 1000Base-X mode may also function. Such +modules are allowed with a warning. + +Signed-off-by: Robert Hancock +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 56 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 56 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + #include + + #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 +@@ -555,6 +557,55 @@ static int at8031_register_regulators(st + return 0; + } + ++static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) ++{ ++ struct phy_device *phydev = upstream; ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); ++ phy_interface_t iface; ++ ++ linkmode_zero(phy_support); ++ phylink_set(phy_support, 1000baseX_Full); ++ phylink_set(phy_support, 1000baseT_Full); ++ phylink_set(phy_support, Autoneg); ++ phylink_set(phy_support, Pause); ++ phylink_set(phy_support, Asym_Pause); ++ ++ linkmode_zero(sfp_support); ++ sfp_parse_support(phydev->sfp_bus, id, sfp_support); ++ /* Some modules support 10G modes as well as others we support. ++ * Mask out non-supported modes so the correct interface is picked. ++ */ ++ linkmode_and(sfp_support, phy_support, sfp_support); ++ ++ if (linkmode_empty(sfp_support)) { ++ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); ++ return -EINVAL; ++ } ++ ++ iface = sfp_select_interface(phydev->sfp_bus, sfp_support); ++ ++ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes ++ * interface for use with SFP modules. ++ * However, some copper modules detected as having a preferred SGMII ++ * interface do default to and function in 1000Base-X mode, so just ++ * print a warning and allow such modules, as they may have some chance ++ * of working. ++ */ ++ if (iface == PHY_INTERFACE_MODE_SGMII) ++ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); ++ else if (iface != PHY_INTERFACE_MODE_1000BASEX) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static const struct sfp_upstream_ops at803x_sfp_ops = { ++ .attach = phy_sfp_attach, ++ .detach = phy_sfp_detach, ++ .module_insert = at803x_sfp_insert, ++}; ++ + static int at803x_parse_dt(struct phy_device *phydev) + { + struct device_node *node = phydev->mdio.dev.of_node; +@@ -662,6 +713,11 @@ static int at803x_parse_dt(struct phy_de + phydev_err(phydev, "failed to get VDDIO regulator\n"); + return PTR_ERR(priv->vddio); + } ++ ++ /* Only AR8031/8033 support 1000Base-X for SFP modules */ ++ ret = phy_sfp_probe(phydev, &at803x_sfp_ops); ++ if (ret < 0) ++ return ret; + } + + return 0; diff --git a/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch b/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch new file mode 100644 index 00000000000..de8951db10c --- /dev/null +++ b/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch @@ -0,0 +1,56 @@ +From 9926de7315be3d606cc011a305ad9adb9e8e14c9 Mon Sep 17 00:00:00 2001 +From: Oleksij Rempel +Date: Sat, 18 Jun 2022 14:23:33 +0200 +Subject: [PATCH] net: phy: at803x: fix NULL pointer dereference on AR9331 PHY + +Latest kernel will explode on the PHY interrupt config, since it depends +now on allocated priv. So, run probe to allocate priv to fix it. + + ar9331_switch ethernet.1:10 lan0 (uninitialized): PHY [!ahb!ethernet@1a000000!mdio!switch@10:00] driver [Qualcomm Atheros AR9331 built-in PHY] (irq=13) + CPU 0 Unable to handle kernel paging request at virtual address 0000000a, epc == 8050e8a8, ra == 80504b34 + ... + Call Trace: + [<8050e8a8>] at803x_config_intr+0x5c/0xd0 + [<80504b34>] phy_request_interrupt+0xa8/0xd0 + [<8050289c>] phylink_bringup_phy+0x2d8/0x3ac + [<80502b68>] phylink_fwnode_phy_connect+0x118/0x130 + [<8074d8ec>] dsa_slave_create+0x270/0x420 + [<80743b04>] dsa_port_setup+0x12c/0x148 + [<8074580c>] dsa_register_switch+0xaf0/0xcc0 + [<80511344>] ar9331_sw_probe+0x370/0x388 + [<8050cb78>] mdio_probe+0x44/0x70 + [<804df300>] really_probe+0x200/0x424 + [<804df7b4>] __driver_probe_device+0x290/0x298 + [<804df810>] driver_probe_device+0x54/0xe4 + [<804dfd50>] __device_attach_driver+0xe4/0x130 + [<804dcb00>] bus_for_each_drv+0xb4/0xd8 + [<804dfac4>] __device_attach+0x104/0x1a4 + [<804ddd24>] bus_probe_device+0x48/0xc4 + [<804deb44>] deferred_probe_work_func+0xf0/0x10c + [<800a0ffc>] process_one_work+0x314/0x4d4 + [<800a17fc>] worker_thread+0x2a4/0x354 + [<800a9a54>] kthread+0x134/0x13c + [<8006306c>] ret_from_kernel_thread+0x14/0x1c + +Same Issue would affect some other PHYs (QCA8081, QCA9561), so fix it +too. + +Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") +Signed-off-by: Oleksij Rempel +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/at803x.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -1594,6 +1594,8 @@ static struct phy_driver at803x_driver[] + /* ATHEROS AR9331 */ + PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), + .name = "Qualcomm Atheros AR9331 built-in PHY", ++ .probe = at803x_probe, ++ .remove = at803x_remove, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, diff --git a/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch b/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch new file mode 100644 index 00000000000..cdae5b4ca42 --- /dev/null +++ b/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch @@ -0,0 +1,31 @@ +From 1f0dd412e34e177621769866bef347f0b22364df Mon Sep 17 00:00:00 2001 +From: Wei Yongjun +Date: Fri, 18 Nov 2022 10:36:35 +0000 +Subject: [PATCH] net: phy: at803x: fix error return code in at803x_probe() + +Fix to return a negative error code from the ccr read error handling +case instead of 0, as done elsewhere in this function. + +Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") +Signed-off-by: Wei Yongjun +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20221118103635.254256-1-weiyongjun@huaweicloud.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/at803x.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/at803x.c ++++ b/drivers/net/phy/at803x.c +@@ -749,8 +749,10 @@ static int at803x_probe(struct phy_devic + int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + int mode_cfg; + +- if (ccr < 0) ++ if (ccr < 0) { ++ ret = ccr; + goto err; ++ } + mode_cfg = ccr & AT803X_MODE_CFG_MASK; + + switch (mode_cfg) { diff --git a/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch b/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch new file mode 100644 index 00000000000..44f0864e9a8 --- /dev/null +++ b/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch @@ -0,0 +1,80 @@ +From 789d3eeb2367f92193a0882f7cdab03f0f9d6930 Mon Sep 17 00:00:00 2001 +From: Thomas Perrot +Date: Thu, 16 Dec 2021 13:42:27 +0530 +Subject: [PATCH] bus: mhi: pci_generic: Introduce Sierra EM919X support + +Add support for EM919X modems, this modem series is based on SDX55 +qcom chip. + +It is mandatory to use the same ring for control+data and diag events. + +Link: https://lore.kernel.org/r/20211123081541.648426-1-thomas.perrot@bootlin.com +Tested-by: Aleksander Morgado +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Thomas Perrot +Signed-off-by: Manivannan Sadhasivam +Link: https://lore.kernel.org/r/20211216081227.237749-11-manivannan.sadhasivam@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/bus/mhi/host/pci_generic.c | 43 +++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -406,6 +406,46 @@ static const struct mhi_pci_dev_info mhi + .mru_default = 32768, + }; + ++static const struct mhi_channel_config mhi_sierra_em919x_channels[] = { ++ MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), ++ MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 256, 0), ++ MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 0), ++ MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 0), ++ MHI_CHANNEL_CONFIG_UL(12, "MBIM", 128, 0), ++ MHI_CHANNEL_CONFIG_DL(13, "MBIM", 128, 0), ++ MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), ++ MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), ++ MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), ++ MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), ++ MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 512, 1), ++ MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 512, 2), ++}; ++ ++static struct mhi_event_config modem_sierra_em919x_mhi_events[] = { ++ /* first ring is control+data and DIAG ring */ ++ MHI_EVENT_CONFIG_CTRL(0, 2048), ++ /* Hardware channels request dedicated hardware event rings */ ++ MHI_EVENT_CONFIG_HW_DATA(1, 2048, 100), ++ MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) ++}; ++ ++static const struct mhi_controller_config modem_sierra_em919x_config = { ++ .max_channels = 128, ++ .timeout_ms = 24000, ++ .num_channels = ARRAY_SIZE(mhi_sierra_em919x_channels), ++ .ch_cfg = mhi_sierra_em919x_channels, ++ .num_events = ARRAY_SIZE(modem_sierra_em919x_mhi_events), ++ .event_cfg = modem_sierra_em919x_mhi_events, ++}; ++ ++static const struct mhi_pci_dev_info mhi_sierra_em919x_info = { ++ .name = "sierra-em919x", ++ .config = &modem_sierra_em919x_config, ++ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, ++ .dma_data_width = 32, ++ .sideband_wake = false, ++}; ++ + static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = { + MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), + MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), +@@ -480,6 +520,9 @@ static const struct mhi_pci_dev_info mhi + }; + + static const struct pci_device_id mhi_pci_id_table[] = { ++ /* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */ ++ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200), ++ .driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info }, + /* Telit FN980 hardware revision v1 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000), + .driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info }, diff --git a/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch b/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch new file mode 100644 index 00000000000..3c71a27b798 --- /dev/null +++ b/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch @@ -0,0 +1,37 @@ +From f369e9ad52ec9361827e21a631b7198c9fca438e Mon Sep 17 00:00:00 2001 +From: Koen Vandeputte +Date: Wed, 31 Aug 2022 12:03:49 +0200 +Subject: [PATCH] bus: mhi: host: always print detected modem name + +This harmless print provides a very easy way of knowing +if the modem is detected properly during probing. + +Promote it to an informational print so no hassle is required +enabling kernel debugging info to obtain it. + +The rationale here is that: +On a lot of low-storage embedded devices, extensive kernel +debugging info is not always present as this would +increase it's size to much causing partition size issues. + +Signed-off-by: Koen Vandeputte +Reviewed-by: Manivannan Sadhasivam +Reviewed-by: Loic Poulain +Link: https://lore.kernel.org/r/20220831100349.1488762-1-koen.vandeputte@citymesh.com +[mani: added missing review tags] +Signed-off-by: Manivannan Sadhasivam +--- + drivers/bus/mhi/host/pci_generic.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/bus/mhi/host/pci_generic.c ++++ b/drivers/bus/mhi/host/pci_generic.c +@@ -806,7 +806,7 @@ static int mhi_pci_probe(struct pci_dev + struct mhi_controller *mhi_cntrl; + int err; + +- dev_dbg(&pdev->dev, "MHI PCI device found: %s\n", info->name); ++ dev_info(&pdev->dev, "MHI PCI device found: %s\n", info->name); + + /* mhi_pdev.mhi_cntrl must be zero-initialized */ + mhi_pdev = devm_kzalloc(&pdev->dev, sizeof(*mhi_pdev), GFP_KERNEL); diff --git a/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch b/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch new file mode 100644 index 00000000000..ebfbaccc9d7 --- /dev/null +++ b/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch @@ -0,0 +1,130 @@ +From e19de30d20809af3221ef8a2648b8a8a52e02d90 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 21 Sep 2022 01:23:14 +0100 +Subject: [PATCH 1/1] net: dsa: mt7530: add support for in-band link status + +Read link status from SGMII PCS for in-band managed 2500Base-X and +1000Base-X connection on a MAC port of the MT7531. This is needed to +get the SFP cage working which is connected to SGMII interface of +port 5 of the MT7531 switch IC on the Bananapi BPi-R3 board. +While at it also handle an_complete for both the autoneg and the +non-autoneg codepath. + +Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 50 +++++++++++++++++++++++++++++----------- + drivers/net/dsa/mt7530.h | 1 + + 2 files changed, 38 insertions(+), 13 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2721,9 +2721,6 @@ mt7531_mac_config(struct dsa_switch *ds, + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- if (phylink_autoneg_inband(mode)) +- return -EINVAL; +- + return mt7531_sgmii_setup_mode_force(priv, port, interface); + default: + return -EINVAL; +@@ -2799,13 +2796,6 @@ unsupported: + return; + } + +- if (phylink_autoneg_inband(mode) && +- state->interface != PHY_INTERFACE_MODE_SGMII) { +- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", +- __func__); +- return; +- } +- + mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); + mcr_new = mcr_cur; + mcr_new &= ~PMCR_LINK_SETTINGS_MASK; +@@ -2942,6 +2932,9 @@ static void mt753x_phylink_get_caps(stru + config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | + MAC_10 | MAC_100 | MAC_1000FD; + ++ if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port)) ++ config->mac_capabilities |= MAC_2500FD; ++ + /* This driver does not make use of the speed, duplex, pause or the + * advertisement in its mac_config, so it is safe to mark this driver + * as non-legacy. +@@ -3007,6 +3000,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 + + status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); + state->link = !!(status & MT7531_SGMII_LINK_STATUS); ++ state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); + if (state->interface == PHY_INTERFACE_MODE_SGMII && + (status & MT7531_SGMII_AN_ENABLE)) { + val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); +@@ -3037,16 +3031,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 + return 0; + } + ++static void ++mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, ++ struct phylink_link_state *state) ++{ ++ unsigned int val; ++ ++ val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); ++ state->link = !!(val & MT7531_SGMII_LINK_STATUS); ++ if (!state->link) ++ return; ++ ++ state->an_complete = state->link; ++ ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) ++ state->speed = SPEED_2500; ++ else ++ state->speed = SPEED_1000; ++ ++ state->duplex = DUPLEX_FULL; ++ state->pause = MLO_PAUSE_NONE; ++} ++ + static void mt7531_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) + { + struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; + int port = pcs_to_mt753x_pcs(pcs)->port; + +- if (state->interface == PHY_INTERFACE_MODE_SGMII) ++ if (state->interface == PHY_INTERFACE_MODE_SGMII) { + mt7531_sgmii_pcs_get_state_an(priv, port, state); +- else +- state->link = false; ++ return; ++ } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || ++ (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { ++ mt7531_sgmii_pcs_get_state_inband(priv, port, state); ++ return; ++ } ++ ++ state->link = false; + } + + static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -3087,6 +3109,8 @@ mt753x_setup(struct dsa_switch *ds) + priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].priv = priv; + priv->pcs[i].port = i; ++ if (mt753x_is_mac_port(i)) ++ priv->pcs[i].pcs.poll = 1; + } + + ret = priv->info->sw_setup(ds); +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -373,6 +373,7 @@ enum mt7530_vlan_port_acc_frm { + #define MT7531_SGMII_LINK_STATUS BIT(18) + #define MT7531_SGMII_AN_ENABLE BIT(12) + #define MT7531_SGMII_AN_RESTART BIT(9) ++#define MT7531_SGMII_AN_COMPLETE BIT(21) + + /* Register for SGMII PCS_SPPED_ABILITY */ + #define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) diff --git a/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch b/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch new file mode 100644 index 00000000000..77cd336d364 --- /dev/null +++ b/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch @@ -0,0 +1,98 @@ +From 8475c4b70b040f9d8cbc308100f2c4d865f810b3 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 13 Sep 2022 20:06:27 +0100 +Subject: [PATCH 1/1] net: sfp: re-implement soft state polling setup + +Re-implement the decision making for soft state polling. Instead of +generating the soft state mask in sfp_soft_start_poll() by looking at +which GPIOs are available, record their availability in +sfp_sm_mod_probe() in sfp->state_hw_mask. + +This will then allow us to clear bits in sfp->state_hw_mask in module +specific quirks when the hardware signals should not be used, thereby +allowing us to switch to using the software state polling. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 12 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -240,6 +240,7 @@ struct sfp { + bool need_poll; + + struct mutex st_mutex; /* Protects state */ ++ unsigned int state_hw_mask; + unsigned int state_soft_mask; + unsigned int state; + struct delayed_work poll; +@@ -505,17 +506,18 @@ static void sfp_soft_set_state(struct sf + static void sfp_soft_start_poll(struct sfp *sfp) + { + const struct sfp_eeprom_id *id = &sfp->id; ++ unsigned int mask = 0; + + sfp->state_soft_mask = 0; +- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && +- !sfp->gpio[GPIO_TX_DISABLE]) +- sfp->state_soft_mask |= SFP_F_TX_DISABLE; +- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && +- !sfp->gpio[GPIO_TX_FAULT]) +- sfp->state_soft_mask |= SFP_F_TX_FAULT; +- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && +- !sfp->gpio[GPIO_LOS]) +- sfp->state_soft_mask |= SFP_F_LOS; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE) ++ mask |= SFP_F_TX_DISABLE; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT) ++ mask |= SFP_F_TX_FAULT; ++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) ++ mask |= SFP_F_LOS; ++ ++ // Poll the soft state for hardware pins we want to ignore ++ sfp->state_soft_mask = ~sfp->state_hw_mask & mask; + + if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && + !sfp->need_poll) +@@ -529,10 +531,11 @@ static void sfp_soft_stop_poll(struct sf + + static unsigned int sfp_get_state(struct sfp *sfp) + { +- unsigned int state = sfp->get_state(sfp); ++ unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT); ++ unsigned int state; + +- if (state & SFP_F_PRESENT && +- sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) ++ state = sfp->get_state(sfp) & sfp->state_hw_mask; ++ if (state & SFP_F_PRESENT && soft) + state |= sfp_soft_get_state(sfp); + + return state; +@@ -1942,6 +1945,15 @@ static int sfp_sm_mod_probe(struct sfp * + if (ret < 0) + return ret; + ++ /* Initialise state bits to use from hardware */ ++ sfp->state_hw_mask = SFP_F_PRESENT; ++ if (sfp->gpio[GPIO_TX_DISABLE]) ++ sfp->state_hw_mask |= SFP_F_TX_DISABLE; ++ if (sfp->gpio[GPIO_TX_FAULT]) ++ sfp->state_hw_mask |= SFP_F_TX_FAULT; ++ if (sfp->gpio[GPIO_LOS]) ++ sfp->state_hw_mask |= SFP_F_LOS; ++ + if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && + !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) + sfp->module_t_start_up = T_START_UP_BAD_GPON; +@@ -2568,6 +2580,8 @@ static int sfp_probe(struct platform_dev + return PTR_ERR(sfp->gpio[i]); + } + ++ sfp->state_hw_mask = SFP_F_PRESENT; ++ + sfp->get_state = sfp_gpio_get_state; + sfp->set_state = sfp_gpio_set_state; + diff --git a/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch b/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch new file mode 100644 index 00000000000..02fa28c5af2 --- /dev/null +++ b/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch @@ -0,0 +1,291 @@ +From 23571c7b96437483d28a990c906cc81f5f66374e Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 13 Sep 2022 20:06:32 +0100 +Subject: [PATCH 1/1] net: sfp: move quirk handling into sfp.c + +We need to handle more quirks than just those which affect the link +modes of the module. Move the quirk lookup into sfp.c, and pass the +quirk to sfp-bus.c + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp-bus.c | 98 ++------------------------------------- + drivers/net/phy/sfp.c | 94 ++++++++++++++++++++++++++++++++++++- + drivers/net/phy/sfp.h | 9 +++- + 3 files changed, 104 insertions(+), 97 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -10,12 +10,6 @@ + + #include "sfp.h" + +-struct sfp_quirk { +- const char *vendor; +- const char *part; +- void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); +-}; +- + /** + * struct sfp_bus - internal representation of a sfp bus + */ +@@ -38,93 +32,6 @@ struct sfp_bus { + bool started; + }; + +-static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, +- unsigned long *modes) +-{ +- phylink_set(modes, 2500baseX_Full); +-} +- +-static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, +- unsigned long *modes) +-{ +- /* Ubiquiti U-Fiber Instant module claims that support all transceiver +- * types including 10G Ethernet which is not truth. So clear all claimed +- * modes and set only one mode which module supports: 1000baseX_Full. +- */ +- phylink_zero(modes); +- phylink_set(modes, 1000baseX_Full); +-} +- +-static const struct sfp_quirk sfp_quirks[] = { +- { +- // Alcatel Lucent G-010S-P can operate at 2500base-X, but +- // incorrectly report 2500MBd NRZ in their EEPROM +- .vendor = "ALCATELLUCENT", +- .part = "G010SP", +- .modes = sfp_quirk_2500basex, +- }, { +- // Alcatel Lucent G-010S-A can operate at 2500base-X, but +- // report 3.2GBd NRZ in their EEPROM +- .vendor = "ALCATELLUCENT", +- .part = "3FE46541AA", +- .modes = sfp_quirk_2500basex, +- }, { +- // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd +- // NRZ in their EEPROM +- .vendor = "HUAWEI", +- .part = "MA5671A", +- .modes = sfp_quirk_2500basex, +- }, { +- // Lantech 8330-262D-E can operate at 2500base-X, but +- // incorrectly report 2500MBd NRZ in their EEPROM +- .vendor = "Lantech", +- .part = "8330-262D-E", +- .modes = sfp_quirk_2500basex, +- }, { +- .vendor = "UBNT", +- .part = "UF-INSTANT", +- .modes = sfp_quirk_ubnt_uf_instant, +- }, +-}; +- +-static size_t sfp_strlen(const char *str, size_t maxlen) +-{ +- size_t size, i; +- +- /* Trailing characters should be filled with space chars */ +- for (i = 0, size = 0; i < maxlen; i++) +- if (str[i] != ' ') +- size = i + 1; +- +- return size; +-} +- +-static bool sfp_match(const char *qs, const char *str, size_t len) +-{ +- if (!qs) +- return true; +- if (strlen(qs) != len) +- return false; +- return !strncmp(qs, str, len); +-} +- +-static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id) +-{ +- const struct sfp_quirk *q; +- unsigned int i; +- size_t vs, ps; +- +- vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name)); +- ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn)); +- +- for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++) +- if (sfp_match(q->vendor, id->base.vendor_name, vs) && +- sfp_match(q->part, id->base.vendor_pn, ps)) +- return q; +- +- return NULL; +-} +- + /** + * sfp_parse_port() - Parse the EEPROM base ID, setting the port type + * @bus: a pointer to the &struct sfp_bus structure for the sfp module +@@ -786,12 +693,13 @@ void sfp_link_down(struct sfp_bus *bus) + } + EXPORT_SYMBOL_GPL(sfp_link_down); + +-int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id) ++int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ++ const struct sfp_quirk *quirk) + { + const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); + int ret = 0; + +- bus->sfp_quirk = sfp_lookup_quirk(id); ++ bus->sfp_quirk = quirk; + + if (ops && ops->module_insert) + ret = ops->module_insert(bus->upstream, id); +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -259,6 +259,8 @@ struct sfp { + unsigned int module_t_start_up; + bool tx_fault_ignore; + ++ const struct sfp_quirk *quirk; ++ + #if IS_ENABLED(CONFIG_HWMON) + struct sfp_diag diag; + struct delayed_work hwmon_probe; +@@ -315,6 +317,93 @@ static const struct of_device_id sfp_of_ + }; + MODULE_DEVICE_TABLE(of, sfp_of_match); + ++static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, ++ unsigned long *modes) ++{ ++ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes); ++} ++ ++static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, ++ unsigned long *modes) ++{ ++ /* Ubiquiti U-Fiber Instant module claims that support all transceiver ++ * types including 10G Ethernet which is not truth. So clear all claimed ++ * modes and set only one mode which module supports: 1000baseX_Full. ++ */ ++ linkmode_zero(modes); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes); ++} ++ ++static const struct sfp_quirk sfp_quirks[] = { ++ { ++ // Alcatel Lucent G-010S-P can operate at 2500base-X, but ++ // incorrectly report 2500MBd NRZ in their EEPROM ++ .vendor = "ALCATELLUCENT", ++ .part = "G010SP", ++ .modes = sfp_quirk_2500basex, ++ }, { ++ // Alcatel Lucent G-010S-A can operate at 2500base-X, but ++ // report 3.2GBd NRZ in their EEPROM ++ .vendor = "ALCATELLUCENT", ++ .part = "3FE46541AA", ++ .modes = sfp_quirk_2500basex, ++ }, { ++ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd ++ // NRZ in their EEPROM ++ .vendor = "HUAWEI", ++ .part = "MA5671A", ++ .modes = sfp_quirk_2500basex, ++ }, { ++ // Lantech 8330-262D-E can operate at 2500base-X, but ++ // incorrectly report 2500MBd NRZ in their EEPROM ++ .vendor = "Lantech", ++ .part = "8330-262D-E", ++ .modes = sfp_quirk_2500basex, ++ }, { ++ .vendor = "UBNT", ++ .part = "UF-INSTANT", ++ .modes = sfp_quirk_ubnt_uf_instant, ++ }, ++}; ++ ++static size_t sfp_strlen(const char *str, size_t maxlen) ++{ ++ size_t size, i; ++ ++ /* Trailing characters should be filled with space chars */ ++ for (i = 0, size = 0; i < maxlen; i++) ++ if (str[i] != ' ') ++ size = i + 1; ++ ++ return size; ++} ++ ++static bool sfp_match(const char *qs, const char *str, size_t len) ++{ ++ if (!qs) ++ return true; ++ if (strlen(qs) != len) ++ return false; ++ return !strncmp(qs, str, len); ++} ++ ++static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id) ++{ ++ const struct sfp_quirk *q; ++ unsigned int i; ++ size_t vs, ps; ++ ++ vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name)); ++ ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn)); ++ ++ for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++) ++ if (sfp_match(q->vendor, id->base.vendor_name, vs) && ++ sfp_match(q->part, id->base.vendor_pn, ps)) ++ return q; ++ ++ return NULL; ++} ++ + static unsigned long poll_jiffies; + + static unsigned int sfp_gpio_get_state(struct sfp *sfp) +@@ -1966,6 +2055,8 @@ static int sfp_sm_mod_probe(struct sfp * + else + sfp->tx_fault_ignore = false; + ++ sfp->quirk = sfp_lookup_quirk(&id); ++ + return 0; + } + +@@ -2077,7 +2168,8 @@ static void sfp_sm_module(struct sfp *sf + break; + + /* Report the module insertion to the upstream device */ +- err = sfp_module_insert(sfp->sfp_bus, &sfp->id); ++ err = sfp_module_insert(sfp->sfp_bus, &sfp->id, ++ sfp->quirk); + if (err < 0) { + sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); + break; +--- a/drivers/net/phy/sfp.h ++++ b/drivers/net/phy/sfp.h +@@ -6,6 +6,12 @@ + + struct sfp; + ++struct sfp_quirk { ++ const char *vendor; ++ const char *part; ++ void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); ++}; ++ + struct sfp_socket_ops { + void (*attach)(struct sfp *sfp); + void (*detach)(struct sfp *sfp); +@@ -23,7 +29,8 @@ int sfp_add_phy(struct sfp_bus *bus, str + void sfp_remove_phy(struct sfp_bus *bus); + void sfp_link_up(struct sfp_bus *bus); + void sfp_link_down(struct sfp_bus *bus); +-int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id); ++int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ++ const struct sfp_quirk *quirk); + void sfp_module_remove(struct sfp_bus *bus); + int sfp_module_start(struct sfp_bus *bus); + void sfp_module_stop(struct sfp_bus *bus); diff --git a/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch b/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch new file mode 100644 index 00000000000..b076676cff6 --- /dev/null +++ b/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch @@ -0,0 +1,69 @@ +From 275416754e9a262c97a1ad6f806a4bc6e0464aa2 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 13 Sep 2022 20:06:37 +0100 +Subject: [PATCH 1/1] net: sfp: move Alcatel Lucent 3FE46541AA fixup + +Add a new fixup mechanism to the SFP quirks, and use it for this +module. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp.c | 14 +++++++++----- + drivers/net/phy/sfp.h | 1 + + 2 files changed, 10 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -317,6 +317,11 @@ static const struct of_device_id sfp_of_ + }; + MODULE_DEVICE_TABLE(of, sfp_of_match); + ++static void sfp_fixup_long_startup(struct sfp *sfp) ++{ ++ sfp->module_t_start_up = T_START_UP_BAD_GPON; ++} ++ + static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, + unsigned long *modes) + { +@@ -347,6 +352,7 @@ static const struct sfp_quirk sfp_quirks + .vendor = "ALCATELLUCENT", + .part = "3FE46541AA", + .modes = sfp_quirk_2500basex, ++ .fixup = sfp_fixup_long_startup, + }, { + // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd + // NRZ in their EEPROM +@@ -2043,11 +2049,7 @@ static int sfp_sm_mod_probe(struct sfp * + if (sfp->gpio[GPIO_LOS]) + sfp->state_hw_mask |= SFP_F_LOS; + +- if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && +- !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) +- sfp->module_t_start_up = T_START_UP_BAD_GPON; +- else +- sfp->module_t_start_up = T_START_UP; ++ sfp->module_t_start_up = T_START_UP; + + if (!memcmp(id.base.vendor_name, "HUAWEI ", 16) && + !memcmp(id.base.vendor_pn, "MA5671A ", 16)) +@@ -2056,6 +2058,8 @@ static int sfp_sm_mod_probe(struct sfp * + sfp->tx_fault_ignore = false; + + sfp->quirk = sfp_lookup_quirk(&id); ++ if (sfp->quirk && sfp->quirk->fixup) ++ sfp->quirk->fixup(sfp); + + return 0; + } +--- a/drivers/net/phy/sfp.h ++++ b/drivers/net/phy/sfp.h +@@ -10,6 +10,7 @@ struct sfp_quirk { + const char *vendor; + const char *part; + void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); ++ void (*fixup)(struct sfp *sfp); + }; + + struct sfp_socket_ops { diff --git a/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch b/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch new file mode 100644 index 00000000000..7f856e5b5be --- /dev/null +++ b/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch @@ -0,0 +1,48 @@ +From 5029be761161374a3624aa7b4670174c35449bf5 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 13 Sep 2022 20:06:42 +0100 +Subject: [PATCH 1/1] net: sfp: move Huawei MA5671A fixup + +Move this module over to the new fixup mechanism. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -322,6 +322,11 @@ static void sfp_fixup_long_startup(struc + sfp->module_t_start_up = T_START_UP_BAD_GPON; + } + ++static void sfp_fixup_ignore_tx_fault(struct sfp *sfp) ++{ ++ sfp->tx_fault_ignore = true; ++} ++ + static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, + unsigned long *modes) + { +@@ -359,6 +364,7 @@ static const struct sfp_quirk sfp_quirks + .vendor = "HUAWEI", + .part = "MA5671A", + .modes = sfp_quirk_2500basex, ++ .fixup = sfp_fixup_ignore_tx_fault, + }, { + // Lantech 8330-262D-E can operate at 2500base-X, but + // incorrectly report 2500MBd NRZ in their EEPROM +@@ -2051,11 +2057,7 @@ static int sfp_sm_mod_probe(struct sfp * + + sfp->module_t_start_up = T_START_UP; + +- if (!memcmp(id.base.vendor_name, "HUAWEI ", 16) && +- !memcmp(id.base.vendor_pn, "MA5671A ", 16)) +- sfp->tx_fault_ignore = true; +- else +- sfp->tx_fault_ignore = false; ++ sfp->tx_fault_ignore = false; + + sfp->quirk = sfp_lookup_quirk(&id); + if (sfp->quirk && sfp->quirk->fixup) diff --git a/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch b/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch new file mode 100644 index 00000000000..81108e19c16 --- /dev/null +++ b/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch @@ -0,0 +1,79 @@ +From 73472c830eae5fce2107f7f086f1e6827d215caf Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Tue, 13 Sep 2022 20:06:48 +0100 +Subject: [PATCH 1/1] net: sfp: add support for HALNy GPON SFP + +Add a quirk for the HALNy HL-GSFP module, which appears to have an +inverted RX_LOS signal, and maybe uses TX_FAULT as a serial port +transmit pin. Rather than use these hardware signals, switch to +using software polling for these status signals. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/sfp-bus.c | 2 +- + drivers/net/phy/sfp.c | 21 ++++++++++++++++++--- + 2 files changed, 19 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/sfp-bus.c ++++ b/drivers/net/phy/sfp-bus.c +@@ -283,7 +283,7 @@ void sfp_parse_support(struct sfp_bus *b + phylink_set(modes, 2500baseX_Full); + } + +- if (bus->sfp_quirk) ++ if (bus->sfp_quirk && bus->sfp_quirk->modes) + bus->sfp_quirk->modes(id, modes); + + linkmode_or(support, support, modes); +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -327,6 +327,15 @@ static void sfp_fixup_ignore_tx_fault(st + sfp->tx_fault_ignore = true; + } + ++static void sfp_fixup_halny_gsfp(struct sfp *sfp) ++{ ++ /* Ignore the TX_FAULT and LOS signals on this module. ++ * these are possibly used for other purposes on this ++ * module, e.g. a serial port. ++ */ ++ sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS); ++} ++ + static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, + unsigned long *modes) + { +@@ -359,6 +368,10 @@ static const struct sfp_quirk sfp_quirks + .modes = sfp_quirk_2500basex, + .fixup = sfp_fixup_long_startup, + }, { ++ .vendor = "HALNy", ++ .part = "HL-GSFP", ++ .fixup = sfp_fixup_halny_gsfp, ++ }, { + // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd + // NRZ in their EEPROM + .vendor = "HUAWEI", +@@ -375,16 +388,18 @@ static const struct sfp_quirk sfp_quirks + .vendor = "UBNT", + .part = "UF-INSTANT", + .modes = sfp_quirk_ubnt_uf_instant, +- }, ++ } + }; + + static size_t sfp_strlen(const char *str, size_t maxlen) + { + size_t size, i; + +- /* Trailing characters should be filled with space chars */ ++ /* Trailing characters should be filled with space chars, but ++ * some manufacturers can't read SFF-8472 and use NUL. ++ */ + for (i = 0, size = 0; i < maxlen; i++) +- if (str[i] != ' ') ++ if (str[i] != ' ' && str[i] != '\0') + size = i + 1; + + return size; diff --git a/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch b/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch new file mode 100644 index 00000000000..ee12399140b --- /dev/null +++ b/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch @@ -0,0 +1,514 @@ +From patchwork Thu Mar 9 10:57:44 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 13167235 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +Date: Thu, 9 Mar 2023 10:57:44 +0000 +From: Daniel Golle +To: netdev@vger.kernel.org, linux-mediatek@lists.infradead.org, + linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, + Russell King , + Heiner Kallweit , + Lorenzo Bianconi , + Mark Lee , + John Crispin , Felix Fietkau , + AngeloGioacchino Del Regno + , + Matthias Brugger , + DENG Qingfang , + Landen Chao , + Sean Wang , + Paolo Abeni , + Jakub Kicinski , + Eric Dumazet , + "David S. Miller" , + Vladimir Oltean , + Florian Fainelli , + Andrew Lunn , + Vladimir Oltean +Cc: =?iso-8859-1?q?Bj=F8rn?= Mork , + Frank Wunderlich , + Alexander Couzens +Subject: [PATCH net-next v13 11/16] net: dsa: mt7530: use external PCS driver +Message-ID: + <2ac2ee40d3b0e705461b50613fda6a7edfdbc4b3.1678357225.git.daniel@makrotopia.org> +References: +MIME-Version: 1.0 +Content-Disposition: inline +In-Reply-To: +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +Implement regmap access wrappers, for now only to be used by the +pcs-mtk driver. +Make use of external PCS driver and drop the reduntant implementation +in mt7530.c. +As a nice side effect the SGMII registers can now also more easily be +inspected for debugging via /sys/kernel/debug/regmap. + +Reviewed-by: Russell King (Oracle) +Tested-by: Bjørn Mork +Signed-off-by: Daniel Golle +Tested-by: Frank Wunderlich +--- + drivers/net/dsa/Kconfig | 1 + + drivers/net/dsa/mt7530.c | 277 ++++++++++----------------------------- + drivers/net/dsa/mt7530.h | 47 +------ + 3 files changed, 71 insertions(+), 254 deletions(-) + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -37,6 +37,7 @@ config NET_DSA_MT7530 + tristate "MediaTek MT753x and MT7621 Ethernet switch support" + select NET_DSA_TAG_MTK + select MEDIATEK_GE_PHY ++ select PCS_MTK_LYNXI + help + This enables support for the MediaTek MT7530, MT7531, and MT7621 + Ethernet switch chips. +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2573,128 +2574,11 @@ static int mt7531_rgmii_setup(struct mt7 + return 0; + } + +-static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, +- phy_interface_t interface, int speed, int duplex) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- unsigned int val; +- +- /* For adjusting speed and duplex of SGMII force mode. */ +- if (interface != PHY_INTERFACE_MODE_SGMII || +- phylink_autoneg_inband(mode)) +- return; +- +- /* SGMII force mode setting */ +- val = mt7530_read(priv, MT7531_SGMII_MODE(port)); +- val &= ~MT7531_SGMII_IF_MODE_MASK; +- +- switch (speed) { +- case SPEED_10: +- val |= MT7531_SGMII_FORCE_SPEED_10; +- break; +- case SPEED_100: +- val |= MT7531_SGMII_FORCE_SPEED_100; +- break; +- case SPEED_1000: +- val |= MT7531_SGMII_FORCE_SPEED_1000; +- break; +- } +- +- /* MT7531 SGMII 1G force mode can only work in full duplex mode, +- * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. +- * +- * The speed check is unnecessary as the MAC capabilities apply +- * this restriction. --rmk +- */ +- if ((speed == SPEED_10 || speed == SPEED_100) && +- duplex != DUPLEX_FULL) +- val |= MT7531_SGMII_FORCE_HALF_DUPLEX; +- +- mt7530_write(priv, MT7531_SGMII_MODE(port), val); +-} +- + static bool mt753x_is_mac_port(u32 port) + { + return (port == 5 || port == 6); + } + +-static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port, +- phy_interface_t interface) +-{ +- u32 val; +- +- if (!mt753x_is_mac_port(port)) +- return -EINVAL; +- +- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), +- MT7531_SGMII_PHYA_PWD); +- +- val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port)); +- val &= ~MT7531_RG_TPHY_SPEED_MASK; +- /* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B +- * encoding. +- */ +- val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ? +- MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G; +- mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val); +- +- mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); +- +- /* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex +- * mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. +- */ +- mt7530_rmw(priv, MT7531_SGMII_MODE(port), +- MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS, +- MT7531_SGMII_FORCE_SPEED_1000); +- +- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); +- +- return 0; +-} +- +-static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port, +- phy_interface_t interface) +-{ +- if (!mt753x_is_mac_port(port)) +- return -EINVAL; +- +- mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port), +- MT7531_SGMII_PHYA_PWD); +- +- mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), +- MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G); +- +- mt7530_set(priv, MT7531_SGMII_MODE(port), +- MT7531_SGMII_REMOTE_FAULT_DIS | +- MT7531_SGMII_SPEED_DUPLEX_AN); +- +- mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port), +- MT7531_SGMII_TX_CONFIG_MASK, 1); +- +- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE); +- +- mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART); +- +- mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0); +- +- return 0; +-} +- +-static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- u32 val; +- +- /* Only restart AN when AN is enabled */ +- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- if (val & MT7531_SGMII_AN_ENABLE) { +- val |= MT7531_SGMII_AN_RESTART; +- mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val); +- } +-} +- + static int + mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface) +@@ -2717,11 +2601,11 @@ mt7531_mac_config(struct dsa_switch *ds, + phydev = dp->slave->phydev; + return mt7531_rgmii_setup(priv, port, interface, phydev); + case PHY_INTERFACE_MODE_SGMII: +- return mt7531_sgmii_setup_mode_an(priv, port, interface); + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- return mt7531_sgmii_setup_mode_force(priv, port, interface); ++ /* handled in SGMII PCS driver */ ++ return 0; + default: + return -EINVAL; + } +@@ -2746,11 +2630,11 @@ mt753x_phylink_mac_select_pcs(struct dsa + + switch (interface) { + case PHY_INTERFACE_MODE_TRGMII: ++ return &priv->pcs[port].pcs; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: +- return &priv->pcs[port].pcs; +- ++ return priv->ports[port].sgmii_pcs; + default: + return NULL; + } +@@ -2991,86 +2875,6 @@ static void mt7530_pcs_get_state(struct + state->pause |= MLO_PAUSE_TX; + } + +-static int +-mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port, +- struct phylink_link_state *state) +-{ +- u32 status, val; +- u16 config_reg; +- +- status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- state->link = !!(status & MT7531_SGMII_LINK_STATUS); +- state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); +- if (state->interface == PHY_INTERFACE_MODE_SGMII && +- (status & MT7531_SGMII_AN_ENABLE)) { +- val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); +- config_reg = val >> 16; +- +- switch (config_reg & LPA_SGMII_SPD_MASK) { +- case LPA_SGMII_1000: +- state->speed = SPEED_1000; +- break; +- case LPA_SGMII_100: +- state->speed = SPEED_100; +- break; +- case LPA_SGMII_10: +- state->speed = SPEED_10; +- break; +- default: +- dev_err(priv->dev, "invalid sgmii PHY speed\n"); +- state->link = false; +- return -EINVAL; +- } +- +- if (config_reg & LPA_SGMII_FULL_DUPLEX) +- state->duplex = DUPLEX_FULL; +- else +- state->duplex = DUPLEX_HALF; +- } +- +- return 0; +-} +- +-static void +-mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, +- struct phylink_link_state *state) +-{ +- unsigned int val; +- +- val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); +- state->link = !!(val & MT7531_SGMII_LINK_STATUS); +- if (!state->link) +- return; +- +- state->an_complete = state->link; +- +- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) +- state->speed = SPEED_2500; +- else +- state->speed = SPEED_1000; +- +- state->duplex = DUPLEX_FULL; +- state->pause = MLO_PAUSE_NONE; +-} +- +-static void mt7531_pcs_get_state(struct phylink_pcs *pcs, +- struct phylink_link_state *state) +-{ +- struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; +- int port = pcs_to_mt753x_pcs(pcs)->port; +- +- if (state->interface == PHY_INTERFACE_MODE_SGMII) { +- mt7531_sgmii_pcs_get_state_an(priv, port, state); +- return; +- } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || +- (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { +- mt7531_sgmii_pcs_get_state_inband(priv, port, state); +- return; +- } +- +- state->link = false; +-} +- + static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, +@@ -3090,18 +2894,57 @@ static const struct phylink_pcs_ops mt75 + .pcs_an_restart = mt7530_pcs_an_restart, + }; + +-static const struct phylink_pcs_ops mt7531_pcs_ops = { +- .pcs_validate = mt753x_pcs_validate, +- .pcs_get_state = mt7531_pcs_get_state, +- .pcs_config = mt753x_pcs_config, +- .pcs_an_restart = mt7531_pcs_an_restart, +- .pcs_link_up = mt7531_pcs_link_up, ++static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ *val = mt7530_read(priv, reg); ++ return 0; ++}; ++ ++static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ mt7530_write(priv, reg, val); ++ return 0; ++}; ++ ++static int mt7530_regmap_update_bits(void *context, unsigned int reg, ++ unsigned int mask, unsigned int val) ++{ ++ struct mt7530_priv *priv = context; ++ ++ mt7530_rmw(priv, reg, mask, val); ++ return 0; ++}; ++ ++static const struct regmap_bus mt7531_regmap_bus = { ++ .reg_write = mt7530_regmap_write, ++ .reg_read = mt7530_regmap_read, ++ .reg_update_bits = mt7530_regmap_update_bits, ++}; ++ ++#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \ ++ { \ ++ .name = _name, \ ++ .reg_bits = 16, \ ++ .val_bits = 32, \ ++ .reg_stride = 4, \ ++ .reg_base = _reg_base, \ ++ .max_register = 0x17c, \ ++ } ++ ++static const struct regmap_config mt7531_pcs_config[] = { ++ MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)), ++ MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)), + }; + + static int + mt753x_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; ++ struct regmap *regmap; + int i, ret; + + /* Initialise the PCS devices */ +@@ -3109,8 +2952,6 @@ mt753x_setup(struct dsa_switch *ds) + priv->pcs[i].pcs.ops = priv->info->pcs_ops; + priv->pcs[i].priv = priv; + priv->pcs[i].port = i; +- if (mt753x_is_mac_port(i)) +- priv->pcs[i].pcs.poll = 1; + } + + ret = priv->info->sw_setup(ds); +@@ -3125,6 +2966,16 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + ++ if (priv->id == ID_MT7531) ++ for (i = 0; i < 2; i++) { ++ regmap = devm_regmap_init(ds->dev, ++ &mt7531_regmap_bus, priv, ++ &mt7531_pcs_config[i]); ++ priv->ports[5 + i].sgmii_pcs = ++ mtk_pcs_lynxi_create(ds->dev, regmap, ++ MT7531_PHYA_CTRL_SIGNAL3, 0); ++ } ++ + return ret; + } + +@@ -3216,7 +3067,7 @@ static const struct mt753x_info mt753x_t + }, + [ID_MT7531] = { + .id = ID_MT7531, +- .pcs_ops = &mt7531_pcs_ops, ++ .pcs_ops = &mt7530_pcs_ops, + .sw_setup = mt7531_setup, + .phy_read = mt7531_ind_phy_read, + .phy_write = mt7531_ind_phy_write, +@@ -3324,7 +3175,7 @@ static void + mt7530_remove(struct mdio_device *mdiodev) + { + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); +- int ret = 0; ++ int ret = 0, i; + + if (!priv) + return; +@@ -3343,6 +3194,10 @@ mt7530_remove(struct mdio_device *mdiode + mt7530_free_irq(priv); + + dsa_unregister_switch(priv->ds); ++ ++ for (i = 0; i < 2; ++i) ++ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); ++ + mutex_destroy(&priv->reg_mutex); + + dev_set_drvdata(&mdiodev->dev, NULL); +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm { + CCR_TX_OCT_CNT_BAD) + + /* MT7531 SGMII register group */ +-#define MT7531_SGMII_REG_BASE 0x5000 +-#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \ +- ((p) - 5) * 0x1000 + (r)) +- +-/* Register forSGMII PCS_CONTROL_1 */ +-#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00) +-#define MT7531_SGMII_LINK_STATUS BIT(18) +-#define MT7531_SGMII_AN_ENABLE BIT(12) +-#define MT7531_SGMII_AN_RESTART BIT(9) +-#define MT7531_SGMII_AN_COMPLETE BIT(21) +- +-/* Register for SGMII PCS_SPPED_ABILITY */ +-#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) +-#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0) +-#define MT7531_SGMII_TX_CONFIG BIT(0) +- +-/* Register for SGMII_MODE */ +-#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20) +-#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8) +-#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1) +-#define MT7531_SGMII_FORCE_DUPLEX BIT(4) +-#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2) +-#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3) +-#define MT7531_SGMII_FORCE_SPEED_100 BIT(2) +-#define MT7531_SGMII_FORCE_SPEED_10 0 +-#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1) +- +-enum mt7531_sgmii_force_duplex { +- MT7531_SGMII_FORCE_FULL_DUPLEX = 0, +- MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10, +-}; +- +-/* Fields of QPHY_PWR_STATE_CTRL */ +-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8) +-#define MT7531_SGMII_PHYA_PWD BIT(4) +- +-/* Values of SGMII SPEED */ +-#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128) +-#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3)) +-#define MT7531_RG_TPHY_SPEED_1_25G 0x0 +-#define MT7531_RG_TPHY_SPEED_3_125G BIT(2) ++#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000) ++#define MT7531_PHYA_CTRL_SIGNAL3 0x128 + + /* Register for system reset */ + #define MT7530_SYS_CTRL 0x7000 +@@ -703,13 +664,13 @@ struct mt7530_fdb { + * @pm: The matrix used to show all connections with the port. + * @pvid: The VLAN specified is to be considered a PVID at ingress. Any + * untagged frames will be assigned to the related VLAN. +- * @vlan_filtering: The flags indicating whether the port that can recognize +- * VLAN-tagged frames. ++ * @sgmii_pcs: Pointer to PCS instance for SerDes ports + */ + struct mt7530_port { + bool enable; + u32 pm; + u16 pvid; ++ struct phylink_pcs *sgmii_pcs; + }; + + /* Port 5 interface select definitions */ diff --git a/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch b/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch new file mode 100644 index 00000000000..413c73f5478 --- /dev/null +++ b/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch @@ -0,0 +1,37 @@ +From ad651d68cee75e9ac20002254c4e5d09ee67a84b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 2 Apr 2023 12:44:37 +0100 +Subject: [PATCH] net: sfp: add quirk enabling 2500Base-x for HG MXPD-483II + +The HG MXPD-483II 1310nm SFP module is meant to operate with 2500Base-X, +however, in their EEPROM they incorrectly specify: + Transceiver type : Ethernet: 1000BASE-LX + ... + BR, Nominal : 2600MBd + +Use sfp_quirk_2500basex for this module to allow 2500Base-X mode anyway. + +https://forum.banana-pi.org/t/bpi-r3-sfp-module-compatibility/14573/60 + +Reported-by: chowtom +Tested-by: chowtom +Signed-off-by: Daniel Golle +Reviewed-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + drivers/net/phy/sfp.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -372,6 +372,10 @@ static const struct sfp_quirk sfp_quirks + .part = "HL-GSFP", + .fixup = sfp_fixup_halny_gsfp, + }, { ++ .vendor = "HG GENUINE", ++ .part = "MXPD-483II", ++ .modes = sfp_quirk_2500basex, ++ }, { + // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd + // NRZ in their EEPROM + .vendor = "HUAWEI", diff --git a/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch b/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch new file mode 100644 index 00000000000..87d7ff6154d --- /dev/null +++ b/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch @@ -0,0 +1,55 @@ +From bdb6cfe7512f7a214815a3092f0be50963dcacbc Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Sat, 18 Jun 2022 11:28:32 +0100 +Subject: [PATCH] net: mii: add mii_bmcr_encode_fixed() + +Add a function to encode a fixed speed/duplex to a BMCR value. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: David S. Miller +--- + include/linux/mii.h | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +--- a/include/linux/mii.h ++++ b/include/linux/mii.h +@@ -595,4 +595,39 @@ static inline u8 mii_resolve_flowctrl_fd + return cap; + } + ++/** ++ * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value ++ * @speed: a SPEED_* value ++ * @duplex: a DUPLEX_* value ++ * ++ * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are ++ * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10 ++ * Mbps. Unknown duplex values are encoded to half-duplex. ++ */ ++static inline u16 mii_bmcr_encode_fixed(int speed, int duplex) ++{ ++ u16 bmcr; ++ ++ switch (speed) { ++ case SPEED_2500: ++ case SPEED_1000: ++ bmcr = BMCR_SPEED1000; ++ break; ++ ++ case SPEED_100: ++ bmcr = BMCR_SPEED100; ++ break; ++ ++ case SPEED_10: ++ default: ++ bmcr = BMCR_SPEED10; ++ break; ++ } ++ ++ if (duplex == DUPLEX_FULL) ++ bmcr |= BMCR_FULLDPLX; ++ ++ return bmcr; ++} ++ + #endif /* __LINUX_MII_H__ */ diff --git a/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch b/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch new file mode 100644 index 00000000000..57137c34fc6 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch @@ -0,0 +1,1724 @@ +From 70479a40954cf353e87a486997a3477108c75aa9 Mon Sep 17 00:00:00 2001 +From: Frank +Date: Fri, 28 Oct 2022 17:26:21 +0800 +Subject: [PATCH] net: phy: Add driver for Motorcomm yt8521 gigabit ethernet + phy + +Add a driver for the motorcomm yt8521 gigabit ethernet phy. We have verified + the driver on StarFive VisionFive development board, which is developed by + Shanghai StarFive Technology Co., Ltd.. On the board, yt8521 gigabit ethernet + phy works in utp mode, RGMII interface, supports 1000M/100M/10M speeds, and + wol(magic package). + +Signed-off-by: Frank +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + MAINTAINERS | 1 + + drivers/net/phy/Kconfig | 2 +- + drivers/net/phy/motorcomm.c | 1635 ++++++++++++++++++++++++++++++++++- + 3 files changed, 1635 insertions(+), 3 deletions(-) + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -12697,6 +12697,7 @@ F: include/uapi/linux/meye.h + + MOTORCOMM PHY DRIVER + M: Peter Geis ++M: Frank + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/phy/motorcomm.c +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -245,7 +245,7 @@ config MOTORCOMM_PHY + tristate "Motorcomm PHYs" + help + Enables support for Motorcomm network PHYs. +- Currently supports the YT8511 gigabit PHY. ++ Currently supports the YT8511, YT8521 Gigabit Ethernet PHYs. + + config NATIONAL_PHY + tristate "National Semiconductor PHYs" +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1,15 +1,106 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * Driver for Motorcomm PHYs ++ * Motorcomm 8511/8521 PHY driver. + * + * Author: Peter Geis ++ * Author: Frank + */ + ++#include + #include + #include + #include + + #define PHY_ID_YT8511 0x0000010a ++#define PHY_ID_YT8521 0x0000011A ++ ++/* YT8521 Register Overview ++ * UTP Register space | FIBER Register space ++ * ------------------------------------------------------------ ++ * | UTP MII | FIBER MII | ++ * | UTP MMD | | ++ * | UTP Extended | FIBER Extended | ++ * ------------------------------------------------------------ ++ * | Common Extended | ++ * ------------------------------------------------------------ ++ */ ++ ++/* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */ ++ ++/* Specific Function Control Register */ ++#define YTPHY_SPECIFIC_FUNCTION_CONTROL_REG 0x10 ++ ++/* 2b00 Manual MDI configuration ++ * 2b01 Manual MDIX configuration ++ * 2b10 Reserved ++ * 2b11 Enable automatic crossover for all modes *default* ++ */ ++#define YTPHY_SFCR_MDI_CROSSOVER_MODE_MASK (BIT(6) | BIT(5)) ++#define YTPHY_SFCR_CROSSOVER_EN BIT(3) ++#define YTPHY_SFCR_SQE_TEST_EN BIT(2) ++#define YTPHY_SFCR_POLARITY_REVERSAL_EN BIT(1) ++#define YTPHY_SFCR_JABBER_DIS BIT(0) ++ ++/* Specific Status Register */ ++#define YTPHY_SPECIFIC_STATUS_REG 0x11 ++#define YTPHY_SSR_SPEED_MODE_OFFSET 14 ++ ++#define YTPHY_SSR_SPEED_MODE_MASK (BIT(15) | BIT(14)) ++#define YTPHY_SSR_SPEED_10M 0x0 ++#define YTPHY_SSR_SPEED_100M 0x1 ++#define YTPHY_SSR_SPEED_1000M 0x2 ++#define YTPHY_SSR_DUPLEX_OFFSET 13 ++#define YTPHY_SSR_DUPLEX BIT(13) ++#define YTPHY_SSR_PAGE_RECEIVED BIT(12) ++#define YTPHY_SSR_SPEED_DUPLEX_RESOLVED BIT(11) ++#define YTPHY_SSR_LINK BIT(10) ++#define YTPHY_SSR_MDIX_CROSSOVER BIT(6) ++#define YTPHY_SSR_DOWNGRADE BIT(5) ++#define YTPHY_SSR_TRANSMIT_PAUSE BIT(3) ++#define YTPHY_SSR_RECEIVE_PAUSE BIT(2) ++#define YTPHY_SSR_POLARITY BIT(1) ++#define YTPHY_SSR_JABBER BIT(0) ++ ++/* Interrupt enable Register */ ++#define YTPHY_INTERRUPT_ENABLE_REG 0x12 ++#define YTPHY_IER_WOL BIT(6) ++ ++/* Interrupt Status Register */ ++#define YTPHY_INTERRUPT_STATUS_REG 0x13 ++#define YTPHY_ISR_AUTONEG_ERR BIT(15) ++#define YTPHY_ISR_SPEED_CHANGED BIT(14) ++#define YTPHY_ISR_DUPLEX_CHANGED BIT(13) ++#define YTPHY_ISR_PAGE_RECEIVED BIT(12) ++#define YTPHY_ISR_LINK_FAILED BIT(11) ++#define YTPHY_ISR_LINK_SUCCESSED BIT(10) ++#define YTPHY_ISR_WOL BIT(6) ++#define YTPHY_ISR_WIRESPEED_DOWNGRADE BIT(5) ++#define YTPHY_ISR_SERDES_LINK_FAILED BIT(3) ++#define YTPHY_ISR_SERDES_LINK_SUCCESSED BIT(2) ++#define YTPHY_ISR_POLARITY_CHANGED BIT(1) ++#define YTPHY_ISR_JABBER_HAPPENED BIT(0) ++ ++/* Speed Auto Downgrade Control Register */ ++#define YTPHY_SPEED_AUTO_DOWNGRADE_CONTROL_REG 0x14 ++#define YTPHY_SADCR_SPEED_DOWNGRADE_EN BIT(5) ++ ++/* If these bits are set to 3, the PHY attempts five times ( 3(set value) + ++ * additional 2) before downgrading, default 0x3 ++ */ ++#define YTPHY_SADCR_SPEED_RETRY_LIMIT (0x3 << 2) ++ ++/* Rx Error Counter Register */ ++#define YTPHY_RX_ERROR_COUNTER_REG 0x15 ++ ++/* Extended Register's Address Offset Register */ ++#define YTPHY_PAGE_SELECT 0x1E ++ ++/* Extended Register's Data Register */ ++#define YTPHY_PAGE_DATA 0x1F ++ ++/* FIBER Auto-Negotiation link partner ability */ ++#define YTPHY_FLPA_PAUSE (0x3 << 7) ++#define YTPHY_FLPA_ASYM_PAUSE (0x2 << 7) + + #define YT8511_PAGE_SELECT 0x1e + #define YT8511_PAGE 0x1f +@@ -38,6 +129,352 @@ + #define YT8511_DELAY_FE_TX_EN (0xf << 12) + #define YT8511_DELAY_FE_TX_DIS (0x2 << 12) + ++/* Extended register is different from MMD Register and MII Register. ++ * We can use ytphy_read_ext/ytphy_write_ext/ytphy_modify_ext function to ++ * operate extended register. ++ * Extended Register start ++ */ ++ ++/* Phy gmii clock gating Register */ ++#define YT8521_CLOCK_GATING_REG 0xC ++#define YT8521_CGR_RX_CLK_EN BIT(12) ++ ++#define YT8521_EXTREG_SLEEP_CONTROL1_REG 0x27 ++#define YT8521_ESC1R_SLEEP_SW BIT(15) ++#define YT8521_ESC1R_PLLON_SLP BIT(14) ++ ++/* Phy fiber Link timer cfg2 Register */ ++#define YT8521_LINK_TIMER_CFG2_REG 0xA5 ++#define YT8521_LTCR_EN_AUTOSEN BIT(15) ++ ++/* 0xA000, 0xA001, 0xA003 ,and 0xA006 ~ 0xA00A are common ext registers ++ * of yt8521 phy. There is no need to switch reg space when operating these ++ * registers. ++ */ ++ ++#define YT8521_REG_SPACE_SELECT_REG 0xA000 ++#define YT8521_RSSR_SPACE_MASK BIT(1) ++#define YT8521_RSSR_FIBER_SPACE (0x1 << 1) ++#define YT8521_RSSR_UTP_SPACE (0x0 << 1) ++#define YT8521_RSSR_TO_BE_ARBITRATED (0xFF) ++ ++#define YT8521_CHIP_CONFIG_REG 0xA001 ++#define YT8521_CCR_SW_RST BIT(15) ++ ++#define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0)) ++#define YT8521_CCR_MODE_UTP_TO_RGMII 0 ++#define YT8521_CCR_MODE_FIBER_TO_RGMII 1 ++#define YT8521_CCR_MODE_UTP_FIBER_TO_RGMII 2 ++#define YT8521_CCR_MODE_UTP_TO_SGMII 3 ++#define YT8521_CCR_MODE_SGPHY_TO_RGMAC 4 ++#define YT8521_CCR_MODE_SGMAC_TO_RGPHY 5 ++#define YT8521_CCR_MODE_UTP_TO_FIBER_AUTO 6 ++#define YT8521_CCR_MODE_UTP_TO_FIBER_FORCE 7 ++ ++/* 3 phy polling modes,poll mode combines utp and fiber mode*/ ++#define YT8521_MODE_FIBER 0x1 ++#define YT8521_MODE_UTP 0x2 ++#define YT8521_MODE_POLL 0x3 ++ ++#define YT8521_RGMII_CONFIG1_REG 0xA003 ++ ++/* TX Gig-E Delay is bits 3:0, default 0x1 ++ * TX Fast-E Delay is bits 7:4, default 0xf ++ * RX Delay is bits 13:10, default 0x0 ++ * Delay = 150ps * N ++ * On = 2250ps, off = 0ps ++ */ ++#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10) ++#define YT8521_RC1R_RX_DELAY_EN (0xF << 10) ++#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) ++#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4) ++#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) ++#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) ++#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0) ++#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) ++#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) ++ ++#define YTPHY_MISC_CONFIG_REG 0xA006 ++#define YTPHY_MCR_FIBER_SPEED_MASK BIT(0) ++#define YTPHY_MCR_FIBER_1000BX (0x1 << 0) ++#define YTPHY_MCR_FIBER_100FX (0x0 << 0) ++ ++/* WOL MAC ADDR: MACADDR2(highest), MACADDR1(middle), MACADDR0(lowest) */ ++#define YTPHY_WOL_MACADDR2_REG 0xA007 ++#define YTPHY_WOL_MACADDR1_REG 0xA008 ++#define YTPHY_WOL_MACADDR0_REG 0xA009 ++ ++#define YTPHY_WOL_CONFIG_REG 0xA00A ++#define YTPHY_WCR_INTR_SEL BIT(6) ++#define YTPHY_WCR_ENABLE BIT(3) ++ ++/* 2b00 84ms ++ * 2b01 168ms *default* ++ * 2b10 336ms ++ * 2b11 672ms ++ */ ++#define YTPHY_WCR_PULSE_WIDTH_MASK (BIT(2) | BIT(1)) ++#define YTPHY_WCR_PULSE_WIDTH_672MS (BIT(2) | BIT(1)) ++ ++/* 1b0 Interrupt and WOL events is level triggered and active LOW *default* ++ * 1b1 Interrupt and WOL events is pulse triggered and active LOW ++ */ ++#define YTPHY_WCR_TYPE_PULSE BIT(0) ++ ++/* Extended Register end */ ++ ++struct yt8521_priv { ++ /* combo_advertising is used for case of YT8521 in combo mode, ++ * this means that yt8521 may work in utp or fiber mode which depends ++ * on which media is connected (YT8521_RSSR_TO_BE_ARBITRATED). ++ */ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(combo_advertising); ++ ++ /* YT8521_MODE_FIBER / YT8521_MODE_UTP / YT8521_MODE_POLL*/ ++ u8 polling_mode; ++ u8 strap_mode; /* 8 working modes */ ++ /* current reg page of yt8521 phy: ++ * YT8521_RSSR_UTP_SPACE ++ * YT8521_RSSR_FIBER_SPACE ++ * YT8521_RSSR_TO_BE_ARBITRATED ++ */ ++ u8 reg_page; ++}; ++ ++/** ++ * ytphy_read_ext() - read a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to read ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns the value of regnum reg or negative error code ++ */ ++static int ytphy_read_ext(struct phy_device *phydev, u16 regnum) ++{ ++ int ret; ++ ++ ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum); ++ if (ret < 0) ++ return ret; ++ ++ return __phy_read(phydev, YTPHY_PAGE_DATA); ++} ++ ++/** ++ * ytphy_read_ext_with_lock() - read a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to read ++ * ++ * returns the value of regnum reg or negative error code ++ */ ++static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum) ++{ ++ int ret; ++ ++ phy_lock_mdio_bus(phydev); ++ ret = ytphy_read_ext(phydev, regnum); ++ phy_unlock_mdio_bus(phydev); ++ ++ return ret; ++} ++ ++/** ++ * ytphy_write_ext() - write a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to write ++ * @val: value to write to @regnum ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative error code ++ */ ++static int ytphy_write_ext(struct phy_device *phydev, u16 regnum, u16 val) ++{ ++ int ret; ++ ++ ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum); ++ if (ret < 0) ++ return ret; ++ ++ return __phy_write(phydev, YTPHY_PAGE_DATA, val); ++} ++ ++/** ++ * ytphy_write_ext_with_lock() - write a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to write ++ * @val: value to write to @regnum ++ * ++ * returns 0 or negative error code ++ */ ++static int ytphy_write_ext_with_lock(struct phy_device *phydev, u16 regnum, ++ u16 val) ++{ ++ int ret; ++ ++ phy_lock_mdio_bus(phydev); ++ ret = ytphy_write_ext(phydev, regnum, val); ++ phy_unlock_mdio_bus(phydev); ++ ++ return ret; ++} ++ ++/** ++ * ytphy_modify_ext() - bits modify a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to write ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * NOTE: Convenience function which allows a PHY's extended register to be ++ * modified as new register value = (old register value & ~mask) | set. ++ * The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative error code ++ */ ++static int ytphy_modify_ext(struct phy_device *phydev, u16 regnum, u16 mask, ++ u16 set) ++{ ++ int ret; ++ ++ ret = __phy_write(phydev, YTPHY_PAGE_SELECT, regnum); ++ if (ret < 0) ++ return ret; ++ ++ return __phy_modify(phydev, YTPHY_PAGE_DATA, mask, set); ++} ++ ++/** ++ * ytphy_modify_ext_with_lock() - bits modify a PHY's extended register ++ * @phydev: a pointer to a &struct phy_device ++ * @regnum: register number to write ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * NOTE: Convenience function which allows a PHY's extended register to be ++ * modified as new register value = (old register value & ~mask) | set. ++ * ++ * returns 0 or negative error code ++ */ ++static int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum, ++ u16 mask, u16 set) ++{ ++ int ret; ++ ++ phy_lock_mdio_bus(phydev); ++ ret = ytphy_modify_ext(phydev, regnum, mask, set); ++ phy_unlock_mdio_bus(phydev); ++ ++ return ret; ++} ++ ++/** ++ * ytphy_get_wol() - report whether wake-on-lan is enabled ++ * @phydev: a pointer to a &struct phy_device ++ * @wol: a pointer to a &struct ethtool_wolinfo ++ * ++ * NOTE: YTPHY_WOL_CONFIG_REG is common ext reg. ++ */ ++static void ytphy_get_wol(struct phy_device *phydev, ++ struct ethtool_wolinfo *wol) ++{ ++ int wol_config; ++ ++ wol->supported = WAKE_MAGIC; ++ wol->wolopts = 0; ++ ++ wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG); ++ if (wol_config < 0) ++ return; ++ ++ if (wol_config & YTPHY_WCR_ENABLE) ++ wol->wolopts |= WAKE_MAGIC; ++} ++ ++/** ++ * ytphy_set_wol() - turn wake-on-lan on or off ++ * @phydev: a pointer to a &struct phy_device ++ * @wol: a pointer to a &struct ethtool_wolinfo ++ * ++ * NOTE: YTPHY_WOL_CONFIG_REG, YTPHY_WOL_MACADDR2_REG, YTPHY_WOL_MACADDR1_REG ++ * and YTPHY_WOL_MACADDR0_REG are common ext reg. The ++ * YTPHY_INTERRUPT_ENABLE_REG of UTP is special, fiber also use this register. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) ++{ ++ struct net_device *p_attached_dev; ++ const u16 mac_addr_reg[] = { ++ YTPHY_WOL_MACADDR2_REG, ++ YTPHY_WOL_MACADDR1_REG, ++ YTPHY_WOL_MACADDR0_REG, ++ }; ++ const u8 *mac_addr; ++ int old_page; ++ int ret = 0; ++ u16 mask; ++ u16 val; ++ u8 i; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ p_attached_dev = phydev->attached_dev; ++ if (!p_attached_dev) ++ return -ENODEV; ++ ++ mac_addr = (const u8 *)p_attached_dev->dev_addr; ++ if (!is_valid_ether_addr(mac_addr)) ++ return -EINVAL; ++ ++ /* lock mdio bus then switch to utp reg space */ ++ old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ /* Store the device address for the magic packet */ ++ for (i = 0; i < 3; i++) { ++ ret = ytphy_write_ext(phydev, mac_addr_reg[i], ++ ((mac_addr[i * 2] << 8)) | ++ (mac_addr[i * 2 + 1])); ++ if (ret < 0) ++ goto err_restore_page; ++ } ++ ++ /* Enable WOL feature */ ++ mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL; ++ val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; ++ val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS; ++ ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, val); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ /* Enable WOL interrupt */ ++ ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0, ++ YTPHY_IER_WOL); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ } else { ++ old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ /* Disable WOL feature */ ++ mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; ++ ret = ytphy_modify_ext(phydev, YTPHY_WOL_CONFIG_REG, mask, 0); ++ ++ /* Disable WOL interrupt */ ++ ret = __phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, ++ YTPHY_IER_WOL, 0); ++ if (ret < 0) ++ goto err_restore_page; ++ } ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ + static int yt8511_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, YT8511_PAGE_SELECT); +@@ -111,6 +548,1181 @@ err_restore_page: + return phy_restore_page(phydev, oldpage, ret); + } + ++/** ++ * yt8521_read_page() - read reg page ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns current reg space of yt8521 (YT8521_RSSR_FIBER_SPACE/ ++ * YT8521_RSSR_UTP_SPACE) or negative errno code ++ */ ++static int yt8521_read_page(struct phy_device *phydev) ++{ ++ int old_page; ++ ++ old_page = ytphy_read_ext(phydev, YT8521_REG_SPACE_SELECT_REG); ++ if (old_page < 0) ++ return old_page; ++ ++ if ((old_page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE) ++ return YT8521_RSSR_FIBER_SPACE; ++ ++ return YT8521_RSSR_UTP_SPACE; ++}; ++ ++/** ++ * yt8521_write_page() - write reg page ++ * @phydev: a pointer to a &struct phy_device ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to write. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_write_page(struct phy_device *phydev, int page) ++{ ++ int mask = YT8521_RSSR_SPACE_MASK; ++ int set; ++ ++ if ((page & YT8521_RSSR_SPACE_MASK) == YT8521_RSSR_FIBER_SPACE) ++ set = YT8521_RSSR_FIBER_SPACE; ++ else ++ set = YT8521_RSSR_UTP_SPACE; ++ ++ return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set); ++}; ++ ++/** ++ * yt8521_probe() - read chip config then set suitable polling_mode ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ struct yt8521_priv *priv; ++ int chip_config; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ phydev->priv = priv; ++ ++ chip_config = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG); ++ if (chip_config < 0) ++ return chip_config; ++ ++ priv->strap_mode = chip_config & YT8521_CCR_MODE_SEL_MASK; ++ switch (priv->strap_mode) { ++ case YT8521_CCR_MODE_FIBER_TO_RGMII: ++ case YT8521_CCR_MODE_SGPHY_TO_RGMAC: ++ case YT8521_CCR_MODE_SGMAC_TO_RGPHY: ++ priv->polling_mode = YT8521_MODE_FIBER; ++ priv->reg_page = YT8521_RSSR_FIBER_SPACE; ++ phydev->port = PORT_FIBRE; ++ break; ++ case YT8521_CCR_MODE_UTP_FIBER_TO_RGMII: ++ case YT8521_CCR_MODE_UTP_TO_FIBER_AUTO: ++ case YT8521_CCR_MODE_UTP_TO_FIBER_FORCE: ++ priv->polling_mode = YT8521_MODE_POLL; ++ priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED; ++ phydev->port = PORT_NONE; ++ break; ++ case YT8521_CCR_MODE_UTP_TO_SGMII: ++ case YT8521_CCR_MODE_UTP_TO_RGMII: ++ priv->polling_mode = YT8521_MODE_UTP; ++ priv->reg_page = YT8521_RSSR_UTP_SPACE; ++ phydev->port = PORT_TP; ++ break; ++ } ++ /* set default reg space */ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ ret = ytphy_write_ext_with_lock(phydev, ++ YT8521_REG_SPACE_SELECT_REG, ++ priv->reg_page); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_utp_read_lpa(struct phy_device *phydev) ++{ ++ int lpa, lpagb; ++ ++ if (phydev->autoneg == AUTONEG_ENABLE) { ++ if (!phydev->autoneg_complete) { ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ++ 0); ++ mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0); ++ return 0; ++ } ++ ++ if (phydev->is_gigabit_capable) { ++ lpagb = __phy_read(phydev, MII_STAT1000); ++ if (lpagb < 0) ++ return lpagb; ++ ++ if (lpagb & LPA_1000MSFAIL) { ++ int adv = __phy_read(phydev, MII_CTRL1000); ++ ++ if (adv < 0) ++ return adv; ++ ++ if (adv & CTL1000_ENABLE_MASTER) ++ phydev_err(phydev, "Master/Slave resolution failed, maybe conflicting manual settings?\n"); ++ else ++ phydev_err(phydev, "Master/Slave resolution failed\n"); ++ return -ENOLINK; ++ } ++ ++ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ++ lpagb); ++ } ++ ++ lpa = __phy_read(phydev, MII_LPA); ++ if (lpa < 0) ++ return lpa; ++ ++ mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa); ++ } else { ++ linkmode_zero(phydev->lp_advertising); ++ } ++ ++ return 0; ++} ++ ++/** ++ * yt8521_adjust_status() - update speed and duplex to phydev. when in fiber ++ * mode, adjust speed and duplex. ++ * @phydev: a pointer to a &struct phy_device ++ * @status: yt8521 status read from YTPHY_SPECIFIC_STATUS_REG ++ * @is_utp: false(yt8521 work in fiber mode) or true(yt8521 work in utp mode) ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 ++ */ ++static int yt8521_adjust_status(struct phy_device *phydev, int status, ++ bool is_utp) ++{ ++ int speed_mode, duplex; ++ int speed; ++ int err; ++ int lpa; ++ ++ if (is_utp) ++ duplex = (status & YTPHY_SSR_DUPLEX) >> YTPHY_SSR_DUPLEX_OFFSET; ++ else ++ duplex = DUPLEX_FULL; /* for fiber, it always DUPLEX_FULL */ ++ ++ speed_mode = (status & YTPHY_SSR_SPEED_MODE_MASK) >> ++ YTPHY_SSR_SPEED_MODE_OFFSET; ++ ++ switch (speed_mode) { ++ case YTPHY_SSR_SPEED_10M: ++ if (is_utp) ++ speed = SPEED_10; ++ else ++ /* for fiber, it will never run here, default to ++ * SPEED_UNKNOWN ++ */ ++ speed = SPEED_UNKNOWN; ++ break; ++ case YTPHY_SSR_SPEED_100M: ++ speed = SPEED_100; ++ break; ++ case YTPHY_SSR_SPEED_1000M: ++ speed = SPEED_1000; ++ break; ++ default: ++ speed = SPEED_UNKNOWN; ++ break; ++ } ++ ++ phydev->speed = speed; ++ phydev->duplex = duplex; ++ ++ if (is_utp) { ++ err = ytphy_utp_read_lpa(phydev); ++ if (err < 0) ++ return err; ++ ++ phy_resolve_aneg_pause(phydev); ++ } else { ++ lpa = __phy_read(phydev, MII_LPA); ++ if (lpa < 0) ++ return lpa; ++ ++ /* only support 1000baseX Full */ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->lp_advertising, lpa & LPA_1000XFULL); ++ ++ if (!(lpa & YTPHY_FLPA_PAUSE)) { ++ phydev->pause = 0; ++ phydev->asym_pause = 0; ++ } else if ((lpa & YTPHY_FLPA_ASYM_PAUSE)) { ++ phydev->pause = 1; ++ phydev->asym_pause = 1; ++ } else { ++ phydev->pause = 1; ++ phydev->asym_pause = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * yt8521_read_status_paged() - determines the speed and duplex of one page ++ * @phydev: a pointer to a &struct phy_device ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to ++ * operate. ++ * ++ * returns 1 (utp or fiber link),0 (no link) or negative errno code ++ */ ++static int yt8521_read_status_paged(struct phy_device *phydev, int page) ++{ ++ int fiber_latch_val; ++ int fiber_curr_val; ++ int old_page; ++ int ret = 0; ++ int status; ++ int link; ++ ++ linkmode_zero(phydev->lp_advertising); ++ phydev->duplex = DUPLEX_UNKNOWN; ++ phydev->speed = SPEED_UNKNOWN; ++ phydev->asym_pause = 0; ++ phydev->pause = 0; ++ ++ /* YT8521 has two reg space (utp/fiber) for linkup with utp/fiber ++ * respectively. but for utp/fiber combo mode, reg space should be ++ * arbitrated based on media priority. by default, utp takes ++ * priority. reg space should be properly set before read ++ * YTPHY_SPECIFIC_STATUS_REG. ++ */ ++ ++ page &= YT8521_RSSR_SPACE_MASK; ++ old_page = phy_select_page(phydev, page); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ /* Read YTPHY_SPECIFIC_STATUS_REG, which indicates the speed and duplex ++ * of the PHY is actually using. ++ */ ++ ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ status = ret; ++ link = !!(status & YTPHY_SSR_LINK); ++ ++ /* When PHY is in fiber mode, speed transferred from 1000Mbps to ++ * 100Mbps,there is not link down from YTPHY_SPECIFIC_STATUS_REG, so ++ * we need check MII_BMSR to identify such case. ++ */ ++ if (page == YT8521_RSSR_FIBER_SPACE) { ++ ret = __phy_read(phydev, MII_BMSR); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ fiber_latch_val = ret; ++ ret = __phy_read(phydev, MII_BMSR); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ fiber_curr_val = ret; ++ if (link && fiber_latch_val != fiber_curr_val) { ++ link = 0; ++ phydev_info(phydev, ++ "%s, fiber link down detect, latch = %04x, curr = %04x\n", ++ __func__, fiber_latch_val, fiber_curr_val); ++ } ++ } else { ++ /* Read autonegotiation status */ ++ ret = __phy_read(phydev, MII_BMSR); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ phydev->autoneg_complete = ret & BMSR_ANEGCOMPLETE ? 1 : 0; ++ } ++ ++ if (link) { ++ if (page == YT8521_RSSR_UTP_SPACE) ++ yt8521_adjust_status(phydev, status, true); ++ else ++ yt8521_adjust_status(phydev, status, false); ++ } ++ return phy_restore_page(phydev, old_page, link); ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_read_status() - determines the negotiated speed and duplex ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_read_status(struct phy_device *phydev) ++{ ++ struct yt8521_priv *priv = phydev->priv; ++ int link_fiber = 0; ++ int link_utp; ++ int link; ++ int ret; ++ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ link = yt8521_read_status_paged(phydev, priv->reg_page); ++ if (link < 0) ++ return link; ++ } else { ++ /* when page is YT8521_RSSR_TO_BE_ARBITRATED, arbitration is ++ * needed. by default, utp is higher priority. ++ */ ++ ++ link_utp = yt8521_read_status_paged(phydev, ++ YT8521_RSSR_UTP_SPACE); ++ if (link_utp < 0) ++ return link_utp; ++ ++ if (!link_utp) { ++ link_fiber = yt8521_read_status_paged(phydev, ++ YT8521_RSSR_FIBER_SPACE); ++ if (link_fiber < 0) ++ return link_fiber; ++ } ++ ++ link = link_utp || link_fiber; ++ } ++ ++ if (link) { ++ if (phydev->link == 0) { ++ /* arbitrate reg space based on linkup media type. */ ++ if (priv->polling_mode == YT8521_MODE_POLL && ++ priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) { ++ if (link_fiber) ++ priv->reg_page = ++ YT8521_RSSR_FIBER_SPACE; ++ else ++ priv->reg_page = YT8521_RSSR_UTP_SPACE; ++ ++ ret = ytphy_write_ext_with_lock(phydev, ++ YT8521_REG_SPACE_SELECT_REG, ++ priv->reg_page); ++ if (ret < 0) ++ return ret; ++ ++ phydev->port = link_fiber ? PORT_FIBRE : PORT_TP; ++ ++ phydev_info(phydev, "%s, link up, media: %s\n", ++ __func__, ++ (phydev->port == PORT_TP) ? ++ "UTP" : "Fiber"); ++ } ++ } ++ phydev->link = 1; ++ } else { ++ if (phydev->link == 1) { ++ phydev_info(phydev, "%s, link down, media: %s\n", ++ __func__, (phydev->port == PORT_TP) ? ++ "UTP" : "Fiber"); ++ ++ /* When in YT8521_MODE_POLL mode, need prepare for next ++ * arbitration. ++ */ ++ if (priv->polling_mode == YT8521_MODE_POLL) { ++ priv->reg_page = YT8521_RSSR_TO_BE_ARBITRATED; ++ phydev->port = PORT_NONE; ++ } ++ } ++ ++ phydev->link = 0; ++ } ++ ++ return 0; ++} ++ ++/** ++ * yt8521_modify_bmcr_paged - bits modify a PHY's BMCR register of one page ++ * @phydev: the phy_device struct ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to operate ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * NOTE: Convenience function which allows a PHY's BMCR register to be ++ * modified as new register value = (old register value & ~mask) | set. ++ * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space ++ * has MII_BMCR. poll mode combines utp and faber,so need do both. ++ * If it is reset, it will wait for completion. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_modify_bmcr_paged(struct phy_device *phydev, int page, ++ u16 mask, u16 set) ++{ ++ int max_cnt = 500; /* the max wait time of reset ~ 500 ms */ ++ int old_page; ++ int ret = 0; ++ ++ old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ ret = __phy_modify(phydev, MII_BMCR, mask, set); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ /* If it is reset, need to wait for the reset to complete */ ++ if (set == BMCR_RESET) { ++ while (max_cnt--) { ++ usleep_range(1000, 1100); ++ ret = __phy_read(phydev, MII_BMCR); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ if (!(ret & BMCR_RESET)) ++ return phy_restore_page(phydev, old_page, 0); ++ } ++ } ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register ++ * @phydev: the phy_device struct ++ * @mask: bit mask of bits to clear ++ * @set: bit mask of bits to set ++ * ++ * NOTE: Convenience function which allows a PHY's BMCR register to be ++ * modified as new register value = (old register value & ~mask) | set. ++ * YT8521 has two space (utp/fiber) and three mode (utp/fiber/poll), each space ++ * has MII_BMCR. poll mode combines utp and faber,so need do both. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_modify_utp_fiber_bmcr(struct phy_device *phydev, u16 mask, ++ u16 set) ++{ ++ struct yt8521_priv *priv = phydev->priv; ++ int ret; ++ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ ret = yt8521_modify_bmcr_paged(phydev, priv->reg_page, mask, ++ set); ++ if (ret < 0) ++ return ret; ++ } else { ++ ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_UTP_SPACE, ++ mask, set); ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_FIBER_SPACE, ++ mask, set); ++ if (ret < 0) ++ return ret; ++ } ++ return 0; ++} ++ ++/** ++ * yt8521_soft_reset() - called to issue a PHY software reset ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_soft_reset(struct phy_device *phydev) ++{ ++ return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_RESET); ++} ++ ++/** ++ * yt8521_suspend() - suspend the hardware ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_suspend(struct phy_device *phydev) ++{ ++ int wol_config; ++ ++ /* YTPHY_WOL_CONFIG_REG is common ext reg */ ++ wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG); ++ if (wol_config < 0) ++ return wol_config; ++ ++ /* if wol enable, do nothing */ ++ if (wol_config & YTPHY_WCR_ENABLE) ++ return 0; ++ ++ return yt8521_modify_utp_fiber_bmcr(phydev, 0, BMCR_PDOWN); ++} ++ ++/** ++ * yt8521_resume() - resume the hardware ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_resume(struct phy_device *phydev) ++{ ++ int ret; ++ int wol_config; ++ ++ /* disable auto sleep */ ++ ret = ytphy_modify_ext_with_lock(phydev, ++ YT8521_EXTREG_SLEEP_CONTROL1_REG, ++ YT8521_ESC1R_SLEEP_SW, 0); ++ if (ret < 0) ++ return ret; ++ ++ wol_config = ytphy_read_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG); ++ if (wol_config < 0) ++ return wol_config; ++ ++ /* if wol enable, do nothing */ ++ if (wol_config & YTPHY_WCR_ENABLE) ++ return 0; ++ ++ return yt8521_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0); ++} ++ ++/** ++ * yt8521_config_init() - called to initialize the PHY ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_config_init(struct phy_device *phydev) ++{ ++ int old_page; ++ int ret = 0; ++ u16 val; ++ ++ old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS; ++ val |= YT8521_RC1R_RX_DELAY_DIS; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS; ++ val |= YT8521_RC1R_RX_DELAY_EN; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN; ++ val |= YT8521_RC1R_RX_DELAY_DIS; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN; ++ val |= YT8521_RC1R_RX_DELAY_EN; ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ break; ++ default: /* do not support other modes */ ++ ret = -EOPNOTSUPP; ++ goto err_restore_page; ++ } ++ ++ /* set rgmii delay mode */ ++ if (phydev->interface != PHY_INTERFACE_MODE_SGMII) { ++ ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, ++ (YT8521_RC1R_RX_DELAY_MASK | ++ YT8521_RC1R_FE_TX_DELAY_MASK | ++ YT8521_RC1R_GE_TX_DELAY_MASK), ++ val); ++ if (ret < 0) ++ goto err_restore_page; ++ } ++ ++ /* disable auto sleep */ ++ ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, ++ YT8521_ESC1R_SLEEP_SW, 0); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ /* enable RXC clock when no wire plug */ ++ ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, ++ YT8521_CGR_RX_CLK_EN, 0); ++ if (ret < 0) ++ goto err_restore_page; ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_prepare_fiber_features() - A small helper function that setup ++ * fiber's features. ++ * @phydev: a pointer to a &struct phy_device ++ * @dst: a pointer to store fiber's features ++ */ ++static void yt8521_prepare_fiber_features(struct phy_device *phydev, ++ unsigned long *dst) ++{ ++ linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, dst); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, dst); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, dst); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, dst); ++} ++ ++/** ++ * yt8521_fiber_setup_forced - configures/forces speed from @phydev ++ * @phydev: target phy_device struct ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_fiber_setup_forced(struct phy_device *phydev) ++{ ++ u16 val; ++ int ret; ++ ++ if (phydev->speed == SPEED_1000) ++ val = YTPHY_MCR_FIBER_1000BX; ++ else if (phydev->speed == SPEED_100) ++ val = YTPHY_MCR_FIBER_100FX; ++ else ++ return -EINVAL; ++ ++ ret = __phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); ++ if (ret < 0) ++ return ret; ++ ++ /* disable Fiber auto sensing */ ++ ret = ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG, ++ YT8521_LTCR_EN_AUTOSEN, 0); ++ if (ret < 0) ++ return ret; ++ ++ ret = ytphy_modify_ext(phydev, YTPHY_MISC_CONFIG_REG, ++ YTPHY_MCR_FIBER_SPEED_MASK, val); ++ if (ret < 0) ++ return ret; ++ ++ return ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, ++ YT8521_CCR_SW_RST, 0); ++} ++ ++/** ++ * ytphy_check_and_restart_aneg - Enable and restart auto-negotiation ++ * @phydev: target phy_device struct ++ * @restart: whether aneg restart is requested ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_check_and_restart_aneg(struct phy_device *phydev, bool restart) ++{ ++ int ret; ++ ++ if (!restart) { ++ /* Advertisement hasn't changed, but maybe aneg was never on to ++ * begin with? Or maybe phy was isolated? ++ */ ++ ret = __phy_read(phydev, MII_BMCR); ++ if (ret < 0) ++ return ret; ++ ++ if (!(ret & BMCR_ANENABLE) || (ret & BMCR_ISOLATE)) ++ restart = true; ++ } ++ /* Enable and Restart Autonegotiation ++ * Don't isolate the PHY if we're negotiating ++ */ ++ if (restart) ++ return __phy_modify(phydev, MII_BMCR, BMCR_ISOLATE, ++ BMCR_ANENABLE | BMCR_ANRESTART); ++ ++ return 0; ++} ++ ++/** ++ * yt8521_fiber_config_aneg - restart auto-negotiation or write ++ * YTPHY_MISC_CONFIG_REG. ++ * @phydev: target phy_device struct ++ * ++ * NOTE:The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_fiber_config_aneg(struct phy_device *phydev) ++{ ++ int err, changed = 0; ++ int bmcr; ++ u16 adv; ++ ++ if (phydev->autoneg != AUTONEG_ENABLE) ++ return yt8521_fiber_setup_forced(phydev); ++ ++ /* enable Fiber auto sensing */ ++ err = ytphy_modify_ext(phydev, YT8521_LINK_TIMER_CFG2_REG, ++ 0, YT8521_LTCR_EN_AUTOSEN); ++ if (err < 0) ++ return err; ++ ++ err = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, ++ YT8521_CCR_SW_RST, 0); ++ if (err < 0) ++ return err; ++ ++ bmcr = __phy_read(phydev, MII_BMCR); ++ if (bmcr < 0) ++ return bmcr; ++ ++ /* When it is coming from fiber forced mode, add bmcr power down ++ * and power up to let aneg work fine. ++ */ ++ if (!(bmcr & BMCR_ANENABLE)) { ++ __phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN); ++ usleep_range(1000, 1100); ++ __phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0); ++ } ++ ++ adv = linkmode_adv_to_mii_adv_x(phydev->advertising, ++ ETHTOOL_LINK_MODE_1000baseX_Full_BIT); ++ ++ /* Setup fiber advertisement */ ++ err = __phy_modify_changed(phydev, MII_ADVERTISE, ++ ADVERTISE_1000XHALF | ADVERTISE_1000XFULL | ++ ADVERTISE_1000XPAUSE | ++ ADVERTISE_1000XPSE_ASYM, ++ adv); ++ if (err < 0) ++ return err; ++ ++ if (err > 0) ++ changed = 1; ++ ++ return ytphy_check_and_restart_aneg(phydev, changed); ++} ++ ++/** ++ * ytphy_setup_master_slave ++ * @phydev: target phy_device struct ++ * ++ * NOTE: The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_setup_master_slave(struct phy_device *phydev) ++{ ++ u16 ctl = 0; ++ ++ if (!phydev->is_gigabit_capable) ++ return 0; ++ ++ switch (phydev->master_slave_set) { ++ case MASTER_SLAVE_CFG_MASTER_PREFERRED: ++ ctl |= CTL1000_PREFER_MASTER; ++ break; ++ case MASTER_SLAVE_CFG_SLAVE_PREFERRED: ++ break; ++ case MASTER_SLAVE_CFG_MASTER_FORCE: ++ ctl |= CTL1000_AS_MASTER; ++ fallthrough; ++ case MASTER_SLAVE_CFG_SLAVE_FORCE: ++ ctl |= CTL1000_ENABLE_MASTER; ++ break; ++ case MASTER_SLAVE_CFG_UNKNOWN: ++ case MASTER_SLAVE_CFG_UNSUPPORTED: ++ return 0; ++ default: ++ phydev_warn(phydev, "Unsupported Master/Slave mode\n"); ++ return -EOPNOTSUPP; ++ } ++ ++ return __phy_modify_changed(phydev, MII_CTRL1000, ++ (CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER | ++ CTL1000_PREFER_MASTER), ctl); ++} ++ ++/** ++ * ytphy_utp_config_advert - sanitize and advertise auto-negotiation parameters ++ * @phydev: target phy_device struct ++ * ++ * NOTE: Writes MII_ADVERTISE with the appropriate values, ++ * after sanitizing the values to make sure we only advertise ++ * what is supported. Returns < 0 on error, 0 if the PHY's advertisement ++ * hasn't changed, and > 0 if it has changed. ++ * The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_utp_config_advert(struct phy_device *phydev) ++{ ++ int err, bmsr, changed = 0; ++ u32 adv; ++ ++ /* Only allow advertising what this PHY supports */ ++ linkmode_and(phydev->advertising, phydev->advertising, ++ phydev->supported); ++ ++ adv = linkmode_adv_to_mii_adv_t(phydev->advertising); ++ ++ /* Setup standard advertisement */ ++ err = __phy_modify_changed(phydev, MII_ADVERTISE, ++ ADVERTISE_ALL | ADVERTISE_100BASE4 | ++ ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM, ++ adv); ++ if (err < 0) ++ return err; ++ if (err > 0) ++ changed = 1; ++ ++ bmsr = __phy_read(phydev, MII_BMSR); ++ if (bmsr < 0) ++ return bmsr; ++ ++ /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all ++ * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a ++ * logical 1. ++ */ ++ if (!(bmsr & BMSR_ESTATEN)) ++ return changed; ++ ++ adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); ++ ++ err = __phy_modify_changed(phydev, MII_CTRL1000, ++ ADVERTISE_1000FULL | ADVERTISE_1000HALF, ++ adv); ++ if (err < 0) ++ return err; ++ if (err > 0) ++ changed = 1; ++ ++ return changed; ++} ++ ++/** ++ * ytphy_utp_config_aneg - restart auto-negotiation or write BMCR ++ * @phydev: target phy_device struct ++ * @changed: whether autoneg is requested ++ * ++ * NOTE: If auto-negotiation is enabled, we configure the ++ * advertising, and then restart auto-negotiation. If it is not ++ * enabled, then we write the BMCR. ++ * The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_utp_config_aneg(struct phy_device *phydev, bool changed) ++{ ++ int err; ++ u16 ctl; ++ ++ err = ytphy_setup_master_slave(phydev); ++ if (err < 0) ++ return err; ++ else if (err) ++ changed = true; ++ ++ if (phydev->autoneg != AUTONEG_ENABLE) { ++ /* configures/forces speed/duplex from @phydev */ ++ ++ ctl = mii_bmcr_encode_fixed(phydev->speed, phydev->duplex); ++ ++ return __phy_modify(phydev, MII_BMCR, ~(BMCR_LOOPBACK | ++ BMCR_ISOLATE | BMCR_PDOWN), ctl); ++ } ++ ++ err = ytphy_utp_config_advert(phydev); ++ if (err < 0) /* error */ ++ return err; ++ else if (err) ++ changed = true; ++ ++ return ytphy_check_and_restart_aneg(phydev, changed); ++} ++ ++/** ++ * yt8521_config_aneg_paged() - switch reg space then call genphy_config_aneg ++ * of one page ++ * @phydev: a pointer to a &struct phy_device ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to ++ * operate. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_config_aneg_paged(struct phy_device *phydev, int page) ++{ ++ __ETHTOOL_DECLARE_LINK_MODE_MASK(fiber_supported); ++ struct yt8521_priv *priv = phydev->priv; ++ int old_page; ++ int ret = 0; ++ ++ page &= YT8521_RSSR_SPACE_MASK; ++ ++ old_page = phy_select_page(phydev, page); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ /* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED, ++ * phydev->advertising should be updated. ++ */ ++ if (priv->reg_page == YT8521_RSSR_TO_BE_ARBITRATED) { ++ linkmode_zero(fiber_supported); ++ yt8521_prepare_fiber_features(phydev, fiber_supported); ++ ++ /* prepare fiber_supported, then setup advertising. */ ++ if (page == YT8521_RSSR_FIBER_SPACE) { ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, ++ fiber_supported); ++ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++ fiber_supported); ++ linkmode_and(phydev->advertising, ++ priv->combo_advertising, fiber_supported); ++ } else { ++ /* ETHTOOL_LINK_MODE_Autoneg_BIT is also used in utp */ ++ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, ++ fiber_supported); ++ linkmode_andnot(phydev->advertising, ++ priv->combo_advertising, ++ fiber_supported); ++ } ++ } ++ ++ if (page == YT8521_RSSR_FIBER_SPACE) ++ ret = yt8521_fiber_config_aneg(phydev); ++ else ++ ret = ytphy_utp_config_aneg(phydev, false); ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_config_aneg() - change reg space then call yt8521_config_aneg_paged ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_config_aneg(struct phy_device *phydev) ++{ ++ struct yt8521_priv *priv = phydev->priv; ++ int ret; ++ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ ret = yt8521_config_aneg_paged(phydev, priv->reg_page); ++ if (ret < 0) ++ return ret; ++ } else { ++ /* If reg_page is YT8521_RSSR_TO_BE_ARBITRATED, ++ * phydev->advertising need to be saved at first run. ++ * Because it contains the advertising which supported by both ++ * mac and yt8521(utp and fiber). ++ */ ++ if (linkmode_empty(priv->combo_advertising)) { ++ linkmode_copy(priv->combo_advertising, ++ phydev->advertising); ++ } ++ ++ ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_UTP_SPACE); ++ if (ret < 0) ++ return ret; ++ ++ ret = yt8521_config_aneg_paged(phydev, YT8521_RSSR_FIBER_SPACE); ++ if (ret < 0) ++ return ret; ++ ++ /* we don't known which will be link, so restore ++ * phydev->advertising as default value. ++ */ ++ linkmode_copy(phydev->advertising, priv->combo_advertising); ++ } ++ return 0; ++} ++ ++/** ++ * yt8521_aneg_done_paged() - determines the auto negotiation result of one ++ * page. ++ * @phydev: a pointer to a &struct phy_device ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to ++ * operate. ++ * ++ * returns 0(no link)or 1(fiber or utp link) or negative errno code ++ */ ++static int yt8521_aneg_done_paged(struct phy_device *phydev, int page) ++{ ++ int old_page; ++ int ret = 0; ++ int link; ++ ++ old_page = phy_select_page(phydev, page & YT8521_RSSR_SPACE_MASK); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG); ++ if (ret < 0) ++ goto err_restore_page; ++ ++ link = !!(ret & YTPHY_SSR_LINK); ++ ret = link; ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_aneg_done() - determines the auto negotiation result ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0(no link)or 1(fiber or utp link) or negative errno code ++ */ ++static int yt8521_aneg_done(struct phy_device *phydev) ++{ ++ struct yt8521_priv *priv = phydev->priv; ++ int link_fiber = 0; ++ int link_utp; ++ int link; ++ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ link = yt8521_aneg_done_paged(phydev, priv->reg_page); ++ } else { ++ link_utp = yt8521_aneg_done_paged(phydev, ++ YT8521_RSSR_UTP_SPACE); ++ if (link_utp < 0) ++ return link_utp; ++ ++ if (!link_utp) { ++ link_fiber = yt8521_aneg_done_paged(phydev, ++ YT8521_RSSR_FIBER_SPACE); ++ if (link_fiber < 0) ++ return link_fiber; ++ } ++ link = link_fiber || link_utp; ++ phydev_info(phydev, "%s, link_fiber: %d, link_utp: %d\n", ++ __func__, link_fiber, link_utp); ++ } ++ ++ return link; ++} ++ ++/** ++ * ytphy_utp_read_abilities - read PHY abilities from Clause 22 registers ++ * @phydev: target phy_device struct ++ * ++ * NOTE: Reads the PHY's abilities and populates ++ * phydev->supported accordingly. ++ * The caller must have taken the MDIO bus lock. ++ * ++ * returns 0 or negative errno code ++ */ ++static int ytphy_utp_read_abilities(struct phy_device *phydev) ++{ ++ int val; ++ ++ linkmode_set_bit_array(phy_basic_ports_array, ++ ARRAY_SIZE(phy_basic_ports_array), ++ phydev->supported); ++ ++ val = __phy_read(phydev, MII_BMSR); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported, ++ val & BMSR_ANEGCAPABLE); ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, phydev->supported, ++ val & BMSR_100FULL); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, phydev->supported, ++ val & BMSR_100HALF); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, phydev->supported, ++ val & BMSR_10FULL); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, phydev->supported, ++ val & BMSR_10HALF); ++ ++ if (val & BMSR_ESTATEN) { ++ val = __phy_read(phydev, MII_ESTATUS); ++ if (val < 0) ++ return val; ++ ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, ++ phydev->supported, val & ESTATUS_1000_TFULL); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, ++ phydev->supported, val & ESTATUS_1000_THALF); ++ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, ++ phydev->supported, val & ESTATUS_1000_XFULL); ++ } ++ ++ return 0; ++} ++ ++/** ++ * yt8521_get_features_paged() - read supported link modes for one page ++ * @phydev: a pointer to a &struct phy_device ++ * @page: The reg page(YT8521_RSSR_FIBER_SPACE/YT8521_RSSR_UTP_SPACE) to ++ * operate. ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_get_features_paged(struct phy_device *phydev, int page) ++{ ++ int old_page; ++ int ret = 0; ++ ++ page &= YT8521_RSSR_SPACE_MASK; ++ old_page = phy_select_page(phydev, page); ++ if (old_page < 0) ++ goto err_restore_page; ++ ++ if (page == YT8521_RSSR_FIBER_SPACE) { ++ linkmode_zero(phydev->supported); ++ yt8521_prepare_fiber_features(phydev, phydev->supported); ++ } else { ++ ret = ytphy_utp_read_abilities(phydev); ++ if (ret < 0) ++ goto err_restore_page; ++ } ++ ++err_restore_page: ++ return phy_restore_page(phydev, old_page, ret); ++} ++ ++/** ++ * yt8521_get_features - switch reg space then call yt8521_get_features_paged ++ * @phydev: target phy_device struct ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8521_get_features(struct phy_device *phydev) ++{ ++ struct yt8521_priv *priv = phydev->priv; ++ int ret; ++ ++ if (priv->reg_page != YT8521_RSSR_TO_BE_ARBITRATED) { ++ ret = yt8521_get_features_paged(phydev, priv->reg_page); ++ } else { ++ ret = yt8521_get_features_paged(phydev, ++ YT8521_RSSR_UTP_SPACE); ++ if (ret < 0) ++ return ret; ++ ++ /* add fiber's features to phydev->supported */ ++ yt8521_prepare_fiber_features(phydev, phydev->supported); ++ } ++ return ret; ++} ++ + static struct phy_driver motorcomm_phy_drvs[] = { + { + PHY_ID_MATCH_EXACT(PHY_ID_YT8511), +@@ -121,16 +1733,35 @@ static struct phy_driver motorcomm_phy_d + .read_page = yt8511_read_page, + .write_page = yt8511_write_page, + }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_YT8521), ++ .name = "YT8521 Gigabit Ethernet", ++ .get_features = yt8521_get_features, ++ .probe = yt8521_probe, ++ .read_page = yt8521_read_page, ++ .write_page = yt8521_write_page, ++ .get_wol = ytphy_get_wol, ++ .set_wol = ytphy_set_wol, ++ .config_aneg = yt8521_config_aneg, ++ .aneg_done = yt8521_aneg_done, ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .soft_reset = yt8521_soft_reset, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++ }, + }; + + module_phy_driver(motorcomm_phy_drvs); + +-MODULE_DESCRIPTION("Motorcomm PHY driver"); ++MODULE_DESCRIPTION("Motorcomm 8511/8521 PHY driver"); + MODULE_AUTHOR("Peter Geis"); ++MODULE_AUTHOR("Frank"); + MODULE_LICENSE("GPL"); + + static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, ++ { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, + { /* sentinal */ } + }; + diff --git a/target/linux/generic/backport-6.1/791-v6.2-02-net-phy-fix-yt8521-duplicated-argument-to-or.patch b/target/linux/generic/backport-6.1/791-v6.2-02-net-phy-fix-yt8521-duplicated-argument-to-or.patch new file mode 100644 index 00000000000..cce71c8d84b --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.2-02-net-phy-fix-yt8521-duplicated-argument-to-or.patch @@ -0,0 +1,49 @@ +From 4e0243e7128c9b25ea2739136076a95d6adaba5e Mon Sep 17 00:00:00 2001 +From: Frank +Date: Fri, 4 Nov 2022 16:44:41 +0800 +Subject: [PATCH] net: phy: fix yt8521 duplicated argument to & or | + +cocci warnings: (new ones prefixed by >>) +>> drivers/net/phy/motorcomm.c:1122:8-35: duplicated argument to & or | + drivers/net/phy/motorcomm.c:1126:8-35: duplicated argument to & or | + drivers/net/phy/motorcomm.c:1130:8-34: duplicated argument to & or | + drivers/net/phy/motorcomm.c:1134:8-34: duplicated argument to & or | + + The second YT8521_RC1R_GE_TX_DELAY_xx should be YT8521_RC1R_FE_TX_DELAY_xx. + +Fixes: 70479a40954c ("net: phy: Add driver for Motorcomm yt8521 gigabit ethernet phy") +Reported-by: kernel test robot +Reported-by: Julia Lawall +Signed-off-by: Frank +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/motorcomm.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1119,19 +1119,19 @@ static int yt8521_config_init(struct phy + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII: +- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS; ++ val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; + val |= YT8521_RC1R_RX_DELAY_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_RXID: +- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_GE_TX_DELAY_DIS; ++ val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; + val |= YT8521_RC1R_RX_DELAY_EN; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: +- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN; ++ val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; + val |= YT8521_RC1R_RX_DELAY_DIS; + break; + case PHY_INTERFACE_MODE_RGMII_ID: +- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_GE_TX_DELAY_EN; ++ val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; + val |= YT8521_RC1R_RX_DELAY_EN; + break; + case PHY_INTERFACE_MODE_SGMII: diff --git a/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch b/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch new file mode 100644 index 00000000000..da60c63905d --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch @@ -0,0 +1,140 @@ +From 813abcd98fb1b2cccf850cdfa092a4bfc50b2363 Mon Sep 17 00:00:00 2001 +From: Frank +Date: Tue, 22 Nov 2022 16:42:32 +0800 +Subject: [PATCH] net: phy: add Motorcomm YT8531S phy id. + +We added patch for motorcomm.c to support YT8531S. This patch has +been tested on AM335x platform which has one YT8531S interface +card and passed all test cases. +The tested cases indluding: YT8531S UTP function with support of +10M/100M/1000M; YT8531S Fiber function with support of 100M/1000M; +and YT8531S Combo function that supports auto detection of media type. + +Since most functions of YT8531S are similar to YT8521 and we reuse some +codes for YT8521 in the patch file. + +Signed-off-by: Frank +Signed-off-by: David S. Miller +--- + drivers/net/phy/Kconfig | 2 +- + drivers/net/phy/motorcomm.c | 52 +++++++++++++++++++++++++++++++++---- + 2 files changed, 48 insertions(+), 6 deletions(-) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -245,7 +245,7 @@ config MOTORCOMM_PHY + tristate "Motorcomm PHYs" + help + Enables support for Motorcomm network PHYs. +- Currently supports the YT8511, YT8521 Gigabit Ethernet PHYs. ++ Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs. + + config NATIONAL_PHY + tristate "National Semiconductor PHYs" +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * Motorcomm 8511/8521 PHY driver. ++ * Motorcomm 8511/8521/8531S PHY driver. + * + * Author: Peter Geis + * Author: Frank +@@ -12,9 +12,10 @@ + #include + + #define PHY_ID_YT8511 0x0000010a +-#define PHY_ID_YT8521 0x0000011A ++#define PHY_ID_YT8521 0x0000011A ++#define PHY_ID_YT8531S 0x4F51E91A + +-/* YT8521 Register Overview ++/* YT8521/YT8531S Register Overview + * UTP Register space | FIBER Register space + * ------------------------------------------------------------ + * | UTP MII | FIBER MII | +@@ -147,7 +148,7 @@ + #define YT8521_LINK_TIMER_CFG2_REG 0xA5 + #define YT8521_LTCR_EN_AUTOSEN BIT(15) + +-/* 0xA000, 0xA001, 0xA003 ,and 0xA006 ~ 0xA00A are common ext registers ++/* 0xA000, 0xA001, 0xA003, 0xA006 ~ 0xA00A and 0xA012 are common ext registers + * of yt8521 phy. There is no need to switch reg space when operating these + * registers. + */ +@@ -221,6 +222,9 @@ + */ + #define YTPHY_WCR_TYPE_PULSE BIT(0) + ++#define YT8531S_SYNCE_CFG_REG 0xA012 ++#define YT8531S_SCR_SYNCE_ENABLE BIT(6) ++ + /* Extended Register end */ + + struct yt8521_priv { +@@ -648,6 +652,26 @@ static int yt8521_probe(struct phy_devic + } + + /** ++ * yt8531s_probe() - read chip config then set suitable polling_mode ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * returns 0 or negative errno code ++ */ ++static int yt8531s_probe(struct phy_device *phydev) ++{ ++ int ret; ++ ++ /* Disable SyncE clock output by default */ ++ ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG, ++ YT8531S_SCR_SYNCE_ENABLE, 0); ++ if (ret < 0) ++ return ret; ++ ++ /* same as yt8521_probe */ ++ return yt8521_probe(phydev); ++} ++ ++/** + * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp + * @phydev: a pointer to a &struct phy_device + * +@@ -1750,11 +1774,28 @@ static struct phy_driver motorcomm_phy_d + .suspend = yt8521_suspend, + .resume = yt8521_resume, + }, ++ { ++ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), ++ .name = "YT8531S Gigabit Ethernet", ++ .get_features = yt8521_get_features, ++ .probe = yt8531s_probe, ++ .read_page = yt8521_read_page, ++ .write_page = yt8521_write_page, ++ .get_wol = ytphy_get_wol, ++ .set_wol = ytphy_set_wol, ++ .config_aneg = yt8521_config_aneg, ++ .aneg_done = yt8521_aneg_done, ++ .config_init = yt8521_config_init, ++ .read_status = yt8521_read_status, ++ .soft_reset = yt8521_soft_reset, ++ .suspend = yt8521_suspend, ++ .resume = yt8521_resume, ++ }, + }; + + module_phy_driver(motorcomm_phy_drvs); + +-MODULE_DESCRIPTION("Motorcomm 8511/8521 PHY driver"); ++MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver"); + MODULE_AUTHOR("Peter Geis"); + MODULE_AUTHOR("Frank"); + MODULE_LICENSE("GPL"); +@@ -1762,6 +1803,7 @@ MODULE_LICENSE("GPL"); + static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, ++ { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, + { /* sentinal */ } + }; + diff --git a/target/linux/generic/backport-6.1/791-v6.3-04-net-phy-fix-the-spelling-problem-of-Sentinel.patch b/target/linux/generic/backport-6.1/791-v6.3-04-net-phy-fix-the-spelling-problem-of-Sentinel.patch new file mode 100644 index 00000000000..94fc32aadb3 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-04-net-phy-fix-the-spelling-problem-of-Sentinel.patch @@ -0,0 +1,26 @@ +From 4104a713204d62aca482eebb0c6226d82a0721eb Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Sat, 28 Jan 2023 14:35:57 +0800 +Subject: [PATCH] net: phy: fix the spelling problem of Sentinel + +CHECK: 'sentinal' may be misspelled - perhaps 'sentinel'? + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20230128063558.5850-1-Frank.Sae@motor-comm.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/motorcomm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1804,7 +1804,7 @@ static const struct mdio_device_id __may + { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, +- { /* sentinal */ } ++ { /* sentinel */ } + }; + + MODULE_DEVICE_TABLE(mdio, motorcomm_tbl); diff --git a/target/linux/generic/backport-6.1/791-v6.3-05-net-phy-motorcomm-change-the-phy-id-of-yt8521-and-yt8531s.patch b/target/linux/generic/backport-6.1/791-v6.3-05-net-phy-motorcomm-change-the-phy-id-of-yt8521-and-yt8531s.patch new file mode 100644 index 00000000000..076fa82d267 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-05-net-phy-motorcomm-change-the-phy-id-of-yt8521-and-yt8531s.patch @@ -0,0 +1,29 @@ +From 3c1dc22162d673d595855d24f95200ed2643f88f Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Sat, 28 Jan 2023 14:35:58 +0800 +Subject: [PATCH] net: phy: motorcomm: change the phy id of yt8521 and yt8531s + to lowercase + +The phy id is usually defined in lower case. + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Link: https://lore.kernel.org/r/20230128063558.5850-2-Frank.Sae@motor-comm.com +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/motorcomm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -12,8 +12,8 @@ + #include + + #define PHY_ID_YT8511 0x0000010a +-#define PHY_ID_YT8521 0x0000011A +-#define PHY_ID_YT8531S 0x4F51E91A ++#define PHY_ID_YT8521 0x0000011a ++#define PHY_ID_YT8531S 0x4f51e91a + + /* YT8521/YT8531S Register Overview + * UTP Register space | FIBER Register space diff --git a/target/linux/generic/backport-6.1/791-v6.3-06-net-phy-Add-BIT-macro-for-Motorcomm-yt8521-yt8531-gigabit.patch b/target/linux/generic/backport-6.1/791-v6.3-06-net-phy-Add-BIT-macro-for-Motorcomm-yt8521-yt8531-gigabit.patch new file mode 100644 index 00000000000..ba9a6ab4ccb --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-06-net-phy-Add-BIT-macro-for-Motorcomm-yt8521-yt8531-gigabit.patch @@ -0,0 +1,107 @@ +From 4869a146cd60fc8115230f0a45e15e534c531922 Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Thu, 2 Feb 2023 11:00:34 +0800 +Subject: [PATCH] net: phy: Add BIT macro for Motorcomm yt8521/yt8531 gigabit + ethernet phy + +Add BIT macro for Motorcomm yt8521/yt8531 gigabit ethernet phy. + This is a preparatory patch. Add BIT macro for 0xA012 reg, and + supplement for 0xA001 and 0xA003 reg. These will be used to support dts. + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/motorcomm.c | 55 ++++++++++++++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 4 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -161,6 +161,11 @@ + + #define YT8521_CHIP_CONFIG_REG 0xA001 + #define YT8521_CCR_SW_RST BIT(15) ++/* 1b0 disable 1.9ns rxc clock delay *default* ++ * 1b1 enable 1.9ns rxc clock delay ++ */ ++#define YT8521_CCR_RXC_DLY_EN BIT(8) ++#define YT8521_CCR_RXC_DLY_1_900_NS 1900 + + #define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0)) + #define YT8521_CCR_MODE_UTP_TO_RGMII 0 +@@ -178,22 +183,41 @@ + #define YT8521_MODE_POLL 0x3 + + #define YT8521_RGMII_CONFIG1_REG 0xA003 +- ++/* 1b0 use original tx_clk_rgmii *default* ++ * 1b1 use inverted tx_clk_rgmii. ++ */ ++#define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14) + /* TX Gig-E Delay is bits 3:0, default 0x1 + * TX Fast-E Delay is bits 7:4, default 0xf + * RX Delay is bits 13:10, default 0x0 + * Delay = 150ps * N + * On = 2250ps, off = 0ps + */ +-#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10) ++#define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10) + #define YT8521_RC1R_RX_DELAY_EN (0xF << 10) + #define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) +-#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4) ++#define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) + #define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) + #define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) +-#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0) ++#define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) + #define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) + #define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) ++#define YT8521_RC1R_RGMII_0_000_NS 0 ++#define YT8521_RC1R_RGMII_0_150_NS 1 ++#define YT8521_RC1R_RGMII_0_300_NS 2 ++#define YT8521_RC1R_RGMII_0_450_NS 3 ++#define YT8521_RC1R_RGMII_0_600_NS 4 ++#define YT8521_RC1R_RGMII_0_750_NS 5 ++#define YT8521_RC1R_RGMII_0_900_NS 6 ++#define YT8521_RC1R_RGMII_1_050_NS 7 ++#define YT8521_RC1R_RGMII_1_200_NS 8 ++#define YT8521_RC1R_RGMII_1_350_NS 9 ++#define YT8521_RC1R_RGMII_1_500_NS 10 ++#define YT8521_RC1R_RGMII_1_650_NS 11 ++#define YT8521_RC1R_RGMII_1_800_NS 12 ++#define YT8521_RC1R_RGMII_1_950_NS 13 ++#define YT8521_RC1R_RGMII_2_100_NS 14 ++#define YT8521_RC1R_RGMII_2_250_NS 15 + + #define YTPHY_MISC_CONFIG_REG 0xA006 + #define YTPHY_MCR_FIBER_SPEED_MASK BIT(0) +@@ -222,6 +246,29 @@ + */ + #define YTPHY_WCR_TYPE_PULSE BIT(0) + ++#define YTPHY_SYNCE_CFG_REG 0xA012 ++#define YT8521_SCR_SYNCE_ENABLE BIT(5) ++/* 1b0 output 25m clock ++ * 1b1 output 125m clock *default* ++ */ ++#define YT8521_SCR_CLK_FRE_SEL_125M BIT(3) ++#define YT8521_SCR_CLK_SRC_MASK GENMASK(2, 1) ++#define YT8521_SCR_CLK_SRC_PLL_125M 0 ++#define YT8521_SCR_CLK_SRC_UTP_RX 1 ++#define YT8521_SCR_CLK_SRC_SDS_RX 2 ++#define YT8521_SCR_CLK_SRC_REF_25M 3 ++#define YT8531_SCR_SYNCE_ENABLE BIT(6) ++/* 1b0 output 25m clock *default* ++ * 1b1 output 125m clock ++ */ ++#define YT8531_SCR_CLK_FRE_SEL_125M BIT(4) ++#define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1) ++#define YT8531_SCR_CLK_SRC_PLL_125M 0 ++#define YT8531_SCR_CLK_SRC_UTP_RX 1 ++#define YT8531_SCR_CLK_SRC_SDS_RX 2 ++#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 ++#define YT8531_SCR_CLK_SRC_REF_25M 4 ++#define YT8531_SCR_CLK_SRC_SSC_25M 5 + #define YT8531S_SYNCE_CFG_REG 0xA012 + #define YT8531S_SCR_SYNCE_ENABLE BIT(6) + diff --git a/target/linux/generic/backport-6.1/791-v6.3-07-net-phy-Add-dts-support-for-Motorcomm-yt8521-gigabit.patch b/target/linux/generic/backport-6.1/791-v6.3-07-net-phy-Add-dts-support-for-Motorcomm-yt8521-gigabit.patch new file mode 100644 index 00000000000..6d89fae84cc --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-07-net-phy-Add-dts-support-for-Motorcomm-yt8521-gigabit.patch @@ -0,0 +1,343 @@ +From a6e68f0f8769f79c67cdcfb6302feecd36197dec Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Thu, 2 Feb 2023 11:00:35 +0800 +Subject: [PATCH] net: phy: Add dts support for Motorcomm yt8521 gigabit + ethernet phy + +Add dts support for Motorcomm yt8521 gigabit ethernet phy. + Add ytphy_rgmii_clk_delay_config function to support dst config for + the delay of rgmii clk. This funciont is common for yt8521, yt8531s + and yt8531. + This patch has been verified on AM335x platform. + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/motorcomm.c | 253 ++++++++++++++++++++++++++++-------- + 1 file changed, 199 insertions(+), 54 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + #define PHY_ID_YT8511 0x0000010a + #define PHY_ID_YT8521 0x0000011a +@@ -187,21 +188,9 @@ + * 1b1 use inverted tx_clk_rgmii. + */ + #define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14) +-/* TX Gig-E Delay is bits 3:0, default 0x1 +- * TX Fast-E Delay is bits 7:4, default 0xf +- * RX Delay is bits 13:10, default 0x0 +- * Delay = 150ps * N +- * On = 2250ps, off = 0ps +- */ + #define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10) +-#define YT8521_RC1R_RX_DELAY_EN (0xF << 10) +-#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10) + #define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4) +-#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4) +-#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4) + #define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0) +-#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0) +-#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0) + #define YT8521_RC1R_RGMII_0_000_NS 0 + #define YT8521_RC1R_RGMII_0_150_NS 1 + #define YT8521_RC1R_RGMII_0_300_NS 2 +@@ -274,6 +263,10 @@ + + /* Extended Register end */ + ++#define YTPHY_DTS_OUTPUT_CLK_DIS 0 ++#define YTPHY_DTS_OUTPUT_CLK_25M 25000000 ++#define YTPHY_DTS_OUTPUT_CLK_125M 125000000 ++ + struct yt8521_priv { + /* combo_advertising is used for case of YT8521 in combo mode, + * this means that yt8521 may work in utp or fiber mode which depends +@@ -641,6 +634,142 @@ static int yt8521_write_page(struct phy_ + }; + + /** ++ * struct ytphy_cfg_reg_map - map a config value to a register value ++ * @cfg: value in device configuration ++ * @reg: value in the register ++ */ ++struct ytphy_cfg_reg_map { ++ u32 cfg; ++ u32 reg; ++}; ++ ++static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = { ++ /* for tx delay / rx delay with YT8521_CCR_RXC_DLY_EN is not set. */ ++ { 0, YT8521_RC1R_RGMII_0_000_NS }, ++ { 150, YT8521_RC1R_RGMII_0_150_NS }, ++ { 300, YT8521_RC1R_RGMII_0_300_NS }, ++ { 450, YT8521_RC1R_RGMII_0_450_NS }, ++ { 600, YT8521_RC1R_RGMII_0_600_NS }, ++ { 750, YT8521_RC1R_RGMII_0_750_NS }, ++ { 900, YT8521_RC1R_RGMII_0_900_NS }, ++ { 1050, YT8521_RC1R_RGMII_1_050_NS }, ++ { 1200, YT8521_RC1R_RGMII_1_200_NS }, ++ { 1350, YT8521_RC1R_RGMII_1_350_NS }, ++ { 1500, YT8521_RC1R_RGMII_1_500_NS }, ++ { 1650, YT8521_RC1R_RGMII_1_650_NS }, ++ { 1800, YT8521_RC1R_RGMII_1_800_NS }, ++ { 1950, YT8521_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */ ++ { 2100, YT8521_RC1R_RGMII_2_100_NS }, ++ { 2250, YT8521_RC1R_RGMII_2_250_NS }, ++ ++ /* only for rx delay with YT8521_CCR_RXC_DLY_EN is set. */ ++ { 0 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_000_NS }, ++ { 150 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_150_NS }, ++ { 300 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_300_NS }, ++ { 450 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_450_NS }, ++ { 600 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_600_NS }, ++ { 750 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_750_NS }, ++ { 900 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_900_NS }, ++ { 1050 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_050_NS }, ++ { 1200 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_200_NS }, ++ { 1350 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_350_NS }, ++ { 1500 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_500_NS }, ++ { 1650 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_650_NS }, ++ { 1800 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_800_NS }, ++ { 1950 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_950_NS }, ++ { 2100 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_100_NS }, ++ { 2250 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_250_NS } ++}; ++ ++static u32 ytphy_get_delay_reg_value(struct phy_device *phydev, ++ const char *prop_name, ++ const struct ytphy_cfg_reg_map *tbl, ++ int tb_size, ++ u16 *rxc_dly_en, ++ u32 dflt) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ int tb_size_half = tb_size / 2; ++ u32 val; ++ int i; ++ ++ if (of_property_read_u32(node, prop_name, &val)) ++ goto err_dts_val; ++ ++ /* when rxc_dly_en is NULL, it is get the delay for tx, only half of ++ * tb_size is valid. ++ */ ++ if (!rxc_dly_en) ++ tb_size = tb_size_half; ++ ++ for (i = 0; i < tb_size; i++) { ++ if (tbl[i].cfg == val) { ++ if (rxc_dly_en && i < tb_size_half) ++ *rxc_dly_en = 0; ++ return tbl[i].reg; ++ } ++ } ++ ++ phydev_warn(phydev, "Unsupported value %d for %s using default (%u)\n", ++ val, prop_name, dflt); ++ ++err_dts_val: ++ /* when rxc_dly_en is not NULL, it is get the delay for rx. ++ * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps, ++ * so YT8521_CCR_RXC_DLY_EN should not be set. ++ */ ++ if (rxc_dly_en) ++ *rxc_dly_en = 0; ++ ++ return dflt; ++} ++ ++static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev) ++{ ++ int tb_size = ARRAY_SIZE(ytphy_rgmii_delays); ++ u16 rxc_dly_en = YT8521_CCR_RXC_DLY_EN; ++ u32 rx_reg, tx_reg; ++ u16 mask, val = 0; ++ int ret; ++ ++ rx_reg = ytphy_get_delay_reg_value(phydev, "rx-internal-delay-ps", ++ ytphy_rgmii_delays, tb_size, ++ &rxc_dly_en, ++ YT8521_RC1R_RGMII_1_950_NS); ++ tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps", ++ ytphy_rgmii_delays, tb_size, NULL, ++ YT8521_RC1R_RGMII_1_950_NS); ++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_RGMII: ++ rxc_dly_en = 0; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg); ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ rxc_dly_en = 0; ++ val |= FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); ++ break; ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) | ++ FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg); ++ break; ++ default: /* do not support other modes */ ++ return -EOPNOTSUPP; ++ } ++ ++ ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG, ++ YT8521_CCR_RXC_DLY_EN, rxc_dly_en); ++ if (ret < 0) ++ return ret; ++ ++ /* Generally, it is not necessary to adjust YT8521_RC1R_FE_TX_DELAY */ ++ mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_GE_TX_DELAY_MASK; ++ return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); ++} ++ ++/** + * yt8521_probe() - read chip config then set suitable polling_mode + * @phydev: a pointer to a &struct phy_device + * +@@ -648,9 +777,12 @@ static int yt8521_write_page(struct phy_ + */ + static int yt8521_probe(struct phy_device *phydev) + { ++ struct device_node *node = phydev->mdio.dev.of_node; + struct device *dev = &phydev->mdio.dev; + struct yt8521_priv *priv; + int chip_config; ++ u16 mask, val; ++ u32 freq; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +@@ -695,7 +827,45 @@ static int yt8521_probe(struct phy_devic + return ret; + } + +- return 0; ++ if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq)) ++ freq = YTPHY_DTS_OUTPUT_CLK_DIS; ++ ++ if (phydev->drv->phy_id == PHY_ID_YT8521) { ++ switch (freq) { ++ case YTPHY_DTS_OUTPUT_CLK_DIS: ++ mask = YT8521_SCR_SYNCE_ENABLE; ++ val = 0; ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_25M: ++ mask = YT8521_SCR_SYNCE_ENABLE | ++ YT8521_SCR_CLK_SRC_MASK | ++ YT8521_SCR_CLK_FRE_SEL_125M; ++ val = YT8521_SCR_SYNCE_ENABLE | ++ FIELD_PREP(YT8521_SCR_CLK_SRC_MASK, ++ YT8521_SCR_CLK_SRC_REF_25M); ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_125M: ++ mask = YT8521_SCR_SYNCE_ENABLE | ++ YT8521_SCR_CLK_SRC_MASK | ++ YT8521_SCR_CLK_FRE_SEL_125M; ++ val = YT8521_SCR_SYNCE_ENABLE | ++ YT8521_SCR_CLK_FRE_SEL_125M | ++ FIELD_PREP(YT8521_SCR_CLK_SRC_MASK, ++ YT8521_SCR_CLK_SRC_PLL_125M); ++ break; ++ default: ++ phydev_warn(phydev, "Freq err:%u\n", freq); ++ return -EINVAL; ++ } ++ } else if (phydev->drv->phy_id == PHY_ID_YT8531S) { ++ return 0; ++ } else { ++ phydev_warn(phydev, "PHY id err\n"); ++ return -EINVAL; ++ } ++ ++ return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask, ++ val); + } + + /** +@@ -1180,61 +1350,36 @@ static int yt8521_resume(struct phy_devi + */ + static int yt8521_config_init(struct phy_device *phydev) + { ++ struct device_node *node = phydev->mdio.dev.of_node; + int old_page; + int ret = 0; +- u16 val; + + old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE); + if (old_page < 0) + goto err_restore_page; + +- switch (phydev->interface) { +- case PHY_INTERFACE_MODE_RGMII: +- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; +- val |= YT8521_RC1R_RX_DELAY_DIS; +- break; +- case PHY_INTERFACE_MODE_RGMII_RXID: +- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS; +- val |= YT8521_RC1R_RX_DELAY_EN; +- break; +- case PHY_INTERFACE_MODE_RGMII_TXID: +- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; +- val |= YT8521_RC1R_RX_DELAY_DIS; +- break; +- case PHY_INTERFACE_MODE_RGMII_ID: +- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN; +- val |= YT8521_RC1R_RX_DELAY_EN; +- break; +- case PHY_INTERFACE_MODE_SGMII: +- break; +- default: /* do not support other modes */ +- ret = -EOPNOTSUPP; +- goto err_restore_page; +- } +- + /* set rgmii delay mode */ + if (phydev->interface != PHY_INTERFACE_MODE_SGMII) { +- ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, +- (YT8521_RC1R_RX_DELAY_MASK | +- YT8521_RC1R_FE_TX_DELAY_MASK | +- YT8521_RC1R_GE_TX_DELAY_MASK), +- val); ++ ret = ytphy_rgmii_clk_delay_config(phydev); + if (ret < 0) + goto err_restore_page; + } + +- /* disable auto sleep */ +- ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, +- YT8521_ESC1R_SLEEP_SW, 0); +- if (ret < 0) +- goto err_restore_page; +- +- /* enable RXC clock when no wire plug */ +- ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, +- YT8521_CGR_RX_CLK_EN, 0); +- if (ret < 0) +- goto err_restore_page; ++ if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) { ++ /* disable auto sleep */ ++ ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG, ++ YT8521_ESC1R_SLEEP_SW, 0); ++ if (ret < 0) ++ goto err_restore_page; ++ } + ++ if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) { ++ /* enable RXC clock when no wire plug */ ++ ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG, ++ YT8521_CGR_RX_CLK_EN, 0); ++ if (ret < 0) ++ goto err_restore_page; ++ } + err_restore_page: + return phy_restore_page(phydev, old_page, ret); + } diff --git a/target/linux/generic/backport-6.1/791-v6.3-08-net-phy-Add-dts-support-for-Motorcomm-yt8531s-gigabit.patch b/target/linux/generic/backport-6.1/791-v6.3-08-net-phy-Add-dts-support-for-Motorcomm-yt8531s-gigabit.patch new file mode 100644 index 00000000000..86fc04695c8 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-08-net-phy-Add-dts-support-for-Motorcomm-yt8531s-gigabit.patch @@ -0,0 +1,100 @@ +From 36152f87dda4af221b16258751451d9cd3d0fb0b Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Thu, 2 Feb 2023 11:00:36 +0800 +Subject: [PATCH] net: phy: Add dts support for Motorcomm yt8531s gigabit + ethernet phy + +Add dts support for Motorcomm yt8531s gigabit ethernet phy. + Change yt8521_probe to support clk config of yt8531s. Becase + yt8521_probe does the things which yt8531s is needed, so + removed yt8531s function. + This patch has been verified on AM335x platform with yt8531s board. + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/motorcomm.c | 51 ++++++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 24 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -258,8 +258,6 @@ + #define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3 + #define YT8531_SCR_CLK_SRC_REF_25M 4 + #define YT8531_SCR_CLK_SRC_SSC_25M 5 +-#define YT8531S_SYNCE_CFG_REG 0xA012 +-#define YT8531S_SCR_SYNCE_ENABLE BIT(6) + + /* Extended Register end */ + +@@ -858,7 +856,32 @@ static int yt8521_probe(struct phy_devic + return -EINVAL; + } + } else if (phydev->drv->phy_id == PHY_ID_YT8531S) { +- return 0; ++ switch (freq) { ++ case YTPHY_DTS_OUTPUT_CLK_DIS: ++ mask = YT8531_SCR_SYNCE_ENABLE; ++ val = 0; ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_25M: ++ mask = YT8531_SCR_SYNCE_ENABLE | ++ YT8531_SCR_CLK_SRC_MASK | ++ YT8531_SCR_CLK_FRE_SEL_125M; ++ val = YT8531_SCR_SYNCE_ENABLE | ++ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, ++ YT8531_SCR_CLK_SRC_REF_25M); ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_125M: ++ mask = YT8531_SCR_SYNCE_ENABLE | ++ YT8531_SCR_CLK_SRC_MASK | ++ YT8531_SCR_CLK_FRE_SEL_125M; ++ val = YT8531_SCR_SYNCE_ENABLE | ++ YT8531_SCR_CLK_FRE_SEL_125M | ++ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, ++ YT8531_SCR_CLK_SRC_PLL_125M); ++ break; ++ default: ++ phydev_warn(phydev, "Freq err:%u\n", freq); ++ return -EINVAL; ++ } + } else { + phydev_warn(phydev, "PHY id err\n"); + return -EINVAL; +@@ -869,26 +892,6 @@ static int yt8521_probe(struct phy_devic + } + + /** +- * yt8531s_probe() - read chip config then set suitable polling_mode +- * @phydev: a pointer to a &struct phy_device +- * +- * returns 0 or negative errno code +- */ +-static int yt8531s_probe(struct phy_device *phydev) +-{ +- int ret; +- +- /* Disable SyncE clock output by default */ +- ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG, +- YT8531S_SCR_SYNCE_ENABLE, 0); +- if (ret < 0) +- return ret; +- +- /* same as yt8521_probe */ +- return yt8521_probe(phydev); +-} +- +-/** + * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp + * @phydev: a pointer to a &struct phy_device + * +@@ -1970,7 +1973,7 @@ static struct phy_driver motorcomm_phy_d + PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), + .name = "YT8531S Gigabit Ethernet", + .get_features = yt8521_get_features, +- .probe = yt8531s_probe, ++ .probe = yt8521_probe, + .read_page = yt8521_read_page, + .write_page = yt8521_write_page, + .get_wol = ytphy_get_wol, diff --git a/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch b/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch new file mode 100644 index 00000000000..9dce5a8add9 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch @@ -0,0 +1,302 @@ +From 4ac94f728a588e7096dd5010cd7141a309ea7805 Mon Sep 17 00:00:00 2001 +From: Frank Sae +Date: Thu, 2 Feb 2023 11:00:37 +0800 +Subject: [PATCH] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet + phy + +Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have + verified the driver on AM335x platform with yt8531 board. On the + board, yt8531 gigabit ethernet phy works in utp mode, RGMII + interface, supports 1000M/100M/10M speeds, and wol(magic package). + +Signed-off-by: Frank Sae +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/phy/Kconfig | 2 +- + drivers/net/phy/motorcomm.c | 208 +++++++++++++++++++++++++++++++++++- + 2 files changed, 207 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -245,7 +245,7 @@ config MOTORCOMM_PHY + tristate "Motorcomm PHYs" + help + Enables support for Motorcomm network PHYs. +- Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs. ++ Currently supports YT85xx Gigabit Ethernet PHYs. + + config NATIONAL_PHY + tristate "National Semiconductor PHYs" +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * Motorcomm 8511/8521/8531S PHY driver. ++ * Motorcomm 8511/8521/8531/8531S PHY driver. + * + * Author: Peter Geis + * Author: Frank +@@ -14,6 +14,7 @@ + + #define PHY_ID_YT8511 0x0000010a + #define PHY_ID_YT8521 0x0000011a ++#define PHY_ID_YT8531 0x4f51e91b + #define PHY_ID_YT8531S 0x4f51e91a + + /* YT8521/YT8531S Register Overview +@@ -517,6 +518,61 @@ err_restore_page: + return phy_restore_page(phydev, old_page, ret); + } + ++static int yt8531_set_wol(struct phy_device *phydev, ++ struct ethtool_wolinfo *wol) ++{ ++ const u16 mac_addr_reg[] = { ++ YTPHY_WOL_MACADDR2_REG, ++ YTPHY_WOL_MACADDR1_REG, ++ YTPHY_WOL_MACADDR0_REG, ++ }; ++ const u8 *mac_addr; ++ u16 mask, val; ++ int ret; ++ u8 i; ++ ++ if (wol->wolopts & WAKE_MAGIC) { ++ mac_addr = phydev->attached_dev->dev_addr; ++ ++ /* Store the device address for the magic packet */ ++ for (i = 0; i < 3; i++) { ++ ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i], ++ ((mac_addr[i * 2] << 8)) | ++ (mac_addr[i * 2 + 1])); ++ if (ret < 0) ++ return ret; ++ } ++ ++ /* Enable WOL feature */ ++ mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL; ++ val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; ++ val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS; ++ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, ++ mask, val); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable WOL interrupt */ ++ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0, ++ YTPHY_IER_WOL); ++ if (ret < 0) ++ return ret; ++ } else { ++ /* Disable WOL feature */ ++ mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL; ++ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG, ++ mask, 0); ++ ++ /* Disable WOL interrupt */ ++ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, ++ YTPHY_IER_WOL, 0); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int yt8511_read_page(struct phy_device *phydev) + { + return __phy_read(phydev, YT8511_PAGE_SELECT); +@@ -767,6 +823,17 @@ static int ytphy_rgmii_clk_delay_config( + return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val); + } + ++static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev) ++{ ++ int ret; ++ ++ phy_lock_mdio_bus(phydev); ++ ret = ytphy_rgmii_clk_delay_config(phydev); ++ phy_unlock_mdio_bus(phydev); ++ ++ return ret; ++} ++ + /** + * yt8521_probe() - read chip config then set suitable polling_mode + * @phydev: a pointer to a &struct phy_device +@@ -891,6 +958,43 @@ static int yt8521_probe(struct phy_devic + val); + } + ++static int yt8531_probe(struct phy_device *phydev) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ u16 mask, val; ++ u32 freq; ++ ++ if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz", &freq)) ++ freq = YTPHY_DTS_OUTPUT_CLK_DIS; ++ ++ switch (freq) { ++ case YTPHY_DTS_OUTPUT_CLK_DIS: ++ mask = YT8531_SCR_SYNCE_ENABLE; ++ val = 0; ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_25M: ++ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | ++ YT8531_SCR_CLK_FRE_SEL_125M; ++ val = YT8531_SCR_SYNCE_ENABLE | ++ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, ++ YT8531_SCR_CLK_SRC_REF_25M); ++ break; ++ case YTPHY_DTS_OUTPUT_CLK_125M: ++ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK | ++ YT8531_SCR_CLK_FRE_SEL_125M; ++ val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M | ++ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK, ++ YT8531_SCR_CLK_SRC_PLL_125M); ++ break; ++ default: ++ phydev_warn(phydev, "Freq err:%u\n", freq); ++ return -EINVAL; ++ } ++ ++ return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask, ++ val); ++} ++ + /** + * ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp + * @phydev: a pointer to a &struct phy_device +@@ -1387,6 +1491,94 @@ err_restore_page: + return phy_restore_page(phydev, old_page, ret); + } + ++static int yt8531_config_init(struct phy_device *phydev) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ int ret; ++ ++ ret = ytphy_rgmii_clk_delay_config_with_lock(phydev); ++ if (ret < 0) ++ return ret; ++ ++ if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) { ++ /* disable auto sleep */ ++ ret = ytphy_modify_ext_with_lock(phydev, ++ YT8521_EXTREG_SLEEP_CONTROL1_REG, ++ YT8521_ESC1R_SLEEP_SW, 0); ++ if (ret < 0) ++ return ret; ++ } ++ ++ if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) { ++ /* enable RXC clock when no wire plug */ ++ ret = ytphy_modify_ext_with_lock(phydev, ++ YT8521_CLOCK_GATING_REG, ++ YT8521_CGR_RX_CLK_EN, 0); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * yt8531_link_change_notify() - Adjust the tx clock direction according to ++ * the current speed and dts config. ++ * @phydev: a pointer to a &struct phy_device ++ * ++ * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please ++ * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not ++ * JH7110. ++ */ ++static void yt8531_link_change_notify(struct phy_device *phydev) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ bool tx_clk_adj_enabled = false; ++ bool tx_clk_1000_inverted; ++ bool tx_clk_100_inverted; ++ bool tx_clk_10_inverted; ++ u16 val = 0; ++ int ret; ++ ++ if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled")) ++ tx_clk_adj_enabled = true; ++ ++ if (!tx_clk_adj_enabled) ++ return; ++ ++ if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted")) ++ tx_clk_10_inverted = true; ++ if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted")) ++ tx_clk_100_inverted = true; ++ if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted")) ++ tx_clk_1000_inverted = true; ++ ++ if (phydev->speed < 0) ++ return; ++ ++ switch (phydev->speed) { ++ case SPEED_1000: ++ if (tx_clk_1000_inverted) ++ val = YT8521_RC1R_TX_CLK_SEL_INVERTED; ++ break; ++ case SPEED_100: ++ if (tx_clk_100_inverted) ++ val = YT8521_RC1R_TX_CLK_SEL_INVERTED; ++ break; ++ case SPEED_10: ++ if (tx_clk_10_inverted) ++ val = YT8521_RC1R_TX_CLK_SEL_INVERTED; ++ break; ++ default: ++ return; ++ } ++ ++ ret = ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG, ++ YT8521_RC1R_TX_CLK_SEL_INVERTED, val); ++ if (ret < 0) ++ phydev_warn(phydev, "Modify TX_CLK_SEL err:%d\n", ret); ++} ++ + /** + * yt8521_prepare_fiber_features() - A small helper function that setup + * fiber's features. +@@ -1970,6 +2162,17 @@ static struct phy_driver motorcomm_phy_d + .resume = yt8521_resume, + }, + { ++ PHY_ID_MATCH_EXACT(PHY_ID_YT8531), ++ .name = "YT8531 Gigabit Ethernet", ++ .probe = yt8531_probe, ++ .config_init = yt8531_config_init, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .get_wol = ytphy_get_wol, ++ .set_wol = yt8531_set_wol, ++ .link_change_notify = yt8531_link_change_notify, ++ }, ++ { + PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), + .name = "YT8531S Gigabit Ethernet", + .get_features = yt8521_get_features, +@@ -1990,7 +2193,7 @@ static struct phy_driver motorcomm_phy_d + + module_phy_driver(motorcomm_phy_drvs); + +-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver"); ++MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver"); + MODULE_AUTHOR("Peter Geis"); + MODULE_AUTHOR("Frank"); + MODULE_LICENSE("GPL"); +@@ -1998,6 +2201,7 @@ MODULE_LICENSE("GPL"); + static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { + { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) }, ++ { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, + { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, + { /* sentinel */ } + }; diff --git a/target/linux/generic/backport-6.1/791-v6.3-10-net-phy-motorcomm-uninitialized-variables-in.patch b/target/linux/generic/backport-6.1/791-v6.3-10-net-phy-motorcomm-uninitialized-variables-in.patch new file mode 100644 index 00000000000..29ae86dbbc2 --- /dev/null +++ b/target/linux/generic/backport-6.1/791-v6.3-10-net-phy-motorcomm-uninitialized-variables-in.patch @@ -0,0 +1,34 @@ +From 9753613f7399601f9bae6ee81e9d4274246c98ab Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Wed, 15 Feb 2023 07:21:47 +0300 +Subject: [PATCH] net: phy: motorcomm: uninitialized variables in + yt8531_link_change_notify() + +These booleans are never set to false, but are just used without being +initialized. + +Fixes: 4ac94f728a58 ("net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy") +Signed-off-by: Dan Carpenter +Reviewed-by: Frank Sae +Link: https://lore.kernel.org/r/Y+xd2yJet2ImHLoQ@kili +Signed-off-by: Jakub Kicinski +--- + drivers/net/phy/motorcomm.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/motorcomm.c ++++ b/drivers/net/phy/motorcomm.c +@@ -1533,10 +1533,10 @@ static int yt8531_config_init(struct phy + static void yt8531_link_change_notify(struct phy_device *phydev) + { + struct device_node *node = phydev->mdio.dev.of_node; ++ bool tx_clk_1000_inverted = false; ++ bool tx_clk_100_inverted = false; ++ bool tx_clk_10_inverted = false; + bool tx_clk_adj_enabled = false; +- bool tx_clk_1000_inverted; +- bool tx_clk_100_inverted; +- bool tx_clk_10_inverted; + u16 val = 0; + int ret; + diff --git a/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch b/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch new file mode 100644 index 00000000000..a2168aaba5f --- /dev/null +++ b/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch @@ -0,0 +1,68 @@ +From 16b1c4e01c89ba07367461e0bc4cb84993c2d027 Mon Sep 17 00:00:00 2001 +From: Jacky Chou +Date: Mon, 15 Nov 2021 11:49:41 +0800 +Subject: [PATCH] net: usb: ax88179_178a: add TSO feature + +On low-effciency embedded platforms, transmission performance is poor +due to on Bulk-out with single packet. +Adding TSO feature improves the transmission performance and reduces +the number of interrupt caused by Bulk-out complete. + +Reference to module, net: usb: aqc111. + +Signed-off-by: Jacky Chou +Signed-off-by: David S. Miller +--- + drivers/net/usb/ax88179_178a.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +--- a/drivers/net/usb/ax88179_178a.c ++++ b/drivers/net/usb/ax88179_178a.c +@@ -1377,11 +1377,12 @@ static int ax88179_bind(struct usbnet *d + dev->mii.phy_id = 0x03; + dev->mii.supports_gmii = 1; + +- dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +- NETIF_F_RXCSUM; ++ dev->net->features |= NETIF_F_SG | NETIF_F_IP_CSUM | ++ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO; + +- dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +- NETIF_F_RXCSUM; ++ dev->net->hw_features |= dev->net->features; ++ ++ netif_set_gso_max_size(dev->net, 16384); + + /* Enable checksum offload */ + *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | +@@ -1587,17 +1588,19 @@ ax88179_tx_fixup(struct usbnet *dev, str + { + u32 tx_hdr1, tx_hdr2; + int frame_size = dev->maxpacket; +- int mss = skb_shinfo(skb)->gso_size; + int headroom; + void *ptr; + + tx_hdr1 = skb->len; +- tx_hdr2 = mss; ++ tx_hdr2 = skb_shinfo(skb)->gso_size; /* Set TSO mss */ + if (((skb->len + 8) % frame_size) == 0) + tx_hdr2 |= 0x80008000; /* Enable padding */ + + headroom = skb_headroom(skb) - 8; + ++ if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb)) ++ return NULL; ++ + if ((skb_header_cloned(skb) || headroom < 0) && + pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { + dev_kfree_skb_any(skb); +@@ -1608,6 +1611,8 @@ ax88179_tx_fixup(struct usbnet *dev, str + put_unaligned_le32(tx_hdr1, ptr); + put_unaligned_le32(tx_hdr2, ptr + 4); + ++ usbnet_set_skb_tx_stats(skb, (skb_shinfo(skb)->gso_segs ?: 1), 0); ++ + return skb; + } + diff --git a/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch b/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch new file mode 100644 index 00000000000..b1072ce6408 --- /dev/null +++ b/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch @@ -0,0 +1,125 @@ +From 13344f8ce8a0d98aa7f5d69ce3b47393c73a343b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 27 Dec 2021 15:59:04 +0100 +Subject: [PATCH] dt-bindings: leds: add Broadcom's BCM63138 controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Broadcom used 2 LEDs hardware blocks for their BCM63xx SoCs: +1. Older one (BCM6318, BCM6328, BCM6362, BCM63268, BCM6838) +2. Newer one (BCM6848, BCM6858, BCM63138, BCM63148, BCM63381, BCM68360) + +The newer one was also later also used on BCM4908 SoC. + +Old block is already documented in the leds-bcm6328.yaml. This binding +documents the new one which uses different registers & programming. It's +first used in BCM63138 thus the binding name. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Rob Herring +Reviewed-by: Florian Fainelli +Signed-off-by: Pavel Machek +--- + .../bindings/leds/leds-bcm63138.yaml | 95 +++++++++++++++++++ + 1 file changed, 95 insertions(+) + create mode 100644 Documentation/devicetree/bindings/leds/leds-bcm63138.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml +@@ -0,0 +1,95 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/leds/leds-bcm63138.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Broadcom's BCM63138 LEDs controller ++ ++maintainers: ++ - Rafał Miłecki ++ ++description: | ++ This LEDs controller was first used on BCM63138 and later reused on BCM4908, ++ BCM6848, BCM6858, BCM63138, BCM63148, BCM63381 and BCM68360 SoCs. ++ ++ It supports up to 32 LEDs that can be connected parallelly or serially. It ++ also includes limited support for hardware blinking. ++ ++ Binding serially connected LEDs isn't documented yet. ++ ++properties: ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - brcm,bcm4908-leds ++ - brcm,bcm6848-leds ++ - brcm,bcm6858-leds ++ - brcm,bcm63148-leds ++ - brcm,bcm63381-leds ++ - brcm,bcm68360-leds ++ - const: brcm,bcm63138-leds ++ - const: brcm,bcm63138-leds ++ ++ reg: ++ maxItems: 1 ++ ++ "#address-cells": ++ const: 1 ++ ++ "#size-cells": ++ const: 0 ++ ++patternProperties: ++ "^led@[a-f0-9]+$": ++ type: object ++ ++ $ref: common.yaml# ++ ++ properties: ++ reg: ++ maxItems: 1 ++ description: LED pin number ++ ++ active-low: ++ type: boolean ++ description: Makes LED active low. ++ ++ required: ++ - reg ++ ++ unevaluatedProperties: false ++ ++required: ++ - reg ++ - "#address-cells" ++ - "#size-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ ++ leds@ff800800 { ++ compatible = "brcm,bcm4908-leds", "brcm,bcm63138-leds"; ++ reg = <0xff800800 0xdc>; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ led@0 { ++ reg = <0x0>; ++ function = LED_FUNCTION_POWER; ++ color = ; ++ default-state = "on"; ++ }; ++ ++ led@3 { ++ reg = <0x3>; ++ function = LED_FUNCTION_STATUS; ++ color = ; ++ active-low; ++ }; ++ }; diff --git a/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch b/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch new file mode 100644 index 00000000000..376584574fc --- /dev/null +++ b/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch @@ -0,0 +1,356 @@ +From a0ba692072d89075d0a75c7ad9df31f2c1ee9a1c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 27 Dec 2021 15:59:05 +0100 +Subject: [PATCH] leds: bcm63138: add support for BCM63138 controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's a new controller first introduced in BCM63138 SoC. Later it was +also used in BCM4908, some BCM68xx and some BCM63xxx SoCs. + +Signed-off-by: Rafał Miłecki +Reviewed-by: Florian Fainelli +Signed-off-by: Pavel Machek +--- + drivers/leds/blink/Kconfig | 12 ++ + drivers/leds/blink/Makefile | 1 + + drivers/leds/blink/leds-bcm63138.c | 308 +++++++++++++++++++++++++++++ + 3 files changed, 321 insertions(+) + create mode 100644 drivers/leds/blink/leds-bcm63138.c + +--- a/drivers/leds/blink/Kconfig ++++ b/drivers/leds/blink/Kconfig +@@ -1,3 +1,15 @@ ++config LEDS_BCM63138 ++ tristate "LED Support for Broadcom BCM63138 SoC" ++ depends on LEDS_CLASS ++ depends on ARCH_BCM4908 || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST ++ depends on HAS_IOMEM ++ depends on OF ++ default ARCH_BCM4908 ++ help ++ This option enables support for LED controller that is part of ++ BCM63138 SoC. The same hardware block is known to be also used ++ in BCM4908, BCM6848, BCM6858, BCM63148, BCM63381 and BCM68360. ++ + config LEDS_LGM + tristate "LED support for LGM SoC series" + depends on X86 || COMPILE_TEST +--- a/drivers/leds/blink/Makefile ++++ b/drivers/leds/blink/Makefile +@@ -1,2 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_LEDS_BCM63138) += leds-bcm63138.o + obj-$(CONFIG_LEDS_LGM) += leds-lgm-sso.o +--- /dev/null ++++ b/drivers/leds/blink/leds-bcm63138.c +@@ -0,0 +1,308 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2021 Rafał Miłecki ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BCM63138_MAX_LEDS 32 ++#define BCM63138_MAX_BRIGHTNESS 9 ++ ++#define BCM63138_LED_BITS 4 /* how many bits control a single LED */ ++#define BCM63138_LED_MASK ((1 << BCM63138_LED_BITS) - 1) /* 0xf */ ++#define BCM63138_LEDS_PER_REG (32 / BCM63138_LED_BITS) /* 8 */ ++ ++#define BCM63138_GLB_CTRL 0x00 ++#define BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL 0x00000002 ++#define BCM63138_GLB_CTRL_SERIAL_LED_EN_POL 0x00000008 ++#define BCM63138_MASK 0x04 ++#define BCM63138_HW_LED_EN 0x08 ++#define BCM63138_SERIAL_LED_SHIFT_SEL 0x0c ++#define BCM63138_FLASH_RATE_CTRL1 0x10 ++#define BCM63138_FLASH_RATE_CTRL2 0x14 ++#define BCM63138_FLASH_RATE_CTRL3 0x18 ++#define BCM63138_FLASH_RATE_CTRL4 0x1c ++#define BCM63138_BRIGHT_CTRL1 0x20 ++#define BCM63138_BRIGHT_CTRL2 0x24 ++#define BCM63138_BRIGHT_CTRL3 0x28 ++#define BCM63138_BRIGHT_CTRL4 0x2c ++#define BCM63138_POWER_LED_CFG 0x30 ++#define BCM63138_HW_POLARITY 0xb4 ++#define BCM63138_SW_DATA 0xb8 ++#define BCM63138_SW_POLARITY 0xbc ++#define BCM63138_PARALLEL_LED_POLARITY 0xc0 ++#define BCM63138_SERIAL_LED_POLARITY 0xc4 ++#define BCM63138_HW_LED_STATUS 0xc8 ++#define BCM63138_FLASH_CTRL_STATUS 0xcc ++#define BCM63138_FLASH_BRT_CTRL 0xd0 ++#define BCM63138_FLASH_P_LED_OUT_STATUS 0xd4 ++#define BCM63138_FLASH_S_LED_OUT_STATUS 0xd8 ++ ++struct bcm63138_leds { ++ struct device *dev; ++ void __iomem *base; ++ spinlock_t lock; ++}; ++ ++struct bcm63138_led { ++ struct bcm63138_leds *leds; ++ struct led_classdev cdev; ++ u32 pin; ++ bool active_low; ++}; ++ ++/* ++ * I/O access ++ */ ++ ++static void bcm63138_leds_write(struct bcm63138_leds *leds, unsigned int reg, ++ u32 data) ++{ ++ writel(data, leds->base + reg); ++} ++ ++static unsigned long bcm63138_leds_read(struct bcm63138_leds *leds, ++ unsigned int reg) ++{ ++ return readl(leds->base + reg); ++} ++ ++static void bcm63138_leds_update_bits(struct bcm63138_leds *leds, ++ unsigned int reg, u32 mask, u32 val) ++{ ++ WARN_ON(val & ~mask); ++ ++ bcm63138_leds_write(leds, reg, (bcm63138_leds_read(leds, reg) & ~mask) | (val & mask)); ++} ++ ++/* ++ * Helpers ++ */ ++ ++static void bcm63138_leds_set_flash_rate(struct bcm63138_leds *leds, ++ struct bcm63138_led *led, ++ u8 value) ++{ ++ int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4; ++ int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS; ++ ++ bcm63138_leds_update_bits(leds, BCM63138_FLASH_RATE_CTRL1 + reg_offset, ++ BCM63138_LED_MASK << shift, value << shift); ++} ++ ++static void bcm63138_leds_set_bright(struct bcm63138_leds *leds, ++ struct bcm63138_led *led, ++ u8 value) ++{ ++ int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4; ++ int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS; ++ ++ bcm63138_leds_update_bits(leds, BCM63138_BRIGHT_CTRL1 + reg_offset, ++ BCM63138_LED_MASK << shift, value << shift); ++} ++ ++static void bcm63138_leds_enable_led(struct bcm63138_leds *leds, ++ struct bcm63138_led *led, ++ enum led_brightness value) ++{ ++ u32 bit = BIT(led->pin); ++ ++ bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, ++ value == LED_OFF ? 0 : bit); ++} ++ ++/* ++ * API callbacks ++ */ ++ ++static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); ++ struct bcm63138_leds *leds = led->leds; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&leds->lock, flags); ++ ++ bcm63138_leds_enable_led(leds, led, value); ++ if (!value) ++ bcm63138_leds_set_flash_rate(leds, led, 0); ++ else ++ bcm63138_leds_set_bright(leds, led, value); ++ ++ spin_unlock_irqrestore(&leds->lock, flags); ++} ++ ++static int bcm63138_leds_blink_set(struct led_classdev *led_cdev, ++ unsigned long *delay_on, ++ unsigned long *delay_off) ++{ ++ struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); ++ struct bcm63138_leds *leds = led->leds; ++ unsigned long flags; ++ u8 value; ++ ++ if (!*delay_on && !*delay_off) { ++ *delay_on = 640; ++ *delay_off = 640; ++ } ++ ++ if (*delay_on != *delay_off) { ++ dev_dbg(led_cdev->dev, "Blinking at unequal delays is not supported\n"); ++ return -EINVAL; ++ } ++ ++ switch (*delay_on) { ++ case 1152 ... 1408: /* 1280 ms ± 10% */ ++ value = 0x7; ++ break; ++ case 576 ... 704: /* 640 ms ± 10% */ ++ value = 0x6; ++ break; ++ case 288 ... 352: /* 320 ms ± 10% */ ++ value = 0x5; ++ break; ++ case 126 ... 154: /* 140 ms ± 10% */ ++ value = 0x4; ++ break; ++ case 59 ... 72: /* 65 ms ± 10% */ ++ value = 0x3; ++ break; ++ default: ++ dev_dbg(led_cdev->dev, "Blinking delay value %lu is unsupported\n", ++ *delay_on); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&leds->lock, flags); ++ ++ bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS); ++ bcm63138_leds_set_flash_rate(leds, led, value); ++ ++ spin_unlock_irqrestore(&leds->lock, flags); ++ ++ return 0; ++} ++ ++/* ++ * LED driver ++ */ ++ ++static void bcm63138_leds_create_led(struct bcm63138_leds *leds, ++ struct device_node *np) ++{ ++ struct led_init_data init_data = { ++ .fwnode = of_fwnode_handle(np), ++ }; ++ struct device *dev = leds->dev; ++ struct bcm63138_led *led; ++ struct pinctrl *pinctrl; ++ u32 bit; ++ int err; ++ ++ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); ++ if (!led) { ++ dev_err(dev, "Failed to alloc LED\n"); ++ return; ++ } ++ ++ led->leds = leds; ++ ++ if (of_property_read_u32(np, "reg", &led->pin)) { ++ dev_err(dev, "Missing \"reg\" property in %pOF\n", np); ++ goto err_free; ++ } ++ ++ if (led->pin >= BCM63138_MAX_LEDS) { ++ dev_err(dev, "Invalid \"reg\" value %d\n", led->pin); ++ goto err_free; ++ } ++ ++ led->active_low = of_property_read_bool(np, "active-low"); ++ ++ led->cdev.max_brightness = BCM63138_MAX_BRIGHTNESS; ++ led->cdev.brightness_set = bcm63138_leds_brightness_set; ++ led->cdev.blink_set = bcm63138_leds_blink_set; ++ ++ err = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); ++ if (err) { ++ dev_err(dev, "Failed to register LED %pOF: %d\n", np, err); ++ goto err_free; ++ } ++ ++ pinctrl = devm_pinctrl_get_select_default(led->cdev.dev); ++ if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) { ++ dev_warn(led->cdev.dev, "Failed to select %pOF pinctrl: %ld\n", ++ np, PTR_ERR(pinctrl)); ++ } ++ ++ bit = BIT(led->pin); ++ bcm63138_leds_update_bits(leds, BCM63138_PARALLEL_LED_POLARITY, bit, ++ led->active_low ? 0 : bit); ++ bcm63138_leds_update_bits(leds, BCM63138_HW_LED_EN, bit, 0); ++ bcm63138_leds_set_flash_rate(leds, led, 0); ++ bcm63138_leds_enable_led(leds, led, led->cdev.brightness); ++ ++ return; ++ ++err_free: ++ devm_kfree(dev, led); ++} ++ ++static int bcm63138_leds_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = dev_of_node(&pdev->dev); ++ struct device *dev = &pdev->dev; ++ struct bcm63138_leds *leds; ++ struct device_node *child; ++ ++ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return -ENOMEM; ++ ++ leds->dev = dev; ++ ++ leds->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(leds->base)) ++ return PTR_ERR(leds->base); ++ ++ spin_lock_init(&leds->lock); ++ ++ bcm63138_leds_write(leds, BCM63138_GLB_CTRL, ++ BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL | ++ BCM63138_GLB_CTRL_SERIAL_LED_EN_POL); ++ bcm63138_leds_write(leds, BCM63138_HW_LED_EN, 0); ++ bcm63138_leds_write(leds, BCM63138_SERIAL_LED_POLARITY, 0); ++ bcm63138_leds_write(leds, BCM63138_PARALLEL_LED_POLARITY, 0); ++ ++ for_each_available_child_of_node(np, child) { ++ bcm63138_leds_create_led(leds, child); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id bcm63138_leds_of_match_table[] = { ++ { .compatible = "brcm,bcm63138-leds", }, ++ { }, ++}; ++ ++static struct platform_driver bcm63138_leds_driver = { ++ .probe = bcm63138_leds_probe, ++ .driver = { ++ .name = "leds-bcm63xxx", ++ .of_match_table = bcm63138_leds_of_match_table, ++ }, ++}; ++ ++module_platform_driver(bcm63138_leds_driver); ++ ++MODULE_AUTHOR("Rafał Miłecki"); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table); diff --git a/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch b/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch new file mode 100644 index 00000000000..483826abed5 --- /dev/null +++ b/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch @@ -0,0 +1,30 @@ +From 13b64a0c19059b38150c79d65d350ae44034c5df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sun, 17 Jul 2022 14:42:46 +0200 +Subject: [PATCH] dt-bindings: leds: leds-bcm63138: unify full stops in + descriptions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Description of "reg" doesn't have full stop at the end. It makes sense +as it's a one-sentence only. Use the same style for "active-low". + +Reported-by: Pavel Machek +Signed-off-by: Rafał Miłecki +Signed-off-by: Pavel Machek +--- + Documentation/devicetree/bindings/leds/leds-bcm63138.yaml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml ++++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml +@@ -54,7 +54,7 @@ patternProperties: + + active-low: + type: boolean +- description: Makes LED active low. ++ description: Makes LED active low + + required: + - reg diff --git a/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch b/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch new file mode 100644 index 00000000000..5430b1f0844 --- /dev/null +++ b/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch @@ -0,0 +1,28 @@ +From bcc607cdbb1f931111196699426f0cb83bfb296a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sun, 17 Jul 2022 14:42:47 +0200 +Subject: [PATCH] leds: add help info about BCM63138 module name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's what we do for all other LEDs drivers. + +Reported-by: Pavel Machek +Signed-off-by: Rafał Miłecki +Signed-off-by: Pavel Machek +--- + drivers/leds/blink/Kconfig | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/leds/blink/Kconfig ++++ b/drivers/leds/blink/Kconfig +@@ -10,6 +10,8 @@ config LEDS_BCM63138 + BCM63138 SoC. The same hardware block is known to be also used + in BCM4908, BCM6848, BCM6858, BCM63148, BCM63381 and BCM68360. + ++ If compiled as module it will be called leds-bcm63138. ++ + config LEDS_LGM + tristate "LED support for LGM SoC series" + depends on X86 || COMPILE_TEST diff --git a/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch b/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch new file mode 100644 index 00000000000..e125a54613b --- /dev/null +++ b/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch @@ -0,0 +1,30 @@ +From 92cfc71ee2ddfb499ed53e21b28bdf8739bc70bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Sun, 17 Jul 2022 14:42:48 +0200 +Subject: [PATCH] leds: leds-bcm63138: get rid of LED_OFF +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The whole "enum led_brightness" is marked as obsolete. Replace it with a +(non-)zero check. + +Reported-by: Pavel Machek +Signed-off-by: Rafał Miłecki +Signed-off-by: Pavel Machek +--- + drivers/leds/blink/leds-bcm63138.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/leds/blink/leds-bcm63138.c ++++ b/drivers/leds/blink/leds-bcm63138.c +@@ -113,8 +113,7 @@ static void bcm63138_leds_enable_led(str + { + u32 bit = BIT(led->pin); + +- bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, +- value == LED_OFF ? 0 : bit); ++ bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, value ? bit : 0); + } + + /* diff --git a/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch b/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch new file mode 100644 index 00000000000..ebab8c7c736 --- /dev/null +++ b/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch @@ -0,0 +1,456 @@ +From 7ae6478b304bc004c3139b422665b0e23b57f05c Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Wed, 13 Oct 2021 14:19:55 +0100 +Subject: [PATCH] nvmem: core: rework nvmem cell instance creation + +In the existing design, we do not create a instance per nvmem cell consumer +but we directly refer cell from nvmem cell list that are added to provider. + +However this design has some limitations when consumers want to assign name +or connection id the nvmem cell instance, ex: via "nvmem-cell-names" or +id in nvmem_cell_get(id). + +Having a name associated with nvmem cell consumer instance will help +provider drivers in performing post processing of nvmem cell data if required +before data is seen by the consumers. This is pretty normal with some vendors +storing nvmem cells like mac-address in a vendor specific data layouts that +are not directly usable by the consumer drivers. + +With this patch nvmem cell will be created dynamically during nvmem_cell_get +and destroyed in nvmem_cell_put, allowing consumers to associate name with +nvmem cell consumer instance. + +With this patch a new struct nvmem_cell_entry replaces struct nvmem_cell +for storing nvmem cell information within the core. +This patch does not change nvmem-consumer interface based on nvmem_cell. + +Tested-by: Joakim Zhang +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20211013131957.30271-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 165 +++++++++++++++++++++++++++---------------- + 1 file changed, 105 insertions(+), 60 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -45,8 +45,7 @@ struct nvmem_device { + #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) + + #define FLAG_COMPAT BIT(0) +- +-struct nvmem_cell { ++struct nvmem_cell_entry { + const char *name; + int offset; + int bytes; +@@ -57,6 +56,11 @@ struct nvmem_cell { + struct list_head node; + }; + ++struct nvmem_cell { ++ struct nvmem_cell_entry *entry; ++ const char *id; ++}; ++ + static DEFINE_MUTEX(nvmem_mutex); + static DEFINE_IDA(nvmem_ida); + +@@ -424,7 +428,7 @@ static struct bus_type nvmem_bus_type = + .name = "nvmem", + }; + +-static void nvmem_cell_drop(struct nvmem_cell *cell) ++static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell) + { + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); + mutex_lock(&nvmem_mutex); +@@ -437,13 +441,13 @@ static void nvmem_cell_drop(struct nvmem + + static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) + { +- struct nvmem_cell *cell, *p; ++ struct nvmem_cell_entry *cell, *p; + + list_for_each_entry_safe(cell, p, &nvmem->cells, node) +- nvmem_cell_drop(cell); ++ nvmem_cell_entry_drop(cell); + } + +-static void nvmem_cell_add(struct nvmem_cell *cell) ++static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell) + { + mutex_lock(&nvmem_mutex); + list_add_tail(&cell->node, &cell->nvmem->cells); +@@ -451,9 +455,9 @@ static void nvmem_cell_add(struct nvmem_ + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); + } + +-static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem, +- const struct nvmem_cell_info *info, +- struct nvmem_cell *cell) ++static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, ++ const struct nvmem_cell_info *info, ++ struct nvmem_cell_entry *cell) + { + cell->nvmem = nvmem; + cell->offset = info->offset; +@@ -477,13 +481,13 @@ static int nvmem_cell_info_to_nvmem_cell + return 0; + } + +-static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, +- const struct nvmem_cell_info *info, +- struct nvmem_cell *cell) ++static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem, ++ const struct nvmem_cell_info *info, ++ struct nvmem_cell_entry *cell) + { + int err; + +- err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell); ++ err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell); + if (err) + return err; + +@@ -507,7 +511,7 @@ static int nvmem_add_cells(struct nvmem_ + const struct nvmem_cell_info *info, + int ncells) + { +- struct nvmem_cell **cells; ++ struct nvmem_cell_entry **cells; + int i, rval; + + cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); +@@ -521,13 +525,13 @@ static int nvmem_add_cells(struct nvmem_ + goto err; + } + +- rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); ++ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]); + if (rval) { + kfree(cells[i]); + goto err; + } + +- nvmem_cell_add(cells[i]); ++ nvmem_cell_entry_add(cells[i]); + } + + /* remove tmp array */ +@@ -536,7 +540,7 @@ static int nvmem_add_cells(struct nvmem_ + return 0; + err: + while (i--) +- nvmem_cell_drop(cells[i]); ++ nvmem_cell_entry_drop(cells[i]); + + kfree(cells); + +@@ -573,7 +577,7 @@ static int nvmem_add_cells_from_table(st + { + const struct nvmem_cell_info *info; + struct nvmem_cell_table *table; +- struct nvmem_cell *cell; ++ struct nvmem_cell_entry *cell; + int rval = 0, i; + + mutex_lock(&nvmem_cell_mutex); +@@ -588,15 +592,13 @@ static int nvmem_add_cells_from_table(st + goto out; + } + +- rval = nvmem_cell_info_to_nvmem_cell(nvmem, +- info, +- cell); ++ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); + if (rval) { + kfree(cell); + goto out; + } + +- nvmem_cell_add(cell); ++ nvmem_cell_entry_add(cell); + } + } + } +@@ -606,10 +608,10 @@ out: + return rval; + } + +-static struct nvmem_cell * +-nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) ++static struct nvmem_cell_entry * ++nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) + { +- struct nvmem_cell *iter, *cell = NULL; ++ struct nvmem_cell_entry *iter, *cell = NULL; + + mutex_lock(&nvmem_mutex); + list_for_each_entry(iter, &nvmem->cells, node) { +@@ -680,7 +682,7 @@ static int nvmem_add_cells_from_of(struc + { + struct device_node *parent, *child; + struct device *dev = &nvmem->dev; +- struct nvmem_cell *cell; ++ struct nvmem_cell_entry *cell; + const __be32 *addr; + int len; + +@@ -729,7 +731,7 @@ static int nvmem_add_cells_from_of(struc + } + + cell->np = of_node_get(child); +- nvmem_cell_add(cell); ++ nvmem_cell_entry_add(cell); + } + + return 0; +@@ -1142,9 +1144,33 @@ struct nvmem_device *devm_nvmem_device_g + } + EXPORT_SYMBOL_GPL(devm_nvmem_device_get); + ++static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id) ++{ ++ struct nvmem_cell *cell; ++ const char *name = NULL; ++ ++ cell = kzalloc(sizeof(*cell), GFP_KERNEL); ++ if (!cell) ++ return ERR_PTR(-ENOMEM); ++ ++ if (id) { ++ name = kstrdup_const(id, GFP_KERNEL); ++ if (!name) { ++ kfree(cell); ++ return ERR_PTR(-ENOMEM); ++ } ++ } ++ ++ cell->id = name; ++ cell->entry = entry; ++ ++ return cell; ++} ++ + static struct nvmem_cell * + nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) + { ++ struct nvmem_cell_entry *cell_entry; + struct nvmem_cell *cell = ERR_PTR(-ENOENT); + struct nvmem_cell_lookup *lookup; + struct nvmem_device *nvmem; +@@ -1169,11 +1195,15 @@ nvmem_cell_get_from_lookup(struct device + break; + } + +- cell = nvmem_find_cell_by_name(nvmem, +- lookup->cell_name); +- if (!cell) { ++ cell_entry = nvmem_find_cell_entry_by_name(nvmem, ++ lookup->cell_name); ++ if (!cell_entry) { + __nvmem_device_put(nvmem); + cell = ERR_PTR(-ENOENT); ++ } else { ++ cell = nvmem_create_cell(cell_entry, con_id); ++ if (IS_ERR(cell)) ++ __nvmem_device_put(nvmem); + } + break; + } +@@ -1184,10 +1214,10 @@ nvmem_cell_get_from_lookup(struct device + } + + #if IS_ENABLED(CONFIG_OF) +-static struct nvmem_cell * +-nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) ++static struct nvmem_cell_entry * ++nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np) + { +- struct nvmem_cell *iter, *cell = NULL; ++ struct nvmem_cell_entry *iter, *cell = NULL; + + mutex_lock(&nvmem_mutex); + list_for_each_entry(iter, &nvmem->cells, node) { +@@ -1217,6 +1247,7 @@ struct nvmem_cell *of_nvmem_cell_get(str + { + struct device_node *cell_np, *nvmem_np; + struct nvmem_device *nvmem; ++ struct nvmem_cell_entry *cell_entry; + struct nvmem_cell *cell; + int index = 0; + +@@ -1237,12 +1268,16 @@ struct nvmem_cell *of_nvmem_cell_get(str + if (IS_ERR(nvmem)) + return ERR_CAST(nvmem); + +- cell = nvmem_find_cell_by_node(nvmem, cell_np); +- if (!cell) { ++ cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); ++ if (!cell_entry) { + __nvmem_device_put(nvmem); + return ERR_PTR(-ENOENT); + } + ++ cell = nvmem_create_cell(cell_entry, id); ++ if (IS_ERR(cell)) ++ __nvmem_device_put(nvmem); ++ + return cell; + } + EXPORT_SYMBOL_GPL(of_nvmem_cell_get); +@@ -1348,13 +1383,17 @@ EXPORT_SYMBOL(devm_nvmem_cell_put); + */ + void nvmem_cell_put(struct nvmem_cell *cell) + { +- struct nvmem_device *nvmem = cell->nvmem; ++ struct nvmem_device *nvmem = cell->entry->nvmem; ++ ++ if (cell->id) ++ kfree_const(cell->id); + ++ kfree(cell); + __nvmem_device_put(nvmem); + } + EXPORT_SYMBOL_GPL(nvmem_cell_put); + +-static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) ++static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf) + { + u8 *p, *b; + int i, extra, bit_offset = cell->bit_offset; +@@ -1388,8 +1427,8 @@ static void nvmem_shift_read_buffer_in_p + } + + static int __nvmem_cell_read(struct nvmem_device *nvmem, +- struct nvmem_cell *cell, +- void *buf, size_t *len) ++ struct nvmem_cell_entry *cell, ++ void *buf, size_t *len, const char *id) + { + int rc; + +@@ -1420,18 +1459,18 @@ static int __nvmem_cell_read(struct nvme + */ + void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) + { +- struct nvmem_device *nvmem = cell->nvmem; ++ struct nvmem_device *nvmem = cell->entry->nvmem; + u8 *buf; + int rc; + + if (!nvmem) + return ERR_PTR(-EINVAL); + +- buf = kzalloc(cell->bytes, GFP_KERNEL); ++ buf = kzalloc(cell->entry->bytes, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + +- rc = __nvmem_cell_read(nvmem, cell, buf, len); ++ rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id); + if (rc) { + kfree(buf); + return ERR_PTR(rc); +@@ -1441,7 +1480,7 @@ void *nvmem_cell_read(struct nvmem_cell + } + EXPORT_SYMBOL_GPL(nvmem_cell_read); + +-static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, ++static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell, + u8 *_buf, int len) + { + struct nvmem_device *nvmem = cell->nvmem; +@@ -1494,16 +1533,7 @@ err: + return ERR_PTR(rc); + } + +-/** +- * nvmem_cell_write() - Write to a given nvmem cell +- * +- * @cell: nvmem cell to be written. +- * @buf: Buffer to be written. +- * @len: length of buffer to be written to nvmem cell. +- * +- * Return: length of bytes written or negative on failure. +- */ +-int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) ++static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len) + { + struct nvmem_device *nvmem = cell->nvmem; + int rc; +@@ -1529,6 +1559,21 @@ int nvmem_cell_write(struct nvmem_cell * + + return len; + } ++ ++/** ++ * nvmem_cell_write() - Write to a given nvmem cell ++ * ++ * @cell: nvmem cell to be written. ++ * @buf: Buffer to be written. ++ * @len: length of buffer to be written to nvmem cell. ++ * ++ * Return: length of bytes written or negative on failure. ++ */ ++int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) ++{ ++ return __nvmem_cell_entry_write(cell->entry, buf, len); ++} ++ + EXPORT_SYMBOL_GPL(nvmem_cell_write); + + static int nvmem_cell_read_common(struct device *dev, const char *cell_id, +@@ -1631,7 +1676,7 @@ static const void *nvmem_cell_read_varia + if (IS_ERR(cell)) + return cell; + +- nbits = cell->nbits; ++ nbits = cell->entry->nbits; + buf = nvmem_cell_read(cell, len); + nvmem_cell_put(cell); + if (IS_ERR(buf)) +@@ -1727,18 +1772,18 @@ EXPORT_SYMBOL_GPL(nvmem_cell_read_variab + ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf) + { +- struct nvmem_cell cell; ++ struct nvmem_cell_entry cell; + int rc; + ssize_t len; + + if (!nvmem) + return -EINVAL; + +- rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); ++ rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); + if (rc) + return rc; + +- rc = __nvmem_cell_read(nvmem, &cell, buf, &len); ++ rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL); + if (rc) + return rc; + +@@ -1758,17 +1803,17 @@ EXPORT_SYMBOL_GPL(nvmem_device_cell_read + int nvmem_device_cell_write(struct nvmem_device *nvmem, + struct nvmem_cell_info *info, void *buf) + { +- struct nvmem_cell cell; ++ struct nvmem_cell_entry cell; + int rc; + + if (!nvmem) + return -EINVAL; + +- rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); ++ rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); + if (rc) + return rc; + +- return nvmem_cell_write(&cell, buf, cell.bytes); ++ return __nvmem_cell_entry_write(&cell, buf, cell.bytes); + } + EXPORT_SYMBOL_GPL(nvmem_device_cell_write); + diff --git a/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch b/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch new file mode 100644 index 00000000000..df264add245 --- /dev/null +++ b/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch @@ -0,0 +1,82 @@ +From 5008062f1c3f5af3acf86164aa6fcc77b0c7bdce Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Wed, 13 Oct 2021 14:19:56 +0100 +Subject: [PATCH] nvmem: core: add nvmem cell post processing callback + +Some NVMEM providers have certain nvmem cells encoded, which requires +post processing before actually using it. + +For example mac-address is stored in either in ascii or delimited or reverse-order. + +Having a post-process callback hook to provider drivers would enable them to +do this vendor specific post processing before nvmem consumers see it. + +Tested-by: Joakim Zhang +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20211013131957.30271-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 9 +++++++++ + include/linux/nvmem-provider.h | 5 +++++ + 2 files changed, 14 insertions(+) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -38,6 +38,7 @@ struct nvmem_device { + unsigned int nkeepout; + nvmem_reg_read_t reg_read; + nvmem_reg_write_t reg_write; ++ nvmem_cell_post_process_t cell_post_process; + struct gpio_desc *wp_gpio; + void *priv; + }; +@@ -799,6 +800,7 @@ struct nvmem_device *nvmem_register(cons + nvmem->type = config->type; + nvmem->reg_read = config->reg_read; + nvmem->reg_write = config->reg_write; ++ nvmem->cell_post_process = config->cell_post_process; + nvmem->keepout = config->keepout; + nvmem->nkeepout = config->nkeepout; + if (config->of_node) +@@ -1441,6 +1443,13 @@ static int __nvmem_cell_read(struct nvme + if (cell->bit_offset || cell->nbits) + nvmem_shift_read_buffer_in_place(cell, buf); + ++ if (nvmem->cell_post_process) { ++ rc = nvmem->cell_post_process(nvmem->priv, id, ++ cell->offset, buf, cell->bytes); ++ if (rc) ++ return rc; ++ } ++ + if (len) + *len = cell->bytes; + +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -19,6 +19,9 @@ typedef int (*nvmem_reg_read_t)(void *pr + void *val, size_t bytes); + typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset, + void *val, size_t bytes); ++/* used for vendor specific post processing of cell data */ ++typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, unsigned int offset, ++ void *buf, size_t bytes); + + enum nvmem_type { + NVMEM_TYPE_UNKNOWN = 0, +@@ -62,6 +65,7 @@ struct nvmem_keepout { + * @no_of_node: Device should not use the parent's of_node even if it's !NULL. + * @reg_read: Callback to read data. + * @reg_write: Callback to write data. ++ * @cell_post_process: Callback for vendor specific post processing of cell data + * @size: Device size. + * @word_size: Minimum read/write access granularity. + * @stride: Minimum read/write access stride. +@@ -92,6 +96,7 @@ struct nvmem_config { + bool no_of_node; + nvmem_reg_read_t reg_read; + nvmem_reg_write_t reg_write; ++ nvmem_cell_post_process_t cell_post_process; + int size; + int word_size; + int stride; diff --git a/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch b/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch new file mode 100644 index 00000000000..ee19228270d --- /dev/null +++ b/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch @@ -0,0 +1,92 @@ +From d0221a780cbc99fec6c27a98dba2828dc5735c00 Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Wed, 13 Oct 2021 14:19:57 +0100 +Subject: [PATCH] nvmem: imx-ocotp: add support for post processing + +Add .cell_post_process callback for imx-ocotp to deal with MAC address, +since MAC address need to be reversed byte for some i.MX SoCs. + +Tested-by: Joakim Zhang +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20211013131957.30271-4-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/imx-ocotp.c | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/drivers/nvmem/imx-ocotp.c ++++ b/drivers/nvmem/imx-ocotp.c +@@ -97,6 +97,7 @@ struct ocotp_params { + unsigned int bank_address_words; + void (*set_timing)(struct ocotp_priv *priv); + struct ocotp_ctrl_reg ctrl; ++ bool reverse_mac_address; + }; + + static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags) +@@ -221,6 +222,25 @@ read_end: + return ret; + } + ++static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset, ++ void *data, size_t bytes) ++{ ++ struct ocotp_priv *priv = context; ++ ++ /* Deal with some post processing of nvmem cell data */ ++ if (id && !strcmp(id, "mac-address")) { ++ if (priv->params->reverse_mac_address) { ++ u8 *buf = data; ++ int i; ++ ++ for (i = 0; i < bytes/2; i++) ++ swap(buf[i], buf[bytes - i - 1]); ++ } ++ } ++ ++ return 0; ++} ++ + static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv) + { + unsigned long clk_rate; +@@ -468,6 +488,7 @@ static struct nvmem_config imx_ocotp_nvm + .stride = 1, + .reg_read = imx_ocotp_read, + .reg_write = imx_ocotp_write, ++ .cell_post_process = imx_ocotp_cell_pp, + }; + + static const struct ocotp_params imx6q_params = { +@@ -530,6 +551,7 @@ static const struct ocotp_params imx8mq_ + .bank_address_words = 0, + .set_timing = imx_ocotp_set_imx6_timing, + .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, ++ .reverse_mac_address = true, + }; + + static const struct ocotp_params imx8mm_params = { +@@ -537,6 +559,7 @@ static const struct ocotp_params imx8mm_ + .bank_address_words = 0, + .set_timing = imx_ocotp_set_imx6_timing, + .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, ++ .reverse_mac_address = true, + }; + + static const struct ocotp_params imx8mn_params = { +@@ -544,6 +567,7 @@ static const struct ocotp_params imx8mn_ + .bank_address_words = 0, + .set_timing = imx_ocotp_set_imx6_timing, + .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, ++ .reverse_mac_address = true, + }; + + static const struct ocotp_params imx8mp_params = { +@@ -551,6 +575,7 @@ static const struct ocotp_params imx8mp_ + .bank_address_words = 0, + .set_timing = imx_ocotp_set_imx6_timing, + .ctrl = IMX_OCOTP_BM_CTRL_8MP, ++ .reverse_mac_address = true, + }; + + static const struct of_device_id imx_ocotp_dt_ids[] = { diff --git a/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch b/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch new file mode 100644 index 00000000000..785bfe53f54 --- /dev/null +++ b/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch @@ -0,0 +1,47 @@ +From 98e2c4efae214fb7086cac9117616eb6ea11475d Mon Sep 17 00:00:00 2001 +From: Chunfeng Yun +Date: Thu, 9 Dec 2021 17:42:34 +0000 +Subject: [PATCH] nvmem: mtk-efuse: support minimum one byte access stride and + granularity + +In order to support nvmem bits property, should support minimum 1 byte +read stride and minimum 1 byte read granularity at the same time. + +Signed-off-by: Chunfeng Yun +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20211209174235.14049-4-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/mtk-efuse.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/drivers/nvmem/mtk-efuse.c ++++ b/drivers/nvmem/mtk-efuse.c +@@ -19,11 +19,12 @@ static int mtk_reg_read(void *context, + unsigned int reg, void *_val, size_t bytes) + { + struct mtk_efuse_priv *priv = context; +- u32 *val = _val; +- int i = 0, words = bytes / 4; ++ void __iomem *addr = priv->base + reg; ++ u8 *val = _val; ++ int i; + +- while (words--) +- *val++ = readl(priv->base + reg + (i++ * 4)); ++ for (i = 0; i < bytes; i++, val++) ++ *val = readb(addr + i); + + return 0; + } +@@ -45,8 +46,8 @@ static int mtk_efuse_probe(struct platfo + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + +- econfig.stride = 4; +- econfig.word_size = 4; ++ econfig.stride = 1; ++ econfig.word_size = 1; + econfig.reg_read = mtk_reg_read; + econfig.size = resource_size(res); + econfig.priv = priv; diff --git a/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch b/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch new file mode 100644 index 00000000000..ca5357c8d98 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch @@ -0,0 +1,72 @@ +From 190fae468592bc2f0efc8b928920f8f712b5831e Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Sun, 20 Feb 2022 15:15:15 +0000 +Subject: [PATCH] nvmem: core: Remove unused devm_nvmem_unregister() + +There are no users and seems no will come of the devm_nvmem_unregister(). +Remove the function and remove the unused devm_nvmem_match() along with it. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 22 ---------------------- + include/linux/nvmem-provider.h | 8 -------- + 2 files changed, 30 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -943,28 +943,6 @@ struct nvmem_device *devm_nvmem_register + } + EXPORT_SYMBOL_GPL(devm_nvmem_register); + +-static int devm_nvmem_match(struct device *dev, void *res, void *data) +-{ +- struct nvmem_device **r = res; +- +- return *r == data; +-} +- +-/** +- * devm_nvmem_unregister() - Unregister previously registered managed nvmem +- * device. +- * +- * @dev: Device that uses the nvmem device. +- * @nvmem: Pointer to previously registered nvmem device. +- * +- * Return: Will be negative on error or zero on success. +- */ +-int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) +-{ +- return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); +-} +-EXPORT_SYMBOL(devm_nvmem_unregister); +- + static struct nvmem_device *__nvmem_device_get(void *data, + int (*match)(struct device *dev, const void *data)) + { +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -133,8 +133,6 @@ void nvmem_unregister(struct nvmem_devic + struct nvmem_device *devm_nvmem_register(struct device *dev, + const struct nvmem_config *cfg); + +-int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem); +- + void nvmem_add_cell_table(struct nvmem_cell_table *table); + void nvmem_del_cell_table(struct nvmem_cell_table *table); + +@@ -153,12 +151,6 @@ devm_nvmem_register(struct device *dev, + return nvmem_register(c); + } + +-static inline int +-devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) +-{ +- return -EOPNOTSUPP; +-} +- + static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} + static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {} + diff --git a/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch b/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch new file mode 100644 index 00000000000..b71a0a365b2 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch @@ -0,0 +1,58 @@ +From 5825b2c6762611e67ccaf3ccf64485365a120f0b Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Sun, 20 Feb 2022 15:15:16 +0000 +Subject: [PATCH] nvmem: core: Use devm_add_action_or_reset() + +Slightly simplify the devm_nvmem_register() by using the +devm_add_action_or_reset(). + +Signed-off-by: Andy Shevchenko +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 22 +++++++++------------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -905,9 +905,9 @@ void nvmem_unregister(struct nvmem_devic + } + EXPORT_SYMBOL_GPL(nvmem_unregister); + +-static void devm_nvmem_release(struct device *dev, void *res) ++static void devm_nvmem_unregister(void *nvmem) + { +- nvmem_unregister(*(struct nvmem_device **)res); ++ nvmem_unregister(nvmem); + } + + /** +@@ -924,20 +924,16 @@ static void devm_nvmem_release(struct de + struct nvmem_device *devm_nvmem_register(struct device *dev, + const struct nvmem_config *config) + { +- struct nvmem_device **ptr, *nvmem; +- +- ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); +- if (!ptr) +- return ERR_PTR(-ENOMEM); ++ struct nvmem_device *nvmem; ++ int ret; + + nvmem = nvmem_register(config); ++ if (IS_ERR(nvmem)) ++ return nvmem; + +- if (!IS_ERR(nvmem)) { +- *ptr = nvmem; +- devres_add(dev, ptr); +- } else { +- devres_free(ptr); +- } ++ ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem); ++ if (ret) ++ return ERR_PTR(ret); + + return nvmem; + } diff --git a/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch b/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch new file mode 100644 index 00000000000..4f471f26673 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch @@ -0,0 +1,30 @@ +From 8c751e0d9a5264376935a84429a2d468c8877d99 Mon Sep 17 00:00:00 2001 +From: Andy Shevchenko +Date: Sun, 20 Feb 2022 15:15:17 +0000 +Subject: [PATCH] nvmem: core: Check input parameter for NULL in + nvmem_unregister() + +nvmem_unregister() frees resources and standard pattern is to allow +caller to not care if it's NULL or not. This will reduce burden on +the callers to perform this check. + +Signed-off-by: Andy Shevchenko +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-4-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -901,7 +901,8 @@ static void nvmem_device_release(struct + */ + void nvmem_unregister(struct nvmem_device *nvmem) + { +- kref_put(&nvmem->refcnt, nvmem_device_release); ++ if (nvmem) ++ kref_put(&nvmem->refcnt, nvmem_device_release); + } + EXPORT_SYMBOL_GPL(nvmem_unregister); + diff --git a/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch b/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch new file mode 100644 index 00000000000..c98f8e9d545 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch @@ -0,0 +1,29 @@ +From 05196facc052385960028ac634447ecf6c764ec3 Mon Sep 17 00:00:00 2001 +From: Srinivas Kandagatla +Date: Sun, 20 Feb 2022 15:15:18 +0000 +Subject: [PATCH] nvmem: qfprom: fix kerneldoc warning + +This patch fixes below kernel doc warning, +warning: expecting prototype for qfprom_efuse_reg_write(). +Prototype was for qfprom_reg_write() instead + +No code changes. + +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-5-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/qfprom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/qfprom.c ++++ b/drivers/nvmem/qfprom.c +@@ -244,7 +244,7 @@ err_clk_prepared: + } + + /** +- * qfprom_efuse_reg_write() - Write to fuses. ++ * qfprom_reg_write() - Write to fuses. + * @context: Our driver data. + * @reg: The offset to write at. + * @_val: Pointer to data to write. diff --git a/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch b/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch new file mode 100644 index 00000000000..6aad6af0800 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch @@ -0,0 +1,38 @@ +From 07ae4fde9efada7878e1383d6ccc7da70315ca23 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sun, 20 Feb 2022 15:15:20 +0000 +Subject: [PATCH] nvmem: sunxi_sid: Add support for D1 variant + +D1 has a smaller eFuse block than some other recent SoCs, and it no +longer requires a workaround to read the eFuse data. + +Signed-off-by: Samuel Holland +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-7-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/sunxi_sid.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/nvmem/sunxi_sid.c ++++ b/drivers/nvmem/sunxi_sid.c +@@ -184,6 +184,11 @@ static const struct sunxi_sid_cfg sun8i_ + .need_register_readout = true, + }; + ++static const struct sunxi_sid_cfg sun20i_d1_cfg = { ++ .value_offset = 0x200, ++ .size = 0x100, ++}; ++ + static const struct sunxi_sid_cfg sun50i_a64_cfg = { + .value_offset = 0x200, + .size = 0x100, +@@ -200,6 +205,7 @@ static const struct of_device_id sunxi_s + { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg }, + { .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg }, ++ { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg }, + { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg }, + { .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg }, diff --git a/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch b/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch new file mode 100644 index 00000000000..a73b42c5de3 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch @@ -0,0 +1,28 @@ +From 4dc8d89faed9bb05f116fa1794fc955b14910386 Mon Sep 17 00:00:00 2001 +From: Xiaoke Wang +Date: Sun, 20 Feb 2022 15:15:21 +0000 +Subject: [PATCH] nvmem: meson-mx-efuse: replace unnecessary devm_kstrdup() + +Replace unnecessary devm_kstrdup() so to avoid redundant memory allocation. + +Suggested-by: Martin Blumenstingl +Signed-off-by: Xiaoke Wang +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/meson-mx-efuse.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/nvmem/meson-mx-efuse.c ++++ b/drivers/nvmem/meson-mx-efuse.c +@@ -209,8 +209,7 @@ static int meson_mx_efuse_probe(struct p + if (IS_ERR(efuse->base)) + return PTR_ERR(efuse->base); + +- efuse->config.name = devm_kstrdup(&pdev->dev, drvdata->name, +- GFP_KERNEL); ++ efuse->config.name = drvdata->name; + efuse->config.owner = THIS_MODULE; + efuse->config.dev = &pdev->dev; + efuse->config.priv = efuse; diff --git a/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch b/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch new file mode 100644 index 00000000000..6afb68b3f91 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch @@ -0,0 +1,139 @@ +From f78451012b9e159afdba31c3eb69f223a9f42adc Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Sun, 20 Feb 2022 15:15:23 +0000 +Subject: [PATCH] nvmem: add driver for Layerscape SFP (Security Fuse + Processor) + +Add support for the Security Fuse Processor found on Layerscape SoCs. +This driver implements basic read access. + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220220151527.17216-10-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 12 +++++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/layerscape-sfp.c | 89 ++++++++++++++++++++++++++++++++++ + 3 files changed, 103 insertions(+) + create mode 100644 drivers/nvmem/layerscape-sfp.c + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -300,4 +300,16 @@ config NVMEM_BRCM_NVRAM + This driver provides support for Broadcom's NVRAM that can be accessed + using I/O mapping. + ++config NVMEM_LAYERSCAPE_SFP ++ tristate "Layerscape SFP (Security Fuse Processor) support" ++ depends on ARCH_LAYERSCAPE || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This driver provides support to read the eFuses on Freescale ++ Layerscape SoC's. For example, the vendor provides a per part ++ unique ID there. ++ ++ This driver can also be built as a module. If so, the module ++ will be called layerscape-sfp. ++ + endif +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -61,3 +61,5 @@ obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem. + nvmem-rmem-y := rmem.o + obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o + nvmem_brcm_nvram-y := brcm_nvram.o ++obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o ++nvmem-layerscape-sfp-y := layerscape-sfp.o +--- /dev/null ++++ b/drivers/nvmem/layerscape-sfp.c +@@ -0,0 +1,89 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Layerscape SFP driver ++ * ++ * Copyright (c) 2022 Michael Walle ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 ++ ++struct layerscape_sfp_priv { ++ void __iomem *base; ++}; ++ ++struct layerscape_sfp_data { ++ int size; ++}; ++ ++static int layerscape_sfp_read(void *context, unsigned int offset, void *val, ++ size_t bytes) ++{ ++ struct layerscape_sfp_priv *priv = context; ++ ++ memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset, ++ bytes); ++ ++ return 0; ++} ++ ++static struct nvmem_config layerscape_sfp_nvmem_config = { ++ .name = "fsl-sfp", ++ .reg_read = layerscape_sfp_read, ++}; ++ ++static int layerscape_sfp_probe(struct platform_device *pdev) ++{ ++ const struct layerscape_sfp_data *data; ++ struct layerscape_sfp_priv *priv; ++ struct nvmem_device *nvmem; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) ++ return PTR_ERR(priv->base); ++ ++ data = device_get_match_data(&pdev->dev); ++ ++ layerscape_sfp_nvmem_config.size = data->size; ++ layerscape_sfp_nvmem_config.dev = &pdev->dev; ++ layerscape_sfp_nvmem_config.priv = priv; ++ ++ nvmem = devm_nvmem_register(&pdev->dev, &layerscape_sfp_nvmem_config); ++ ++ return PTR_ERR_OR_ZERO(nvmem); ++} ++ ++static const struct layerscape_sfp_data ls1028a_data = { ++ .size = 0x88, ++}; ++ ++static const struct of_device_id layerscape_sfp_dt_ids[] = { ++ { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, layerscape_sfp_dt_ids); ++ ++static struct platform_driver layerscape_sfp_driver = { ++ .probe = layerscape_sfp_probe, ++ .driver = { ++ .name = "layerscape_sfp", ++ .of_match_table = layerscape_sfp_dt_ids, ++ }, ++}; ++module_platform_driver(layerscape_sfp_driver); ++ ++MODULE_AUTHOR("Michael Walle "); ++MODULE_DESCRIPTION("Layerscape Security Fuse Processor driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch b/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch new file mode 100644 index 00000000000..74bd4a7eb67 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch @@ -0,0 +1,32 @@ +From bc5c75e0a5a9400f81a987cc720100ac475fa4d8 Mon Sep 17 00:00:00 2001 +From: Knox Chiou +Date: Wed, 23 Feb 2022 22:35:00 +0000 +Subject: [PATCH] nvmem: qfprom: Increase fuse blow timeout to prevent write + fail + +sc7180 blow fuses got slightly chances to hit qfprom_reg_write timeout. +Current timeout is simply too low. Since blowing fuses is a +very rare operation, so the risk associated with overestimating this +number is low. +Increase fuse blow timeout from 1ms to 10ms. + +Reviewed-by: Douglas Anderson +Signed-off-by: Knox Chiou +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220223223502.29454-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/qfprom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/qfprom.c ++++ b/drivers/nvmem/qfprom.c +@@ -22,7 +22,7 @@ + + /* Amount of time required to hold charge to blow fuse in micro-seconds */ + #define QFPROM_FUSE_BLOW_POLL_US 100 +-#define QFPROM_FUSE_BLOW_TIMEOUT_US 1000 ++#define QFPROM_FUSE_BLOW_TIMEOUT_US 10000 + + #define QFPROM_BLOW_STATUS_OFFSET 0x048 + #define QFPROM_BLOW_STATUS_BUSY 0x1 diff --git a/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch b/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch new file mode 100644 index 00000000000..2a9dc749478 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch @@ -0,0 +1,291 @@ +From 8747ec2e9762ed9ae53b3a590938f454b6a1abdf Mon Sep 17 00:00:00 2001 +From: Vincent Shih +Date: Wed, 23 Feb 2022 22:35:01 +0000 +Subject: [PATCH] nvmem: Add driver for OCOTP in Sunplus SP7021 + +Add driver for OCOTP in Sunplus SP7021 + +Signed-off-by: Vincent Shih +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220223223502.29454-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 5 + + drivers/nvmem/Kconfig | 12 ++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/sunplus-ocotp.c | 228 ++++++++++++++++++++++++++++++++++ + 4 files changed, 247 insertions(+) + create mode 100644 drivers/nvmem/sunplus-ocotp.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -17962,6 +17962,11 @@ L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/ethernet/dlink/sundance.c + ++SUNPLUS OCOTP DRIVER ++M: Vincent Shih ++S: Maintained ++F: drivers/nvmem/sunplus-ocotp.c ++ + SUPERH + M: Yoshinori Sato + M: Rich Felker +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -312,4 +312,16 @@ config NVMEM_LAYERSCAPE_SFP + This driver can also be built as a module. If so, the module + will be called layerscape-sfp. + ++config NVMEM_SUNPLUS_OCOTP ++ tristate "Sunplus SoC OTP support" ++ depends on SOC_SP7021 || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This is a driver for the On-chip OTP controller (OCOTP) available ++ on Sunplus SoCs. It provides access to 128 bytes of one-time ++ programmable eFuse. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-sunplus-ocotp. ++ + endif +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -63,3 +63,5 @@ obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_ + nvmem_brcm_nvram-y := brcm_nvram.o + obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o + nvmem-layerscape-sfp-y := layerscape-sfp.o ++obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o ++nvmem_sunplus_ocotp-y := sunplus-ocotp.o +--- /dev/null ++++ b/drivers/nvmem/sunplus-ocotp.c +@@ -0,0 +1,228 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++/* ++ * The OCOTP driver for Sunplus SP7021 ++ * ++ * Copyright (C) 2019 Sunplus Technology Inc., All rights reserved. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * OTP memory ++ * Each bank contains 4 words (32 bits). ++ * Bank 0 starts at offset 0 from the base. ++ */ ++ ++#define OTP_WORDS_PER_BANK 4 ++#define OTP_WORD_SIZE sizeof(u32) ++#define OTP_BIT_ADDR_OF_BANK (8 * OTP_WORD_SIZE * OTP_WORDS_PER_BANK) ++#define QAC628_OTP_NUM_BANKS 8 ++#define QAC628_OTP_SIZE (QAC628_OTP_NUM_BANKS * OTP_WORDS_PER_BANK * OTP_WORD_SIZE) ++#define OTP_READ_TIMEOUT_US 200000 ++ ++/* HB_GPIO */ ++#define ADDRESS_8_DATA 0x20 ++ ++/* OTP_RX */ ++#define OTP_CONTROL_2 0x48 ++#define OTP_RD_PERIOD GENMASK(15, 8) ++#define OTP_RD_PERIOD_MASK ~GENMASK(15, 8) ++#define CPU_CLOCK FIELD_PREP(OTP_RD_PERIOD, 30) ++#define SEL_BAK_KEY2 BIT(5) ++#define SEL_BAK_KEY2_MASK ~BIT(5) ++#define SW_TRIM_EN BIT(4) ++#define SW_TRIM_EN_MASK ~BIT(4) ++#define SEL_BAK_KEY BIT(3) ++#define SEL_BAK_KEY_MASK ~BIT(3) ++#define OTP_READ BIT(2) ++#define OTP_LOAD_SECURE_DATA BIT(1) ++#define OTP_LOAD_SECURE_DATA_MASK ~BIT(1) ++#define OTP_DO_CRC BIT(0) ++#define OTP_DO_CRC_MASK ~BIT(0) ++#define OTP_STATUS 0x4c ++#define OTP_READ_DONE BIT(4) ++#define OTP_READ_DONE_MASK ~BIT(4) ++#define OTP_LOAD_SECURE_DONE_MASK ~BIT(2) ++#define OTP_READ_ADDRESS 0x50 ++ ++enum base_type { ++ HB_GPIO, ++ OTPRX, ++ BASEMAX, ++}; ++ ++struct sp_ocotp_priv { ++ struct device *dev; ++ void __iomem *base[BASEMAX]; ++ struct clk *clk; ++}; ++ ++struct sp_ocotp_data { ++ int size; ++}; ++ ++const struct sp_ocotp_data sp_otp_v0 = { ++ .size = QAC628_OTP_SIZE, ++}; ++ ++static int sp_otp_read_real(struct sp_ocotp_priv *otp, int addr, char *value) ++{ ++ unsigned int addr_data; ++ unsigned int byte_shift; ++ unsigned int status; ++ int ret; ++ ++ addr_data = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); ++ addr_data = addr_data / OTP_WORD_SIZE; ++ ++ byte_shift = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); ++ byte_shift = byte_shift % OTP_WORD_SIZE; ++ ++ addr = addr / (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); ++ addr = addr * OTP_BIT_ADDR_OF_BANK; ++ ++ writel(readl(otp->base[OTPRX] + OTP_STATUS) & OTP_READ_DONE_MASK & ++ OTP_LOAD_SECURE_DONE_MASK, otp->base[OTPRX] + OTP_STATUS); ++ writel(addr, otp->base[OTPRX] + OTP_READ_ADDRESS); ++ writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) | OTP_READ, ++ otp->base[OTPRX] + OTP_CONTROL_2); ++ writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) & SEL_BAK_KEY2_MASK & SW_TRIM_EN_MASK ++ & SEL_BAK_KEY_MASK & OTP_LOAD_SECURE_DATA_MASK & OTP_DO_CRC_MASK, ++ otp->base[OTPRX] + OTP_CONTROL_2); ++ writel((readl(otp->base[OTPRX] + OTP_CONTROL_2) & OTP_RD_PERIOD_MASK) | CPU_CLOCK, ++ otp->base[OTPRX] + OTP_CONTROL_2); ++ ++ ret = readl_poll_timeout(otp->base[OTPRX] + OTP_STATUS, status, ++ status & OTP_READ_DONE, 10, OTP_READ_TIMEOUT_US); ++ ++ if (ret < 0) ++ return ret; ++ ++ *value = (readl(otp->base[HB_GPIO] + ADDRESS_8_DATA + addr_data * OTP_WORD_SIZE) ++ >> (8 * byte_shift)) & 0xff; ++ ++ return ret; ++} ++ ++static int sp_ocotp_read(void *priv, unsigned int offset, void *value, size_t bytes) ++{ ++ struct sp_ocotp_priv *otp = priv; ++ unsigned int addr; ++ char *buf = value; ++ char val[4]; ++ int ret; ++ ++ ret = clk_enable(otp->clk); ++ if (ret) ++ return ret; ++ ++ *buf = 0; ++ for (addr = offset; addr < (offset + bytes); addr++) { ++ ret = sp_otp_read_real(otp, addr, val); ++ if (ret < 0) { ++ dev_err(otp->dev, "OTP read fail:%d at %d", ret, addr); ++ goto disable_clk; ++ } ++ ++ *buf++ = *val; ++ } ++ ++disable_clk: ++ clk_disable(otp->clk); ++ ++ return ret; ++} ++ ++static struct nvmem_config sp_ocotp_nvmem_config = { ++ .name = "sp-ocotp", ++ .read_only = true, ++ .word_size = 1, ++ .size = QAC628_OTP_SIZE, ++ .stride = 1, ++ .reg_read = sp_ocotp_read, ++ .owner = THIS_MODULE, ++}; ++ ++static int sp_ocotp_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct nvmem_device *nvmem; ++ struct sp_ocotp_priv *otp; ++ struct resource *res; ++ int ret; ++ ++ otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); ++ if (!otp) ++ return -ENOMEM; ++ ++ otp->dev = dev; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio"); ++ otp->base[HB_GPIO] = devm_ioremap_resource(dev, res); ++ if (IS_ERR(otp->base[HB_GPIO])) ++ return PTR_ERR(otp->base[HB_GPIO]); ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx"); ++ otp->base[OTPRX] = devm_ioremap_resource(dev, res); ++ if (IS_ERR(otp->base[OTPRX])) ++ return PTR_ERR(otp->base[OTPRX]); ++ ++ otp->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(otp->clk)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(otp->clk), ++ "devm_clk_get fail\n"); ++ ++ ret = clk_prepare(otp->clk); ++ if (ret < 0) { ++ dev_err(dev, "failed to prepare clk: %d\n", ret); ++ return ret; ++ } ++ ++ sp_ocotp_nvmem_config.priv = otp; ++ sp_ocotp_nvmem_config.dev = dev; ++ ++ nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config); ++ if (IS_ERR(nvmem)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(nvmem), ++ "register nvmem device fail\n"); ++ ++ platform_set_drvdata(pdev, nvmem); ++ ++ dev_dbg(dev, "banks:%d x wpb:%d x wsize:%d = %d", ++ (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, ++ (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); ++ ++ dev_info(dev, "by Sunplus (C) 2020"); ++ ++ return 0; ++} ++ ++static const struct of_device_id sp_ocotp_dt_ids[] = { ++ { .compatible = "sunplus,sp7021-ocotp", .data = &sp_otp_v0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, sp_ocotp_dt_ids); ++ ++static struct platform_driver sp_otp_driver = { ++ .probe = sp_ocotp_probe, ++ .driver = { ++ .name = "sunplus,sp7021-ocotp", ++ .of_match_table = sp_ocotp_dt_ids, ++ } ++}; ++module_platform_driver(sp_otp_driver); ++ ++MODULE_AUTHOR("Vincent Shih "); ++MODULE_DESCRIPTION("Sunplus On-Chip OTP driver"); ++MODULE_LICENSE("GPL"); ++ diff --git a/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch b/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch new file mode 100644 index 00000000000..99781b3a7b3 --- /dev/null +++ b/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch @@ -0,0 +1,146 @@ +From 6e977eaa8280e957b87904b536661550f2a6b3e8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 25 Feb 2022 17:58:20 +0000 +Subject: [PATCH] nvmem: brcm_nvram: parse NVRAM content into NVMEM cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +NVRAM consist of header and NUL separated key-value pairs. Parse it and +create NVMEM cell for every key-value entry. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220225175822.8293-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/brcm_nvram.c | 90 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 90 insertions(+) + +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -6,12 +6,26 @@ + #include + #include + #include ++#include + #include + #include ++#include ++ ++#define NVRAM_MAGIC "FLSH" + + struct brcm_nvram { + struct device *dev; + void __iomem *base; ++ struct nvmem_cell_info *cells; ++ int ncells; ++}; ++ ++struct brcm_nvram_header { ++ char magic[4]; ++ __le32 len; ++ __le32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ ++ __le32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ ++ __le32 config_ncdl; /* ncdl values for memc */ + }; + + static int brcm_nvram_read(void *context, unsigned int offset, void *val, +@@ -26,6 +40,75 @@ static int brcm_nvram_read(void *context + return 0; + } + ++static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data, ++ size_t len) ++{ ++ struct device *dev = priv->dev; ++ char *var, *value, *eq; ++ int idx; ++ ++ priv->ncells = 0; ++ for (var = data + sizeof(struct brcm_nvram_header); ++ var < (char *)data + len && *var; ++ var += strlen(var) + 1) { ++ priv->ncells++; ++ } ++ ++ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL); ++ if (!priv->cells) ++ return -ENOMEM; ++ ++ for (var = data + sizeof(struct brcm_nvram_header), idx = 0; ++ var < (char *)data + len && *var; ++ var = value + strlen(value) + 1, idx++) { ++ eq = strchr(var, '='); ++ if (!eq) ++ break; ++ *eq = '\0'; ++ value = eq + 1; ++ ++ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL); ++ if (!priv->cells[idx].name) ++ return -ENOMEM; ++ priv->cells[idx].offset = value - (char *)data; ++ priv->cells[idx].bytes = strlen(value); ++ } ++ ++ return 0; ++} ++ ++static int brcm_nvram_parse(struct brcm_nvram *priv) ++{ ++ struct device *dev = priv->dev; ++ struct brcm_nvram_header header; ++ uint8_t *data; ++ size_t len; ++ int err; ++ ++ memcpy_fromio(&header, priv->base, sizeof(header)); ++ ++ if (memcmp(header.magic, NVRAM_MAGIC, 4)) { ++ dev_err(dev, "Invalid NVRAM magic\n"); ++ return -EINVAL; ++ } ++ ++ len = le32_to_cpu(header.len); ++ ++ data = kcalloc(1, len, GFP_KERNEL); ++ memcpy_fromio(data, priv->base, len); ++ data[len - 1] = '\0'; ++ ++ err = brcm_nvram_add_cells(priv, data, len); ++ if (err) { ++ dev_err(dev, "Failed to add cells: %d\n", err); ++ return err; ++ } ++ ++ kfree(data); ++ ++ return 0; ++} ++ + static int brcm_nvram_probe(struct platform_device *pdev) + { + struct nvmem_config config = { +@@ -35,6 +118,7 @@ static int brcm_nvram_probe(struct platf + struct device *dev = &pdev->dev; + struct resource *res; + struct brcm_nvram *priv; ++ int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -46,7 +130,13 @@ static int brcm_nvram_probe(struct platf + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + ++ err = brcm_nvram_parse(priv); ++ if (err) ++ return err; ++ + config.dev = dev; ++ config.cells = priv->cells; ++ config.ncells = priv->ncells; + config.priv = priv; + config.size = resource_size(res); + diff --git a/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch b/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch new file mode 100644 index 00000000000..ef3107db946 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch @@ -0,0 +1,32 @@ +From 6bd0ffeaa389866089e9573b2298ae58d6359b75 Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Mon, 21 Mar 2022 12:03:24 +0100 +Subject: [PATCH] nvmem: bcm-ocotp: mark ACPI device ID table as maybe unused +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +"bcm_otpc_acpi_ids" is used with ACPI_PTR, so a build with !CONFIG_ACPI +has a warning: + + drivers/nvmem/bcm-ocotp.c:247:36: error: + ‘bcm_otpc_acpi_ids’ defined but not used [-Werror=unused-const-variable=] + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20220321110326.44652-1-krzk@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/bcm-ocotp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/bcm-ocotp.c ++++ b/drivers/nvmem/bcm-ocotp.c +@@ -244,7 +244,7 @@ static const struct of_device_id bcm_otp + }; + MODULE_DEVICE_TABLE(of, bcm_otpc_dt_ids); + +-static const struct acpi_device_id bcm_otpc_acpi_ids[] = { ++static const struct acpi_device_id bcm_otpc_acpi_ids[] __maybe_unused = { + { .id = "BRCM0700", .driver_data = (kernel_ulong_t)&otp_map }, + { .id = "BRCM0701", .driver_data = (kernel_ulong_t)&otp_map_v2 }, + { /* sentinel */ } diff --git a/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch b/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch new file mode 100644 index 00000000000..a84d2316f0c --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch @@ -0,0 +1,30 @@ +From 1066f8156351fcd997125257cea47cf805ba4f6d Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Mon, 21 Mar 2022 12:03:25 +0100 +Subject: [PATCH] nvmem: sunplus-ocotp: staticize sp_otp_v0 + +The "sp_otp_v0" file scope variable is not used outside, so make it +static to fix warning: + + drivers/nvmem/sunplus-ocotp.c:74:29: sparse: + sparse: symbol 'sp_otp_v0' was not declared. Should it be static? + +Reported-by: kernel test robot +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20220321110326.44652-2-krzk@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/sunplus-ocotp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/sunplus-ocotp.c ++++ b/drivers/nvmem/sunplus-ocotp.c +@@ -71,7 +71,7 @@ struct sp_ocotp_data { + int size; + }; + +-const struct sp_ocotp_data sp_otp_v0 = { ++static const struct sp_ocotp_data sp_otp_v0 = { + .size = QAC628_OTP_SIZE, + }; + diff --git a/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch b/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch new file mode 100644 index 00000000000..886ebc12a9c --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch @@ -0,0 +1,27 @@ +From 874dfbcf219ccc42a2cbd187d087c7db82c3024b Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Mon, 21 Mar 2022 12:03:26 +0100 +Subject: [PATCH] nvmem: sunplus-ocotp: drop useless probe confirmation + +Printing probe success is discouraged, because we can use tracing for +this purpose. Remove useless print message after Sunplus OCOTP driver +probe. + +Signed-off-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/20220321110326.44652-3-krzk@kernel.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/sunplus-ocotp.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/nvmem/sunplus-ocotp.c ++++ b/drivers/nvmem/sunplus-ocotp.c +@@ -202,8 +202,6 @@ static int sp_ocotp_probe(struct platfor + (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, + (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); + +- dev_info(dev, "by Sunplus (C) 2020"); +- + return 0; + } + diff --git a/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch b/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch new file mode 100644 index 00000000000..3b1e76147a8 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch @@ -0,0 +1,41 @@ +From dbc2f62061c6bfba0aee93161ee3194dcee84bd0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 29 Apr 2022 17:26:46 +0100 +Subject: [PATCH] nvmem: core: support passing DT node in cell info +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some hardware may have NVMEM cells described in Device Tree using +individual nodes. Let drivers pass such nodes to the NVMEM subsystem so +they can be later used by NVMEM consumers. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 1 + + include/linux/nvmem-consumer.h | 1 + + 2 files changed, 2 insertions(+) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -467,6 +467,7 @@ static int nvmem_cell_info_to_nvmem_cell + + cell->bit_offset = info->bit_offset; + cell->nbits = info->nbits; ++ cell->np = info->np; + + if (cell->nbits) + cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, +--- a/include/linux/nvmem-consumer.h ++++ b/include/linux/nvmem-consumer.h +@@ -25,6 +25,7 @@ struct nvmem_cell_info { + unsigned int bytes; + unsigned int bit_offset; + unsigned int nbits; ++ struct device_node *np; + }; + + /** diff --git a/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch b/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch new file mode 100644 index 00000000000..a9eacd9419c --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch @@ -0,0 +1,38 @@ +From 207775f7e17b8fd0426a2ac4a5b81e4e1d71849e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 29 Apr 2022 17:26:47 +0100 +Subject: [PATCH] nvmem: brcm_nvram: find Device Tree nodes for NVMEM cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DT binding for Broadcom's NVRAM supports specifying NVMEM cells as NVMEM +device (provider) subnodes. Look for such subnodes when collecing NVMEM +cells. This allows NVMEM consumers to use NVRAM variables. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/brcm_nvram.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -72,6 +73,7 @@ static int brcm_nvram_add_cells(struct b + return -ENOMEM; + priv->cells[idx].offset = value - (char *)data; + priv->cells[idx].bytes = strlen(value); ++ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); + } + + return 0; diff --git a/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch b/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch new file mode 100644 index 00000000000..ebeb6f5ad39 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch @@ -0,0 +1,130 @@ +From b6b7ef932ae838209254f016ecf8862d716a5ced Mon Sep 17 00:00:00 2001 +From: Sven Peter +Date: Fri, 29 Apr 2022 17:26:50 +0100 +Subject: [PATCH] nvmem: Add Apple eFuse driver + +Apple SoCs contain eFuses used to store factory-programmed data such +as calibration values for the PCIe or the Type-C PHY. They are organized +as 32bit values exposed as MMIO. + +Signed-off-by: Sven Peter +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-6-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 12 ++++++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/apple-efuses.c | 80 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 94 insertions(+) + create mode 100644 drivers/nvmem/apple-efuses.c + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -324,4 +324,16 @@ config NVMEM_SUNPLUS_OCOTP + This driver can also be built as a module. If so, the module + will be called nvmem-sunplus-ocotp. + ++config NVMEM_APPLE_EFUSES ++ tristate "Apple eFuse support" ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ help ++ Say y here to enable support for reading eFuses on Apple SoCs ++ such as the M1. These are e.g. used to store factory programmed ++ calibration data required for the PCIe or the USB-C PHY. ++ ++ This driver can also be built as a module. If so, the module will ++ be called nvmem-apple-efuses. ++ + endif +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -65,3 +65,5 @@ obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nv + nvmem-layerscape-sfp-y := layerscape-sfp.o + obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o + nvmem_sunplus_ocotp-y := sunplus-ocotp.o ++obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o ++nvmem-apple-efuses-y := apple-efuses.o +--- /dev/null ++++ b/drivers/nvmem/apple-efuses.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Apple SoC eFuse driver ++ * ++ * Copyright (C) The Asahi Linux Contributors ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++struct apple_efuses_priv { ++ void __iomem *fuses; ++}; ++ ++static int apple_efuses_read(void *context, unsigned int offset, void *val, ++ size_t bytes) ++{ ++ struct apple_efuses_priv *priv = context; ++ u32 *dst = val; ++ ++ while (bytes >= sizeof(u32)) { ++ *dst++ = readl_relaxed(priv->fuses + offset); ++ bytes -= sizeof(u32); ++ offset += sizeof(u32); ++ } ++ ++ return 0; ++} ++ ++static int apple_efuses_probe(struct platform_device *pdev) ++{ ++ struct apple_efuses_priv *priv; ++ struct resource *res; ++ struct nvmem_config config = { ++ .dev = &pdev->dev, ++ .read_only = true, ++ .reg_read = apple_efuses_read, ++ .stride = sizeof(u32), ++ .word_size = sizeof(u32), ++ .name = "apple_efuses_nvmem", ++ .id = NVMEM_DEVID_AUTO, ++ .root_only = true, ++ }; ++ ++ priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->fuses = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ if (IS_ERR(priv->fuses)) ++ return PTR_ERR(priv->fuses); ++ ++ config.priv = priv; ++ config.size = resource_size(res); ++ ++ return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); ++} ++ ++static const struct of_device_id apple_efuses_of_match[] = { ++ { .compatible = "apple,efuses", }, ++ {} ++}; ++ ++MODULE_DEVICE_TABLE(of, apple_efuses_of_match); ++ ++static struct platform_driver apple_efuses_driver = { ++ .driver = { ++ .name = "apple_efuses", ++ .of_match_table = apple_efuses_of_match, ++ }, ++ .probe = apple_efuses_probe, ++}; ++ ++module_platform_driver(apple_efuses_driver); ++ ++MODULE_AUTHOR("Sven Peter "); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch b/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch new file mode 100644 index 00000000000..cd51d970069 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch @@ -0,0 +1,31 @@ +From 517f6e2641a2802dce5a5aa0d18c7d37a35678d2 Mon Sep 17 00:00:00 2001 +From: Minghao Chi +Date: Fri, 29 Apr 2022 17:26:54 +0100 +Subject: [PATCH] nvmem: qfprom: using pm_runtime_resume_and_get instead of + pm_runtime_get_sync + +Using pm_runtime_resume_and_get is more appropriate +for simplifing code + +Reported-by: Zeal Robot +Signed-off-by: Minghao Chi +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-10-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/qfprom.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/nvmem/qfprom.c ++++ b/drivers/nvmem/qfprom.c +@@ -217,9 +217,8 @@ static int qfprom_enable_fuse_blowing(co + goto err_clk_rate_set; + } + +- ret = pm_runtime_get_sync(priv->dev); ++ ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) { +- pm_runtime_put_noidle(priv->dev); + dev_err(priv->dev, "Failed to enable power-domain\n"); + goto err_reg_enable; + } diff --git a/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch b/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch new file mode 100644 index 00000000000..e187238ca38 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch @@ -0,0 +1,109 @@ +From 943eadbdb11314b41eacbcc484dfb7f93e271ff4 Mon Sep 17 00:00:00 2001 +From: Sean Anderson +Date: Fri, 29 Apr 2022 17:27:00 +0100 +Subject: [PATCH] nvmem: sfp: Use regmap + +This converts the SFP driver to use regmap. This will allow easily +supporting devices with different endians. We disallow byte-level +access, as regmap_bulk_read doesn't support it (and it's unclear what +the correct result would be when we have an endianness difference). + +Signed-off-by: Sean Anderson +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-16-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 1 + + drivers/nvmem/layerscape-sfp.c | 30 ++++++++++++++++++++++-------- + 2 files changed, 23 insertions(+), 8 deletions(-) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -304,6 +304,7 @@ config NVMEM_LAYERSCAPE_SFP + tristate "Layerscape SFP (Security Fuse Processor) support" + depends on ARCH_LAYERSCAPE || COMPILE_TEST + depends on HAS_IOMEM ++ select REGMAP_MMIO + help + This driver provides support to read the eFuses on Freescale + Layerscape SoC's. For example, the vendor provides a per part +--- a/drivers/nvmem/layerscape-sfp.c ++++ b/drivers/nvmem/layerscape-sfp.c +@@ -13,15 +13,17 @@ + #include + #include + #include ++#include + + #define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 + + struct layerscape_sfp_priv { +- void __iomem *base; ++ struct regmap *regmap; + }; + + struct layerscape_sfp_data { + int size; ++ enum regmap_endian endian; + }; + + static int layerscape_sfp_read(void *context, unsigned int offset, void *val, +@@ -29,15 +31,16 @@ static int layerscape_sfp_read(void *con + { + struct layerscape_sfp_priv *priv = context; + +- memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset, +- bytes); +- +- return 0; ++ return regmap_bulk_read(priv->regmap, ++ LAYERSCAPE_SFP_OTP_OFFSET + offset, val, ++ bytes / 4); + } + + static struct nvmem_config layerscape_sfp_nvmem_config = { + .name = "fsl-sfp", + .reg_read = layerscape_sfp_read, ++ .word_size = 4, ++ .stride = 4, + }; + + static int layerscape_sfp_probe(struct platform_device *pdev) +@@ -45,16 +48,26 @@ static int layerscape_sfp_probe(struct p + const struct layerscape_sfp_data *data; + struct layerscape_sfp_priv *priv; + struct nvmem_device *nvmem; ++ struct regmap_config config = { 0 }; ++ void __iomem *base; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + +- priv->base = devm_platform_ioremap_resource(pdev, 0); +- if (IS_ERR(priv->base)) +- return PTR_ERR(priv->base); ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); + + data = device_get_match_data(&pdev->dev); ++ config.reg_bits = 32; ++ config.reg_stride = 4; ++ config.val_bits = 32; ++ config.val_format_endian = data->endian; ++ config.max_register = LAYERSCAPE_SFP_OTP_OFFSET + data->size - 4; ++ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, &config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); + + layerscape_sfp_nvmem_config.size = data->size; + layerscape_sfp_nvmem_config.dev = &pdev->dev; +@@ -67,6 +80,7 @@ static int layerscape_sfp_probe(struct p + + static const struct layerscape_sfp_data ls1028a_data = { + .size = 0x88, ++ .endian = REGMAP_ENDIAN_LITTLE, + }; + + static const struct of_device_id layerscape_sfp_dt_ids[] = { diff --git a/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch b/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch new file mode 100644 index 00000000000..ee000986181 --- /dev/null +++ b/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch @@ -0,0 +1,38 @@ +From 33a1c6618677fe33f8e84cb7bedc45abbce89a50 Mon Sep 17 00:00:00 2001 +From: Sean Anderson +Date: Fri, 29 Apr 2022 17:27:01 +0100 +Subject: [PATCH] nvmem: sfp: Add support for TA 2.1 devices + +This adds support for Trust Architecture (TA) 2.1 devices to the SFP driver. +There are few differences between TA 2.1 and TA 3.0, especially for +read-only support, so just re-use the existing data. + +Signed-off-by: Sean Anderson +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220429162701.2222-17-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layerscape-sfp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/nvmem/layerscape-sfp.c ++++ b/drivers/nvmem/layerscape-sfp.c +@@ -78,12 +78,18 @@ static int layerscape_sfp_probe(struct p + return PTR_ERR_OR_ZERO(nvmem); + } + ++static const struct layerscape_sfp_data ls1021a_data = { ++ .size = 0x88, ++ .endian = REGMAP_ENDIAN_BIG, ++}; ++ + static const struct layerscape_sfp_data ls1028a_data = { + .size = 0x88, + .endian = REGMAP_ENDIAN_LITTLE, + }; + + static const struct of_device_id layerscape_sfp_dt_ids[] = { ++ { .compatible = "fsl,ls1021a-sfp", .data = &ls1021a_data }, + { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, + {}, + }; diff --git a/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch b/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch new file mode 100644 index 00000000000..b1855d1f2f2 --- /dev/null +++ b/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch @@ -0,0 +1,389 @@ +From 98830350d3fc824c1ff5c338140fe20f041a5916 Mon Sep 17 00:00:00 2001 +From: Claudiu Beznea +Date: Wed, 6 Jul 2022 11:06:22 +0100 +Subject: [PATCH] nvmem: microchip-otpc: add support + +Add support for Microchip OTP controller available on SAMA7G5. The OTPC +controls the access to a non-volatile memory. The memory behind OTPC is +organized into packets, packets are composed by a fixed length header +(4 bytes long) and a variable length payload (payload length is available +in the header). When software request the data at an offset in memory +the OTPC will return (via header + data registers) the whole packet that +has a word at that offset. For the OTP memory layout like below: + +offset OTP Memory layout + + . . + . ... . + . . +0x0E +-----------+ <--- packet X + | header X | +0x12 +-----------+ + | payload X | +0x16 | | + | | +0x1A | | + +-----------+ + . . + . ... . + . . + +if user requests data at address 0x16 the data started at 0x0E will be +returned by controller. User will be able to fetch the whole packet +starting at 0x0E (or parts of the packet) via proper registers. The same +packet will be returned if software request the data at offset 0x0E or +0x12 or 0x1A. + +The OTP will be populated by Microchip with at least 2 packets first one +being boot configuration packet and the 2nd one being temperature +calibration packet. The packet order will be preserved b/w different chip +revisions but the packet sizes may change. + +For the above reasons and to keep the same software able to work on all +chip variants the read function of the driver is working with a packet +id instead of an offset in OTP memory. + +Signed-off-by: Claudiu Beznea +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220706100627.6534-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 8 + + drivers/nvmem/Kconfig | 7 + + drivers/nvmem/Makefile | 2 + + drivers/nvmem/microchip-otpc.c | 288 +++++++++++++++++++++++++++++++++ + 4 files changed, 305 insertions(+) + create mode 100644 drivers/nvmem/microchip-otpc.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -12361,6 +12361,14 @@ S: Supported + F: Documentation/devicetree/bindings/mtd/atmel-nand.txt + F: drivers/mtd/nand/raw/atmel/* + ++MICROCHIP OTPC DRIVER ++M: Claudiu Beznea ++L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ++S: Supported ++F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml ++F: drivers/nvmem/microchip-otpc.c ++F: dt-bindings/nvmem/microchip,sama7g5-otpc.h ++ + MICROCHIP PWM DRIVER + M: Claudiu Beznea + L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -107,6 +107,13 @@ config MTK_EFUSE + This driver can also be built as a module. If so, the module + will be called efuse-mtk. + ++config MICROCHIP_OTPC ++ tristate "Microchip OTPC support" ++ depends on ARCH_AT91 || COMPILE_TEST ++ help ++ This driver enable the OTP controller available on Microchip SAMA7G5 ++ SoCs. It controlls the access to the OTP memory connected to it. ++ + config NVMEM_NINTENDO_OTP + tristate "Nintendo Wii and Wii U OTP Support" + depends on WII || COMPILE_TEST +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -67,3 +67,5 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvm + nvmem_sunplus_ocotp-y := sunplus-ocotp.o + obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o + nvmem-apple-efuses-y := apple-efuses.o ++obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o ++nvmem-microchip-otpc-y := microchip-otpc.o +--- /dev/null ++++ b/drivers/nvmem/microchip-otpc.c +@@ -0,0 +1,288 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * OTP Memory controller ++ * ++ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries ++ * ++ * Author: Claudiu Beznea ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MCHP_OTPC_CR (0x0) ++#define MCHP_OTPC_CR_READ BIT(6) ++#define MCHP_OTPC_MR (0x4) ++#define MCHP_OTPC_MR_ADDR GENMASK(31, 16) ++#define MCHP_OTPC_AR (0x8) ++#define MCHP_OTPC_SR (0xc) ++#define MCHP_OTPC_SR_READ BIT(6) ++#define MCHP_OTPC_HR (0x20) ++#define MCHP_OTPC_HR_SIZE GENMASK(15, 8) ++#define MCHP_OTPC_DR (0x24) ++ ++#define MCHP_OTPC_NAME "mchp-otpc" ++#define MCHP_OTPC_SIZE (11 * 1024) ++ ++/** ++ * struct mchp_otpc - OTPC private data structure ++ * @base: base address ++ * @dev: struct device pointer ++ * @packets: list of packets in OTP memory ++ * @npackets: number of packets in OTP memory ++ */ ++struct mchp_otpc { ++ void __iomem *base; ++ struct device *dev; ++ struct list_head packets; ++ u32 npackets; ++}; ++ ++/** ++ * struct mchp_otpc_packet - OTPC packet data structure ++ * @list: list head ++ * @id: packet ID ++ * @offset: packet offset (in words) in OTP memory ++ */ ++struct mchp_otpc_packet { ++ struct list_head list; ++ u32 id; ++ u32 offset; ++}; ++ ++static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc, ++ u32 id) ++{ ++ struct mchp_otpc_packet *packet; ++ ++ if (id >= otpc->npackets) ++ return NULL; ++ ++ list_for_each_entry(packet, &otpc->packets, list) { ++ if (packet->id == id) ++ return packet; ++ } ++ ++ return NULL; ++} ++ ++static int mchp_otpc_prepare_read(struct mchp_otpc *otpc, ++ unsigned int offset) ++{ ++ u32 tmp; ++ ++ /* Set address. */ ++ tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR); ++ tmp &= ~MCHP_OTPC_MR_ADDR; ++ tmp |= FIELD_PREP(MCHP_OTPC_MR_ADDR, offset); ++ writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR); ++ ++ /* Set read. */ ++ tmp = readl_relaxed(otpc->base + MCHP_OTPC_CR); ++ tmp |= MCHP_OTPC_CR_READ; ++ writel_relaxed(tmp, otpc->base + MCHP_OTPC_CR); ++ ++ /* Wait for packet to be transferred into temporary buffers. */ ++ return read_poll_timeout(readl_relaxed, tmp, !(tmp & MCHP_OTPC_SR_READ), ++ 10000, 2000, false, otpc->base + MCHP_OTPC_SR); ++} ++ ++/* ++ * OTPC memory is organized into packets. Each packets contains a header and ++ * a payload. Header is 4 bytes long and contains the size of the payload. ++ * Payload size varies. The memory footprint is something as follows: ++ * ++ * Memory offset Memory footprint Packet ID ++ * ------------- ---------------- --------- ++ * ++ * 0x0 +------------+ <-- packet 0 ++ * | header 0 | ++ * 0x4 +------------+ ++ * | payload 0 | ++ * . . ++ * . ... . ++ * . . ++ * offset1 +------------+ <-- packet 1 ++ * | header 1 | ++ * offset1 + 0x4 +------------+ ++ * | payload 1 | ++ * . . ++ * . ... . ++ * . . ++ * offset2 +------------+ <-- packet 2 ++ * . . ++ * . ... . ++ * . . ++ * offsetN +------------+ <-- packet N ++ * | header N | ++ * offsetN + 0x4 +------------+ ++ * | payload N | ++ * . . ++ * . ... . ++ * . . ++ * +------------+ ++ * ++ * where offset1, offset2, offsetN depends on the size of payload 0, payload 1, ++ * payload N-1. ++ * ++ * The access to memory is done on a per packet basis: the control registers ++ * need to be updated with an offset address (within a packet range) and the ++ * data registers will be update by controller with information contained by ++ * that packet. E.g. if control registers are updated with any address within ++ * the range [offset1, offset2) the data registers are updated by controller ++ * with packet 1. Header data is accessible though MCHP_OTPC_HR register. ++ * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers. ++ * There is no direct mapping b/w the offset requested by software and the ++ * offset returned by hardware. ++ * ++ * For this, the read function will return the first requested bytes in the ++ * packet. The user will have to be aware of the memory footprint before doing ++ * the read request. ++ */ ++static int mchp_otpc_read(void *priv, unsigned int off, void *val, ++ size_t bytes) ++{ ++ struct mchp_otpc *otpc = priv; ++ struct mchp_otpc_packet *packet; ++ u32 *buf = val; ++ u32 offset; ++ size_t len = 0; ++ int ret, payload_size; ++ ++ /* ++ * We reach this point with off being multiple of stride = 4 to ++ * be able to cross the subsystem. Inside the driver we use continuous ++ * unsigned integer numbers for packet id, thus devide off by 4 ++ * before passing it to mchp_otpc_id_to_packet(). ++ */ ++ packet = mchp_otpc_id_to_packet(otpc, off / 4); ++ if (!packet) ++ return -EINVAL; ++ offset = packet->offset; ++ ++ while (len < bytes) { ++ ret = mchp_otpc_prepare_read(otpc, offset); ++ if (ret) ++ return ret; ++ ++ /* Read and save header content. */ ++ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR); ++ len += sizeof(*buf); ++ offset++; ++ if (len >= bytes) ++ break; ++ ++ /* Read and save payload content. */ ++ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1)); ++ writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); ++ do { ++ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR); ++ len += sizeof(*buf); ++ offset++; ++ payload_size--; ++ } while (payload_size >= 0 && len < bytes); ++ } ++ ++ return 0; ++} ++ ++static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size) ++{ ++ struct mchp_otpc_packet *packet; ++ u32 word, word_pos = 0, id = 0, npackets = 0, payload_size; ++ int ret; ++ ++ INIT_LIST_HEAD(&otpc->packets); ++ *size = 0; ++ ++ while (*size < MCHP_OTPC_SIZE) { ++ ret = mchp_otpc_prepare_read(otpc, word_pos); ++ if (ret) ++ return ret; ++ ++ word = readl_relaxed(otpc->base + MCHP_OTPC_HR); ++ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, word); ++ if (!payload_size) ++ break; ++ ++ packet = devm_kzalloc(otpc->dev, sizeof(*packet), GFP_KERNEL); ++ if (!packet) ++ return -ENOMEM; ++ ++ packet->id = id++; ++ packet->offset = word_pos; ++ INIT_LIST_HEAD(&packet->list); ++ list_add_tail(&packet->list, &otpc->packets); ++ ++ /* Count size by adding header and paload sizes. */ ++ *size += 4 * (payload_size + 1); ++ /* Next word: this packet (header, payload) position + 1. */ ++ word_pos += payload_size + 2; ++ ++ npackets++; ++ } ++ ++ otpc->npackets = npackets; ++ ++ return 0; ++} ++ ++static struct nvmem_config mchp_nvmem_config = { ++ .name = MCHP_OTPC_NAME, ++ .type = NVMEM_TYPE_OTP, ++ .read_only = true, ++ .word_size = 4, ++ .stride = 4, ++ .reg_read = mchp_otpc_read, ++}; ++ ++static int mchp_otpc_probe(struct platform_device *pdev) ++{ ++ struct nvmem_device *nvmem; ++ struct mchp_otpc *otpc; ++ u32 size; ++ int ret; ++ ++ otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL); ++ if (!otpc) ++ return -ENOMEM; ++ ++ otpc->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(otpc->base)) ++ return PTR_ERR(otpc->base); ++ ++ otpc->dev = &pdev->dev; ++ ret = mchp_otpc_init_packets_list(otpc, &size); ++ if (ret) ++ return ret; ++ ++ mchp_nvmem_config.dev = otpc->dev; ++ mchp_nvmem_config.size = size; ++ mchp_nvmem_config.priv = otpc; ++ nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config); ++ ++ return PTR_ERR_OR_ZERO(nvmem); ++} ++ ++static const struct of_device_id __maybe_unused mchp_otpc_ids[] = { ++ { .compatible = "microchip,sama7g5-otpc", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, mchp_otpc_ids); ++ ++static struct platform_driver mchp_otpc_driver = { ++ .probe = mchp_otpc_probe, ++ .driver = { ++ .name = MCHP_OTPC_NAME, ++ .of_match_table = of_match_ptr(mchp_otpc_ids), ++ }, ++}; ++module_platform_driver(mchp_otpc_driver); ++ ++MODULE_AUTHOR("Claudiu Beznea "); ++MODULE_DESCRIPTION("Microchip SAMA7G5 OTPC driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch b/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch new file mode 100644 index 00000000000..6a4126b9ded --- /dev/null +++ b/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch @@ -0,0 +1,32 @@ +From f5c97da8037b18d1256a58459fa96ed68e50fb41 Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Wed, 6 Jul 2022 11:06:27 +0100 +Subject: [PATCH] nvmem: mtk-efuse: Simplify with + devm_platform_get_and_ioremap_resource() + +Convert platform_get_resource(), devm_ioremap_resource() to a single +call to devm_platform_get_and_ioremap_resource(), as this is exactly +what this function does. + +No functional changes. + +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220706100627.6534-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/mtk-efuse.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/nvmem/mtk-efuse.c ++++ b/drivers/nvmem/mtk-efuse.c +@@ -41,8 +41,7 @@ static int mtk_efuse_probe(struct platfo + if (!priv) + return -ENOMEM; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- priv->base = devm_ioremap_resource(dev, res); ++ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + diff --git a/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch b/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch new file mode 100644 index 00000000000..9138807bc91 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch @@ -0,0 +1,286 @@ +From d5542923f200f95bddf524f36fd495f78aa28e3c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 16 Sep 2022 13:20:48 +0100 +Subject: [PATCH] nvmem: add driver handling U-Boot environment variables +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +U-Boot stores its setup as environment variables. It's a list of +key-value pairs stored on flash device with a custom header. + +This commit adds an NVMEM driver that: +1. Provides NVMEM access to environment vars binary data +2. Extracts variables as NVMEM cells + +Current Linux's NVMEM sysfs API allows reading whole NVMEM data block. +It can be used by user-space tools for reading U-Boot env vars block +without the hassle of finding its location. Parsing will still need to +be re-done there. + +Kernel-parsed NVMEM cells can be read however by Linux drivers. This may +be useful for Ethernet drivers for reading device MAC address which is +often stored as U-Boot env variable. + +Reviewed-by: Ahmad Fatoum +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + MAINTAINERS | 1 + + drivers/nvmem/Kconfig | 13 +++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/u-boot-env.c | 218 +++++++++++++++++++++++++++++++++++++ + 4 files changed, 234 insertions(+) + create mode 100644 drivers/nvmem/u-boot-env.c + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -344,4 +344,17 @@ config NVMEM_APPLE_EFUSES + This driver can also be built as a module. If so, the module will + be called nvmem-apple-efuses. + ++config NVMEM_U_BOOT_ENV ++ tristate "U-Boot environment variables support" ++ depends on OF && MTD ++ select CRC32 ++ help ++ U-Boot stores its setup as environment variables. This driver adds ++ support for verifying & exporting such data. It also exposes variables ++ as NVMEM cells so they can be referenced by other drivers. ++ ++ Currently this drivers works only with env variables on top of MTD. ++ ++ If compiled as module it will be called nvmem_u-boot-env. ++ + endif +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -69,3 +69,5 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvme + nvmem-apple-efuses-y := apple-efuses.o + obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o + nvmem-microchip-otpc-y := microchip-otpc.o ++obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o ++nvmem_u-boot-env-y := u-boot-env.o +--- /dev/null ++++ b/drivers/nvmem/u-boot-env.c +@@ -0,0 +1,218 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2022 Rafał Miłecki ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum u_boot_env_format { ++ U_BOOT_FORMAT_SINGLE, ++ U_BOOT_FORMAT_REDUNDANT, ++}; ++ ++struct u_boot_env { ++ struct device *dev; ++ enum u_boot_env_format format; ++ ++ struct mtd_info *mtd; ++ ++ /* Cells */ ++ struct nvmem_cell_info *cells; ++ int ncells; ++}; ++ ++struct u_boot_env_image_single { ++ __le32 crc32; ++ uint8_t data[]; ++} __packed; ++ ++struct u_boot_env_image_redundant { ++ __le32 crc32; ++ u8 mark; ++ uint8_t data[]; ++} __packed; ++ ++static int u_boot_env_read(void *context, unsigned int offset, void *val, ++ size_t bytes) ++{ ++ struct u_boot_env *priv = context; ++ struct device *dev = priv->dev; ++ size_t bytes_read; ++ int err; ++ ++ err = mtd_read(priv->mtd, offset, bytes, &bytes_read, val); ++ if (err && !mtd_is_bitflip(err)) { ++ dev_err(dev, "Failed to read from mtd: %d\n", err); ++ return err; ++ } ++ ++ if (bytes_read != bytes) { ++ dev_err(dev, "Failed to read %zu bytes\n", bytes); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf, ++ size_t data_offset, size_t data_len) ++{ ++ struct device *dev = priv->dev; ++ char *data = buf + data_offset; ++ char *var, *value, *eq; ++ int idx; ++ ++ priv->ncells = 0; ++ for (var = data; var < data + data_len && *var; var += strlen(var) + 1) ++ priv->ncells++; ++ ++ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL); ++ if (!priv->cells) ++ return -ENOMEM; ++ ++ for (var = data, idx = 0; ++ var < data + data_len && *var; ++ var = value + strlen(value) + 1, idx++) { ++ eq = strchr(var, '='); ++ if (!eq) ++ break; ++ *eq = '\0'; ++ value = eq + 1; ++ ++ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL); ++ if (!priv->cells[idx].name) ++ return -ENOMEM; ++ priv->cells[idx].offset = data_offset + value - data; ++ priv->cells[idx].bytes = strlen(value); ++ } ++ ++ if (WARN_ON(idx != priv->ncells)) ++ priv->ncells = idx; ++ ++ return 0; ++} ++ ++static int u_boot_env_parse(struct u_boot_env *priv) ++{ ++ struct device *dev = priv->dev; ++ size_t crc32_data_offset; ++ size_t crc32_data_len; ++ size_t crc32_offset; ++ size_t data_offset; ++ size_t data_len; ++ uint32_t crc32; ++ uint32_t calc; ++ size_t bytes; ++ uint8_t *buf; ++ int err; ++ ++ buf = kcalloc(1, priv->mtd->size, GFP_KERNEL); ++ if (!buf) { ++ err = -ENOMEM; ++ goto err_out; ++ } ++ ++ err = mtd_read(priv->mtd, 0, priv->mtd->size, &bytes, buf); ++ if ((err && !mtd_is_bitflip(err)) || bytes != priv->mtd->size) { ++ dev_err(dev, "Failed to read from mtd: %d\n", err); ++ goto err_kfree; ++ } ++ ++ switch (priv->format) { ++ case U_BOOT_FORMAT_SINGLE: ++ crc32_offset = offsetof(struct u_boot_env_image_single, crc32); ++ crc32_data_offset = offsetof(struct u_boot_env_image_single, data); ++ data_offset = offsetof(struct u_boot_env_image_single, data); ++ break; ++ case U_BOOT_FORMAT_REDUNDANT: ++ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32); ++ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark); ++ data_offset = offsetof(struct u_boot_env_image_redundant, data); ++ break; ++ } ++ crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset)); ++ crc32_data_len = priv->mtd->size - crc32_data_offset; ++ data_len = priv->mtd->size - data_offset; ++ ++ calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L; ++ if (calc != crc32) { ++ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32); ++ err = -EINVAL; ++ goto err_kfree; ++ } ++ ++ buf[priv->mtd->size - 1] = '\0'; ++ err = u_boot_env_add_cells(priv, buf, data_offset, data_len); ++ if (err) ++ dev_err(dev, "Failed to add cells: %d\n", err); ++ ++err_kfree: ++ kfree(buf); ++err_out: ++ return err; ++} ++ ++static int u_boot_env_probe(struct platform_device *pdev) ++{ ++ struct nvmem_config config = { ++ .name = "u-boot-env", ++ .reg_read = u_boot_env_read, ++ }; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct u_boot_env *priv; ++ int err; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ priv->dev = dev; ++ ++ priv->format = (uintptr_t)of_device_get_match_data(dev); ++ ++ priv->mtd = of_get_mtd_device_by_node(np); ++ if (IS_ERR(priv->mtd)) { ++ dev_err_probe(dev, PTR_ERR(priv->mtd), "Failed to get %pOF MTD\n", np); ++ return PTR_ERR(priv->mtd); ++ } ++ ++ err = u_boot_env_parse(priv); ++ if (err) ++ return err; ++ ++ config.dev = dev; ++ config.cells = priv->cells; ++ config.ncells = priv->ncells; ++ config.priv = priv; ++ config.size = priv->mtd->size; ++ ++ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); ++} ++ ++static const struct of_device_id u_boot_env_of_match_table[] = { ++ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, }, ++ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, ++ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, ++ {}, ++}; ++ ++static struct platform_driver u_boot_env_driver = { ++ .probe = u_boot_env_probe, ++ .driver = { ++ .name = "u_boot_env", ++ .of_match_table = u_boot_env_of_match_table, ++ }, ++}; ++module_platform_driver(u_boot_env_driver); ++ ++MODULE_AUTHOR("Rafał Miłecki"); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch b/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch new file mode 100644 index 00000000000..48ad63fab5f --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch @@ -0,0 +1,29 @@ +From d3524bb5b9a0c567b853a0024526afe87dde01ed Mon Sep 17 00:00:00 2001 +From: Kenneth Lee +Date: Fri, 16 Sep 2022 13:20:52 +0100 +Subject: [PATCH] nvmem: brcm_nvram: Use kzalloc for allocating only one + element + +Use kzalloc(...) rather than kcalloc(1, ...) because the number of +elements we are specifying in this case is 1, so kzalloc would +accomplish the same thing and we can simplify. + +Signed-off-by: Kenneth Lee +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-6-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/brcm_nvram.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -96,7 +96,7 @@ static int brcm_nvram_parse(struct brcm_ + + len = le32_to_cpu(header.len); + +- data = kcalloc(1, len, GFP_KERNEL); ++ data = kzalloc(len, GFP_KERNEL); + memcpy_fromio(data, priv->base, len); + data[len - 1] = '\0'; + diff --git a/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch b/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch new file mode 100644 index 00000000000..ae02439bd73 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch @@ -0,0 +1,281 @@ +From 28fc7c986f01fdcfd28af648be2597624cac0e27 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 16 Sep 2022 13:20:54 +0100 +Subject: [PATCH] nvmem: prefix all symbols with NVMEM_ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This unifies all NVMEM symbols. They follow one style now. + +Reviewed-by: Matthias Brugger +Acked-by: Arnd Bergmann +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm/configs/multi_v7_defconfig | 6 +++--- + arch/arm/configs/qcom_defconfig | 2 +- + arch/arm64/configs/defconfig | 10 +++++----- + arch/mips/configs/ci20_defconfig | 2 +- + drivers/cpufreq/Kconfig.arm | 2 +- + drivers/nvmem/Kconfig | 24 ++++++++++++------------ + drivers/nvmem/Makefile | 24 ++++++++++++------------ + drivers/soc/mediatek/Kconfig | 2 +- + drivers/thermal/qcom/Kconfig | 2 +- + 9 files changed, 37 insertions(+), 37 deletions(-) + +--- a/arch/arm/configs/multi_v7_defconfig ++++ b/arch/arm/configs/multi_v7_defconfig +@@ -1125,10 +1125,10 @@ CONFIG_TI_PIPE3=y + CONFIG_TWL4030_USB=m + CONFIG_RAS=y + CONFIG_NVMEM_IMX_OCOTP=y +-CONFIG_ROCKCHIP_EFUSE=m ++CONFIG_NVMEM_ROCKCHIP_EFUSE=m + CONFIG_NVMEM_SUNXI_SID=y + CONFIG_NVMEM_VF610_OCOTP=y +-CONFIG_MESON_MX_EFUSE=m ++CONFIG_NVMEM_MESON_MX_EFUSE=m + CONFIG_NVMEM_RMEM=m + CONFIG_FSI=m + CONFIG_FSI_MASTER_GPIO=m +--- a/arch/arm/configs/qcom_defconfig ++++ b/arch/arm/configs/qcom_defconfig +@@ -274,7 +274,7 @@ CONFIG_PHY_QCOM_USB_HS=y + CONFIG_PHY_QCOM_USB_HSIC=y + CONFIG_PHY_QCOM_QMP=y + CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y +-CONFIG_QCOM_QFPROM=y ++CONFIG_NVMEM_QCOM_QFPROM=y + CONFIG_INTERCONNECT=y + CONFIG_INTERCONNECT_QCOM=y + CONFIG_INTERCONNECT_QCOM_MSM8974=m +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -1135,11 +1135,11 @@ CONFIG_QCOM_L3_PMU=y + CONFIG_NVMEM_IMX_OCOTP=y + CONFIG_NVMEM_IMX_OCOTP_SCU=y + CONFIG_QCOM_QFPROM=y +-CONFIG_MTK_EFUSE=y +-CONFIG_ROCKCHIP_EFUSE=y ++CONFIG_NVMEM_MTK_EFUSE=y ++CONFIG_NVMEM_ROCKCHIP_EFUSE=y + CONFIG_NVMEM_SUNXI_SID=y +-CONFIG_UNIPHIER_EFUSE=y +-CONFIG_MESON_EFUSE=m ++CONFIG_NVMEM_UNIPHIER_EFUSE=y ++CONFIG_NVMEM_MESON_EFUSE=m + CONFIG_NVMEM_RMEM=m + CONFIG_FPGA=y + CONFIG_FPGA_MGR_STRATIX10_SOC=m +--- a/arch/mips/configs/ci20_defconfig ++++ b/arch/mips/configs/ci20_defconfig +@@ -137,7 +137,7 @@ CONFIG_MEMORY=y + CONFIG_JZ4780_NEMC=y + CONFIG_PWM=y + CONFIG_PWM_JZ4740=m +-CONFIG_JZ4780_EFUSE=y ++CONFIG_NVMEM_JZ4780_EFUSE=y + CONFIG_JZ4770_PHY=y + CONFIG_EXT4_FS=y + # CONFIG_DNOTIFY is not set +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -153,7 +153,7 @@ config ARM_OMAP2PLUS_CPUFREQ + config ARM_QCOM_CPUFREQ_NVMEM + tristate "Qualcomm nvmem based CPUFreq" + depends on ARCH_QCOM +- depends on QCOM_QFPROM ++ depends on NVMEM_QCOM_QFPROM + depends on QCOM_SMEM + select PM_OPP + help +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -52,7 +52,7 @@ config NVMEM_IMX_OCOTP_SCU + This is a driver for the SCU On-Chip OTP Controller (OCOTP) + available on i.MX8 SoCs. + +-config JZ4780_EFUSE ++config NVMEM_JZ4780_EFUSE + tristate "JZ4780 EFUSE Memory Support" + depends on MACH_INGENIC || COMPILE_TEST + depends on HAS_IOMEM +@@ -96,7 +96,7 @@ config NVMEM_MXS_OCOTP + This driver can also be built as a module. If so, the module + will be called nvmem-mxs-ocotp. + +-config MTK_EFUSE ++config NVMEM_MTK_EFUSE + tristate "Mediatek SoCs EFUSE support" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_IOMEM +@@ -107,7 +107,7 @@ config MTK_EFUSE + This driver can also be built as a module. If so, the module + will be called efuse-mtk. + +-config MICROCHIP_OTPC ++config NVMEM_MICROCHIP_OTPC + tristate "Microchip OTPC support" + depends on ARCH_AT91 || COMPILE_TEST + help +@@ -126,7 +126,7 @@ config NVMEM_NINTENDO_OTP + This driver can also be built as a module. If so, the module + will be called nvmem-nintendo-otp. + +-config QCOM_QFPROM ++config NVMEM_QCOM_QFPROM + tristate "QCOM QFPROM Support" + depends on ARCH_QCOM || COMPILE_TEST + depends on HAS_IOMEM +@@ -145,7 +145,7 @@ config NVMEM_SPMI_SDAM + Qualcomm Technologies, Inc. PMICs. It provides the clients + an interface to read/write to the SDAM module's shared memory. + +-config ROCKCHIP_EFUSE ++config NVMEM_ROCKCHIP_EFUSE + tristate "Rockchip eFuse Support" + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on HAS_IOMEM +@@ -156,7 +156,7 @@ config ROCKCHIP_EFUSE + This driver can also be built as a module. If so, the module + will be called nvmem_rockchip_efuse. + +-config ROCKCHIP_OTP ++config NVMEM_ROCKCHIP_OTP + tristate "Rockchip OTP controller support" + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on HAS_IOMEM +@@ -199,7 +199,7 @@ config NVMEM_SUNXI_SID + This driver can also be built as a module. If so, the module + will be called nvmem_sunxi_sid. + +-config UNIPHIER_EFUSE ++config NVMEM_UNIPHIER_EFUSE + tristate "UniPhier SoCs eFuse support" + depends on ARCH_UNIPHIER || COMPILE_TEST + depends on HAS_IOMEM +@@ -221,7 +221,7 @@ config NVMEM_VF610_OCOTP + This driver can also be build as a module. If so, the module will + be called nvmem-vf610-ocotp. + +-config MESON_EFUSE ++config NVMEM_MESON_EFUSE + tristate "Amlogic Meson GX eFuse Support" + depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM + help +@@ -231,7 +231,7 @@ config MESON_EFUSE + This driver can also be built as a module. If so, the module + will be called nvmem_meson_efuse. + +-config MESON_MX_EFUSE ++config NVMEM_MESON_MX_EFUSE + tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" + depends on ARCH_MESON || COMPILE_TEST + help +@@ -251,13 +251,13 @@ config NVMEM_SNVS_LPGPR + This driver can also be built as a module. If so, the module + will be called nvmem-snvs-lpgpr. + +-config RAVE_SP_EEPROM ++config NVMEM_RAVE_SP_EEPROM + tristate "Rave SP EEPROM Support" + depends on RAVE_SP_CORE + help + Say y here to enable Rave SP EEPROM support. + +-config SC27XX_EFUSE ++config NVMEM_SC27XX_EFUSE + tristate "Spreadtrum SC27XX eFuse Support" + depends on MFD_SC27XX_PMIC || COMPILE_TEST + depends on HAS_IOMEM +@@ -278,7 +278,7 @@ config NVMEM_ZYNQMP + + If sure, say yes. If unsure, say no. + +-config SPRD_EFUSE ++config NVMEM_SPRD_EFUSE + tristate "Spreadtrum SoC eFuse Support" + depends on ARCH_SPRD || COMPILE_TEST + depends on HAS_IOMEM +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -15,7 +15,7 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-i + nvmem-imx-ocotp-y := imx-ocotp.o + obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o + nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o +-obj-$(CONFIG_JZ4780_EFUSE) += nvmem_jz4780_efuse.o ++obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o + nvmem_jz4780_efuse-y := jz4780-efuse.o + obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o + nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o +@@ -25,37 +25,37 @@ obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-m + nvmem-mxs-ocotp-y := mxs-ocotp.o + obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o + nvmem-nintendo-otp-y := nintendo-otp.o +-obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o ++obj-$(CONFIG_NVMEM_MTK_EFUSE) += nvmem_mtk-efuse.o + nvmem_mtk-efuse-y := mtk-efuse.o +-obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o ++obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o + nvmem_qfprom-y := qfprom.o + obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o + nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o +-obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o ++obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o + nvmem_rockchip_efuse-y := rockchip-efuse.o +-obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o ++obj-$(CONFIG_NVMEM_ROCKCHIP_OTP) += nvmem-rockchip-otp.o + nvmem-rockchip-otp-y := rockchip-otp.o + obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o + nvmem_stm32_romem-y := stm32-romem.o + obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o + nvmem_sunxi_sid-y := sunxi_sid.o +-obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o ++obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o + nvmem-uniphier-efuse-y := uniphier-efuse.o + obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o + nvmem-vf610-ocotp-y := vf610-ocotp.o +-obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o ++obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o + nvmem_meson_efuse-y := meson-efuse.o +-obj-$(CONFIG_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o ++obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o + nvmem_meson_mx_efuse-y := meson-mx-efuse.o + obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o + nvmem_snvs_lpgpr-y := snvs_lpgpr.o +-obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o ++obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o + nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o +-obj-$(CONFIG_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o ++obj-$(CONFIG_NVMEM_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o + nvmem-sc27xx-efuse-y := sc27xx-efuse.o + obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o + nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o +-obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o ++obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o + nvmem_sprd_efuse-y := sprd-efuse.o + obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o + nvmem-rmem-y := rmem.o +@@ -67,7 +67,7 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvm + nvmem_sunplus_ocotp-y := sunplus-ocotp.o + obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o + nvmem-apple-efuses-y := apple-efuses.o +-obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o ++obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o + nvmem-microchip-otpc-y := microchip-otpc.o + obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o + nvmem_u-boot-env-y := u-boot-env.o +--- a/drivers/thermal/qcom/Kconfig ++++ b/drivers/thermal/qcom/Kconfig +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config QCOM_TSENS + tristate "Qualcomm TSENS Temperature Alarm" +- depends on QCOM_QFPROM ++ depends on NVMEM_QCOM_QFPROM + depends on ARCH_QCOM || COMPILE_TEST + help + This enables the thermal sysfs driver for the TSENS device. It shows diff --git a/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch b/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch new file mode 100644 index 00000000000..4e45524bffc --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch @@ -0,0 +1,535 @@ +From a06d9e5a63b7c2f622c908cd9600ce735e70f7c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 16 Sep 2022 13:20:55 +0100 +Subject: [PATCH] nvmem: sort config symbols alphabetically +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Match what most subsystems do +2. Simplify maintenance a bit +3. Reduce amount of conflicts for new drivers patches + +While at it unify indent level in Makefile. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-9-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 300 +++++++++++++++++++++-------------------- + drivers/nvmem/Makefile | 114 ++++++++-------- + 2 files changed, 208 insertions(+), 206 deletions(-) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -21,6 +21,40 @@ config NVMEM_SYSFS + This interface is mostly used by userspace applications to + read/write directly into nvmem. + ++# Devices ++ ++config NVMEM_APPLE_EFUSES ++ tristate "Apple eFuse support" ++ depends on ARCH_APPLE || COMPILE_TEST ++ default ARCH_APPLE ++ help ++ Say y here to enable support for reading eFuses on Apple SoCs ++ such as the M1. These are e.g. used to store factory programmed ++ calibration data required for the PCIe or the USB-C PHY. ++ ++ This driver can also be built as a module. If so, the module will ++ be called nvmem-apple-efuses. ++ ++config NVMEM_BCM_OCOTP ++ tristate "Broadcom On-Chip OTP Controller support" ++ depends on ARCH_BCM_IPROC || COMPILE_TEST ++ depends on HAS_IOMEM ++ default ARCH_BCM_IPROC ++ help ++ Say y here to enable read/write access to the Broadcom OTP ++ controller. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-bcm-ocotp. ++ ++config NVMEM_BRCM_NVRAM ++ tristate "Broadcom's NVRAM support" ++ depends on ARCH_BCM_5301X || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This driver provides support for Broadcom's NVRAM that can be accessed ++ using I/O mapping. ++ + config NVMEM_IMX_IIM + tristate "i.MX IC Identification Module support" + depends on ARCH_MXC || COMPILE_TEST +@@ -64,6 +98,19 @@ config NVMEM_JZ4780_EFUSE + To compile this driver as a module, choose M here: the module + will be called nvmem_jz4780_efuse. + ++config NVMEM_LAYERSCAPE_SFP ++ tristate "Layerscape SFP (Security Fuse Processor) support" ++ depends on ARCH_LAYERSCAPE || COMPILE_TEST ++ depends on HAS_IOMEM ++ select REGMAP_MMIO ++ help ++ This driver provides support to read the eFuses on Freescale ++ Layerscape SoC's. For example, the vendor provides a per part ++ unique ID there. ++ ++ This driver can also be built as a module. If so, the module ++ will be called layerscape-sfp. ++ + config NVMEM_LPC18XX_EEPROM + tristate "NXP LPC18XX EEPROM Memory Support" + depends on ARCH_LPC18XX || COMPILE_TEST +@@ -84,17 +131,32 @@ config NVMEM_LPC18XX_OTP + To compile this driver as a module, choose M here: the module + will be called nvmem_lpc18xx_otp. + +-config NVMEM_MXS_OCOTP +- tristate "Freescale MXS On-Chip OTP Memory Support" +- depends on ARCH_MXS || COMPILE_TEST +- depends on HAS_IOMEM ++config NVMEM_MESON_EFUSE ++ tristate "Amlogic Meson GX eFuse Support" ++ depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM + help +- If you say Y here, you will get readonly access to the +- One Time Programmable memory pages that are stored +- on the Freescale i.MX23/i.MX28 processor. ++ This is a driver to retrieve specific values from the eFuse found on ++ the Amlogic Meson GX SoCs. + + This driver can also be built as a module. If so, the module +- will be called nvmem-mxs-ocotp. ++ will be called nvmem_meson_efuse. ++ ++config NVMEM_MESON_MX_EFUSE ++ tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" ++ depends on ARCH_MESON || COMPILE_TEST ++ help ++ This is a driver to retrieve specific values from the eFuse found on ++ the Amlogic Meson6, Meson8 and Meson8b SoCs. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem_meson_mx_efuse. ++ ++config NVMEM_MICROCHIP_OTPC ++ tristate "Microchip OTPC support" ++ depends on ARCH_AT91 || COMPILE_TEST ++ help ++ This driver enable the OTP controller available on Microchip SAMA7G5 ++ SoCs. It controlls the access to the OTP memory connected to it. + + config NVMEM_MTK_EFUSE + tristate "Mediatek SoCs EFUSE support" +@@ -107,12 +169,17 @@ config NVMEM_MTK_EFUSE + This driver can also be built as a module. If so, the module + will be called efuse-mtk. + +-config NVMEM_MICROCHIP_OTPC +- tristate "Microchip OTPC support" +- depends on ARCH_AT91 || COMPILE_TEST ++config NVMEM_MXS_OCOTP ++ tristate "Freescale MXS On-Chip OTP Memory Support" ++ depends on ARCH_MXS || COMPILE_TEST ++ depends on HAS_IOMEM + help +- This driver enable the OTP controller available on Microchip SAMA7G5 +- SoCs. It controlls the access to the OTP memory connected to it. ++ If you say Y here, you will get readonly access to the ++ One Time Programmable memory pages that are stored ++ on the Freescale i.MX23/i.MX28 processor. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-mxs-ocotp. + + config NVMEM_NINTENDO_OTP + tristate "Nintendo Wii and Wii U OTP Support" +@@ -137,13 +204,21 @@ config NVMEM_QCOM_QFPROM + This driver can also be built as a module. If so, the module + will be called nvmem_qfprom. + +-config NVMEM_SPMI_SDAM +- tristate "SPMI SDAM Support" +- depends on SPMI ++config NVMEM_RAVE_SP_EEPROM ++ tristate "Rave SP EEPROM Support" ++ depends on RAVE_SP_CORE + help +- This driver supports the Shared Direct Access Memory Module on +- Qualcomm Technologies, Inc. PMICs. It provides the clients +- an interface to read/write to the SDAM module's shared memory. ++ Say y here to enable Rave SP EEPROM support. ++ ++config NVMEM_RMEM ++ tristate "Reserved Memory Based Driver Support" ++ depends on HAS_IOMEM ++ help ++ This driver maps reserved memory into an nvmem device. It might be ++ useful to expose information left by firmware in memory. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-rmem. + + config NVMEM_ROCKCHIP_EFUSE + tristate "Rockchip eFuse Support" +@@ -167,79 +242,16 @@ config NVMEM_ROCKCHIP_OTP + This driver can also be built as a module. If so, the module + will be called nvmem_rockchip_otp. + +-config NVMEM_BCM_OCOTP +- tristate "Broadcom On-Chip OTP Controller support" +- depends on ARCH_BCM_IPROC || COMPILE_TEST +- depends on HAS_IOMEM +- default ARCH_BCM_IPROC +- help +- Say y here to enable read/write access to the Broadcom OTP +- controller. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem-bcm-ocotp. +- +-config NVMEM_STM32_ROMEM +- tristate "STMicroelectronics STM32 factory-programmed memory support" +- depends on ARCH_STM32 || COMPILE_TEST +- help +- Say y here to enable read-only access for STMicroelectronics STM32 +- factory-programmed memory area. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem-stm32-romem. +- +-config NVMEM_SUNXI_SID +- tristate "Allwinner SoCs SID support" +- depends on ARCH_SUNXI +- help +- This is a driver for the 'security ID' available on various Allwinner +- devices. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem_sunxi_sid. +- +-config NVMEM_UNIPHIER_EFUSE +- tristate "UniPhier SoCs eFuse support" +- depends on ARCH_UNIPHIER || COMPILE_TEST +- depends on HAS_IOMEM +- help +- This is a simple driver to dump specified values of UniPhier SoC +- from eFuse. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem-uniphier-efuse. +- +-config NVMEM_VF610_OCOTP +- tristate "VF610 SoC OCOTP support" +- depends on SOC_VF610 || COMPILE_TEST ++config NVMEM_SC27XX_EFUSE ++ tristate "Spreadtrum SC27XX eFuse Support" ++ depends on MFD_SC27XX_PMIC || COMPILE_TEST + depends on HAS_IOMEM + help +- This is a driver for the 'OCOTP' peripheral available on Vybrid +- devices like VF5xx and VF6xx. +- +- This driver can also be build as a module. If so, the module will +- be called nvmem-vf610-ocotp. +- +-config NVMEM_MESON_EFUSE +- tristate "Amlogic Meson GX eFuse Support" +- depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM +- help +- This is a driver to retrieve specific values from the eFuse found on +- the Amlogic Meson GX SoCs. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem_meson_efuse. +- +-config NVMEM_MESON_MX_EFUSE +- tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" +- depends on ARCH_MESON || COMPILE_TEST +- help +- This is a driver to retrieve specific values from the eFuse found on +- the Amlogic Meson6, Meson8 and Meson8b SoCs. ++ This is a simple driver to dump specified values of Spreadtrum ++ SC27XX PMICs from eFuse. + + This driver can also be built as a module. If so, the module +- will be called nvmem_meson_mx_efuse. ++ will be called nvmem-sc27xx-efuse. + + config NVMEM_SNVS_LPGPR + tristate "Support for Low Power General Purpose Register" +@@ -251,32 +263,13 @@ config NVMEM_SNVS_LPGPR + This driver can also be built as a module. If so, the module + will be called nvmem-snvs-lpgpr. + +-config NVMEM_RAVE_SP_EEPROM +- tristate "Rave SP EEPROM Support" +- depends on RAVE_SP_CORE +- help +- Say y here to enable Rave SP EEPROM support. +- +-config NVMEM_SC27XX_EFUSE +- tristate "Spreadtrum SC27XX eFuse Support" +- depends on MFD_SC27XX_PMIC || COMPILE_TEST +- depends on HAS_IOMEM +- help +- This is a simple driver to dump specified values of Spreadtrum +- SC27XX PMICs from eFuse. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem-sc27xx-efuse. +- +-config NVMEM_ZYNQMP +- bool "Xilinx ZYNQMP SoC nvmem firmware support" +- depends on ARCH_ZYNQMP ++config NVMEM_SPMI_SDAM ++ tristate "SPMI SDAM Support" ++ depends on SPMI + help +- This is a driver to access hardware related data like +- soc revision, IDCODE... etc by using the firmware +- interface. +- +- If sure, say yes. If unsure, say no. ++ This driver supports the Shared Direct Access Memory Module on ++ Qualcomm Technologies, Inc. PMICs. It provides the clients ++ an interface to read/write to the SDAM module's shared memory. + + config NVMEM_SPRD_EFUSE + tristate "Spreadtrum SoC eFuse Support" +@@ -289,36 +282,15 @@ config NVMEM_SPRD_EFUSE + This driver can also be built as a module. If so, the module + will be called nvmem-sprd-efuse. + +-config NVMEM_RMEM +- tristate "Reserved Memory Based Driver Support" +- depends on HAS_IOMEM +- help +- This driver maps reserved memory into an nvmem device. It might be +- useful to expose information left by firmware in memory. +- +- This driver can also be built as a module. If so, the module +- will be called nvmem-rmem. +- +-config NVMEM_BRCM_NVRAM +- tristate "Broadcom's NVRAM support" +- depends on ARCH_BCM_5301X || COMPILE_TEST +- depends on HAS_IOMEM +- help +- This driver provides support for Broadcom's NVRAM that can be accessed +- using I/O mapping. +- +-config NVMEM_LAYERSCAPE_SFP +- tristate "Layerscape SFP (Security Fuse Processor) support" +- depends on ARCH_LAYERSCAPE || COMPILE_TEST +- depends on HAS_IOMEM +- select REGMAP_MMIO ++config NVMEM_STM32_ROMEM ++ tristate "STMicroelectronics STM32 factory-programmed memory support" ++ depends on ARCH_STM32 || COMPILE_TEST + help +- This driver provides support to read the eFuses on Freescale +- Layerscape SoC's. For example, the vendor provides a per part +- unique ID there. ++ Say y here to enable read-only access for STMicroelectronics STM32 ++ factory-programmed memory area. + + This driver can also be built as a module. If so, the module +- will be called layerscape-sfp. ++ will be called nvmem-stm32-romem. + + config NVMEM_SUNPLUS_OCOTP + tristate "Sunplus SoC OTP support" +@@ -332,17 +304,15 @@ config NVMEM_SUNPLUS_OCOTP + This driver can also be built as a module. If so, the module + will be called nvmem-sunplus-ocotp. + +-config NVMEM_APPLE_EFUSES +- tristate "Apple eFuse support" +- depends on ARCH_APPLE || COMPILE_TEST +- default ARCH_APPLE ++config NVMEM_SUNXI_SID ++ tristate "Allwinner SoCs SID support" ++ depends on ARCH_SUNXI + help +- Say y here to enable support for reading eFuses on Apple SoCs +- such as the M1. These are e.g. used to store factory programmed +- calibration data required for the PCIe or the USB-C PHY. ++ This is a driver for the 'security ID' available on various Allwinner ++ devices. + +- This driver can also be built as a module. If so, the module will +- be called nvmem-apple-efuses. ++ This driver can also be built as a module. If so, the module ++ will be called nvmem_sunxi_sid. + + config NVMEM_U_BOOT_ENV + tristate "U-Boot environment variables support" +@@ -357,4 +327,36 @@ config NVMEM_U_BOOT_ENV + + If compiled as module it will be called nvmem_u-boot-env. + ++config NVMEM_UNIPHIER_EFUSE ++ tristate "UniPhier SoCs eFuse support" ++ depends on ARCH_UNIPHIER || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This is a simple driver to dump specified values of UniPhier SoC ++ from eFuse. ++ ++ This driver can also be built as a module. If so, the module ++ will be called nvmem-uniphier-efuse. ++ ++config NVMEM_VF610_OCOTP ++ tristate "VF610 SoC OCOTP support" ++ depends on SOC_VF610 || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This is a driver for the 'OCOTP' peripheral available on Vybrid ++ devices like VF5xx and VF6xx. ++ ++ This driver can also be build as a module. If so, the module will ++ be called nvmem-vf610-ocotp. ++ ++config NVMEM_ZYNQMP ++ bool "Xilinx ZYNQMP SoC nvmem firmware support" ++ depends on ARCH_ZYNQMP ++ help ++ This is a driver to access hardware related data like ++ soc revision, IDCODE... etc by using the firmware ++ interface. ++ ++ If sure, say yes. If unsure, say no. ++ + endif +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -7,67 +7,67 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o + nvmem_core-y := core.o + + # Devices +-obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o +-nvmem-bcm-ocotp-y := bcm-ocotp.o +-obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o +-nvmem-imx-iim-y := imx-iim.o +-obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o +-nvmem-imx-ocotp-y := imx-ocotp.o ++obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o ++nvmem-apple-efuses-y := apple-efuses.o ++obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o ++nvmem-bcm-ocotp-y := bcm-ocotp.o ++obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o ++nvmem_brcm_nvram-y := brcm_nvram.o ++obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o ++nvmem-imx-iim-y := imx-iim.o ++obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o ++nvmem-imx-ocotp-y := imx-ocotp.o + obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o +-nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o +-obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o +-nvmem_jz4780_efuse-y := jz4780-efuse.o ++nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o ++obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o ++nvmem_jz4780_efuse-y := jz4780-efuse.o ++obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o ++nvmem-layerscape-sfp-y := layerscape-sfp.o + obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o +-nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o +-obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o +-nvmem_lpc18xx_otp-y := lpc18xx_otp.o +-obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o +-nvmem-mxs-ocotp-y := mxs-ocotp.o +-obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o +-nvmem-nintendo-otp-y := nintendo-otp.o ++nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o ++obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o ++nvmem_lpc18xx_otp-y := lpc18xx_otp.o ++obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o ++nvmem_meson_efuse-y := meson-efuse.o ++obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o ++nvmem_meson_mx_efuse-y := meson-mx-efuse.o ++obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o ++nvmem-microchip-otpc-y := microchip-otpc.o + obj-$(CONFIG_NVMEM_MTK_EFUSE) += nvmem_mtk-efuse.o +-nvmem_mtk-efuse-y := mtk-efuse.o +-obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o +-nvmem_qfprom-y := qfprom.o +-obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o +-nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o ++nvmem_mtk-efuse-y := mtk-efuse.o ++obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o ++nvmem-mxs-ocotp-y := mxs-ocotp.o ++obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o ++nvmem-nintendo-otp-y := nintendo-otp.o ++obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o ++nvmem_qfprom-y := qfprom.o ++obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o ++nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o ++obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o ++nvmem-rmem-y := rmem.o + obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o +-nvmem_rockchip_efuse-y := rockchip-efuse.o ++nvmem_rockchip_efuse-y := rockchip-efuse.o + obj-$(CONFIG_NVMEM_ROCKCHIP_OTP) += nvmem-rockchip-otp.o +-nvmem-rockchip-otp-y := rockchip-otp.o +-obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o +-nvmem_stm32_romem-y := stm32-romem.o +-obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o +-nvmem_sunxi_sid-y := sunxi_sid.o +-obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o +-nvmem-uniphier-efuse-y := uniphier-efuse.o +-obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o +-nvmem-vf610-ocotp-y := vf610-ocotp.o +-obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o +-nvmem_meson_efuse-y := meson-efuse.o +-obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o +-nvmem_meson_mx_efuse-y := meson-mx-efuse.o +-obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o +-nvmem_snvs_lpgpr-y := snvs_lpgpr.o +-obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o +-nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o ++nvmem-rockchip-otp-y := rockchip-otp.o + obj-$(CONFIG_NVMEM_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o +-nvmem-sc27xx-efuse-y := sc27xx-efuse.o +-obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o +-nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o +-obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o +-nvmem_sprd_efuse-y := sprd-efuse.o +-obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o +-nvmem-rmem-y := rmem.o +-obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o +-nvmem_brcm_nvram-y := brcm_nvram.o +-obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o +-nvmem-layerscape-sfp-y := layerscape-sfp.o ++nvmem-sc27xx-efuse-y := sc27xx-efuse.o ++obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o ++nvmem_snvs_lpgpr-y := snvs_lpgpr.o ++obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o ++nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o ++obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o ++nvmem_sprd_efuse-y := sprd-efuse.o ++obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o ++nvmem_stm32_romem-y := stm32-romem.o + obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o +-nvmem_sunplus_ocotp-y := sunplus-ocotp.o +-obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o +-nvmem-apple-efuses-y := apple-efuses.o +-obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o +-nvmem-microchip-otpc-y := microchip-otpc.o +-obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o +-nvmem_u-boot-env-y := u-boot-env.o ++nvmem_sunplus_ocotp-y := sunplus-ocotp.o ++obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o ++nvmem_sunxi_sid-y := sunxi_sid.o ++obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o ++nvmem_u-boot-env-y := u-boot-env.o ++obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o ++nvmem-uniphier-efuse-y := uniphier-efuse.o ++obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o ++nvmem-vf610-ocotp-y := vf610-ocotp.o ++obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o ++nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o diff --git a/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch b/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch new file mode 100644 index 00000000000..e0a082adc45 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch @@ -0,0 +1,31 @@ +From d4d432670f7dee0a5432fcffcfc8699b25181ace Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 16 Sep 2022 13:20:57 +0100 +Subject: [PATCH] nvmem: u-boot-env: find Device Tree nodes for NVMEM cells +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DT binding allows specifying NVMEM cells as NVMEM device (provider) +subnodes. Looks for such subnodes when building NVMEM cells. + +This allows NVMEM consumers to use U-Boot environment variables. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-11-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/u-boot-env.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -92,6 +92,7 @@ static int u_boot_env_add_cells(struct u + return -ENOMEM; + priv->cells[idx].offset = data_offset + value - data; + priv->cells[idx].bytes = strlen(value); ++ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); + } + + if (WARN_ON(idx != priv->ncells)) diff --git a/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch b/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch new file mode 100644 index 00000000000..945c6128ff4 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch @@ -0,0 +1,274 @@ +From 9e8f208ad5229ddda97cd4a83ecf89c735d99592 Mon Sep 17 00:00:00 2001 +From: Horatiu Vultur +Date: Fri, 16 Sep 2022 13:20:59 +0100 +Subject: [PATCH] nvmem: lan9662-otp: add support + +Add support for OTP controller available on LAN9662. The OTPC controls +the access to a non-volatile memory. The size of the memory is 8KB. +The OTPC can access the memory based on an offset. +Implement both the read and the write functionality. + +Signed-off-by: Horatiu Vultur +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-13-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 8 ++ + drivers/nvmem/Makefile | 2 + + drivers/nvmem/lan9662-otpc.c | 222 +++++++++++++++++++++++++++++++++++ + 3 files changed, 232 insertions(+) + create mode 100644 drivers/nvmem/lan9662-otpc.c + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -98,6 +98,14 @@ config NVMEM_JZ4780_EFUSE + To compile this driver as a module, choose M here: the module + will be called nvmem_jz4780_efuse. + ++config NVMEM_LAN9662_OTPC ++ tristate "Microchip LAN9662 OTP controller support" ++ depends on SOC_LAN966 || COMPILE_TEST ++ depends on HAS_IOMEM ++ help ++ This driver enables the OTP controller available on Microchip LAN9662 ++ SoCs. It controls the access to the OTP memory connected to it. ++ + config NVMEM_LAYERSCAPE_SFP + tristate "Layerscape SFP (Security Fuse Processor) support" + depends on ARCH_LAYERSCAPE || COMPILE_TEST +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -21,6 +21,8 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvm + nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o + obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o + nvmem_jz4780_efuse-y := jz4780-efuse.o ++obj-$(CONFIG_NVMEM_LAN9662_OTPC) += nvmem-lan9662-otpc.o ++nvmem-lan9662-otpc-y := lan9662-otpc.o + obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o + nvmem-layerscape-sfp-y := layerscape-sfp.o + obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o +--- /dev/null ++++ b/drivers/nvmem/lan9662-otpc.c +@@ -0,0 +1,222 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define OTP_OTP_PWR_DN(t) (t + 0x00) ++#define OTP_OTP_PWR_DN_OTP_PWRDN_N BIT(0) ++#define OTP_OTP_ADDR_HI(t) (t + 0x04) ++#define OTP_OTP_ADDR_LO(t) (t + 0x08) ++#define OTP_OTP_PRGM_DATA(t) (t + 0x10) ++#define OTP_OTP_PRGM_MODE(t) (t + 0x14) ++#define OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE BIT(0) ++#define OTP_OTP_RD_DATA(t) (t + 0x18) ++#define OTP_OTP_FUNC_CMD(t) (t + 0x20) ++#define OTP_OTP_FUNC_CMD_OTP_PROGRAM BIT(1) ++#define OTP_OTP_FUNC_CMD_OTP_READ BIT(0) ++#define OTP_OTP_CMD_GO(t) (t + 0x28) ++#define OTP_OTP_CMD_GO_OTP_GO BIT(0) ++#define OTP_OTP_PASS_FAIL(t) (t + 0x2c) ++#define OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED BIT(3) ++#define OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED BIT(2) ++#define OTP_OTP_PASS_FAIL_OTP_FAIL BIT(0) ++#define OTP_OTP_STATUS(t) (t + 0x30) ++#define OTP_OTP_STATUS_OTP_CPUMPEN BIT(1) ++#define OTP_OTP_STATUS_OTP_BUSY BIT(0) ++ ++#define OTP_MEM_SIZE 8192 ++#define OTP_SLEEP_US 10 ++#define OTP_TIMEOUT_US 500000 ++ ++struct lan9662_otp { ++ struct device *dev; ++ void __iomem *base; ++}; ++ ++static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) ++{ ++ u32 val; ++ ++ return readl_poll_timeout(reg, val, !(val & flag), ++ OTP_SLEEP_US, OTP_TIMEOUT_US); ++} ++ ++static int lan9662_otp_power(struct lan9662_otp *otp, bool up) ++{ ++ void __iomem *pwrdn = OTP_OTP_PWR_DN(otp->base); ++ ++ if (up) { ++ writel(readl(pwrdn) & ~OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn); ++ if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base), ++ OTP_OTP_STATUS_OTP_CPUMPEN)) ++ return -ETIMEDOUT; ++ } else { ++ writel(readl(pwrdn) | OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn); ++ } ++ ++ return 0; ++} ++ ++static int lan9662_otp_execute(struct lan9662_otp *otp) ++{ ++ if (lan9662_otp_wait_flag_clear(OTP_OTP_CMD_GO(otp->base), ++ OTP_OTP_CMD_GO_OTP_GO)) ++ return -ETIMEDOUT; ++ ++ if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base), ++ OTP_OTP_STATUS_OTP_BUSY)) ++ return -ETIMEDOUT; ++ ++ return 0; ++} ++ ++static void lan9662_otp_set_address(struct lan9662_otp *otp, u32 offset) ++{ ++ writel(0xff & (offset >> 8), OTP_OTP_ADDR_HI(otp->base)); ++ writel(0xff & offset, OTP_OTP_ADDR_LO(otp->base)); ++} ++ ++static int lan9662_otp_read_byte(struct lan9662_otp *otp, u32 offset, u8 *dst) ++{ ++ u32 pass; ++ int rc; ++ ++ lan9662_otp_set_address(otp, offset); ++ writel(OTP_OTP_FUNC_CMD_OTP_READ, OTP_OTP_FUNC_CMD(otp->base)); ++ writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base)); ++ rc = lan9662_otp_execute(otp); ++ if (!rc) { ++ pass = readl(OTP_OTP_PASS_FAIL(otp->base)); ++ if (pass & OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED) ++ return -EACCES; ++ *dst = (u8) readl(OTP_OTP_RD_DATA(otp->base)); ++ } ++ return rc; ++} ++ ++static int lan9662_otp_write_byte(struct lan9662_otp *otp, u32 offset, u8 data) ++{ ++ u32 pass; ++ int rc; ++ ++ lan9662_otp_set_address(otp, offset); ++ writel(OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE, OTP_OTP_PRGM_MODE(otp->base)); ++ writel(data, OTP_OTP_PRGM_DATA(otp->base)); ++ writel(OTP_OTP_FUNC_CMD_OTP_PROGRAM, OTP_OTP_FUNC_CMD(otp->base)); ++ writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base)); ++ ++ rc = lan9662_otp_execute(otp); ++ if (!rc) { ++ pass = readl(OTP_OTP_PASS_FAIL(otp->base)); ++ if (pass & OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED) ++ return -EACCES; ++ if (pass & OTP_OTP_PASS_FAIL_OTP_FAIL) ++ return -EIO; ++ } ++ return rc; ++} ++ ++static int lan9662_otp_read(void *context, unsigned int offset, ++ void *_val, size_t bytes) ++{ ++ struct lan9662_otp *otp = context; ++ u8 *val = _val; ++ uint8_t data; ++ int i, rc = 0; ++ ++ lan9662_otp_power(otp, true); ++ for (i = 0; i < bytes; i++) { ++ rc = lan9662_otp_read_byte(otp, offset + i, &data); ++ if (rc < 0) ++ break; ++ *val++ = data; ++ } ++ lan9662_otp_power(otp, false); ++ ++ return rc; ++} ++ ++static int lan9662_otp_write(void *context, unsigned int offset, ++ void *_val, size_t bytes) ++{ ++ struct lan9662_otp *otp = context; ++ u8 *val = _val; ++ u8 data, newdata; ++ int i, rc = 0; ++ ++ lan9662_otp_power(otp, true); ++ for (i = 0; i < bytes; i++) { ++ /* Skip zero bytes */ ++ if (val[i]) { ++ rc = lan9662_otp_read_byte(otp, offset + i, &data); ++ if (rc < 0) ++ break; ++ ++ newdata = data | val[i]; ++ if (newdata == data) ++ continue; ++ ++ rc = lan9662_otp_write_byte(otp, offset + i, ++ newdata); ++ if (rc < 0) ++ break; ++ } ++ } ++ lan9662_otp_power(otp, false); ++ ++ return rc; ++} ++ ++static struct nvmem_config otp_config = { ++ .name = "lan9662-otp", ++ .stride = 1, ++ .word_size = 1, ++ .reg_read = lan9662_otp_read, ++ .reg_write = lan9662_otp_write, ++ .size = OTP_MEM_SIZE, ++}; ++ ++static int lan9662_otp_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct nvmem_device *nvmem; ++ struct lan9662_otp *otp; ++ ++ otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL); ++ if (!otp) ++ return -ENOMEM; ++ ++ otp->dev = dev; ++ otp->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(otp->base)) ++ return PTR_ERR(otp->base); ++ ++ otp_config.priv = otp; ++ otp_config.dev = dev; ++ ++ nvmem = devm_nvmem_register(dev, &otp_config); ++ ++ return PTR_ERR_OR_ZERO(nvmem); ++} ++ ++static const struct of_device_id lan9662_otp_match[] = { ++ { .compatible = "microchip,lan9662-otp", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, lan9662_otp_match); ++ ++static struct platform_driver lan9662_otp_driver = { ++ .probe = lan9662_otp_probe, ++ .driver = { ++ .name = "lan9662-otp", ++ .of_match_table = lan9662_otp_match, ++ }, ++}; ++module_platform_driver(lan9662_otp_driver); ++ ++MODULE_AUTHOR("Horatiu Vultur "); ++MODULE_DESCRIPTION("lan9662 OTP driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch b/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch new file mode 100644 index 00000000000..633a668a962 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch @@ -0,0 +1,32 @@ +From 3717ca3e0cc8683f93b41d3f06ca79631eb58715 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 16 Sep 2022 13:21:00 +0100 +Subject: [PATCH] nvmem: u-boot-env: fix crc32 casting type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes: +drivers/nvmem/u-boot-env.c:141:17: sparse: sparse: cast to restricted __le32 + +Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables") +Reported-by: kernel test robot +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20220916122100.170016-14-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/u-boot-env.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -139,7 +139,7 @@ static int u_boot_env_parse(struct u_boo + data_offset = offsetof(struct u_boot_env_image_redundant, data); + break; + } +- crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset)); ++ crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset)); + crc32_data_len = priv->mtd->size - crc32_data_offset; + data_len = priv->mtd->size - data_offset; + diff --git a/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch b/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch new file mode 100644 index 00000000000..b663a1328df --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch @@ -0,0 +1,34 @@ +From 1aeb122d214b92474c86fde00a03d6e2d69381b5 Mon Sep 17 00:00:00 2001 +From: Horatiu Vultur +Date: Wed, 28 Sep 2022 21:51:12 +0200 +Subject: [PATCH] nvmem: lan9662-otp: Fix compatible string + +The device tree bindings for lan9662-otp expects the compatible string +to be one of following compatible strings: +microchip,lan9662-otpc +microchip,lan9668-otpc + +The problem is that the lan9662-otp driver contains the +microchip,lan9662-otp compatible string instead of +microchip,lan9662-otpc. +Fix this by updating the compatible string in the driver. + +Fixes: 9e8f208ad5229d ("nvmem: lan9662-otp: add support") +Signed-off-by: Horatiu Vultur +Link: https://lore.kernel.org/r/20220928195112.630351-1-horatiu.vultur@microchip.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/lan9662-otpc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/lan9662-otpc.c ++++ b/drivers/nvmem/lan9662-otpc.c +@@ -203,7 +203,7 @@ static int lan9662_otp_probe(struct plat + } + + static const struct of_device_id lan9662_otp_match[] = { +- { .compatible = "microchip,lan9662-otp", }, ++ { .compatible = "microchip,lan9662-otpc", }, + { }, + }; + MODULE_DEVICE_TABLE(of, lan9662_otp_match); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch b/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch new file mode 100644 index 00000000000..967e891dbd9 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch @@ -0,0 +1,59 @@ +From ee424f7d3960152f5f862bbb6943e59828dc7917 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Fri, 4 Nov 2022 17:52:03 +0100 +Subject: [PATCH] nvmem: u-boot-env: fix crc32_data_offset on redundant + u-boot-env + +The Western Digital MyBook Live (PowerPC 464/APM82181) +has a set of redundant u-boot-env. Loading up the driver +the following error: + +| u_boot_env: Invalid calculated CRC32: 0x4f8f2c86 (expected: 0x98b14514) +| u_boot_env: probe of partition@1e000 failed with error -22 + +Looking up the userspace libubootenv utilities source [0], +it looks like the "mark" or "flag" is not part of the +crc32 sum... which is unfortunate :( + +|static int libuboot_load(struct uboot_ctx *ctx) +|{ +|[...] +| if (ctx->redundant) { +| [...] +| offsetdata = offsetof(struct uboot_env_redund, data); +| [...] //-----^^ +| } +| usable_envsize = ctx->size - offsetdata; +| buf[0] = malloc(bufsize); +|[...] +| for (i = 0; i < copies; i++) { +| data = (uint8_t *)(buf[i] + offsetdata); +| uint32_t crc; +| +| ret = devread(ctx, i, buf[i]); +| [...] +| crc = *(uint32_t *)(buf[i] + offsetcrc); +| dev->crc = crc32(0, (uint8_t *)data, usable_envsize); +| + +[0] https://github.com/sbabic/libubootenv/blob/master/src/uboot_env.c#L951 + +Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables") +Signed-off-by: Christian Lamparter +Link: https://lore.kernel.org/r/70a16eae113e08db2390b76e174f4837caa135c3.1667580636.git.chunkeey@gmail.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/u-boot-env.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -135,7 +135,7 @@ static int u_boot_env_parse(struct u_boo + break; + case U_BOOT_FORMAT_REDUNDANT: + crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32); +- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark); ++ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data); + data_offset = offsetof(struct u_boot_env_image_redundant, data); + break; + } diff --git a/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch b/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch new file mode 100644 index 00000000000..0c842f07932 --- /dev/null +++ b/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch @@ -0,0 +1,35 @@ +From 022b68f271de0e53024e6d5e96fee8e76d25eb95 Mon Sep 17 00:00:00 2001 +From: Horatiu Vultur +Date: Fri, 18 Nov 2022 06:38:40 +0000 +Subject: [PATCH] nvmem: lan9662-otp: Change return type of + lan9662_otp_wait_flag_clear() + +The blamed commit introduced the following smatch warning in the +function lan9662_otp_wait_flag_clear: +drivers/nvmem/lan9662-otpc.c:43 lan9662_otp_wait_flag_clear() warn: signedness bug returning '(-110)' + +Fix this by changing the return type of the function +lan9662_otp_wait_flag_clear() to be int instead of bool. + +Fixes: 9e8f208ad5229d ("nvmem: lan9662-otp: add support") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Signed-off-by: Horatiu Vultur +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063840.6357-5-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/lan9662-otpc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/lan9662-otpc.c ++++ b/drivers/nvmem/lan9662-otpc.c +@@ -36,7 +36,7 @@ struct lan9662_otp { + void __iomem *base; + }; + +-static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) ++static int lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) + { + u32 val; + diff --git a/target/linux/generic/backport-6.1/808-v6.2-0001-nvmem-stm32-move-STM32MP15_BSEC_NUM_LOWER-in-config.patch b/target/linux/generic/backport-6.1/808-v6.2-0001-nvmem-stm32-move-STM32MP15_BSEC_NUM_LOWER-in-config.patch new file mode 100644 index 00000000000..33759632ebe --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0001-nvmem-stm32-move-STM32MP15_BSEC_NUM_LOWER-in-config.patch @@ -0,0 +1,82 @@ +From fbfc4ca465a1f8d81bf2d67d95bf7fc67c3cf0c2 Mon Sep 17 00:00:00 2001 +From: Patrick Delaunay +Date: Fri, 18 Nov 2022 06:39:20 +0000 +Subject: [PATCH] nvmem: stm32: move STM32MP15_BSEC_NUM_LOWER in config + +Support STM32MP15_BSEC_NUM_LOWER in stm32 romem config to prepare +the next SoC in STM32MP family. + +Signed-off-by: Patrick Delaunay +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 21 ++++++++++++++++----- + 1 file changed, 16 insertions(+), 5 deletions(-) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -22,16 +22,15 @@ + /* shadow registers offest */ + #define STM32MP15_BSEC_DATA0 0x200 + +-/* 32 (x 32-bits) lower shadow registers */ +-#define STM32MP15_BSEC_NUM_LOWER 32 +- + struct stm32_romem_cfg { + int size; ++ u8 lower; + }; + + struct stm32_romem_priv { + void __iomem *base; + struct nvmem_config cfg; ++ u8 lower; + }; + + static int stm32_romem_read(void *context, unsigned int offset, void *buf, +@@ -85,7 +84,7 @@ static int stm32_bsec_read(void *context + for (i = roffset; (i < roffset + rbytes); i += 4) { + u32 otp = i >> 2; + +- if (otp < STM32MP15_BSEC_NUM_LOWER) { ++ if (otp < priv->lower) { + /* read lower data from shadow registers */ + val = readl_relaxed( + priv->base + STM32MP15_BSEC_DATA0 + i); +@@ -159,6 +158,8 @@ static int stm32_romem_probe(struct plat + priv->cfg.priv = priv; + priv->cfg.owner = THIS_MODULE; + ++ priv->lower = 0; ++ + cfg = (const struct stm32_romem_cfg *) + of_match_device(dev->driver->of_match_table, dev)->data; + if (!cfg) { +@@ -167,6 +168,7 @@ static int stm32_romem_probe(struct plat + priv->cfg.reg_read = stm32_romem_read; + } else { + priv->cfg.size = cfg->size; ++ priv->lower = cfg->lower; + priv->cfg.reg_read = stm32_bsec_read; + priv->cfg.reg_write = stm32_bsec_write; + } +@@ -174,8 +176,17 @@ static int stm32_romem_probe(struct plat + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); + } + ++/* ++ * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits) ++ * => 96 x 32-bits data words ++ * - Lower: 1K bits, 2:1 redundancy, incremental bit programming ++ * => 32 (x 32-bits) lower shadow registers = words 0 to 31 ++ * - Upper: 2K bits, ECC protection, word programming only ++ * => 64 (x 32-bits) = words 32 to 95 ++ */ + static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { +- .size = 384, /* 96 x 32-bits data words */ ++ .size = 384, ++ .lower = 32, + }; + + static const struct of_device_id stm32_romem_of_match[] = { diff --git a/target/linux/generic/backport-6.1/808-v6.2-0002-nvmem-stm32-add-warning-when-upper-OTPs-are-updated.patch b/target/linux/generic/backport-6.1/808-v6.2-0002-nvmem-stm32-add-warning-when-upper-OTPs-are-updated.patch new file mode 100644 index 00000000000..5791df2606f --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0002-nvmem-stm32-add-warning-when-upper-OTPs-are-updated.patch @@ -0,0 +1,34 @@ +From d61784e6410f3df2028e6eb91b06ffed37a660e0 Mon Sep 17 00:00:00 2001 +From: Patrick Delaunay +Date: Fri, 18 Nov 2022 06:39:21 +0000 +Subject: [PATCH] nvmem: stm32: add warning when upper OTPs are updated + +As the upper OTPs are ECC protected, they support only one 32 bits word +programming. +For a second modification of this word, these ECC become invalid and +this OTP will be no more accessible, the shadowed value is invalid. + +This patch adds a warning to indicate an upper OTP update, because this +operation is dangerous as OTP is not locked by the driver after the first +update to avoid a second update. + +Signed-off-by: Patrick Delaunay +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -132,6 +132,9 @@ static int stm32_bsec_write(void *contex + } + } + ++ if (offset + bytes >= priv->lower * 4) ++ dev_warn(dev, "Update of upper OTPs with ECC protection (word programming, only once)\n"); ++ + return 0; + } + diff --git a/target/linux/generic/backport-6.1/808-v6.2-0003-nvmem-stm32-add-nvmem-type-attribute.patch b/target/linux/generic/backport-6.1/808-v6.2-0003-nvmem-stm32-add-nvmem-type-attribute.patch new file mode 100644 index 00000000000..b83ad69c6b4 --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0003-nvmem-stm32-add-nvmem-type-attribute.patch @@ -0,0 +1,26 @@ +From a3816a7d7c097c1da46aad5f5d1e229b607dce04 Mon Sep 17 00:00:00 2001 +From: Patrick Delaunay +Date: Fri, 18 Nov 2022 06:39:22 +0000 +Subject: [PATCH] nvmem: stm32: add nvmem type attribute + +Inform NVMEM framework of type attribute for stm32-romem as NVMEM_TYPE_OTP +so userspace is able to know how the data is stored in BSEC. + +Signed-off-by: Patrick Delaunay +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-4-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -160,6 +160,7 @@ static int stm32_romem_probe(struct plat + priv->cfg.dev = dev; + priv->cfg.priv = priv; + priv->cfg.owner = THIS_MODULE; ++ priv->cfg.type = NVMEM_TYPE_OTP; + + priv->lower = 0; + diff --git a/target/linux/generic/backport-6.1/808-v6.2-0004-nvmem-stm32-fix-spelling-typo-in-comment.patch b/target/linux/generic/backport-6.1/808-v6.2-0004-nvmem-stm32-fix-spelling-typo-in-comment.patch new file mode 100644 index 00000000000..52ba1e65b56 --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0004-nvmem-stm32-fix-spelling-typo-in-comment.patch @@ -0,0 +1,27 @@ +From 06aac0e11960a7ddccc1888326b5906d017e0f24 Mon Sep 17 00:00:00 2001 +From: Jiangshan Yi +Date: Fri, 18 Nov 2022 06:39:24 +0000 +Subject: [PATCH] nvmem: stm32: fix spelling typo in comment + +Fix spelling typo in comment. + +Reported-by: k2ci +Signed-off-by: Jiangshan Yi +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-6-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -19,7 +19,7 @@ + #define STM32_SMC_WRITE_SHADOW 0x03 + #define STM32_SMC_READ_OTP 0x04 + +-/* shadow registers offest */ ++/* shadow registers offset */ + #define STM32MP15_BSEC_DATA0 0x200 + + struct stm32_romem_cfg { diff --git a/target/linux/generic/backport-6.1/808-v6.2-0005-nvmem-Kconfig-Fix-spelling-mistake-controlls-control.patch b/target/linux/generic/backport-6.1/808-v6.2-0005-nvmem-Kconfig-Fix-spelling-mistake-controlls-control.patch new file mode 100644 index 00000000000..8f024f4c1ac --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0005-nvmem-Kconfig-Fix-spelling-mistake-controlls-control.patch @@ -0,0 +1,27 @@ +From fb817c4ef63e8cfb6e77ae4a2875ae854c80708f Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Fri, 18 Nov 2022 06:39:26 +0000 +Subject: [PATCH] nvmem: Kconfig: Fix spelling mistake "controlls" -> + "controls" + +There is a spelling mistake in a Kconfig description. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -164,7 +164,7 @@ config NVMEM_MICROCHIP_OTPC + depends on ARCH_AT91 || COMPILE_TEST + help + This driver enable the OTP controller available on Microchip SAMA7G5 +- SoCs. It controlls the access to the OTP memory connected to it. ++ SoCs. It controls the access to the OTP memory connected to it. + + config NVMEM_MTK_EFUSE + tristate "Mediatek SoCs EFUSE support" diff --git a/target/linux/generic/backport-6.1/808-v6.2-0006-nvmem-u-boot-env-add-Broadcom-format-support.patch b/target/linux/generic/backport-6.1/808-v6.2-0006-nvmem-u-boot-env-add-Broadcom-format-support.patch new file mode 100644 index 00000000000..861386ad310 --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0006-nvmem-u-boot-env-add-Broadcom-format-support.patch @@ -0,0 +1,67 @@ +From ada84d07af6097b2addd18262668ce6cb9e15206 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Fri, 18 Nov 2022 06:39:27 +0000 +Subject: [PATCH] nvmem: u-boot-env: add Broadcom format support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Broadcom uses U-Boot for a lot of their bcmbca familiy chipsets. They +decided to store U-Boot environment data inside U-Boot partition and to +use a custom header (with "uEnv" magic and env data length). + +Add support for Broadcom's specific binding and their custom format. + +Ref: 6b0584c19d87 ("dt-bindings: nvmem: u-boot,env: add Broadcom's variant binding") +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20221118063932.6418-9-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/u-boot-env.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -16,6 +16,7 @@ + enum u_boot_env_format { + U_BOOT_FORMAT_SINGLE, + U_BOOT_FORMAT_REDUNDANT, ++ U_BOOT_FORMAT_BROADCOM, + }; + + struct u_boot_env { +@@ -40,6 +41,13 @@ struct u_boot_env_image_redundant { + uint8_t data[]; + } __packed; + ++struct u_boot_env_image_broadcom { ++ __le32 magic; ++ __le32 len; ++ __le32 crc32; ++ uint8_t data[0]; ++} __packed; ++ + static int u_boot_env_read(void *context, unsigned int offset, void *val, + size_t bytes) + { +@@ -138,6 +146,11 @@ static int u_boot_env_parse(struct u_boo + crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data); + data_offset = offsetof(struct u_boot_env_image_redundant, data); + break; ++ case U_BOOT_FORMAT_BROADCOM: ++ crc32_offset = offsetof(struct u_boot_env_image_broadcom, crc32); ++ crc32_data_offset = offsetof(struct u_boot_env_image_broadcom, data); ++ data_offset = offsetof(struct u_boot_env_image_broadcom, data); ++ break; + } + crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset)); + crc32_data_len = priv->mtd->size - crc32_data_offset; +@@ -202,6 +215,7 @@ static const struct of_device_id u_boot_ + { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, }, + { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, + { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, ++ { .compatible = "brcm,env", .data = (void *)U_BOOT_FORMAT_BROADCOM, }, + {}, + }; + diff --git a/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch b/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch new file mode 100644 index 00000000000..14108b59276 --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch @@ -0,0 +1,30 @@ +From b0576ade3aaf24b376ea1a4406ae138e2a22b0c0 Mon Sep 17 00:00:00 2001 +From: Jiasheng Jiang +Date: Fri, 27 Jan 2023 10:40:06 +0000 +Subject: [PATCH] nvmem: brcm_nvram: Add check for kzalloc + +Add the check for the return value of kzalloc in order to avoid +NULL pointer dereference. + +Fixes: 6e977eaa8280 ("nvmem: brcm_nvram: parse NVRAM content into NVMEM cells") +Cc: stable@vger.kernel.org +Signed-off-by: Jiasheng Jiang +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230127104015.23839-2-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/brcm_nvram.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -97,6 +97,9 @@ static int brcm_nvram_parse(struct brcm_ + len = le32_to_cpu(header.len); + + data = kzalloc(len, GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ + memcpy_fromio(data, priv->base, len); + data[len - 1] = '\0'; + diff --git a/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch b/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch new file mode 100644 index 00000000000..632b01cb2ac --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch @@ -0,0 +1,55 @@ +From c151d5ed8e8fe0474bd61dce7f2076ca5916c683 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Fri, 27 Jan 2023 10:40:07 +0000 +Subject: [PATCH] nvmem: sunxi_sid: Always use 32-bit MMIO reads + +The SID SRAM on at least some SoCs (A64 and D1) returns different values +when read with bus cycles narrower than 32 bits. This is not immediately +obvious, because memcpy_fromio() uses word-size accesses as long as +enough data is being copied. + +The vendor driver always uses 32-bit MMIO reads, so do the same here. +This is faster than the register-based method, which is currently used +as a workaround on A64. And it fixes the values returned on D1, where +the SRAM method was being used. + +The special case for the last word is needed to maintain .word_size == 1 +for sysfs ABI compatibility, as noted previously in commit de2a3eaea552 +("nvmem: sunxi_sid: Optimize register read-out method"). + +Fixes: 07ae4fde9efa ("nvmem: sunxi_sid: Add support for D1 variant") +Cc: stable@vger.kernel.org +Tested-by: Heiko Stuebner +Signed-off-by: Samuel Holland +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230127104015.23839-3-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/sunxi_sid.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/nvmem/sunxi_sid.c ++++ b/drivers/nvmem/sunxi_sid.c +@@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context, + void *val, size_t bytes) + { + struct sunxi_sid *sid = context; ++ u32 word; + +- memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes); ++ /* .stride = 4 so offset is guaranteed to be aligned */ ++ __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4); ++ ++ val += round_down(bytes, 4); ++ offset += round_down(bytes, 4); ++ bytes = bytes % 4; ++ ++ if (!bytes) ++ return 0; ++ ++ /* Handle any trailing bytes */ ++ word = readl_relaxed(sid->base + sid->value_offset + offset); ++ memcpy(val, &word, bytes); + + return 0; + } diff --git a/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch b/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch new file mode 100644 index 00000000000..a229c303ad0 --- /dev/null +++ b/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch @@ -0,0 +1,48 @@ +From edcf2fb660526b5ed29f93bd17328a2b4835c8b2 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Fri, 27 Jan 2023 10:40:12 +0000 +Subject: [PATCH] nvmem: core: fix device node refcounting + +In of_nvmem_cell_get(), of_get_next_parent() is used on cell_np. This +will decrement the refcount on cell_np, but cell_np is still used later +in the code. Use of_get_parent() instead and of_node_put() in the +appropriate places. + +Fixes: 69aba7948cbe ("nvmem: Add a simple NVMEM framework for consumers") +Fixes: 7ae6478b304b ("nvmem: core: rework nvmem cell instance creation") +Cc: stable@vger.kernel.org +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230127104015.23839-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -1237,16 +1237,21 @@ struct nvmem_cell *of_nvmem_cell_get(str + if (!cell_np) + return ERR_PTR(-ENOENT); + +- nvmem_np = of_get_next_parent(cell_np); +- if (!nvmem_np) ++ nvmem_np = of_get_parent(cell_np); ++ if (!nvmem_np) { ++ of_node_put(cell_np); + return ERR_PTR(-EINVAL); ++ } + + nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); + of_node_put(nvmem_np); +- if (IS_ERR(nvmem)) ++ if (IS_ERR(nvmem)) { ++ of_node_put(cell_np); + return ERR_CAST(nvmem); ++ } + + cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); ++ of_node_put(cell_np); + if (!cell_entry) { + __nvmem_device_put(nvmem); + return ERR_PTR(-ENOENT); diff --git a/target/linux/generic/backport-6.1/809-v6.3-0001-nvmem-core-remove-spurious-white-space.patch b/target/linux/generic/backport-6.1/809-v6.3-0001-nvmem-core-remove-spurious-white-space.patch new file mode 100644 index 00000000000..01400fd490d --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0001-nvmem-core-remove-spurious-white-space.patch @@ -0,0 +1,26 @@ +From 2e8dc541ae207349b51c65391be625ffe1f86e0c Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Mon, 6 Feb 2023 13:43:41 +0000 +Subject: [PATCH] nvmem: core: remove spurious white space + +Remove a spurious white space in for the ida_alloc() call. + +Signed-off-by: Russell King (Oracle) +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -764,7 +764,7 @@ struct nvmem_device *nvmem_register(cons + if (!nvmem) + return ERR_PTR(-ENOMEM); + +- rval = ida_alloc(&nvmem_ida, GFP_KERNEL); ++ rval = ida_alloc(&nvmem_ida, GFP_KERNEL); + if (rval < 0) { + kfree(nvmem); + return ERR_PTR(rval); diff --git a/target/linux/generic/backport-6.1/809-v6.3-0002-nvmem-core-add-an-index-parameter-to-the-cell.patch b/target/linux/generic/backport-6.1/809-v6.3-0002-nvmem-core-add-an-index-parameter-to-the-cell.patch new file mode 100644 index 00000000000..454d3bf0ed1 --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0002-nvmem-core-add-an-index-parameter-to-the-cell.patch @@ -0,0 +1,180 @@ +From 5d8e6e6c10a3d37486d263b16ddc15991a7e4a88 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:46 +0000 +Subject: [PATCH] nvmem: core: add an index parameter to the cell + +Sometimes a cell can represend multiple values. For example, a base +ethernet address stored in the NVMEM can be expanded into multiple +discreet ones by adding an offset. + +For this use case, introduce an index parameter which is then used to +distiguish between values. This parameter will then be passed to the +post process hook which can then use it to create different values +during reading. + +At the moment, there is only support for the device tree path. You can +add the index to the phandle, e.g. + + &net { + nvmem-cells = <&base_mac_address 2>; + nvmem-cell-names = "mac-address"; + }; + + &nvmem_provider { + base_mac_address: base-mac-address@0 { + #nvmem-cell-cells = <1>; + reg = <0 6>; + }; + }; + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-13-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 37 ++++++++++++++++++++++++---------- + drivers/nvmem/imx-ocotp.c | 4 ++-- + include/linux/nvmem-provider.h | 4 ++-- + 3 files changed, 30 insertions(+), 15 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -60,6 +60,7 @@ struct nvmem_cell_entry { + struct nvmem_cell { + struct nvmem_cell_entry *entry; + const char *id; ++ int index; + }; + + static DEFINE_MUTEX(nvmem_mutex); +@@ -1122,7 +1123,8 @@ struct nvmem_device *devm_nvmem_device_g + } + EXPORT_SYMBOL_GPL(devm_nvmem_device_get); + +-static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id) ++static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, ++ const char *id, int index) + { + struct nvmem_cell *cell; + const char *name = NULL; +@@ -1141,6 +1143,7 @@ static struct nvmem_cell *nvmem_create_c + + cell->id = name; + cell->entry = entry; ++ cell->index = index; + + return cell; + } +@@ -1179,7 +1182,7 @@ nvmem_cell_get_from_lookup(struct device + __nvmem_device_put(nvmem); + cell = ERR_PTR(-ENOENT); + } else { +- cell = nvmem_create_cell(cell_entry, con_id); ++ cell = nvmem_create_cell(cell_entry, con_id, 0); + if (IS_ERR(cell)) + __nvmem_device_put(nvmem); + } +@@ -1227,15 +1230,27 @@ struct nvmem_cell *of_nvmem_cell_get(str + struct nvmem_device *nvmem; + struct nvmem_cell_entry *cell_entry; + struct nvmem_cell *cell; ++ struct of_phandle_args cell_spec; + int index = 0; ++ int cell_index = 0; ++ int ret; + + /* if cell name exists, find index to the name */ + if (id) + index = of_property_match_string(np, "nvmem-cell-names", id); + +- cell_np = of_parse_phandle(np, "nvmem-cells", index); +- if (!cell_np) +- return ERR_PTR(-ENOENT); ++ ret = of_parse_phandle_with_optional_args(np, "nvmem-cells", ++ "#nvmem-cell-cells", ++ index, &cell_spec); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ if (cell_spec.args_count > 1) ++ return ERR_PTR(-EINVAL); ++ ++ cell_np = cell_spec.np; ++ if (cell_spec.args_count) ++ cell_index = cell_spec.args[0]; + + nvmem_np = of_get_parent(cell_np); + if (!nvmem_np) { +@@ -1257,7 +1272,7 @@ struct nvmem_cell *of_nvmem_cell_get(str + return ERR_PTR(-ENOENT); + } + +- cell = nvmem_create_cell(cell_entry, id); ++ cell = nvmem_create_cell(cell_entry, id, cell_index); + if (IS_ERR(cell)) + __nvmem_device_put(nvmem); + +@@ -1410,8 +1425,8 @@ static void nvmem_shift_read_buffer_in_p + } + + static int __nvmem_cell_read(struct nvmem_device *nvmem, +- struct nvmem_cell_entry *cell, +- void *buf, size_t *len, const char *id) ++ struct nvmem_cell_entry *cell, ++ void *buf, size_t *len, const char *id, int index) + { + int rc; + +@@ -1425,7 +1440,7 @@ static int __nvmem_cell_read(struct nvme + nvmem_shift_read_buffer_in_place(cell, buf); + + if (nvmem->cell_post_process) { +- rc = nvmem->cell_post_process(nvmem->priv, id, ++ rc = nvmem->cell_post_process(nvmem->priv, id, index, + cell->offset, buf, cell->bytes); + if (rc) + return rc; +@@ -1460,7 +1475,7 @@ void *nvmem_cell_read(struct nvmem_cell + if (!buf) + return ERR_PTR(-ENOMEM); + +- rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id); ++ rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id, cell->index); + if (rc) { + kfree(buf); + return ERR_PTR(rc); +@@ -1773,7 +1788,7 @@ ssize_t nvmem_device_cell_read(struct nv + if (rc) + return rc; + +- rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL); ++ rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL, 0); + if (rc) + return rc; + +--- a/drivers/nvmem/imx-ocotp.c ++++ b/drivers/nvmem/imx-ocotp.c +@@ -222,8 +222,8 @@ read_end: + return ret; + } + +-static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset, +- void *data, size_t bytes) ++static int imx_ocotp_cell_pp(void *context, const char *id, int index, ++ unsigned int offset, void *data, size_t bytes) + { + struct ocotp_priv *priv = context; + +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -20,8 +20,8 @@ typedef int (*nvmem_reg_read_t)(void *pr + typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset, + void *val, size_t bytes); + /* used for vendor specific post processing of cell data */ +-typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, unsigned int offset, +- void *buf, size_t bytes); ++typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int index, ++ unsigned int offset, void *buf, size_t bytes); + + enum nvmem_type { + NVMEM_TYPE_UNKNOWN = 0, diff --git a/target/linux/generic/backport-6.1/809-v6.3-0003-nvmem-core-move-struct-nvmem_cell_info-to-nvmem-prov.patch b/target/linux/generic/backport-6.1/809-v6.3-0003-nvmem-core-move-struct-nvmem_cell_info-to-nvmem-prov.patch new file mode 100644 index 00000000000..f3829b3e17f --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0003-nvmem-core-move-struct-nvmem_cell_info-to-nvmem-prov.patch @@ -0,0 +1,78 @@ +From fbd03d27776c6121a483921601418e3c8f0ff37e Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:47 +0000 +Subject: [PATCH] nvmem: core: move struct nvmem_cell_info to nvmem-provider.h + +struct nvmem_cell_info is used to describe a cell. Thus this should +really be in the nvmem-provider's header. There are two (unused) nvmem +access methods which use the nvmem_cell_info to describe the cell to be +accesses. One can argue, that they will create a cell before accessing, +thus they are both a provider and a consumer. + +struct nvmem_cell_info will get used more and more by nvmem-providers, +don't force them to also include the consumer header, although they are +not. + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-14-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/nvmem-consumer.h | 10 +--------- + include/linux/nvmem-provider.h | 19 ++++++++++++++++++- + 2 files changed, 19 insertions(+), 10 deletions(-) + +--- a/include/linux/nvmem-consumer.h ++++ b/include/linux/nvmem-consumer.h +@@ -18,15 +18,7 @@ struct device_node; + /* consumer cookie */ + struct nvmem_cell; + struct nvmem_device; +- +-struct nvmem_cell_info { +- const char *name; +- unsigned int offset; +- unsigned int bytes; +- unsigned int bit_offset; +- unsigned int nbits; +- struct device_node *np; +-}; ++struct nvmem_cell_info; + + /** + * struct nvmem_cell_lookup - cell lookup entry +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -14,7 +14,6 @@ + #include + + struct nvmem_device; +-struct nvmem_cell_info; + typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset, + void *val, size_t bytes); + typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset, +@@ -48,6 +47,24 @@ struct nvmem_keepout { + }; + + /** ++ * struct nvmem_cell_info - NVMEM cell description ++ * @name: Name. ++ * @offset: Offset within the NVMEM device. ++ * @bytes: Length of the cell. ++ * @bit_offset: Bit offset if cell is smaller than a byte. ++ * @nbits: Number of bits. ++ * @np: Optional device_node pointer. ++ */ ++struct nvmem_cell_info { ++ const char *name; ++ unsigned int offset; ++ unsigned int bytes; ++ unsigned int bit_offset; ++ unsigned int nbits; ++ struct device_node *np; ++}; ++ ++/** + * struct nvmem_config - NVMEM device configuration + * + * @dev: Parent device. diff --git a/target/linux/generic/backport-6.1/809-v6.3-0004-nvmem-core-drop-the-removal-of-the-cells-in-nvmem_ad.patch b/target/linux/generic/backport-6.1/809-v6.3-0004-nvmem-core-drop-the-removal-of-the-cells-in-nvmem_ad.patch new file mode 100644 index 00000000000..8f996eab348 --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0004-nvmem-core-drop-the-removal-of-the-cells-in-nvmem_ad.patch @@ -0,0 +1,65 @@ +From cc5bdd323dde6494623f3ffe3a5b887fa21cd375 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:48 +0000 +Subject: [PATCH] nvmem: core: drop the removal of the cells in + nvmem_add_cells() + +If nvmem_add_cells() fails, the whole nvmem_register() will fail +and the cells will then be removed anyway. This is a preparation +to introduce a nvmem_add_one_cell() which can then be used by +nvmem_add_cells(). + +This is then the same to what nvmem_add_cells_from_table() and +nvmem_add_cells_from_of() do. + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-15-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 14 ++++---------- + 1 file changed, 4 insertions(+), 10 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -515,7 +515,7 @@ static int nvmem_add_cells(struct nvmem_ + int ncells) + { + struct nvmem_cell_entry **cells; +- int i, rval; ++ int i, rval = 0; + + cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); + if (!cells) +@@ -525,28 +525,22 @@ static int nvmem_add_cells(struct nvmem_ + cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); + if (!cells[i]) { + rval = -ENOMEM; +- goto err; ++ goto out; + } + + rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]); + if (rval) { + kfree(cells[i]); +- goto err; ++ goto out; + } + + nvmem_cell_entry_add(cells[i]); + } + ++out: + /* remove tmp array */ + kfree(cells); + +- return 0; +-err: +- while (i--) +- nvmem_cell_entry_drop(cells[i]); +- +- kfree(cells); +- + return rval; + } + diff --git a/target/linux/generic/backport-6.1/809-v6.3-0005-nvmem-core-add-nvmem_add_one_cell.patch b/target/linux/generic/backport-6.1/809-v6.3-0005-nvmem-core-add-nvmem_add_one_cell.patch new file mode 100644 index 00000000000..711ce229b2c --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0005-nvmem-core-add-nvmem_add_one_cell.patch @@ -0,0 +1,122 @@ +From 2ded6830d376d5e7bf43d59f7f7fdf1a59abc676 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:49 +0000 +Subject: [PATCH] nvmem: core: add nvmem_add_one_cell() + +Add a new function to add exactly one cell. This will be used by the +nvmem layout drivers to add custom cells. In contrast to the +nvmem_add_cells(), this has the advantage that we don't have to assemble +a list of cells on runtime. + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-16-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 59 ++++++++++++++++++++-------------- + include/linux/nvmem-provider.h | 8 +++++ + 2 files changed, 43 insertions(+), 24 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -502,6 +502,36 @@ static int nvmem_cell_info_to_nvmem_cell + } + + /** ++ * nvmem_add_one_cell() - Add one cell information to an nvmem device ++ * ++ * @nvmem: nvmem device to add cells to. ++ * @info: nvmem cell info to add to the device ++ * ++ * Return: 0 or negative error code on failure. ++ */ ++int nvmem_add_one_cell(struct nvmem_device *nvmem, ++ const struct nvmem_cell_info *info) ++{ ++ struct nvmem_cell_entry *cell; ++ int rval; ++ ++ cell = kzalloc(sizeof(*cell), GFP_KERNEL); ++ if (!cell) ++ return -ENOMEM; ++ ++ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); ++ if (rval) { ++ kfree(cell); ++ return rval; ++ } ++ ++ nvmem_cell_entry_add(cell); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nvmem_add_one_cell); ++ ++/** + * nvmem_add_cells() - Add cell information to an nvmem device + * + * @nvmem: nvmem device to add cells to. +@@ -514,34 +544,15 @@ static int nvmem_add_cells(struct nvmem_ + const struct nvmem_cell_info *info, + int ncells) + { +- struct nvmem_cell_entry **cells; +- int i, rval = 0; +- +- cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); +- if (!cells) +- return -ENOMEM; ++ int i, rval; + + for (i = 0; i < ncells; i++) { +- cells[i] = kzalloc(sizeof(**cells), GFP_KERNEL); +- if (!cells[i]) { +- rval = -ENOMEM; +- goto out; +- } +- +- rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]); +- if (rval) { +- kfree(cells[i]); +- goto out; +- } +- +- nvmem_cell_entry_add(cells[i]); ++ rval = nvmem_add_one_cell(nvmem, &info[i]); ++ if (rval) ++ return rval; + } + +-out: +- /* remove tmp array */ +- kfree(cells); +- +- return rval; ++ return 0; + } + + /** +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -153,6 +153,9 @@ struct nvmem_device *devm_nvmem_register + void nvmem_add_cell_table(struct nvmem_cell_table *table); + void nvmem_del_cell_table(struct nvmem_cell_table *table); + ++int nvmem_add_one_cell(struct nvmem_device *nvmem, ++ const struct nvmem_cell_info *info); ++ + #else + + static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) +@@ -170,6 +173,11 @@ devm_nvmem_register(struct device *dev, + + static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} + static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {} ++static inline int nvmem_add_one_cell(struct nvmem_device *nvmem, ++ const struct nvmem_cell_info *info) ++{ ++ return -EOPNOTSUPP; ++} + + #endif /* CONFIG_NVMEM */ + #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */ diff --git a/target/linux/generic/backport-6.1/809-v6.3-0006-nvmem-core-use-nvmem_add_one_cell-in-nvmem_add_cells.patch b/target/linux/generic/backport-6.1/809-v6.3-0006-nvmem-core-use-nvmem_add_one_cell-in-nvmem_add_cells.patch new file mode 100644 index 00000000000..e1791e5c83c --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0006-nvmem-core-use-nvmem_add_one_cell-in-nvmem_add_cells.patch @@ -0,0 +1,93 @@ +From 50014d659617dc58780a5d31ceb76c82779a9d8b Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:50 +0000 +Subject: [PATCH] nvmem: core: use nvmem_add_one_cell() in + nvmem_add_cells_from_of() + +Convert nvmem_add_cells_from_of() to use the new nvmem_add_one_cell(). +This will remove duplicate code and it will make it possible to add a +hook to a nvmem layout in between, which can change fields before the +cell is finally added. + +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-17-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 45 ++++++++++++++------------------------------ + 1 file changed, 14 insertions(+), 31 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -688,15 +688,14 @@ static int nvmem_validate_keepouts(struc + + static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) + { +- struct device_node *parent, *child; + struct device *dev = &nvmem->dev; +- struct nvmem_cell_entry *cell; ++ struct device_node *child; + const __be32 *addr; +- int len; ++ int len, ret; + +- parent = dev->of_node; ++ for_each_child_of_node(dev->of_node, child) { ++ struct nvmem_cell_info info = {0}; + +- for_each_child_of_node(parent, child) { + addr = of_get_property(child, "reg", &len); + if (!addr) + continue; +@@ -706,40 +705,24 @@ static int nvmem_add_cells_from_of(struc + return -EINVAL; + } + +- cell = kzalloc(sizeof(*cell), GFP_KERNEL); +- if (!cell) { +- of_node_put(child); +- return -ENOMEM; +- } +- +- cell->nvmem = nvmem; +- cell->offset = be32_to_cpup(addr++); +- cell->bytes = be32_to_cpup(addr); +- cell->name = kasprintf(GFP_KERNEL, "%pOFn", child); ++ info.offset = be32_to_cpup(addr++); ++ info.bytes = be32_to_cpup(addr); ++ info.name = kasprintf(GFP_KERNEL, "%pOFn", child); + + addr = of_get_property(child, "bits", &len); + if (addr && len == (2 * sizeof(u32))) { +- cell->bit_offset = be32_to_cpup(addr++); +- cell->nbits = be32_to_cpup(addr); ++ info.bit_offset = be32_to_cpup(addr++); ++ info.nbits = be32_to_cpup(addr); + } + +- if (cell->nbits) +- cell->bytes = DIV_ROUND_UP( +- cell->nbits + cell->bit_offset, +- BITS_PER_BYTE); +- +- if (!IS_ALIGNED(cell->offset, nvmem->stride)) { +- dev_err(dev, "cell %s unaligned to nvmem stride %d\n", +- cell->name, nvmem->stride); +- /* Cells already added will be freed later. */ +- kfree_const(cell->name); +- kfree(cell); ++ info.np = of_node_get(child); ++ ++ ret = nvmem_add_one_cell(nvmem, &info); ++ kfree(info.name); ++ if (ret) { + of_node_put(child); +- return -EINVAL; ++ return ret; + } +- +- cell->np = of_node_get(child); +- nvmem_cell_entry_add(cell); + } + + return 0; diff --git a/target/linux/generic/backport-6.1/809-v6.3-0007-nvmem-stm32-add-OP-TEE-support-for-STM32MP13x.patch b/target/linux/generic/backport-6.1/809-v6.3-0007-nvmem-stm32-add-OP-TEE-support-for-STM32MP13x.patch new file mode 100644 index 00000000000..172a78b76af --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0007-nvmem-stm32-add-OP-TEE-support-for-STM32MP13x.patch @@ -0,0 +1,562 @@ +From 6a0bc3522e746025e2d9a63ab2cb5d7062c2d39c Mon Sep 17 00:00:00 2001 +From: Patrick Delaunay +Date: Mon, 6 Feb 2023 13:43:51 +0000 +Subject: [PATCH] nvmem: stm32: add OP-TEE support for STM32MP13x + +For boot with OP-TEE on STM32MP13, the communication with the secure +world no more use STMicroelectronics SMC but communication with the +STM32MP BSEC TA, for data access (read/write) or lock operation: +- all the request are sent to OP-TEE trusted application, +- for upper OTP with ECC protection and with word programming only + each OTP are permanently locked when programmed to avoid ECC error + on the second write operation + +Signed-off-by: Patrick Delaunay +Reviewed-by: Etienne Carriere +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-18-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 11 + + drivers/nvmem/Makefile | 1 + + drivers/nvmem/stm32-bsec-optee-ta.c | 298 ++++++++++++++++++++++++++++ + drivers/nvmem/stm32-bsec-optee-ta.h | 80 ++++++++ + drivers/nvmem/stm32-romem.c | 54 ++++- + 5 files changed, 441 insertions(+), 3 deletions(-) + create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.c + create mode 100644 drivers/nvmem/stm32-bsec-optee-ta.h + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -290,9 +290,20 @@ config NVMEM_SPRD_EFUSE + This driver can also be built as a module. If so, the module + will be called nvmem-sprd-efuse. + ++config NVMEM_STM32_BSEC_OPTEE_TA ++ bool "STM32MP BSEC OP-TEE TA support for nvmem-stm32-romem driver" ++ depends on OPTEE ++ help ++ Say y here to enable the accesses to STM32MP SoC OTPs by the OP-TEE ++ trusted application STM32MP BSEC. ++ ++ This library is a used by stm32-romem driver or included in the module ++ called nvmem-stm32-romem. ++ + config NVMEM_STM32_ROMEM + tristate "STMicroelectronics STM32 factory-programmed memory support" + depends on ARCH_STM32 || COMPILE_TEST ++ imply NVMEM_STM32_BSEC_OPTEE_TA + help + Say y here to enable read-only access for STMicroelectronics STM32 + factory-programmed memory area. +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -61,6 +61,7 @@ obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem + nvmem_sprd_efuse-y := sprd-efuse.o + obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o + nvmem_stm32_romem-y := stm32-romem.o ++nvmem_stm32_romem-$(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA) += stm32-bsec-optee-ta.o + obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o + nvmem_sunplus_ocotp-y := sunplus-ocotp.o + obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o +--- /dev/null ++++ b/drivers/nvmem/stm32-bsec-optee-ta.c +@@ -0,0 +1,298 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver ++ * ++ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved ++ */ ++ ++#include ++ ++#include "stm32-bsec-optee-ta.h" ++ ++/* ++ * Read OTP memory ++ * ++ * [in] value[0].a OTP start offset in byte ++ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock) ++ * [out] memref[1].buffer Output buffer to store read values ++ * [out] memref[1].size Size of OTP to be read ++ * ++ * Return codes: ++ * TEE_SUCCESS - Invoke command success ++ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param ++ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller ++ */ ++#define PTA_BSEC_READ_MEM 0x0 ++ ++/* ++ * Write OTP memory ++ * ++ * [in] value[0].a OTP start offset in byte ++ * [in] value[0].b Access type (0:shadow, 1:fuse, 2:lock) ++ * [in] memref[1].buffer Input buffer to read values ++ * [in] memref[1].size Size of OTP to be written ++ * ++ * Return codes: ++ * TEE_SUCCESS - Invoke command success ++ * TEE_ERROR_BAD_PARAMETERS - Incorrect input param ++ * TEE_ERROR_ACCESS_DENIED - OTP not accessible by caller ++ */ ++#define PTA_BSEC_WRITE_MEM 0x1 ++ ++/* value of PTA_BSEC access type = value[in] b */ ++#define SHADOW_ACCESS 0 ++#define FUSE_ACCESS 1 ++#define LOCK_ACCESS 2 ++ ++/* Bitfield definition for LOCK status */ ++#define LOCK_PERM BIT(30) ++ ++/* OP-TEE STM32MP BSEC TA UUID */ ++static const uuid_t stm32mp_bsec_ta_uuid = ++ UUID_INIT(0x94cf71ad, 0x80e6, 0x40b5, ++ 0xa7, 0xc6, 0x3d, 0xc5, 0x01, 0xeb, 0x28, 0x03); ++ ++/* ++ * Check whether this driver supports the BSEC TA in the TEE instance ++ * represented by the params (ver/data) to this function. ++ */ ++static int stm32_bsec_optee_ta_match(struct tee_ioctl_version_data *ver, ++ const void *data) ++{ ++ /* Currently this driver only supports GP compliant, OP-TEE based TA */ ++ if ((ver->impl_id == TEE_IMPL_ID_OPTEE) && ++ (ver->gen_caps & TEE_GEN_CAP_GP)) ++ return 1; ++ else ++ return 0; ++} ++ ++/* Open a session to OP-TEE for STM32MP BSEC TA */ ++static int stm32_bsec_ta_open_session(struct tee_context *ctx, u32 *id) ++{ ++ struct tee_ioctl_open_session_arg sess_arg; ++ int rc; ++ ++ memset(&sess_arg, 0, sizeof(sess_arg)); ++ export_uuid(sess_arg.uuid, &stm32mp_bsec_ta_uuid); ++ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL; ++ sess_arg.num_params = 0; ++ ++ rc = tee_client_open_session(ctx, &sess_arg, NULL); ++ if ((rc < 0) || (sess_arg.ret != 0)) { ++ pr_err("%s: tee_client_open_session failed err:%#x, ret:%#x\n", ++ __func__, sess_arg.ret, rc); ++ if (!rc) ++ rc = -EINVAL; ++ } else { ++ *id = sess_arg.session; ++ } ++ ++ return rc; ++} ++ ++/* close a session to OP-TEE for STM32MP BSEC TA */ ++static void stm32_bsec_ta_close_session(void *ctx, u32 id) ++{ ++ tee_client_close_session(ctx, id); ++} ++ ++/* stm32_bsec_optee_ta_open() - initialize the STM32MP BSEC TA */ ++int stm32_bsec_optee_ta_open(struct tee_context **ctx) ++{ ++ struct tee_context *tee_ctx; ++ u32 session_id; ++ int rc; ++ ++ /* Open context with TEE driver */ ++ tee_ctx = tee_client_open_context(NULL, stm32_bsec_optee_ta_match, NULL, NULL); ++ if (IS_ERR(tee_ctx)) { ++ rc = PTR_ERR(tee_ctx); ++ if (rc == -ENOENT) ++ return -EPROBE_DEFER; ++ pr_err("%s: tee_client_open_context failed (%d)\n", __func__, rc); ++ ++ return rc; ++ } ++ ++ /* Check STM32MP BSEC TA presence */ ++ rc = stm32_bsec_ta_open_session(tee_ctx, &session_id); ++ if (rc) { ++ tee_client_close_context(tee_ctx); ++ return rc; ++ } ++ ++ stm32_bsec_ta_close_session(tee_ctx, session_id); ++ ++ *ctx = tee_ctx; ++ ++ return 0; ++} ++ ++/* stm32_bsec_optee_ta_open() - release the PTA STM32MP BSEC TA */ ++void stm32_bsec_optee_ta_close(void *ctx) ++{ ++ tee_client_close_context(ctx); ++} ++ ++/* stm32_bsec_optee_ta_read() - nvmem read access using PTA client driver */ ++int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset, ++ void *buf, size_t bytes) ++{ ++ struct tee_shm *shm; ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[2]; ++ u8 *shm_buf; ++ u32 start, num_bytes; ++ int ret; ++ u32 session_id; ++ ++ ret = stm32_bsec_ta_open_session(ctx, &session_id); ++ if (ret) ++ return ret; ++ ++ memset(&arg, 0, sizeof(arg)); ++ memset(¶m, 0, sizeof(param)); ++ ++ arg.func = PTA_BSEC_READ_MEM; ++ arg.session = session_id; ++ arg.num_params = 2; ++ ++ /* align access on 32bits */ ++ start = ALIGN_DOWN(offset, 4); ++ num_bytes = round_up(offset + bytes - start, 4); ++ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; ++ param[0].u.value.a = start; ++ param[0].u.value.b = SHADOW_ACCESS; ++ ++ shm = tee_shm_alloc_kernel_buf(ctx, num_bytes); ++ if (IS_ERR(shm)) { ++ ret = PTR_ERR(shm); ++ goto out_tee_session; ++ } ++ ++ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT; ++ param[1].u.memref.shm = shm; ++ param[1].u.memref.size = num_bytes; ++ ++ ret = tee_client_invoke_func(ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", ++ arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ if (!ret) { ++ shm_buf = tee_shm_get_va(shm, 0); ++ if (IS_ERR(shm_buf)) { ++ ret = PTR_ERR(shm_buf); ++ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret); ++ } else { ++ /* read data from 32 bits aligned buffer */ ++ memcpy(buf, &shm_buf[offset % 4], bytes); ++ } ++ } ++ ++ tee_shm_free(shm); ++ ++out_tee_session: ++ stm32_bsec_ta_close_session(ctx, session_id); ++ ++ return ret; ++} ++ ++/* stm32_bsec_optee_ta_write() - nvmem write access using PTA client driver */ ++int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower, ++ unsigned int offset, void *buf, size_t bytes) ++{ struct tee_shm *shm; ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[2]; ++ u8 *shm_buf; ++ int ret; ++ u32 session_id; ++ ++ ret = stm32_bsec_ta_open_session(ctx, &session_id); ++ if (ret) ++ return ret; ++ ++ /* Allow only writing complete 32-bits aligned words */ ++ if ((bytes % 4) || (offset % 4)) ++ return -EINVAL; ++ ++ memset(&arg, 0, sizeof(arg)); ++ memset(¶m, 0, sizeof(param)); ++ ++ arg.func = PTA_BSEC_WRITE_MEM; ++ arg.session = session_id; ++ arg.num_params = 2; ++ ++ param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; ++ param[0].u.value.a = offset; ++ param[0].u.value.b = FUSE_ACCESS; ++ ++ shm = tee_shm_alloc_kernel_buf(ctx, bytes); ++ if (IS_ERR(shm)) { ++ ret = PTR_ERR(shm); ++ goto out_tee_session; ++ } ++ ++ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT; ++ param[1].u.memref.shm = shm; ++ param[1].u.memref.size = bytes; ++ ++ shm_buf = tee_shm_get_va(shm, 0); ++ if (IS_ERR(shm_buf)) { ++ ret = PTR_ERR(shm_buf); ++ pr_err("tee_shm_get_va failed for transmit (%d)\n", ret); ++ tee_shm_free(shm); ++ ++ goto out_tee_session; ++ } ++ ++ memcpy(shm_buf, buf, bytes); ++ ++ ret = tee_client_invoke_func(ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ pr_debug("Write OTPs %d to %zu, ret=%d\n", offset / 4, (offset + bytes) / 4, ret); ++ ++ /* Lock the upper OTPs with ECC protection, word programming only */ ++ if (!ret && ((offset + bytes) >= (lower * 4))) { ++ u32 start, nb_lock; ++ u32 *lock = (u32 *)shm_buf; ++ int i; ++ ++ /* ++ * don't lock the lower OTPs, no ECC protection and incremental ++ * bit programming, a second write is allowed ++ */ ++ start = max_t(u32, offset, lower * 4); ++ nb_lock = (offset + bytes - start) / 4; ++ ++ param[0].u.value.a = start; ++ param[0].u.value.b = LOCK_ACCESS; ++ param[1].u.memref.size = nb_lock * 4; ++ ++ for (i = 0; i < nb_lock; i++) ++ lock[i] = LOCK_PERM; ++ ++ ret = tee_client_invoke_func(ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ pr_err("TA_BSEC invoke failed TEE err:%#x, ret:%#x\n", arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ pr_debug("Lock upper OTPs %d to %d, ret=%d\n", ++ start / 4, start / 4 + nb_lock, ret); ++ } ++ ++ tee_shm_free(shm); ++ ++out_tee_session: ++ stm32_bsec_ta_close_session(ctx, session_id); ++ ++ return ret; ++} +--- /dev/null ++++ b/drivers/nvmem/stm32-bsec-optee-ta.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * OP-TEE STM32MP BSEC PTA interface, used by STM32 ROMEM driver ++ * ++ * Copyright (C) 2022, STMicroelectronics - All Rights Reserved ++ */ ++ ++#if IS_ENABLED(CONFIG_NVMEM_STM32_BSEC_OPTEE_TA) ++/** ++ * stm32_bsec_optee_ta_open() - initialize the STM32 BSEC TA ++ * @ctx: the OP-TEE context on success ++ * ++ * Return: ++ * On success, 0. On failure, -errno. ++ */ ++int stm32_bsec_optee_ta_open(struct tee_context **ctx); ++ ++/** ++ * stm32_bsec_optee_ta_close() - release the STM32 BSEC TA ++ * @ctx: the OP-TEE context ++ * ++ * This function used to clean the OP-TEE resources initialized in ++ * stm32_bsec_optee_ta_open(); it can be used as callback to ++ * devm_add_action_or_reset() ++ */ ++void stm32_bsec_optee_ta_close(void *ctx); ++ ++/** ++ * stm32_bsec_optee_ta_read() - nvmem read access using TA client driver ++ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open ++ * @offset: nvmem offset ++ * @buf: buffer to fill with nvem values ++ * @bytes: number of bytes to read ++ * ++ * Return: ++ * On success, 0. On failure, -errno. ++ */ ++int stm32_bsec_optee_ta_read(struct tee_context *ctx, unsigned int offset, ++ void *buf, size_t bytes); ++ ++/** ++ * stm32_bsec_optee_ta_write() - nvmem write access using TA client driver ++ * @ctx: the OP-TEE context provided by stm32_bsec_optee_ta_open ++ * @lower: number of lower OTP, not protected by ECC ++ * @offset: nvmem offset ++ * @buf: buffer with nvem values ++ * @bytes: number of bytes to write ++ * ++ * Return: ++ * On success, 0. On failure, -errno. ++ */ ++int stm32_bsec_optee_ta_write(struct tee_context *ctx, unsigned int lower, ++ unsigned int offset, void *buf, size_t bytes); ++ ++#else ++ ++static inline int stm32_bsec_optee_ta_open(struct tee_context **ctx) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void stm32_bsec_optee_ta_close(void *ctx) ++{ ++} ++ ++static inline int stm32_bsec_optee_ta_read(struct tee_context *ctx, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline int stm32_bsec_optee_ta_write(struct tee_context *ctx, ++ unsigned int lower, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ return -EOPNOTSUPP; ++} ++#endif /* CONFIG_NVMEM_STM32_BSEC_OPTEE_TA */ +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -11,6 +11,9 @@ + #include + #include + #include ++#include ++ ++#include "stm32-bsec-optee-ta.h" + + /* BSEC secure service access from non-secure */ + #define STM32_SMC_BSEC 0x82001003 +@@ -25,12 +28,14 @@ + struct stm32_romem_cfg { + int size; + u8 lower; ++ bool ta; + }; + + struct stm32_romem_priv { + void __iomem *base; + struct nvmem_config cfg; + u8 lower; ++ struct tee_context *ctx; + }; + + static int stm32_romem_read(void *context, unsigned int offset, void *buf, +@@ -138,12 +143,29 @@ static int stm32_bsec_write(void *contex + return 0; + } + ++static int stm32_bsec_pta_read(void *context, unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ struct stm32_romem_priv *priv = context; ++ ++ return stm32_bsec_optee_ta_read(priv->ctx, offset, buf, bytes); ++} ++ ++static int stm32_bsec_pta_write(void *context, unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ struct stm32_romem_priv *priv = context; ++ ++ return stm32_bsec_optee_ta_write(priv->ctx, priv->lower, offset, buf, bytes); ++} ++ + static int stm32_romem_probe(struct platform_device *pdev) + { + const struct stm32_romem_cfg *cfg; + struct device *dev = &pdev->dev; + struct stm32_romem_priv *priv; + struct resource *res; ++ int rc; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -173,15 +195,31 @@ static int stm32_romem_probe(struct plat + } else { + priv->cfg.size = cfg->size; + priv->lower = cfg->lower; +- priv->cfg.reg_read = stm32_bsec_read; +- priv->cfg.reg_write = stm32_bsec_write; ++ if (cfg->ta) { ++ rc = stm32_bsec_optee_ta_open(&priv->ctx); ++ /* wait for OP-TEE client driver to be up and ready */ ++ if (rc) ++ return rc; ++ } ++ if (priv->ctx) { ++ rc = devm_add_action_or_reset(dev, stm32_bsec_optee_ta_close, priv->ctx); ++ if (rc) { ++ dev_err(dev, "devm_add_action_or_reset() failed (%d)\n", rc); ++ return rc; ++ } ++ priv->cfg.reg_read = stm32_bsec_pta_read; ++ priv->cfg.reg_write = stm32_bsec_pta_write; ++ } else { ++ priv->cfg.reg_read = stm32_bsec_read; ++ priv->cfg.reg_write = stm32_bsec_write; ++ } + } + + return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); + } + + /* +- * STM32MP15 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits) ++ * STM32MP15/13 BSEC OTP regions: 4096 OTP bits (with 3072 effective bits) + * => 96 x 32-bits data words + * - Lower: 1K bits, 2:1 redundancy, incremental bit programming + * => 32 (x 32-bits) lower shadow registers = words 0 to 31 +@@ -191,6 +229,13 @@ static int stm32_romem_probe(struct plat + static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { + .size = 384, + .lower = 32, ++ .ta = false, ++}; ++ ++static const struct stm32_romem_cfg stm32mp13_bsec_cfg = { ++ .size = 384, ++ .lower = 32, ++ .ta = true, + }; + + static const struct of_device_id stm32_romem_of_match[] = { +@@ -198,7 +243,10 @@ static const struct of_device_id stm32_r + .compatible = "st,stm32mp15-bsec", + .data = (void *)&stm32mp15_bsec_cfg, + }, { ++ .compatible = "st,stm32mp13-bsec", ++ .data = (void *)&stm32mp13_bsec_cfg, + }, ++ { /* sentinel */ }, + }; + MODULE_DEVICE_TABLE(of, stm32_romem_of_match); + diff --git a/target/linux/generic/backport-6.1/809-v6.3-0008-nvmem-stm32-detect-bsec-pta-presence-for-STM32MP15x.patch b/target/linux/generic/backport-6.1/809-v6.3-0008-nvmem-stm32-detect-bsec-pta-presence-for-STM32MP15x.patch new file mode 100644 index 00000000000..cea8e93858f --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0008-nvmem-stm32-detect-bsec-pta-presence-for-STM32MP15x.patch @@ -0,0 +1,85 @@ +From df2f34ef1d924125ffaf29dfdaf7cdbd3183c321 Mon Sep 17 00:00:00 2001 +From: Patrick Delaunay +Date: Mon, 6 Feb 2023 13:43:52 +0000 +Subject: [PATCH] nvmem: stm32: detect bsec pta presence for STM32MP15x + +On STM32MP15x SoC, the SMC backend is optional when OP-TEE is used; +the PTA BSEC should be used as it is done on STM32MP13x platform, +but the BSEC SMC can be also used: it is a legacy mode in OP-TEE, +not recommended but used in previous OP-TEE firmware. + +The presence of OP-TEE is dynamically detected in STM32MP15x device tree +and the supported NVMEM backend is dynamically detected: +- PTA with stm32_bsec_pta_find +- SMC with stm32_bsec_check + +With OP-TEE but without PTA and SMC detection, the probe is deferred for +STM32MP15x devices. + +On STM32MP13x platform, only the PTA is supported with cfg->ta = true +and this detection is skipped. + +Signed-off-by: Patrick Delaunay +Reviewed-by: Etienne Carriere +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-19-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 38 +++++++++++++++++++++++++++++++++---- + 1 file changed, 34 insertions(+), 4 deletions(-) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -159,6 +159,31 @@ static int stm32_bsec_pta_write(void *co + return stm32_bsec_optee_ta_write(priv->ctx, priv->lower, offset, buf, bytes); + } + ++static bool stm32_bsec_smc_check(void) ++{ ++ u32 val; ++ int ret; ++ ++ /* check that the OP-TEE support the BSEC SMC (legacy mode) */ ++ ret = stm32_bsec_smc(STM32_SMC_READ_SHADOW, 0, 0, &val); ++ ++ return !ret; ++} ++ ++static bool optee_presence_check(void) ++{ ++ struct device_node *np; ++ bool tee_detected = false; ++ ++ /* check that the OP-TEE node is present and available. */ ++ np = of_find_compatible_node(NULL, NULL, "linaro,optee-tz"); ++ if (np && of_device_is_available(np)) ++ tee_detected = true; ++ of_node_put(np); ++ ++ return tee_detected; ++} ++ + static int stm32_romem_probe(struct platform_device *pdev) + { + const struct stm32_romem_cfg *cfg; +@@ -195,11 +220,16 @@ static int stm32_romem_probe(struct plat + } else { + priv->cfg.size = cfg->size; + priv->lower = cfg->lower; +- if (cfg->ta) { ++ if (cfg->ta || optee_presence_check()) { + rc = stm32_bsec_optee_ta_open(&priv->ctx); +- /* wait for OP-TEE client driver to be up and ready */ +- if (rc) +- return rc; ++ if (rc) { ++ /* wait for OP-TEE client driver to be up and ready */ ++ if (rc == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ /* BSEC PTA is required or SMC not supported */ ++ if (cfg->ta || !stm32_bsec_smc_check()) ++ return rc; ++ } + } + if (priv->ctx) { + rc = devm_add_action_or_reset(dev, stm32_bsec_optee_ta_close, priv->ctx); diff --git a/target/linux/generic/backport-6.1/809-v6.3-0009-nvmem-rave-sp-eeprm-fix-kernel-doc-bad-line-warning.patch b/target/linux/generic/backport-6.1/809-v6.3-0009-nvmem-rave-sp-eeprm-fix-kernel-doc-bad-line-warning.patch new file mode 100644 index 00000000000..9d6275a737b --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0009-nvmem-rave-sp-eeprm-fix-kernel-doc-bad-line-warning.patch @@ -0,0 +1,32 @@ +From 3e5ac22aa564026e99defc3a8e02082521a5b231 Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Mon, 6 Feb 2023 13:43:53 +0000 +Subject: [PATCH] nvmem: rave-sp-eeprm: fix kernel-doc bad line warning + +Convert an empty line to " *" to avoid a kernel-doc warning: + +drivers/nvmem/rave-sp-eeprom.c:48: warning: bad line: + +Signed-off-by: Randy Dunlap +Cc: Srinivas Kandagatla +Cc: Andrey Vostrikov +Cc: Nikita Yushchenko +Cc: Andrey Smirnov +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-20-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/rave-sp-eeprom.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/rave-sp-eeprom.c ++++ b/drivers/nvmem/rave-sp-eeprom.c +@@ -45,7 +45,7 @@ enum rave_sp_eeprom_header_size { + * @type: Access type (see enum rave_sp_eeprom_access_type) + * @success: Success flag (Success = 1, Failure = 0) + * @data: Read data +- ++ * + * Note this structure corresponds to RSP_*_EEPROM payload from RAVE + * SP ICD + */ diff --git a/target/linux/generic/backport-6.1/809-v6.3-0010-nvmem-qcom-spmi-sdam-register-at-device-init-time.patch b/target/linux/generic/backport-6.1/809-v6.3-0010-nvmem-qcom-spmi-sdam-register-at-device-init-time.patch new file mode 100644 index 00000000000..1ab9e609d33 --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0010-nvmem-qcom-spmi-sdam-register-at-device-init-time.patch @@ -0,0 +1,43 @@ +From eb7dda20f42a9137e9ee53d5ed3b743d49338cb5 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 6 Feb 2023 13:43:54 +0000 +Subject: [PATCH] nvmem: qcom-spmi-sdam: register at device init time + +There are currently no in-tree users of the Qualcomm SDAM nvmem driver +and there is generally no point in registering a driver that can be +built as a module at subsys init time. + +Register the driver at the normal device init time instead and let +driver core sort out the probe order. + +Signed-off-by: Johan Hovold +Reviewed-by: Bjorn Andersson +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-21-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/qcom-spmi-sdam.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +--- a/drivers/nvmem/qcom-spmi-sdam.c ++++ b/drivers/nvmem/qcom-spmi-sdam.c +@@ -175,18 +175,7 @@ static struct platform_driver sdam_drive + }, + .probe = sdam_probe, + }; +- +-static int __init sdam_init(void) +-{ +- return platform_driver_register(&sdam_driver); +-} +-subsys_initcall(sdam_init); +- +-static void __exit sdam_exit(void) +-{ +- return platform_driver_unregister(&sdam_driver); +-} +-module_exit(sdam_exit); ++module_platform_driver(sdam_driver); + + MODULE_DESCRIPTION("QCOM SPMI SDAM driver"); + MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/backport-6.1/809-v6.3-0011-nvmem-stm32-fix-OPTEE-dependency.patch b/target/linux/generic/backport-6.1/809-v6.3-0011-nvmem-stm32-fix-OPTEE-dependency.patch new file mode 100644 index 00000000000..dcf704c6ffb --- /dev/null +++ b/target/linux/generic/backport-6.1/809-v6.3-0011-nvmem-stm32-fix-OPTEE-dependency.patch @@ -0,0 +1,46 @@ +From 1dc7e37bb0ec1c997fac82031332a38c7610352f Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Mon, 6 Feb 2023 13:43:56 +0000 +Subject: [PATCH] nvmem: stm32: fix OPTEE dependency + +The stm32 nvmem driver fails to link as built-in when OPTEE +is a loadable module: + +aarch64-linux-ld: drivers/nvmem/stm32-bsec-optee-ta.o: in function `stm32_bsec: +stm32-bsec-optee-ta.c:(.text+0xc8): undefined reference to `tee_client_open_session' +aarch64-linux-ld: drivers/nvmem/stm32-bsec-optee-ta.o: in function `stm32_bsec: +stm32-bsec-optee-ta.c:(.text+0x1fc): undefined reference to `tee_client_open_context' + +Change the CONFIG_NVMEM_STM32_ROMEM definition so it can only +be built-in if OPTEE is either built-in or disabled, and +make NVMEM_STM32_BSEC_OPTEE_TA a hidden symbol instead. + +Signed-off-by: Arnd Bergmann +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-23-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -291,8 +291,7 @@ config NVMEM_SPRD_EFUSE + will be called nvmem-sprd-efuse. + + config NVMEM_STM32_BSEC_OPTEE_TA +- bool "STM32MP BSEC OP-TEE TA support for nvmem-stm32-romem driver" +- depends on OPTEE ++ def_bool NVMEM_STM32_ROMEM && OPTEE + help + Say y here to enable the accesses to STM32MP SoC OTPs by the OP-TEE + trusted application STM32MP BSEC. +@@ -303,7 +302,7 @@ config NVMEM_STM32_BSEC_OPTEE_TA + config NVMEM_STM32_ROMEM + tristate "STMicroelectronics STM32 factory-programmed memory support" + depends on ARCH_STM32 || COMPILE_TEST +- imply NVMEM_STM32_BSEC_OPTEE_TA ++ depends on OPTEE || !OPTEE + help + Say y here to enable read-only access for STMicroelectronics STM32 + factory-programmed memory area. diff --git a/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch b/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch new file mode 100644 index 00000000000..25802be7e3d --- /dev/null +++ b/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch @@ -0,0 +1,59 @@ +From 078c6a1cbd4cd7496048786beec2e312577bebbf Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Tue, 11 Jan 2022 23:11:32 +0100 +Subject: [PATCH 1/1] net: qmi_wwan: add ZTE MF286D modem 19d2:1485 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Modem from ZTE MF286D is an Qualcomm MDM9250 based 3G/4G modem. + +T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=5000 MxCh= 0 +D: Ver= 3.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1 +P: Vendor=19d2 ProdID=1485 Rev=52.87 +S: Manufacturer=ZTE,Incorporated +S: Product=ZTE Technologies MSM +S: SerialNumber=MF286DZTED000000 +C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=896mA +A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=06 Prot=00 +I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=ff Driver=rndis_host +E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host +E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=83(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=84(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option +E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms +E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan +E: Ad=88(I) Atr=03(Int.) MxPS= 8 Ivl=32ms +E: Ad=8e(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=0f(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +I:* If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs +E: Ad=05(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms +E: Ad=89(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms + +Signed-off-by: Pawel Dembicki +Acked-by: Bjørn Mork +Signed-off-by: David S. Miller +--- + drivers/net/usb/qmi_wwan.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1314,6 +1314,7 @@ static const struct usb_device_id produc + {QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */ + {QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */ + {QMI_FIXED_INTF(0x19d2, 0x1432, 3)}, /* ZTE ME3620 */ ++ {QMI_FIXED_INTF(0x19d2, 0x1485, 5)}, /* ZTE MF286D */ + {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ + {QMI_FIXED_INTF(0x2001, 0x7e16, 3)}, /* D-Link DWM-221 */ + {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ diff --git a/target/linux/generic/backport-6.1/811-v6.4-0001-nvmem-xilinx-zynqmp-make-modular.patch b/target/linux/generic/backport-6.1/811-v6.4-0001-nvmem-xilinx-zynqmp-make-modular.patch new file mode 100644 index 00000000000..8328e87c0af --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0001-nvmem-xilinx-zynqmp-make-modular.patch @@ -0,0 +1,35 @@ +From bcd1fe07def0f070eb5f31594620aaee6f81d31a Mon Sep 17 00:00:00 2001 +From: Nick Alcock +Date: Tue, 4 Apr 2023 18:21:11 +0100 +Subject: [PATCH] nvmem: xilinx: zynqmp: make modular + +This driver has a MODULE_LICENSE but is not tristate so cannot be +built as a module, unlike all its peers: make it modular to match. + +Signed-off-by: Nick Alcock +Suggested-by: Michal Simek +Cc: Luis Chamberlain +Cc: linux-modules@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Cc: Hitomi Hasegawa +Cc: Srinivas Kandagatla +Cc: Michal Simek +Cc: linux-arm-kernel@lists.infradead.org +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-4-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -368,7 +368,7 @@ config NVMEM_VF610_OCOTP + be called nvmem-vf610-ocotp. + + config NVMEM_ZYNQMP +- bool "Xilinx ZYNQMP SoC nvmem firmware support" ++ tristate "Xilinx ZYNQMP SoC nvmem firmware support" + depends on ARCH_ZYNQMP + help + This is a driver to access hardware related data like diff --git a/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch b/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch new file mode 100644 index 00000000000..23518d21f70 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch @@ -0,0 +1,387 @@ +From 266570f496b90dea8fda893c2cf7c28d63ae2bd9 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:21 +0100 +Subject: [PATCH] nvmem: core: introduce NVMEM layouts + +NVMEM layouts are used to generate NVMEM cells during runtime. Think of +an EEPROM with a well-defined conent. For now, the content can be +described by a device tree or a board file. But this only works if the +offsets and lengths are static and don't change. One could also argue +that putting the layout of the EEPROM in the device tree is the wrong +place. Instead, the device tree should just have a specific compatible +string. + +Right now there are two use cases: + (1) The NVMEM cell needs special processing. E.g. if it only specifies + a base MAC address offset and you need to add an offset, or it + needs to parse a MAC from ASCII format or some proprietary format. + (Post processing of cells is added in a later commit). + (2) u-boot environment parsing. The cells don't have a particular + offset but it needs parsing the content to determine the offsets + and length. + +Co-developed-by: Miquel Raynal +Signed-off-by: Miquel Raynal +Signed-off-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-14-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/driver-api/nvmem.rst | 15 ++++ + drivers/nvmem/Kconfig | 4 + + drivers/nvmem/Makefile | 1 + + drivers/nvmem/core.c | 120 +++++++++++++++++++++++++++++ + drivers/nvmem/layouts/Kconfig | 5 ++ + drivers/nvmem/layouts/Makefile | 4 + + include/linux/nvmem-consumer.h | 7 ++ + include/linux/nvmem-provider.h | 51 ++++++++++++ + 8 files changed, 207 insertions(+) + create mode 100644 drivers/nvmem/layouts/Kconfig + create mode 100644 drivers/nvmem/layouts/Makefile + +--- a/Documentation/driver-api/nvmem.rst ++++ b/Documentation/driver-api/nvmem.rst +@@ -189,3 +189,18 @@ ex:: + ===================== + + See Documentation/devicetree/bindings/nvmem/nvmem.txt ++ ++8. NVMEM layouts ++================ ++ ++NVMEM layouts are yet another mechanism to create cells. With the device ++tree binding it is possible to specify simple cells by using an offset ++and a length. Sometimes, the cells doesn't have a static offset, but ++the content is still well defined, e.g. tag-length-values. In this case, ++the NVMEM device content has to be first parsed and the cells need to ++be added accordingly. Layouts let you read the content of the NVMEM device ++and let you add cells dynamically. ++ ++Another use case for layouts is the post processing of cells. With layouts, ++it is possible to associate a custom post processing hook to a cell. It ++even possible to add this hook to cells not created by the layout itself. +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -21,6 +21,10 @@ config NVMEM_SYSFS + This interface is mostly used by userspace applications to + read/write directly into nvmem. + ++# Layouts ++ ++source "drivers/nvmem/layouts/Kconfig" ++ + # Devices + + config NVMEM_APPLE_EFUSES +--- a/drivers/nvmem/Makefile ++++ b/drivers/nvmem/Makefile +@@ -5,6 +5,7 @@ + + obj-$(CONFIG_NVMEM) += nvmem_core.o + nvmem_core-y := core.o ++obj-y += layouts/ + + # Devices + obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -40,6 +40,7 @@ struct nvmem_device { + nvmem_reg_write_t reg_write; + nvmem_cell_post_process_t cell_post_process; + struct gpio_desc *wp_gpio; ++ struct nvmem_layout *layout; + void *priv; + }; + +@@ -74,6 +75,9 @@ static LIST_HEAD(nvmem_lookup_list); + + static BLOCKING_NOTIFIER_HEAD(nvmem_notifier); + ++static DEFINE_SPINLOCK(nvmem_layout_lock); ++static LIST_HEAD(nvmem_layouts); ++ + static int __nvmem_reg_read(struct nvmem_device *nvmem, unsigned int offset, + void *val, size_t bytes) + { +@@ -728,6 +732,101 @@ static int nvmem_add_cells_from_of(struc + return 0; + } + ++int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner) ++{ ++ layout->owner = owner; ++ ++ spin_lock(&nvmem_layout_lock); ++ list_add(&layout->node, &nvmem_layouts); ++ spin_unlock(&nvmem_layout_lock); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(__nvmem_layout_register); ++ ++void nvmem_layout_unregister(struct nvmem_layout *layout) ++{ ++ spin_lock(&nvmem_layout_lock); ++ list_del(&layout->node); ++ spin_unlock(&nvmem_layout_lock); ++} ++EXPORT_SYMBOL_GPL(nvmem_layout_unregister); ++ ++static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem) ++{ ++ struct device_node *layout_np, *np = nvmem->dev.of_node; ++ struct nvmem_layout *l, *layout = NULL; ++ ++ layout_np = of_get_child_by_name(np, "nvmem-layout"); ++ if (!layout_np) ++ return NULL; ++ ++ spin_lock(&nvmem_layout_lock); ++ ++ list_for_each_entry(l, &nvmem_layouts, node) { ++ if (of_match_node(l->of_match_table, layout_np)) { ++ if (try_module_get(l->owner)) ++ layout = l; ++ ++ break; ++ } ++ } ++ ++ spin_unlock(&nvmem_layout_lock); ++ of_node_put(layout_np); ++ ++ return layout; ++} ++ ++static void nvmem_layout_put(struct nvmem_layout *layout) ++{ ++ if (layout) ++ module_put(layout->owner); ++} ++ ++static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem) ++{ ++ struct nvmem_layout *layout = nvmem->layout; ++ int ret; ++ ++ if (layout && layout->add_cells) { ++ ret = layout->add_cells(&nvmem->dev, nvmem, layout); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++#if IS_ENABLED(CONFIG_OF) ++/** ++ * of_nvmem_layout_get_container() - Get OF node to layout container. ++ * ++ * @nvmem: nvmem device. ++ * ++ * Return: a node pointer with refcount incremented or NULL if no ++ * container exists. Use of_node_put() on it when done. ++ */ ++struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem) ++{ ++ return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout"); ++} ++EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container); ++#endif ++ ++const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout) ++{ ++ struct device_node __maybe_unused *layout_np; ++ const struct of_device_id *match; ++ ++ layout_np = of_nvmem_layout_get_container(nvmem); ++ match = of_match_node(layout->of_match_table, layout_np); ++ ++ return match ? match->data : NULL; ++} ++EXPORT_SYMBOL_GPL(nvmem_layout_get_match_data); ++ + /** + * nvmem_register() - Register a nvmem device for given nvmem_config. + * Also creates a binary entry in /sys/bus/nvmem/devices/dev-name/nvmem +@@ -834,6 +933,12 @@ struct nvmem_device *nvmem_register(cons + goto err_put_device; + } + ++ /* ++ * If the driver supplied a layout by config->layout, the module ++ * pointer will be NULL and nvmem_layout_put() will be a noop. ++ */ ++ nvmem->layout = config->layout ?: nvmem_layout_get(nvmem); ++ + if (config->cells) { + rval = nvmem_add_cells(nvmem, config->cells, config->ncells); + if (rval) +@@ -854,12 +959,17 @@ struct nvmem_device *nvmem_register(cons + if (rval) + goto err_remove_cells; + ++ rval = nvmem_add_cells_from_layout(nvmem); ++ if (rval) ++ goto err_remove_cells; ++ + blocking_notifier_call_chain(&nvmem_notifier, NVMEM_ADD, nvmem); + + return nvmem; + + err_remove_cells: + nvmem_device_remove_all_cells(nvmem); ++ nvmem_layout_put(nvmem->layout); + if (config->compat) + nvmem_sysfs_remove_compat(nvmem, config); + err_put_device: +@@ -881,6 +991,7 @@ static void nvmem_device_release(struct + device_remove_bin_file(nvmem->base_dev, &nvmem->eeprom); + + nvmem_device_remove_all_cells(nvmem); ++ nvmem_layout_put(nvmem->layout); + device_unregister(&nvmem->dev); + } + +@@ -1246,6 +1357,15 @@ struct nvmem_cell *of_nvmem_cell_get(str + return ERR_PTR(-EINVAL); + } + ++ /* nvmem layouts produce cells within the nvmem-layout container */ ++ if (of_node_name_eq(nvmem_np, "nvmem-layout")) { ++ nvmem_np = of_get_next_parent(nvmem_np); ++ if (!nvmem_np) { ++ of_node_put(cell_np); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ + nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); + of_node_put(nvmem_np); + if (IS_ERR(nvmem)) { +--- /dev/null ++++ b/drivers/nvmem/layouts/Kconfig +@@ -0,0 +1,5 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++menu "Layout Types" ++ ++endmenu +--- /dev/null ++++ b/drivers/nvmem/layouts/Makefile +@@ -0,0 +1,4 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# Makefile for nvmem layouts. ++# +--- a/include/linux/nvmem-consumer.h ++++ b/include/linux/nvmem-consumer.h +@@ -239,6 +239,7 @@ struct nvmem_cell *of_nvmem_cell_get(str + const char *id); + struct nvmem_device *of_nvmem_device_get(struct device_node *np, + const char *name); ++struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem); + #else + static inline struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, + const char *id) +@@ -251,6 +252,12 @@ static inline struct nvmem_device *of_nv + { + return ERR_PTR(-EOPNOTSUPP); + } ++ ++static inline struct device_node * ++of_nvmem_layout_get_container(struct nvmem_device *nvmem) ++{ ++ return ERR_PTR(-EOPNOTSUPP); ++} + #endif /* CONFIG_NVMEM && CONFIG_OF */ + + #endif /* ifndef _LINUX_NVMEM_CONSUMER_H */ +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -88,6 +88,7 @@ struct nvmem_cell_info { + * @stride: Minimum read/write access stride. + * @priv: User context passed to read/write callbacks. + * @ignore_wp: Write Protect pin is managed by the provider. ++ * @layout: Fixed layout associated with this nvmem device. + * + * Note: A default "nvmem" name will be assigned to the device if + * no name is specified in its configuration. In such case "" is +@@ -109,6 +110,7 @@ struct nvmem_config { + bool read_only; + bool root_only; + bool ignore_wp; ++ struct nvmem_layout *layout; + struct device_node *of_node; + bool no_of_node; + nvmem_reg_read_t reg_read; +@@ -142,6 +144,33 @@ struct nvmem_cell_table { + struct list_head node; + }; + ++/** ++ * struct nvmem_layout - NVMEM layout definitions ++ * ++ * @name: Layout name. ++ * @of_match_table: Open firmware match table. ++ * @add_cells: Will be called if a nvmem device is found which ++ * has this layout. The function will add layout ++ * specific cells with nvmem_add_one_cell(). ++ * @owner: Pointer to struct module. ++ * @node: List node. ++ * ++ * A nvmem device can hold a well defined structure which can just be ++ * evaluated during runtime. For example a TLV list, or a list of "name=val" ++ * pairs. A nvmem layout can parse the nvmem device and add appropriate ++ * cells. ++ */ ++struct nvmem_layout { ++ const char *name; ++ const struct of_device_id *of_match_table; ++ int (*add_cells)(struct device *dev, struct nvmem_device *nvmem, ++ struct nvmem_layout *layout); ++ ++ /* private */ ++ struct module *owner; ++ struct list_head node; ++}; ++ + #if IS_ENABLED(CONFIG_NVMEM) + + struct nvmem_device *nvmem_register(const struct nvmem_config *cfg); +@@ -156,6 +185,14 @@ void nvmem_del_cell_table(struct nvmem_c + int nvmem_add_one_cell(struct nvmem_device *nvmem, + const struct nvmem_cell_info *info); + ++int __nvmem_layout_register(struct nvmem_layout *layout, struct module *owner); ++#define nvmem_layout_register(layout) \ ++ __nvmem_layout_register(layout, THIS_MODULE) ++void nvmem_layout_unregister(struct nvmem_layout *layout); ++ ++const void *nvmem_layout_get_match_data(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout); ++ + #else + + static inline struct nvmem_device *nvmem_register(const struct nvmem_config *c) +@@ -179,5 +216,19 @@ static inline int nvmem_add_one_cell(str + return -EOPNOTSUPP; + } + ++static inline int nvmem_layout_register(struct nvmem_layout *layout) ++{ ++ return -EOPNOTSUPP; ++} ++ ++static inline void nvmem_layout_unregister(struct nvmem_layout *layout) {} ++ ++static inline const void * ++nvmem_layout_get_match_data(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout) ++{ ++ return NULL; ++} ++ + #endif /* CONFIG_NVMEM */ + #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */ diff --git a/target/linux/generic/backport-6.1/811-v6.4-0003-nvmem-core-handle-the-absence-of-expected-layouts.patch b/target/linux/generic/backport-6.1/811-v6.4-0003-nvmem-core-handle-the-absence-of-expected-layouts.patch new file mode 100644 index 00000000000..6fa7b6382d8 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0003-nvmem-core-handle-the-absence-of-expected-layouts.patch @@ -0,0 +1,61 @@ +From 6468a6f45148fb5e95c86b4efebf63f9abcd2137 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:22 +0100 +Subject: [PATCH] nvmem: core: handle the absence of expected layouts + +Make nvmem_layout_get() return -EPROBE_DEFER while the expected layout +is not available. This condition cannot be triggered today as nvmem +layout drivers are initialed as part of an early init call, but soon +these drivers will be converted into modules and be initialized with a +standard priority, so the unavailability of the drivers might become a +reality that must be taken care of. + +Let's anticipate this by telling the caller the layout might not yet be +available. A probe deferral is requested in this case. + +Please note this does not affect any nvmem device not using layouts, +because an early check against the "nvmem-layout" container presence +will return NULL in this case. + +Signed-off-by: Miquel Raynal +Tested-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-15-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -755,7 +755,7 @@ EXPORT_SYMBOL_GPL(nvmem_layout_unregiste + static struct nvmem_layout *nvmem_layout_get(struct nvmem_device *nvmem) + { + struct device_node *layout_np, *np = nvmem->dev.of_node; +- struct nvmem_layout *l, *layout = NULL; ++ struct nvmem_layout *l, *layout = ERR_PTR(-EPROBE_DEFER); + + layout_np = of_get_child_by_name(np, "nvmem-layout"); + if (!layout_np) +@@ -938,6 +938,13 @@ struct nvmem_device *nvmem_register(cons + * pointer will be NULL and nvmem_layout_put() will be a noop. + */ + nvmem->layout = config->layout ?: nvmem_layout_get(nvmem); ++ if (IS_ERR(nvmem->layout)) { ++ rval = PTR_ERR(nvmem->layout); ++ nvmem->layout = NULL; ++ ++ if (rval == -EPROBE_DEFER) ++ goto err_teardown_compat; ++ } + + if (config->cells) { + rval = nvmem_add_cells(nvmem, config->cells, config->ncells); +@@ -970,6 +977,7 @@ struct nvmem_device *nvmem_register(cons + err_remove_cells: + nvmem_device_remove_all_cells(nvmem); + nvmem_layout_put(nvmem->layout); ++err_teardown_compat: + if (config->compat) + nvmem_sysfs_remove_compat(nvmem, config); + err_put_device: diff --git a/target/linux/generic/backport-6.1/811-v6.4-0004-nvmem-core-request-layout-modules-loading.patch b/target/linux/generic/backport-6.1/811-v6.4-0004-nvmem-core-request-layout-modules-loading.patch new file mode 100644 index 00000000000..b9341666f91 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0004-nvmem-core-request-layout-modules-loading.patch @@ -0,0 +1,52 @@ +From b1c37bec1ccfe5ccab72bc0ddc0dfa45c43e2de2 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:23 +0100 +Subject: [PATCH] nvmem: core: request layout modules loading + +When a storage device like an eeprom or an mtd device probes, it +registers an nvmem device if the nvmem subsystem has been enabled (bool +symbol). During nvmem registration, if the device is using layouts to +expose dynamic nvmem cells, the core will first try to get a reference +over the layout driver callbacks. In practice there is not relationship +that can be described between the storage driver and the nvmem +layout. So there is no way we can enforce both drivers will be built-in +or both will be modules. If the storage device driver is built-in but +the layout is built as a module, instead of badly failing with an +endless probe deferral loop, lets just make a modprobe call in case the +driver was made available in an initramfs with +of_device_node_request_module(), and offer a fully functional system to +the user. + +Signed-off-by: Miquel Raynal +Tested-by: Michael Walle +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-16-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + struct nvmem_device { +@@ -761,6 +762,13 @@ static struct nvmem_layout *nvmem_layout + if (!layout_np) + return NULL; + ++ /* ++ * In case the nvmem device was built-in while the layout was built as a ++ * module, we shall manually request the layout driver loading otherwise ++ * we'll never have any match. ++ */ ++ of_request_module(layout_np); ++ + spin_lock(&nvmem_layout_lock); + + list_for_each_entry(l, &nvmem_layouts, node) { diff --git a/target/linux/generic/backport-6.1/811-v6.4-0005-nvmem-core-add-per-cell-post-processing.patch b/target/linux/generic/backport-6.1/811-v6.4-0005-nvmem-core-add-per-cell-post-processing.patch new file mode 100644 index 00000000000..53628cd4e4f --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0005-nvmem-core-add-per-cell-post-processing.patch @@ -0,0 +1,86 @@ +From 345ec382cd4b736c36e01f155d08c913b225b736 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:24 +0100 +Subject: [PATCH] nvmem: core: add per-cell post processing + +Instead of relying on the name the consumer is using for the cell, like +it is done for the nvmem .cell_post_process configuration parameter, +provide a per-cell post processing hook. This can then be populated by +the NVMEM provider (or the NVMEM layout) when adding the cell. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-17-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 17 +++++++++++++++++ + include/linux/nvmem-provider.h | 3 +++ + 2 files changed, 20 insertions(+) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -54,6 +54,7 @@ struct nvmem_cell_entry { + int bytes; + int bit_offset; + int nbits; ++ nvmem_cell_post_process_t read_post_process; + struct device_node *np; + struct nvmem_device *nvmem; + struct list_head node; +@@ -470,6 +471,7 @@ static int nvmem_cell_info_to_nvmem_cell + cell->offset = info->offset; + cell->bytes = info->bytes; + cell->name = info->name; ++ cell->read_post_process = info->read_post_process; + + cell->bit_offset = info->bit_offset; + cell->nbits = info->nbits; +@@ -1563,6 +1565,13 @@ static int __nvmem_cell_read(struct nvme + if (cell->bit_offset || cell->nbits) + nvmem_shift_read_buffer_in_place(cell, buf); + ++ if (cell->read_post_process) { ++ rc = cell->read_post_process(nvmem->priv, id, index, ++ cell->offset, buf, cell->bytes); ++ if (rc) ++ return rc; ++ } ++ + if (nvmem->cell_post_process) { + rc = nvmem->cell_post_process(nvmem->priv, id, index, + cell->offset, buf, cell->bytes); +@@ -1671,6 +1680,14 @@ static int __nvmem_cell_entry_write(stru + (cell->bit_offset == 0 && len != cell->bytes)) + return -EINVAL; + ++ /* ++ * Any cells which have a read_post_process hook are read-only because ++ * we cannot reverse the operation and it might affect other cells, ++ * too. ++ */ ++ if (cell->read_post_process) ++ return -EINVAL; ++ + if (cell->bit_offset || cell->nbits) { + buf = nvmem_cell_prepare_write_buffer(cell, buf, len); + if (IS_ERR(buf)) +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -54,6 +54,8 @@ struct nvmem_keepout { + * @bit_offset: Bit offset if cell is smaller than a byte. + * @nbits: Number of bits. + * @np: Optional device_node pointer. ++ * @read_post_process: Callback for optional post processing of cell data ++ * on reads. + */ + struct nvmem_cell_info { + const char *name; +@@ -62,6 +64,7 @@ struct nvmem_cell_info { + unsigned int bit_offset; + unsigned int nbits; + struct device_node *np; ++ nvmem_cell_post_process_t read_post_process; + }; + + /** diff --git a/target/linux/generic/backport-6.1/811-v6.4-0006-nvmem-core-allow-to-modify-a-cell-before-adding-it.patch b/target/linux/generic/backport-6.1/811-v6.4-0006-nvmem-core-allow-to-modify-a-cell-before-adding-it.patch new file mode 100644 index 00000000000..32990148c80 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0006-nvmem-core-allow-to-modify-a-cell-before-adding-it.patch @@ -0,0 +1,59 @@ +From de12c9691501ccba41a154c223869f82be4c12fd Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:25 +0100 +Subject: [PATCH] nvmem: core: allow to modify a cell before adding it + +Provide a way to modify a cell before it will get added. This is useful +to attach a custom post processing hook via a layout. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-18-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 4 ++++ + include/linux/nvmem-provider.h | 5 +++++ + 2 files changed, 9 insertions(+) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -695,6 +695,7 @@ static int nvmem_validate_keepouts(struc + + static int nvmem_add_cells_from_of(struct nvmem_device *nvmem) + { ++ struct nvmem_layout *layout = nvmem->layout; + struct device *dev = &nvmem->dev; + struct device_node *child; + const __be32 *addr; +@@ -724,6 +725,9 @@ static int nvmem_add_cells_from_of(struc + + info.np = of_node_get(child); + ++ if (layout && layout->fixup_cell_info) ++ layout->fixup_cell_info(nvmem, layout, &info); ++ + ret = nvmem_add_one_cell(nvmem, &info); + kfree(info.name); + if (ret) { +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -155,6 +155,8 @@ struct nvmem_cell_table { + * @add_cells: Will be called if a nvmem device is found which + * has this layout. The function will add layout + * specific cells with nvmem_add_one_cell(). ++ * @fixup_cell_info: Will be called before a cell is added. Can be ++ * used to modify the nvmem_cell_info. + * @owner: Pointer to struct module. + * @node: List node. + * +@@ -168,6 +170,9 @@ struct nvmem_layout { + const struct of_device_id *of_match_table; + int (*add_cells)(struct device *dev, struct nvmem_device *nvmem, + struct nvmem_layout *layout); ++ void (*fixup_cell_info)(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout, ++ struct nvmem_cell_info *cell); + + /* private */ + struct module *owner; diff --git a/target/linux/generic/backport-6.1/811-v6.4-0007-nvmem-imx-ocotp-replace-global-post-processing-with-.patch b/target/linux/generic/backport-6.1/811-v6.4-0007-nvmem-imx-ocotp-replace-global-post-processing-with-.patch new file mode 100644 index 00000000000..2a5fa618ea6 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0007-nvmem-imx-ocotp-replace-global-post-processing-with-.patch @@ -0,0 +1,81 @@ +From 6c56a82d7895a213a43182a5d01a21a906a79847 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:26 +0100 +Subject: [PATCH] nvmem: imx-ocotp: replace global post processing with layouts + +In preparation of retiring the global post processing hook change this +driver to use layouts. The layout will be supplied during registration +and will be used to add the post processing hook to all added cells. + +Signed-off-by: Michael Walle +Tested-by: Michael Walle # on kontron-pitx-imx8m +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-19-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/imx-ocotp.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +--- a/drivers/nvmem/imx-ocotp.c ++++ b/drivers/nvmem/imx-ocotp.c +@@ -225,18 +225,13 @@ read_end: + static int imx_ocotp_cell_pp(void *context, const char *id, int index, + unsigned int offset, void *data, size_t bytes) + { +- struct ocotp_priv *priv = context; ++ u8 *buf = data; ++ int i; + + /* Deal with some post processing of nvmem cell data */ +- if (id && !strcmp(id, "mac-address")) { +- if (priv->params->reverse_mac_address) { +- u8 *buf = data; +- int i; +- +- for (i = 0; i < bytes/2; i++) +- swap(buf[i], buf[bytes - i - 1]); +- } +- } ++ if (id && !strcmp(id, "mac-address")) ++ for (i = 0; i < bytes / 2; i++) ++ swap(buf[i], buf[bytes - i - 1]); + + return 0; + } +@@ -488,7 +483,6 @@ static struct nvmem_config imx_ocotp_nvm + .stride = 1, + .reg_read = imx_ocotp_read, + .reg_write = imx_ocotp_write, +- .cell_post_process = imx_ocotp_cell_pp, + }; + + static const struct ocotp_params imx6q_params = { +@@ -595,6 +589,17 @@ static const struct of_device_id imx_oco + }; + MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); + ++static void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout, ++ struct nvmem_cell_info *cell) ++{ ++ cell->read_post_process = imx_ocotp_cell_pp; ++} ++ ++struct nvmem_layout imx_ocotp_layout = { ++ .fixup_cell_info = imx_ocotp_fixup_cell_info, ++}; ++ + static int imx_ocotp_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -619,6 +624,9 @@ static int imx_ocotp_probe(struct platfo + imx_ocotp_nvmem_config.size = 4 * priv->params->nregs; + imx_ocotp_nvmem_config.dev = dev; + imx_ocotp_nvmem_config.priv = priv; ++ if (priv->params->reverse_mac_address) ++ imx_ocotp_nvmem_config.layout = &imx_ocotp_layout; ++ + priv->config = &imx_ocotp_nvmem_config; + + clk_prepare_enable(priv->clk); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0008-nvmem-cell-drop-global-cell_post_process.patch b/target/linux/generic/backport-6.1/811-v6.4-0008-nvmem-cell-drop-global-cell_post_process.patch new file mode 100644 index 00000000000..eac202b8829 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0008-nvmem-cell-drop-global-cell_post_process.patch @@ -0,0 +1,68 @@ +From 011e40a166fdaa65fb9946b7cd91efec85b70dbb Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:27 +0100 +Subject: [PATCH] nvmem: cell: drop global cell_post_process + +There are no users anymore for the global cell_post_process callback +anymore. New users should use proper nvmem layouts. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-20-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 9 --------- + include/linux/nvmem-provider.h | 2 -- + 2 files changed, 11 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -39,7 +39,6 @@ struct nvmem_device { + unsigned int nkeepout; + nvmem_reg_read_t reg_read; + nvmem_reg_write_t reg_write; +- nvmem_cell_post_process_t cell_post_process; + struct gpio_desc *wp_gpio; + struct nvmem_layout *layout; + void *priv; +@@ -903,7 +902,6 @@ struct nvmem_device *nvmem_register(cons + nvmem->type = config->type; + nvmem->reg_read = config->reg_read; + nvmem->reg_write = config->reg_write; +- nvmem->cell_post_process = config->cell_post_process; + nvmem->keepout = config->keepout; + nvmem->nkeepout = config->nkeepout; + if (config->of_node) +@@ -1575,13 +1573,6 @@ static int __nvmem_cell_read(struct nvme + if (rc) + return rc; + } +- +- if (nvmem->cell_post_process) { +- rc = nvmem->cell_post_process(nvmem->priv, id, index, +- cell->offset, buf, cell->bytes); +- if (rc) +- return rc; +- } + + if (len) + *len = cell->bytes; +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -85,7 +85,6 @@ struct nvmem_cell_info { + * @no_of_node: Device should not use the parent's of_node even if it's !NULL. + * @reg_read: Callback to read data. + * @reg_write: Callback to write data. +- * @cell_post_process: Callback for vendor specific post processing of cell data + * @size: Device size. + * @word_size: Minimum read/write access granularity. + * @stride: Minimum read/write access stride. +@@ -118,7 +117,6 @@ struct nvmem_config { + bool no_of_node; + nvmem_reg_read_t reg_read; + nvmem_reg_write_t reg_write; +- nvmem_cell_post_process_t cell_post_process; + int size; + int word_size; + int stride; diff --git a/target/linux/generic/backport-6.1/811-v6.4-0009-nvmem-core-provide-own-priv-pointer-in-post-process-.patch b/target/linux/generic/backport-6.1/811-v6.4-0009-nvmem-core-provide-own-priv-pointer-in-post-process-.patch new file mode 100644 index 00000000000..46b30a2ed90 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0009-nvmem-core-provide-own-priv-pointer-in-post-process-.patch @@ -0,0 +1,76 @@ +From 8a134fd9f9323f4c39ec27055b3d3723cfb5c1e9 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:28 +0100 +Subject: [PATCH] nvmem: core: provide own priv pointer in post process + callback + +It doesn't make any more sense to have a opaque pointer set up by the +nvmem device. Usually, the layout isn't associated with a particular +nvmem device. Instead, let the caller who set the post process callback +provide the priv pointer. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-21-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 4 +++- + include/linux/nvmem-provider.h | 5 ++++- + 2 files changed, 7 insertions(+), 2 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -54,6 +54,7 @@ struct nvmem_cell_entry { + int bit_offset; + int nbits; + nvmem_cell_post_process_t read_post_process; ++ void *priv; + struct device_node *np; + struct nvmem_device *nvmem; + struct list_head node; +@@ -471,6 +472,7 @@ static int nvmem_cell_info_to_nvmem_cell + cell->bytes = info->bytes; + cell->name = info->name; + cell->read_post_process = info->read_post_process; ++ cell->priv = info->priv; + + cell->bit_offset = info->bit_offset; + cell->nbits = info->nbits; +@@ -1568,7 +1570,7 @@ static int __nvmem_cell_read(struct nvme + nvmem_shift_read_buffer_in_place(cell, buf); + + if (cell->read_post_process) { +- rc = cell->read_post_process(nvmem->priv, id, index, ++ rc = cell->read_post_process(cell->priv, id, index, + cell->offset, buf, cell->bytes); + if (rc) + return rc; +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -20,7 +20,8 @@ typedef int (*nvmem_reg_write_t)(void *p + void *val, size_t bytes); + /* used for vendor specific post processing of cell data */ + typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, int index, +- unsigned int offset, void *buf, size_t bytes); ++ unsigned int offset, void *buf, ++ size_t bytes); + + enum nvmem_type { + NVMEM_TYPE_UNKNOWN = 0, +@@ -56,6 +57,7 @@ struct nvmem_keepout { + * @np: Optional device_node pointer. + * @read_post_process: Callback for optional post processing of cell data + * on reads. ++ * @priv: Opaque data passed to the read_post_process hook. + */ + struct nvmem_cell_info { + const char *name; +@@ -65,6 +67,7 @@ struct nvmem_cell_info { + unsigned int nbits; + struct device_node *np; + nvmem_cell_post_process_t read_post_process; ++ void *priv; + }; + + /** diff --git a/target/linux/generic/backport-6.1/811-v6.4-0010-nvmem-layouts-sl28vpd-Add-new-layout-driver.patch b/target/linux/generic/backport-6.1/811-v6.4-0010-nvmem-layouts-sl28vpd-Add-new-layout-driver.patch new file mode 100644 index 00000000000..7d97658b60e --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0010-nvmem-layouts-sl28vpd-Add-new-layout-driver.patch @@ -0,0 +1,215 @@ +From d9fae023fe86069750092fc1c2f3a73e2fb18512 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 4 Apr 2023 18:21:29 +0100 +Subject: [PATCH] nvmem: layouts: sl28vpd: Add new layout driver + +This layout applies to the VPD of the Kontron sl28 boards. The VPD only +contains a base MAC address. Therefore, we have to add an individual +offset to it. This is done by taking the second argument of the nvmem +phandle into account. Also this let us checking the VPD version and the +checksum. + +Signed-off-by: Michael Walle +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-22-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/Kconfig | 9 ++ + drivers/nvmem/layouts/Makefile | 2 + + drivers/nvmem/layouts/sl28vpd.c | 165 ++++++++++++++++++++++++++++++++ + 3 files changed, 176 insertions(+) + create mode 100644 drivers/nvmem/layouts/sl28vpd.c + +--- a/drivers/nvmem/layouts/Kconfig ++++ b/drivers/nvmem/layouts/Kconfig +@@ -2,4 +2,13 @@ + + menu "Layout Types" + ++config NVMEM_LAYOUT_SL28_VPD ++ tristate "Kontron sl28 VPD layout support" ++ select CRC8 ++ help ++ Say Y here if you want to support the VPD layout of the Kontron ++ SMARC-sAL28 boards. ++ ++ If unsure, say N. ++ + endmenu +--- a/drivers/nvmem/layouts/Makefile ++++ b/drivers/nvmem/layouts/Makefile +@@ -2,3 +2,5 @@ + # + # Makefile for nvmem layouts. + # ++ ++obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o +--- /dev/null ++++ b/drivers/nvmem/layouts/sl28vpd.c +@@ -0,0 +1,165 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SL28VPD_MAGIC 'V' ++ ++struct sl28vpd_header { ++ u8 magic; ++ u8 version; ++} __packed; ++ ++struct sl28vpd_v1 { ++ struct sl28vpd_header header; ++ char serial_number[15]; ++ u8 base_mac_address[ETH_ALEN]; ++ u8 crc8; ++} __packed; ++ ++static int sl28vpd_mac_address_pp(void *priv, const char *id, int index, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ if (bytes != ETH_ALEN) ++ return -EINVAL; ++ ++ if (index < 0) ++ return -EINVAL; ++ ++ if (!is_valid_ether_addr(buf)) ++ return -EINVAL; ++ ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static const struct nvmem_cell_info sl28vpd_v1_entries[] = { ++ { ++ .name = "serial-number", ++ .offset = offsetof(struct sl28vpd_v1, serial_number), ++ .bytes = sizeof_field(struct sl28vpd_v1, serial_number), ++ }, ++ { ++ .name = "base-mac-address", ++ .offset = offsetof(struct sl28vpd_v1, base_mac_address), ++ .bytes = sizeof_field(struct sl28vpd_v1, base_mac_address), ++ .read_post_process = sl28vpd_mac_address_pp, ++ }, ++}; ++ ++static int sl28vpd_v1_check_crc(struct device *dev, struct nvmem_device *nvmem) ++{ ++ struct sl28vpd_v1 data_v1; ++ u8 table[CRC8_TABLE_SIZE]; ++ int ret; ++ u8 crc; ++ ++ crc8_populate_msb(table, 0x07); ++ ++ ret = nvmem_device_read(nvmem, 0, sizeof(data_v1), &data_v1); ++ if (ret < 0) ++ return ret; ++ else if (ret != sizeof(data_v1)) ++ return -EIO; ++ ++ crc = crc8(table, (void *)&data_v1, sizeof(data_v1) - 1, 0); ++ ++ if (crc != data_v1.crc8) { ++ dev_err(dev, ++ "Checksum is invalid (got %02x, expected %02x).\n", ++ crc, data_v1.crc8); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem, ++ struct nvmem_layout *layout) ++{ ++ const struct nvmem_cell_info *pinfo; ++ struct nvmem_cell_info info = {0}; ++ struct device_node *layout_np; ++ struct sl28vpd_header hdr; ++ int ret, i; ++ ++ /* check header */ ++ ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); ++ if (ret < 0) ++ return ret; ++ else if (ret != sizeof(hdr)) ++ return -EIO; ++ ++ if (hdr.magic != SL28VPD_MAGIC) { ++ dev_err(dev, "Invalid magic value (%02x)\n", hdr.magic); ++ return -EINVAL; ++ } ++ ++ if (hdr.version != 1) { ++ dev_err(dev, "Version %d is unsupported.\n", hdr.version); ++ return -EINVAL; ++ } ++ ++ ret = sl28vpd_v1_check_crc(dev, nvmem); ++ if (ret) ++ return ret; ++ ++ layout_np = of_nvmem_layout_get_container(nvmem); ++ if (!layout_np) ++ return -ENOENT; ++ ++ for (i = 0; i < ARRAY_SIZE(sl28vpd_v1_entries); i++) { ++ pinfo = &sl28vpd_v1_entries[i]; ++ ++ info.name = pinfo->name; ++ info.offset = pinfo->offset; ++ info.bytes = pinfo->bytes; ++ info.read_post_process = pinfo->read_post_process; ++ info.np = of_get_child_by_name(layout_np, pinfo->name); ++ ++ ret = nvmem_add_one_cell(nvmem, &info); ++ if (ret) { ++ of_node_put(layout_np); ++ return ret; ++ } ++ } ++ ++ of_node_put(layout_np); ++ ++ return 0; ++} ++ ++static const struct of_device_id sl28vpd_of_match_table[] = { ++ { .compatible = "kontron,sl28-vpd" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table); ++ ++struct nvmem_layout sl28vpd_layout = { ++ .name = "sl28-vpd", ++ .of_match_table = sl28vpd_of_match_table, ++ .add_cells = sl28vpd_add_cells, ++}; ++ ++static int __init sl28vpd_init(void) ++{ ++ return nvmem_layout_register(&sl28vpd_layout); ++} ++ ++static void __exit sl28vpd_exit(void) ++{ ++ nvmem_layout_unregister(&sl28vpd_layout); ++} ++ ++module_init(sl28vpd_init); ++module_exit(sl28vpd_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Michael Walle "); ++MODULE_DESCRIPTION("NVMEM layout driver for the VPD of Kontron sl28 boards"); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0011-nvmem-layouts-onie-tlv-Add-new-layout-driver.patch b/target/linux/generic/backport-6.1/811-v6.4-0011-nvmem-layouts-onie-tlv-Add-new-layout-driver.patch new file mode 100644 index 00000000000..ca8b4bc0691 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0011-nvmem-layouts-onie-tlv-Add-new-layout-driver.patch @@ -0,0 +1,306 @@ +From d3c0d12f6474216bf386101e2449cc73e5c5b61d Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:31 +0100 +Subject: [PATCH] nvmem: layouts: onie-tlv: Add new layout driver + +This layout applies on top of any non volatile storage device containing +an ONIE table factory flashed. This table follows the tlv +(type-length-value) organization described in the link below. We cannot +afford using regular parsers because the content of these tables is +manufacturer specific and must be dynamically discovered. + +Link: https://opencomputeproject.github.io/onie/design-spec/hw_requirements.html +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-24-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/Kconfig | 9 ++ + drivers/nvmem/layouts/Makefile | 1 + + drivers/nvmem/layouts/onie-tlv.c | 257 +++++++++++++++++++++++++++++++ + 3 files changed, 267 insertions(+) + create mode 100644 drivers/nvmem/layouts/onie-tlv.c + +--- a/drivers/nvmem/layouts/Kconfig ++++ b/drivers/nvmem/layouts/Kconfig +@@ -11,4 +11,13 @@ config NVMEM_LAYOUT_SL28_VPD + + If unsure, say N. + ++config NVMEM_LAYOUT_ONIE_TLV ++ tristate "ONIE tlv support" ++ select CRC32 ++ help ++ Say Y here if you want to support the Open Compute Project ONIE ++ Type-Length-Value standard table. ++ ++ If unsure, say N. ++ + endmenu +--- a/drivers/nvmem/layouts/Makefile ++++ b/drivers/nvmem/layouts/Makefile +@@ -4,3 +4,4 @@ + # + + obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o ++obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o +--- /dev/null ++++ b/drivers/nvmem/layouts/onie-tlv.c +@@ -0,0 +1,257 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * ONIE tlv NVMEM cells provider ++ * ++ * Copyright (C) 2022 Open Compute Group ONIE ++ * Author: Miquel Raynal ++ * Based on the nvmem driver written by: Vadym Kochan ++ * Inspired by the first layout written by: Rafał Miłecki ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define ONIE_TLV_MAX_LEN 2048 ++#define ONIE_TLV_CRC_FIELD_SZ 6 ++#define ONIE_TLV_CRC_SZ 4 ++#define ONIE_TLV_HDR_ID "TlvInfo" ++ ++struct onie_tlv_hdr { ++ u8 id[8]; ++ u8 version; ++ __be16 data_len; ++} __packed; ++ ++struct onie_tlv { ++ u8 type; ++ u8 len; ++} __packed; ++ ++static const char *onie_tlv_cell_name(u8 type) ++{ ++ switch (type) { ++ case 0x21: ++ return "product-name"; ++ case 0x22: ++ return "part-number"; ++ case 0x23: ++ return "serial-number"; ++ case 0x24: ++ return "mac-address"; ++ case 0x25: ++ return "manufacture-date"; ++ case 0x26: ++ return "device-version"; ++ case 0x27: ++ return "label-revision"; ++ case 0x28: ++ return "platform-name"; ++ case 0x29: ++ return "onie-version"; ++ case 0x2A: ++ return "num-macs"; ++ case 0x2B: ++ return "manufacturer"; ++ case 0x2C: ++ return "country-code"; ++ case 0x2D: ++ return "vendor"; ++ case 0x2E: ++ return "diag-version"; ++ case 0x2F: ++ return "service-tag"; ++ case 0xFD: ++ return "vendor-extension"; ++ case 0xFE: ++ return "crc32"; ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++static int onie_tlv_mac_read_cb(void *priv, const char *id, int index, ++ unsigned int offset, void *buf, ++ size_t bytes) ++{ ++ eth_addr_add(buf, index); ++ ++ return 0; ++} ++ ++static nvmem_cell_post_process_t onie_tlv_read_cb(u8 type, u8 *buf) ++{ ++ switch (type) { ++ case 0x24: ++ return &onie_tlv_mac_read_cb; ++ default: ++ break; ++ } ++ ++ return NULL; ++} ++ ++static int onie_tlv_add_cells(struct device *dev, struct nvmem_device *nvmem, ++ size_t data_len, u8 *data) ++{ ++ struct nvmem_cell_info cell = {}; ++ struct device_node *layout; ++ struct onie_tlv tlv; ++ unsigned int hdr_len = sizeof(struct onie_tlv_hdr); ++ unsigned int offset = 0; ++ int ret; ++ ++ layout = of_nvmem_layout_get_container(nvmem); ++ if (!layout) ++ return -ENOENT; ++ ++ while (offset < data_len) { ++ memcpy(&tlv, data + offset, sizeof(tlv)); ++ if (offset + tlv.len >= data_len) { ++ dev_err(dev, "Out of bounds field (0x%x bytes at 0x%x)\n", ++ tlv.len, hdr_len + offset); ++ break; ++ } ++ ++ cell.name = onie_tlv_cell_name(tlv.type); ++ if (!cell.name) ++ continue; ++ ++ cell.offset = hdr_len + offset + sizeof(tlv.type) + sizeof(tlv.len); ++ cell.bytes = tlv.len; ++ cell.np = of_get_child_by_name(layout, cell.name); ++ cell.read_post_process = onie_tlv_read_cb(tlv.type, data + offset + sizeof(tlv)); ++ ++ ret = nvmem_add_one_cell(nvmem, &cell); ++ if (ret) { ++ of_node_put(layout); ++ return ret; ++ } ++ ++ offset += sizeof(tlv) + tlv.len; ++ } ++ ++ of_node_put(layout); ++ ++ return 0; ++} ++ ++static bool onie_tlv_hdr_is_valid(struct device *dev, struct onie_tlv_hdr *hdr) ++{ ++ if (memcmp(hdr->id, ONIE_TLV_HDR_ID, sizeof(hdr->id))) { ++ dev_err(dev, "Invalid header\n"); ++ return false; ++ } ++ ++ if (hdr->version != 0x1) { ++ dev_err(dev, "Invalid version number\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool onie_tlv_crc_is_valid(struct device *dev, size_t table_len, u8 *table) ++{ ++ struct onie_tlv crc_hdr; ++ u32 read_crc, calc_crc; ++ __be32 crc_be; ++ ++ memcpy(&crc_hdr, table + table_len - ONIE_TLV_CRC_FIELD_SZ, sizeof(crc_hdr)); ++ if (crc_hdr.type != 0xfe || crc_hdr.len != ONIE_TLV_CRC_SZ) { ++ dev_err(dev, "Invalid CRC field\n"); ++ return false; ++ } ++ ++ /* The table contains a JAMCRC, which is XOR'ed compared to the original ++ * CRC32 implementation as known in the Ethernet world. ++ */ ++ memcpy(&crc_be, table + table_len - ONIE_TLV_CRC_SZ, ONIE_TLV_CRC_SZ); ++ read_crc = be32_to_cpu(crc_be); ++ calc_crc = crc32(~0, table, table_len - ONIE_TLV_CRC_SZ) ^ 0xFFFFFFFF; ++ if (read_crc != calc_crc) { ++ dev_err(dev, "Invalid CRC read: 0x%08x, expected: 0x%08x\n", ++ read_crc, calc_crc); ++ return false; ++ } ++ ++ return true; ++} ++ ++static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem, ++ struct nvmem_layout *layout) ++{ ++ struct onie_tlv_hdr hdr; ++ size_t table_len, data_len, hdr_len; ++ u8 *table, *data; ++ int ret; ++ ++ ret = nvmem_device_read(nvmem, 0, sizeof(hdr), &hdr); ++ if (ret < 0) ++ return ret; ++ ++ if (!onie_tlv_hdr_is_valid(dev, &hdr)) { ++ dev_err(dev, "Invalid ONIE TLV header\n"); ++ return -EINVAL; ++ } ++ ++ hdr_len = sizeof(hdr.id) + sizeof(hdr.version) + sizeof(hdr.data_len); ++ data_len = be16_to_cpu(hdr.data_len); ++ table_len = hdr_len + data_len; ++ if (table_len > ONIE_TLV_MAX_LEN) { ++ dev_err(dev, "Invalid ONIE TLV data length\n"); ++ return -EINVAL; ++ } ++ ++ table = devm_kmalloc(dev, table_len, GFP_KERNEL); ++ if (!table) ++ return -ENOMEM; ++ ++ ret = nvmem_device_read(nvmem, 0, table_len, table); ++ if (ret != table_len) ++ return ret; ++ ++ if (!onie_tlv_crc_is_valid(dev, table_len, table)) ++ return -EINVAL; ++ ++ data = table + hdr_len; ++ ret = onie_tlv_add_cells(dev, nvmem, data_len, data); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct of_device_id onie_tlv_of_match_table[] = { ++ { .compatible = "onie,tlv-layout", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, onie_tlv_of_match_table); ++ ++static struct nvmem_layout onie_tlv_layout = { ++ .name = "ONIE tlv layout", ++ .of_match_table = onie_tlv_of_match_table, ++ .add_cells = onie_tlv_parse_table, ++}; ++ ++static int __init onie_tlv_init(void) ++{ ++ return nvmem_layout_register(&onie_tlv_layout); ++} ++ ++static void __exit onie_tlv_exit(void) ++{ ++ nvmem_layout_unregister(&onie_tlv_layout); ++} ++ ++module_init(onie_tlv_init); ++module_exit(onie_tlv_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Miquel Raynal "); ++MODULE_DESCRIPTION("NVMEM layout driver for Onie TLV table parsing"); ++MODULE_ALIAS("NVMEM layout driver for Onie TLV table parsing"); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0012-nvmem-stm32-romem-mark-OF-related-data-as-maybe-unus.patch b/target/linux/generic/backport-6.1/811-v6.4-0012-nvmem-stm32-romem-mark-OF-related-data-as-maybe-unus.patch new file mode 100644 index 00000000000..94a0911d73c --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0012-nvmem-stm32-romem-mark-OF-related-data-as-maybe-unus.patch @@ -0,0 +1,32 @@ +From a4fb434ef96ace5af758ca2c52c3a3f8f3abc87c Mon Sep 17 00:00:00 2001 +From: Krzysztof Kozlowski +Date: Tue, 4 Apr 2023 18:21:34 +0100 +Subject: [PATCH] nvmem: stm32-romem: mark OF related data as maybe unused +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The driver can be compile tested with !CONFIG_OF making certain data +unused: + + drivers/nvmem/stm32-romem.c:271:34: error: ‘stm32_romem_of_match’ defined but not used [-Werror=unused-const-variable=] + +Signed-off-by: Krzysztof Kozlowski +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-27-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/stm32-romem.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -268,7 +268,7 @@ static const struct stm32_romem_cfg stm3 + .ta = true, + }; + +-static const struct of_device_id stm32_romem_of_match[] = { ++static const struct of_device_id stm32_romem_of_match[] __maybe_unused = { + { .compatible = "st,stm32f4-otp", }, { + .compatible = "st,stm32mp15-bsec", + .data = (void *)&stm32mp15_bsec_cfg, diff --git a/target/linux/generic/backport-6.1/811-v6.4-0013-nvmem-mtk-efuse-Support-postprocessing-for-GPU-speed.patch b/target/linux/generic/backport-6.1/811-v6.4-0013-nvmem-mtk-efuse-Support-postprocessing-for-GPU-speed.patch new file mode 100644 index 00000000000..abda402bddb --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0013-nvmem-mtk-efuse-Support-postprocessing-for-GPU-speed.patch @@ -0,0 +1,120 @@ +From de6e05097f7db066afb0ad4c88b730949f7b7749 Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Tue, 4 Apr 2023 18:21:35 +0100 +Subject: [PATCH] nvmem: mtk-efuse: Support postprocessing for GPU speed + binning data + +On some MediaTek SoCs GPU speed binning data is available for read +in the SoC's eFuse array but it has a format that is incompatible +with what the OPP API expects, as we read a number from 0 to 7 but +opp-supported-hw is expecting a bitmask to enable an OPP entry: +being what we read limited to 0-7, it's straightforward to simply +convert the value to BIT(value) as a post-processing action. + +So, introduce post-processing support and enable it by evaluating +the newly introduced platform data's `uses_post_processing` member, +currently enabled only for MT8186. + +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-28-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/mtk-efuse.c | 53 +++++++++++++++++++++++++++++++++++++-- + 1 file changed, 51 insertions(+), 2 deletions(-) + +--- a/drivers/nvmem/mtk-efuse.c ++++ b/drivers/nvmem/mtk-efuse.c +@@ -10,6 +10,11 @@ + #include + #include + #include ++#include ++ ++struct mtk_efuse_pdata { ++ bool uses_post_processing; ++}; + + struct mtk_efuse_priv { + void __iomem *base; +@@ -29,6 +34,37 @@ static int mtk_reg_read(void *context, + return 0; + } + ++static int mtk_efuse_gpu_speedbin_pp(void *context, const char *id, int index, ++ unsigned int offset, void *data, size_t bytes) ++{ ++ u8 *val = data; ++ ++ if (val[0] < 8) ++ val[0] = BIT(val[0]); ++ ++ return 0; ++} ++ ++static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem, ++ struct nvmem_layout *layout, ++ struct nvmem_cell_info *cell) ++{ ++ size_t sz = strlen(cell->name); ++ ++ /* ++ * On some SoCs, the GPU speedbin is not read as bitmask but as ++ * a number with range [0-7] (max 3 bits): post process to use ++ * it in OPP tables to describe supported-hw. ++ */ ++ if (cell->nbits <= 3 && ++ strncmp(cell->name, "gpu-speedbin", min(sz, strlen("gpu-speedbin"))) == 0) ++ cell->read_post_process = mtk_efuse_gpu_speedbin_pp; ++} ++ ++static struct nvmem_layout mtk_efuse_layout = { ++ .fixup_cell_info = mtk_efuse_fixup_cell_info, ++}; ++ + static int mtk_efuse_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -36,6 +72,7 @@ static int mtk_efuse_probe(struct platfo + struct nvmem_device *nvmem; + struct nvmem_config econfig = {}; + struct mtk_efuse_priv *priv; ++ const struct mtk_efuse_pdata *pdata; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -45,20 +82,32 @@ static int mtk_efuse_probe(struct platfo + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + ++ pdata = device_get_match_data(dev); + econfig.stride = 1; + econfig.word_size = 1; + econfig.reg_read = mtk_reg_read; + econfig.size = resource_size(res); + econfig.priv = priv; + econfig.dev = dev; ++ if (pdata->uses_post_processing) ++ econfig.layout = &mtk_efuse_layout; + nvmem = devm_nvmem_register(dev, &econfig); + + return PTR_ERR_OR_ZERO(nvmem); + } + ++static const struct mtk_efuse_pdata mtk_mt8186_efuse_pdata = { ++ .uses_post_processing = true, ++}; ++ ++static const struct mtk_efuse_pdata mtk_efuse_pdata = { ++ .uses_post_processing = false, ++}; ++ + static const struct of_device_id mtk_efuse_of_match[] = { +- { .compatible = "mediatek,mt8173-efuse",}, +- { .compatible = "mediatek,efuse",}, ++ { .compatible = "mediatek,mt8173-efuse", .data = &mtk_efuse_pdata }, ++ { .compatible = "mediatek,mt8186-efuse", .data = &mtk_mt8186_efuse_pdata }, ++ { .compatible = "mediatek,efuse", .data = &mtk_efuse_pdata }, + {/* sentinel */}, + }; + MODULE_DEVICE_TABLE(of, mtk_efuse_of_match); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch b/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch new file mode 100644 index 00000000000..a0874f73d15 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch @@ -0,0 +1,39 @@ +From 1dc552fa33cf98af3e784dbc0500da93cae3b24a Mon Sep 17 00:00:00 2001 +From: Yang Li +Date: Tue, 4 Apr 2023 18:21:38 +0100 +Subject: [PATCH] nvmem: bcm-ocotp: Use devm_platform_ioremap_resource() + +According to commit 7945f929f1a7 ("drivers: provide +devm_platform_ioremap_resource()"), convert platform_get_resource(), +devm_ioremap_resource() to a single call to use +devm_platform_ioremap_resource(), as this is exactly what this function +does. + +Signed-off-by: Yang Li +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-31-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/bcm-ocotp.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/nvmem/bcm-ocotp.c ++++ b/drivers/nvmem/bcm-ocotp.c +@@ -254,7 +254,6 @@ MODULE_DEVICE_TABLE(acpi, bcm_otpc_acpi_ + static int bcm_otpc_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +- struct resource *res; + struct otpc_priv *priv; + struct nvmem_device *nvmem; + int err; +@@ -269,8 +268,7 @@ static int bcm_otpc_probe(struct platfor + return -ENODEV; + + /* Get OTP base address register. */ +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- priv->base = devm_ioremap_resource(dev, res); ++ priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) { + dev_err(dev, "unable to map I/O memory\n"); + return PTR_ERR(priv->base); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0015-nvmem-nintendo-otp-Use-devm_platform_ioremap_resourc.patch b/target/linux/generic/backport-6.1/811-v6.4-0015-nvmem-nintendo-otp-Use-devm_platform_ioremap_resourc.patch new file mode 100644 index 00000000000..890dacd08db --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0015-nvmem-nintendo-otp-Use-devm_platform_ioremap_resourc.patch @@ -0,0 +1,39 @@ +From 649409990d2e93fac657be7c6960c28a2c601d65 Mon Sep 17 00:00:00 2001 +From: Yang Li +Date: Tue, 4 Apr 2023 18:21:39 +0100 +Subject: [PATCH] nvmem: nintendo-otp: Use devm_platform_ioremap_resource() + +According to commit 7945f929f1a7 ("drivers: provide +devm_platform_ioremap_resource()"), convert platform_get_resource(), +devm_ioremap_resource() to a single call to use +devm_platform_ioremap_resource(), as this is exactly what this function +does. + +Signed-off-by: Yang Li +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-32-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/nintendo-otp.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/nvmem/nintendo-otp.c ++++ b/drivers/nvmem/nintendo-otp.c +@@ -76,7 +76,6 @@ static int nintendo_otp_probe(struct pla + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = + of_match_device(nintendo_otp_of_table, dev); +- struct resource *res; + struct nvmem_device *nvmem; + struct nintendo_otp_priv *priv; + +@@ -92,8 +91,7 @@ static int nintendo_otp_probe(struct pla + if (!priv) + return -ENOMEM; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- priv->regs = devm_ioremap_resource(dev, res); ++ priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + diff --git a/target/linux/generic/backport-6.1/811-v6.4-0016-nvmem-vf610-ocotp-Use-devm_platform_get_and_ioremap_.patch b/target/linux/generic/backport-6.1/811-v6.4-0016-nvmem-vf610-ocotp-Use-devm_platform_get_and_ioremap_.patch new file mode 100644 index 00000000000..3f5d3c1ad4c --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0016-nvmem-vf610-ocotp-Use-devm_platform_get_and_ioremap_.patch @@ -0,0 +1,32 @@ +From c2367aa60d5e34d48582362c6de34b4131d92be7 Mon Sep 17 00:00:00 2001 +From: Yang Li +Date: Tue, 4 Apr 2023 18:21:40 +0100 +Subject: [PATCH] nvmem: vf610-ocotp: Use + devm_platform_get_and_ioremap_resource() + +According to commit 890cc39a8799 ("drivers: provide +devm_platform_get_and_ioremap_resource()"), convert +platform_get_resource(), devm_ioremap_resource() to a single +call to devm_platform_get_and_ioremap_resource(), as this is exactly +what this function does. + +Signed-off-by: Yang Li +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-33-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/vf610-ocotp.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/nvmem/vf610-ocotp.c ++++ b/drivers/nvmem/vf610-ocotp.c +@@ -219,8 +219,7 @@ static int vf610_ocotp_probe(struct plat + if (!ocotp_dev) + return -ENOMEM; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- ocotp_dev->base = devm_ioremap_resource(dev, res); ++ ocotp_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(ocotp_dev->base)) + return PTR_ERR(ocotp_dev->base); + diff --git a/target/linux/generic/backport-6.1/811-v6.4-0017-nvmem-core-support-specifying-both-cell-raw-data-pos.patch b/target/linux/generic/backport-6.1/811-v6.4-0017-nvmem-core-support-specifying-both-cell-raw-data-pos.patch new file mode 100644 index 00000000000..eeb407e9bb6 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0017-nvmem-core-support-specifying-both-cell-raw-data-pos.patch @@ -0,0 +1,115 @@ +From 55d4980ce55b6bb4be66877de4dbec513911b988 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 4 Apr 2023 18:21:42 +0100 +Subject: [PATCH] nvmem: core: support specifying both: cell raw data & post + read lengths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Callback .read_post_process() is designed to modify raw cell content +before providing it to the consumer. So far we were dealing with +modifications that didn't affect cell size (length). In some cases +however cell content needs to be reformatted and resized. + +It's required e.g. to provide properly formatted MAC address in case +it's stored in a non-binary format (e.g. using ASCII). + +There were few discussions how to optimally handle that. Following +possible solutions were considered: +1. Allow .read_post_process() to realloc (resize) content buffer +2. Allow .read_post_process() to adjust (decrease) just buffer length +3. Register NVMEM cells using post-read sizes + +The preferred solution was the last one. The problem is that simply +adjusting "bytes" in NVMEM providers would result in core code NOT +passing whole raw data to .read_post_process() callbacks. It means +callback functions couldn't do their job without somehow manually +reading original cell content on their own. + +This patch deals with that by registering NVMEM cells with both lengths: +raw content one and post read one. It allows: +1. Core code to read whole raw cell content +2. Callbacks to return content they want + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-35-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/core.c | 11 +++++++---- + include/linux/nvmem-provider.h | 2 ++ + 2 files changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/nvmem/core.c ++++ b/drivers/nvmem/core.c +@@ -50,6 +50,7 @@ struct nvmem_device { + struct nvmem_cell_entry { + const char *name; + int offset; ++ size_t raw_len; + int bytes; + int bit_offset; + int nbits; +@@ -469,6 +470,7 @@ static int nvmem_cell_info_to_nvmem_cell + { + cell->nvmem = nvmem; + cell->offset = info->offset; ++ cell->raw_len = info->raw_len ?: info->bytes; + cell->bytes = info->bytes; + cell->name = info->name; + cell->read_post_process = info->read_post_process; +@@ -1560,7 +1562,7 @@ static int __nvmem_cell_read(struct nvme + { + int rc; + +- rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->bytes); ++ rc = nvmem_reg_read(nvmem, cell->offset, buf, cell->raw_len); + + if (rc) + return rc; +@@ -1571,7 +1573,7 @@ static int __nvmem_cell_read(struct nvme + + if (cell->read_post_process) { + rc = cell->read_post_process(cell->priv, id, index, +- cell->offset, buf, cell->bytes); ++ cell->offset, buf, cell->raw_len); + if (rc) + return rc; + } +@@ -1594,14 +1596,15 @@ static int __nvmem_cell_read(struct nvme + */ + void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) + { +- struct nvmem_device *nvmem = cell->entry->nvmem; ++ struct nvmem_cell_entry *entry = cell->entry; ++ struct nvmem_device *nvmem = entry->nvmem; + u8 *buf; + int rc; + + if (!nvmem) + return ERR_PTR(-EINVAL); + +- buf = kzalloc(cell->entry->bytes, GFP_KERNEL); ++ buf = kzalloc(max_t(size_t, entry->raw_len, entry->bytes), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -51,6 +51,7 @@ struct nvmem_keepout { + * struct nvmem_cell_info - NVMEM cell description + * @name: Name. + * @offset: Offset within the NVMEM device. ++ * @raw_len: Length of raw data (without post processing). + * @bytes: Length of the cell. + * @bit_offset: Bit offset if cell is smaller than a byte. + * @nbits: Number of bits. +@@ -62,6 +63,7 @@ struct nvmem_keepout { + struct nvmem_cell_info { + const char *name; + unsigned int offset; ++ size_t raw_len; + unsigned int bytes; + unsigned int bit_offset; + unsigned int nbits; diff --git a/target/linux/generic/backport-6.1/811-v6.4-0018-nvmem-u-boot-env-post-process-ethaddr-env-variable.patch b/target/linux/generic/backport-6.1/811-v6.4-0018-nvmem-u-boot-env-post-process-ethaddr-env-variable.patch new file mode 100644 index 00000000000..adde0ffc4b1 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0018-nvmem-u-boot-env-post-process-ethaddr-env-variable.patch @@ -0,0 +1,81 @@ +From c49f1a8af6bcf6d18576bca898f8083ca4b129e1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 4 Apr 2023 18:21:43 +0100 +Subject: [PATCH] nvmem: u-boot-env: post-process "ethaddr" env variable +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +U-Boot environment variables are stored in ASCII format so "ethaddr" +requires parsing into binary to make it work with Ethernet interfaces. + +This includes support for indexes to support #nvmem-cell-cells = <1>. + +Signed-off-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-36-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/Kconfig | 1 + + drivers/nvmem/u-boot-env.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 27 insertions(+) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -340,6 +340,7 @@ config NVMEM_U_BOOT_ENV + tristate "U-Boot environment variables support" + depends on OF && MTD + select CRC32 ++ select GENERIC_NET_UTILS + help + U-Boot stores its setup as environment variables. This driver adds + support for verifying & exporting such data. It also exposes variables +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -4,6 +4,8 @@ + */ + + #include ++#include ++#include + #include + #include + #include +@@ -70,6 +72,25 @@ static int u_boot_env_read(void *context + return 0; + } + ++static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, int index, ++ unsigned int offset, void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (bytes != 3 * ETH_ALEN - 1) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ + static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf, + size_t data_offset, size_t data_len) + { +@@ -101,6 +122,11 @@ static int u_boot_env_add_cells(struct u + priv->cells[idx].offset = data_offset + value - data; + priv->cells[idx].bytes = strlen(value); + priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); ++ if (!strcmp(var, "ethaddr")) { ++ priv->cells[idx].raw_len = strlen(value); ++ priv->cells[idx].bytes = ETH_ALEN; ++ priv->cells[idx].read_post_process = u_boot_env_read_post_process_ethaddr; ++ } + } + + if (WARN_ON(idx != priv->ncells)) diff --git a/target/linux/generic/backport-6.1/811-v6.4-0019-nvmem-Add-macro-to-register-nvmem-layout-drivers.patch b/target/linux/generic/backport-6.1/811-v6.4-0019-nvmem-Add-macro-to-register-nvmem-layout-drivers.patch new file mode 100644 index 00000000000..7c6fe22b5f3 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0019-nvmem-Add-macro-to-register-nvmem-layout-drivers.patch @@ -0,0 +1,42 @@ +From 814c978f02db17f16e6aa2efa2a929372f06da09 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:44 +0100 +Subject: [PATCH] nvmem: Add macro to register nvmem layout drivers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Provide a module_nvmem_layout_driver() macro at the end of the +nvmem-provider.h header to reduce the boilerplate when registering nvmem +layout drivers. + +Suggested-by: Srinivas Kandagatla +Signed-off-by: Miquel Raynal +Acked-by: Rafał Miłecki +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-37-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/nvmem-provider.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/include/linux/nvmem-provider.h ++++ b/include/linux/nvmem-provider.h +@@ -9,6 +9,7 @@ + #ifndef _LINUX_NVMEM_PROVIDER_H + #define _LINUX_NVMEM_PROVIDER_H + ++#include + #include + #include + #include +@@ -242,4 +243,9 @@ nvmem_layout_get_match_data(struct nvmem + } + + #endif /* CONFIG_NVMEM */ ++ ++#define module_nvmem_layout_driver(__layout_driver) \ ++ module_driver(__layout_driver, nvmem_layout_register, \ ++ nvmem_layout_unregister) ++ + #endif /* ifndef _LINUX_NVMEM_PROVIDER_H */ diff --git a/target/linux/generic/backport-6.1/811-v6.4-0020-nvmem-layouts-sl28vpd-Use-module_nvmem_layout_driver.patch b/target/linux/generic/backport-6.1/811-v6.4-0020-nvmem-layouts-sl28vpd-Use-module_nvmem_layout_driver.patch new file mode 100644 index 00000000000..06646dd68bf --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0020-nvmem-layouts-sl28vpd-Use-module_nvmem_layout_driver.patch @@ -0,0 +1,39 @@ +From 0abdf99fe0c86252ba274703425f8d543d7e7f0d Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:45 +0100 +Subject: [PATCH] nvmem: layouts: sl28vpd: Use module_nvmem_layout_driver() + +Stop open-coding the module init/exit functions. Use the +module_nvmem_layout_driver() instead. + +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-38-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/sl28vpd.c | 14 +------------- + 1 file changed, 1 insertion(+), 13 deletions(-) + +--- a/drivers/nvmem/layouts/sl28vpd.c ++++ b/drivers/nvmem/layouts/sl28vpd.c +@@ -146,19 +146,7 @@ struct nvmem_layout sl28vpd_layout = { + .of_match_table = sl28vpd_of_match_table, + .add_cells = sl28vpd_add_cells, + }; +- +-static int __init sl28vpd_init(void) +-{ +- return nvmem_layout_register(&sl28vpd_layout); +-} +- +-static void __exit sl28vpd_exit(void) +-{ +- nvmem_layout_unregister(&sl28vpd_layout); +-} +- +-module_init(sl28vpd_init); +-module_exit(sl28vpd_exit); ++module_nvmem_layout_driver(sl28vpd_layout); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Michael Walle "); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0021-nvmem-layouts-onie-tlv-Use-module_nvmem_layout_drive.patch b/target/linux/generic/backport-6.1/811-v6.4-0021-nvmem-layouts-onie-tlv-Use-module_nvmem_layout_drive.patch new file mode 100644 index 00000000000..826f4378c2f --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0021-nvmem-layouts-onie-tlv-Use-module_nvmem_layout_drive.patch @@ -0,0 +1,39 @@ +From d119eb38faab61125aaa4f63c74eef61585cf34c Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:46 +0100 +Subject: [PATCH] nvmem: layouts: onie-tlv: Use module_nvmem_layout_driver() + +Stop open-coding the module init/exit functions. Use the +module_nvmem_layout_driver() instead. + +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-39-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/onie-tlv.c | 14 +------------- + 1 file changed, 1 insertion(+), 13 deletions(-) + +--- a/drivers/nvmem/layouts/onie-tlv.c ++++ b/drivers/nvmem/layouts/onie-tlv.c +@@ -237,19 +237,7 @@ static struct nvmem_layout onie_tlv_layo + .of_match_table = onie_tlv_of_match_table, + .add_cells = onie_tlv_parse_table, + }; +- +-static int __init onie_tlv_init(void) +-{ +- return nvmem_layout_register(&onie_tlv_layout); +-} +- +-static void __exit onie_tlv_exit(void) +-{ +- nvmem_layout_unregister(&onie_tlv_layout); +-} +- +-module_init(onie_tlv_init); +-module_exit(onie_tlv_exit); ++module_nvmem_layout_driver(onie_tlv_layout); + + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Miquel Raynal "); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0022-nvmem-layouts-onie-tlv-Drop-wrong-module-alias.patch b/target/linux/generic/backport-6.1/811-v6.4-0022-nvmem-layouts-onie-tlv-Drop-wrong-module-alias.patch new file mode 100644 index 00000000000..f20db85ceb6 --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0022-nvmem-layouts-onie-tlv-Drop-wrong-module-alias.patch @@ -0,0 +1,24 @@ +From 6b13e4b6a9a45028ac730e550380077df1845912 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:47 +0100 +Subject: [PATCH] nvmem: layouts: onie-tlv: Drop wrong module alias + +The MODULE_ALIAS macro is misused here as it carries the +description. There is currently no relevant alias to provide so let's +just drop it. + +Signed-off-by: Miquel Raynal +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-40-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/onie-tlv.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/nvmem/layouts/onie-tlv.c ++++ b/drivers/nvmem/layouts/onie-tlv.c +@@ -242,4 +242,3 @@ module_nvmem_layout_driver(onie_tlv_layo + MODULE_LICENSE("GPL"); + MODULE_AUTHOR("Miquel Raynal "); + MODULE_DESCRIPTION("NVMEM layout driver for Onie TLV table parsing"); +-MODULE_ALIAS("NVMEM layout driver for Onie TLV table parsing"); diff --git a/target/linux/generic/backport-6.1/811-v6.4-0023-nvmem-layouts-sl28vpd-set-varaiable-sl28vpd_layout-s.patch b/target/linux/generic/backport-6.1/811-v6.4-0023-nvmem-layouts-sl28vpd-set-varaiable-sl28vpd_layout-s.patch new file mode 100644 index 00000000000..5cf847b57ae --- /dev/null +++ b/target/linux/generic/backport-6.1/811-v6.4-0023-nvmem-layouts-sl28vpd-set-varaiable-sl28vpd_layout-s.patch @@ -0,0 +1,31 @@ +From a8642cd11635a35a5f1dc31857887900d6610778 Mon Sep 17 00:00:00 2001 +From: Tom Rix +Date: Tue, 4 Apr 2023 18:21:48 +0100 +Subject: [PATCH] nvmem: layouts: sl28vpd: set varaiable sl28vpd_layout + storage-class-specifier to static + +smatch reports +drivers/nvmem/layouts/sl28vpd.c:144:21: warning: symbol + 'sl28vpd_layout' was not declared. Should it be static? + +This variable is only used in one file so it should be static. + +Signed-off-by: Tom Rix +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-41-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/nvmem/layouts/sl28vpd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/layouts/sl28vpd.c ++++ b/drivers/nvmem/layouts/sl28vpd.c +@@ -141,7 +141,7 @@ static const struct of_device_id sl28vpd + }; + MODULE_DEVICE_TABLE(of, sl28vpd_of_match_table); + +-struct nvmem_layout sl28vpd_layout = { ++static struct nvmem_layout sl28vpd_layout = { + .name = "sl28-vpd", + .of_match_table = sl28vpd_of_match_table, + .add_cells = sl28vpd_add_cells, diff --git a/target/linux/generic/backport-6.1/812-v6.2-firmware-nvram-bcm47xx-support-init-from-IO-memory.patch b/target/linux/generic/backport-6.1/812-v6.2-firmware-nvram-bcm47xx-support-init-from-IO-memory.patch new file mode 100644 index 00000000000..13ee2d42293 --- /dev/null +++ b/target/linux/generic/backport-6.1/812-v6.2-firmware-nvram-bcm47xx-support-init-from-IO-memory.patch @@ -0,0 +1,100 @@ +From a5be5ce0e25439fae3cd42e3d775979547926812 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 3 Nov 2022 09:25:29 +0100 +Subject: [PATCH] firmware/nvram: bcm47xx: support init from IO memory +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Provide NVMEM content to the NVRAM driver from a simple +memory resource. This is necessary to use NVRAM in a memory- +mapped flash device. Patch taken from OpenWrts development +tree. + +This patch makes it possible to use memory-mapped NVRAM +on the D-Link DWL-8610AP and the D-Link DIR-890L. + +Cc: Hauke Mehrtens +Cc: linux-mips@vger.kernel.org +Cc: Florian Fainelli +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: Thomas Bogendoerfer +Signed-off-by: Rafał Miłecki +[Added an export for modules potentially using the init symbol] +Signed-off-by: Linus Walleij +Link: https://lore.kernel.org/r/20221103082529.359084-1-linus.walleij@linaro.org +Signed-off-by: Florian Fainelli +--- + drivers/firmware/broadcom/bcm47xx_nvram.c | 18 ++++++++++++++++++ + drivers/nvmem/brcm_nvram.c | 3 +++ + include/linux/bcm47xx_nvram.h | 6 ++++++ + 3 files changed, 27 insertions(+) + +--- a/drivers/firmware/broadcom/bcm47xx_nvram.c ++++ b/drivers/firmware/broadcom/bcm47xx_nvram.c +@@ -110,6 +110,24 @@ found: + return 0; + } + ++int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size) ++{ ++ if (nvram_len) { ++ pr_warn("nvram already initialized\n"); ++ return -EEXIST; ++ } ++ ++ if (!bcm47xx_nvram_is_valid(nvram_start)) { ++ pr_err("No valid NVRAM found\n"); ++ return -ENOENT; ++ } ++ ++ bcm47xx_nvram_copy(nvram_start, res_size); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(bcm47xx_nvram_init_from_iomem); ++ + /* + * On bcm47xx we need access to the NVRAM very early, so we can't use mtd + * subsystem to access flash. We can't even use platform device / driver to +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -3,6 +3,7 @@ + * Copyright (C) 2021 Rafał Miłecki + */ + ++#include + #include + #include + #include +@@ -139,6 +140,8 @@ static int brcm_nvram_probe(struct platf + if (err) + return err; + ++ bcm47xx_nvram_init_from_iomem(priv->base, resource_size(res)); ++ + config.dev = dev; + config.cells = priv->cells; + config.ncells = priv->ncells; +--- a/include/linux/bcm47xx_nvram.h ++++ b/include/linux/bcm47xx_nvram.h +@@ -11,6 +11,7 @@ + #include + + #ifdef CONFIG_BCM47XX_NVRAM ++int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, size_t res_size); + int bcm47xx_nvram_init_from_mem(u32 base, u32 lim); + int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len); + int bcm47xx_nvram_gpio_pin(const char *name); +@@ -20,6 +21,11 @@ static inline void bcm47xx_nvram_release + vfree(nvram); + }; + #else ++static inline int bcm47xx_nvram_init_from_iomem(void __iomem *nvram_start, ++ size_t res_size) ++{ ++ return -ENOTSUPP; ++} + static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim) + { + return -ENOTSUPP; diff --git a/target/linux/generic/backport-6.1/813-v6.5-nvmem-brcm_nvram-add-.read_post_process-for-MACs.patch b/target/linux/generic/backport-6.1/813-v6.5-nvmem-brcm_nvram-add-.read_post_process-for-MACs.patch new file mode 100644 index 00000000000..8749cad7f77 --- /dev/null +++ b/target/linux/generic/backport-6.1/813-v6.5-nvmem-brcm_nvram-add-.read_post_process-for-MACs.patch @@ -0,0 +1,77 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Thu, 6 Apr 2023 12:46:16 +0200 +Subject: [PATCH] nvmem: brcm_nvram: add .read_post_process() for MACs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +1. Parse ASCII MAC format into byte based +2. Calculate relative addresses based on index argument + +Signed-off-by: Rafał Miłecki +--- + drivers/nvmem/Kconfig | 1 + + drivers/nvmem/brcm_nvram.c | 28 ++++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +--- a/drivers/nvmem/Kconfig ++++ b/drivers/nvmem/Kconfig +@@ -55,6 +55,7 @@ config NVMEM_BRCM_NVRAM + tristate "Broadcom's NVRAM support" + depends on ARCH_BCM_5301X || COMPILE_TEST + depends on HAS_IOMEM ++ select GENERIC_NET_UTILS + help + This driver provides support for Broadcom's NVRAM that can be accessed + using I/O mapping. +--- a/drivers/nvmem/brcm_nvram.c ++++ b/drivers/nvmem/brcm_nvram.c +@@ -4,6 +4,8 @@ + */ + + #include ++#include ++#include + #include + #include + #include +@@ -42,6 +44,25 @@ static int brcm_nvram_read(void *context + return 0; + } + ++static int brcm_nvram_read_post_process_macaddr(void *context, const char *id, int index, ++ unsigned int offset, void *buf, size_t bytes) ++{ ++ u8 mac[ETH_ALEN]; ++ ++ if (bytes != 3 * ETH_ALEN - 1) ++ return -EINVAL; ++ ++ if (!mac_pton(buf, mac)) ++ return -EINVAL; ++ ++ if (index) ++ eth_addr_add(mac, index); ++ ++ ether_addr_copy(buf, mac); ++ ++ return 0; ++} ++ + static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data, + size_t len) + { +@@ -75,6 +96,13 @@ static int brcm_nvram_add_cells(struct b + priv->cells[idx].offset = value - (char *)data; + priv->cells[idx].bytes = strlen(value); + priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); ++ if (!strcmp(var, "et0macaddr") || ++ !strcmp(var, "et1macaddr") || ++ !strcmp(var, "et2macaddr")) { ++ priv->cells[idx].raw_len = strlen(value); ++ priv->cells[idx].bytes = ETH_ALEN; ++ priv->cells[idx].read_post_process = brcm_nvram_read_post_process_macaddr; ++ } + } + + return 0; diff --git a/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch b/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch new file mode 100644 index 00000000000..98687126487 --- /dev/null +++ b/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch @@ -0,0 +1,51 @@ +From 5cb03751455c299b1bf10cb48631bf359cfb11b5 Mon Sep 17 00:00:00 2001 +From: "mark-yw.chen" +Date: Wed, 1 Sep 2021 11:32:25 +0800 +Subject: [PATCH 1/5] Bluetooth: btusb: Support public address configuration + for MediaTek Chip. + +The MediaTek chip support vendor specific HCI command(0xfc1a) to +change the public address. Add hdev->set_bdaddr handler for MediaTek +Chip. After doing a power cycle or MediaTek Bluetooth reset, BD_ADDR +will bring back the original one. + +Signed-off-by: mark-yw.chen +Signed-off-by: Marcel Holtmann +--- + drivers/bluetooth/btusb.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -2272,6 +2272,23 @@ struct btmtk_section_map { + }; + } __packed; + ++static int btusb_set_bdaddr_mtk(struct hci_dev *hdev, const bdaddr_t *bdaddr) ++{ ++ struct sk_buff *skb; ++ long ret; ++ ++ skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT); ++ if (IS_ERR(skb)) { ++ ret = PTR_ERR(skb); ++ bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", ++ ret); ++ return ret; ++ } ++ kfree_skb(skb); ++ ++ return 0; ++} ++ + static void btusb_mtk_wmt_recv(struct urb *urb) + { + struct hci_dev *hdev = urb->context; +@@ -3923,6 +3940,7 @@ static int btusb_probe(struct usb_interf + hdev->shutdown = btusb_mtk_shutdown; + hdev->manufacturer = 70; + hdev->cmd_timeout = btusb_mtk_cmd_timeout; ++ hdev->set_bdaddr = btusb_set_bdaddr_mtk; + set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); + data->recv_acl = btusb_recv_acl_mtk; + } diff --git a/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch b/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch new file mode 100644 index 00000000000..cff537a8669 --- /dev/null +++ b/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch @@ -0,0 +1,29 @@ +From af774a731f7b4c2a90a8476cd44045ba8d1263ba Mon Sep 17 00:00:00 2001 +From: David Yang +Date: Wed, 13 Oct 2021 08:56:33 +0800 +Subject: [PATCH 2/5] Bluetooth: btusb: Fix application of sizeof to pointer + +The coccinelle check report: +"./drivers/bluetooth/btusb.c:2239:36-42: +ERROR: application of sizeof to pointer". +Using the real size to fix it. + +Fixes: 5a87679ffd443 ("Bluetooth: btusb: Support public address configuration for MediaTek Chip.") +Reported-by: Zeal Robot +Signed-off-by: David Yang +Signed-off-by: Marcel Holtmann +--- + drivers/bluetooth/btusb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -2277,7 +2277,7 @@ static int btusb_set_bdaddr_mtk(struct h + struct sk_buff *skb; + long ret; + +- skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT); ++ skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", diff --git a/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch b/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch new file mode 100644 index 00000000000..d670195da1f --- /dev/null +++ b/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch @@ -0,0 +1,70 @@ +From e57186fc02cedff191c469a26cce615371e41740 Mon Sep 17 00:00:00 2001 +From: Yake Yang +Date: Wed, 23 Feb 2022 07:55:59 +0800 +Subject: [PATCH 3/5] Bluetooth: btusb: Add a new PID/VID 13d3/3567 for MT7921 + +Add VID 13D3 & PID 3567 for MediaTek MT7921 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=05 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=13d3 ProdID=3567 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us + +Co-developed-by: Sean Wang +Signed-off-by: Sean Wang +Signed-off-by: Yake Yang +Signed-off-by: Marcel Holtmann +--- + drivers/bluetooth/btusb.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -464,6 +464,9 @@ static const struct usb_device_id blackl + { USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, ++ { USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH | ++ BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, diff --git a/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch b/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch new file mode 100644 index 00000000000..be9dc734215 --- /dev/null +++ b/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch @@ -0,0 +1,68 @@ +From e507366cd1e8e1d4eebe537c08fd142cf0b617fa Mon Sep 17 00:00:00 2001 +From: Sean Wang +Date: Thu, 28 Apr 2022 02:38:39 +0800 +Subject: [PATCH 4/5] Bluetooth: btusb: Add a new PID/VID 0489/e0c8 for MT7921 + +Add VID 0489 & PID e0c8 for MediaTek MT7921 USB Bluetooth chip. + +The information in /sys/kernel/debug/usb/devices about the Bluetooth +device is listed as the below. + +T: Bus=01 Lev=01 Prnt=01 Port=13 Cnt=03 Dev#= 4 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0489 ProdID=e0c8 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us + +Signed-off-by: Sean Wang +Signed-off-by: Marcel Holtmann +--- + drivers/bluetooth/btusb.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -455,6 +455,9 @@ static const struct usb_device_id blackl + BTUSB_VALID_LE_STATES }, + + /* Additional MediaTek MT7921 Bluetooth devices */ ++ { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH | ++ BTUSB_VALID_LE_STATES }, + { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, diff --git a/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch b/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch new file mode 100644 index 00000000000..24ec68a2ca5 --- /dev/null +++ b/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch @@ -0,0 +1,66 @@ +From be55622ce673f9692cc15d26d77a050cda42a3d3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 9 Sep 2022 21:00:30 +0100 +Subject: [PATCH 1/1] Bluetooth: btusb: Add a new VID/PID 0e8d/0608 for MT7921 + +Add a new PID/VID 0e8d/0608 for MT7921K chip found on AMD RZ608 module. + +From /sys/kernel/debug/usb/devices: +T: Bus=01 Lev=02 Prnt=02 Port=01 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 +D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 +P: Vendor=0e8d ProdID=0608 Rev= 1.00 +S: Manufacturer=MediaTek Inc. +S: Product=Wireless_Device +S: SerialNumber=000000000 +C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA +A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 +I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us +E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms +E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms +I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms +I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms +I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms +I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms +I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms +I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms +I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb +E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms +E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms +I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us +I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) +E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us +E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us + +Signed-off-by: Daniel Golle +Signed-off-by: Luiz Augusto von Dentz +--- + drivers/bluetooth/btusb.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/bluetooth/btusb.c ++++ b/drivers/bluetooth/btusb.c +@@ -473,6 +473,9 @@ static const struct usb_device_id blackl + { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | + BTUSB_WIDEBAND_SPEECH | + BTUSB_VALID_LE_STATES }, ++ { USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK | ++ BTUSB_WIDEBAND_SPEECH | ++ BTUSB_VALID_LE_STATES }, + + /* MediaTek MT7922A Bluetooth devices */ + { USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK | diff --git a/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch b/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch new file mode 100644 index 00000000000..b00cf574199 --- /dev/null +++ b/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch @@ -0,0 +1,359 @@ +From 66a8f7f04979f4ad739085f01d99c8caf620b4f5 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Tue, 18 Jan 2022 18:35:02 +0100 +Subject: [PATCH] of: base: make small of_parse_phandle() variants static + inline + +Make all the smaller variants of the of_parse_phandle() static inline. +This also let us remove the empty function stubs if CONFIG_OF is not +defined. + +Suggested-by: Rob Herring +Signed-off-by: Michael Walle +[robh: move index < 0 check into __of_parse_phandle_with_args] +Signed-off-by: Rob Herring +Link: https://lore.kernel.org/r/20220118173504.2867523-2-michael@walle.cc +--- + drivers/of/base.c | 131 +++------------------------------------ + include/linux/of.h | 148 ++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 129 insertions(+), 150 deletions(-) + +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -1371,15 +1371,18 @@ int of_phandle_iterator_args(struct of_p + return count; + } + +-static int __of_parse_phandle_with_args(const struct device_node *np, +- const char *list_name, +- const char *cells_name, +- int cell_count, int index, +- struct of_phandle_args *out_args) ++int __of_parse_phandle_with_args(const struct device_node *np, ++ const char *list_name, ++ const char *cells_name, ++ int cell_count, int index, ++ struct of_phandle_args *out_args) + { + struct of_phandle_iterator it; + int rc, cur_index = 0; + ++ if (index < 0) ++ return -EINVAL; ++ + /* Loop over the phandles until all the requested entry is found */ + of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { + /* +@@ -1422,82 +1425,7 @@ static int __of_parse_phandle_with_args( + of_node_put(it.node); + return rc; + } +- +-/** +- * of_parse_phandle - Resolve a phandle property to a device_node pointer +- * @np: Pointer to device node holding phandle property +- * @phandle_name: Name of property holding a phandle value +- * @index: For properties holding a table of phandles, this is the index into +- * the table +- * +- * Return: The device_node pointer with refcount incremented. Use +- * of_node_put() on it when done. +- */ +-struct device_node *of_parse_phandle(const struct device_node *np, +- const char *phandle_name, int index) +-{ +- struct of_phandle_args args; +- +- if (index < 0) +- return NULL; +- +- if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, +- index, &args)) +- return NULL; +- +- return args.np; +-} +-EXPORT_SYMBOL(of_parse_phandle); +- +-/** +- * of_parse_phandle_with_args() - Find a node pointed by phandle in a list +- * @np: pointer to a device tree node containing a list +- * @list_name: property name that contains a list +- * @cells_name: property name that specifies phandles' arguments count +- * @index: index of a phandle to parse out +- * @out_args: optional pointer to output arguments structure (will be filled) +- * +- * This function is useful to parse lists of phandles and their arguments. +- * Returns 0 on success and fills out_args, on error returns appropriate +- * errno value. +- * +- * Caller is responsible to call of_node_put() on the returned out_args->np +- * pointer. +- * +- * Example:: +- * +- * phandle1: node1 { +- * #list-cells = <2>; +- * }; +- * +- * phandle2: node2 { +- * #list-cells = <1>; +- * }; +- * +- * node3 { +- * list = <&phandle1 1 2 &phandle2 3>; +- * }; +- * +- * To get a device_node of the ``node2`` node you may call this: +- * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); +- */ +-int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, +- const char *cells_name, int index, +- struct of_phandle_args *out_args) +-{ +- int cell_count = -1; +- +- if (index < 0) +- return -EINVAL; +- +- /* If cells_name is NULL we assume a cell count of 0 */ +- if (!cells_name) +- cell_count = 0; +- +- return __of_parse_phandle_with_args(np, list_name, cells_name, +- cell_count, index, out_args); +-} +-EXPORT_SYMBOL(of_parse_phandle_with_args); ++EXPORT_SYMBOL(__of_parse_phandle_with_args); + + /** + * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it +@@ -1684,47 +1612,6 @@ free: + EXPORT_SYMBOL(of_parse_phandle_with_args_map); + + /** +- * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list +- * @np: pointer to a device tree node containing a list +- * @list_name: property name that contains a list +- * @cell_count: number of argument cells following the phandle +- * @index: index of a phandle to parse out +- * @out_args: optional pointer to output arguments structure (will be filled) +- * +- * This function is useful to parse lists of phandles and their arguments. +- * Returns 0 on success and fills out_args, on error returns appropriate +- * errno value. +- * +- * Caller is responsible to call of_node_put() on the returned out_args->np +- * pointer. +- * +- * Example:: +- * +- * phandle1: node1 { +- * }; +- * +- * phandle2: node2 { +- * }; +- * +- * node3 { +- * list = <&phandle1 0 2 &phandle2 2 3>; +- * }; +- * +- * To get a device_node of the ``node2`` node you may call this: +- * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args); +- */ +-int of_parse_phandle_with_fixed_args(const struct device_node *np, +- const char *list_name, int cell_count, +- int index, struct of_phandle_args *out_args) +-{ +- if (index < 0) +- return -EINVAL; +- return __of_parse_phandle_with_args(np, list_name, NULL, cell_count, +- index, out_args); +-} +-EXPORT_SYMBOL(of_parse_phandle_with_fixed_args); +- +-/** + * of_count_phandle_with_args() - Find the number of phandles references in a property + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -363,18 +363,12 @@ extern const struct of_device_id *of_mat + const struct of_device_id *matches, const struct device_node *node); + extern int of_modalias_node(struct device_node *node, char *modalias, int len); + extern void of_print_phandle_args(const char *msg, const struct of_phandle_args *args); +-extern struct device_node *of_parse_phandle(const struct device_node *np, +- const char *phandle_name, +- int index); +-extern int of_parse_phandle_with_args(const struct device_node *np, +- const char *list_name, const char *cells_name, int index, +- struct of_phandle_args *out_args); ++extern int __of_parse_phandle_with_args(const struct device_node *np, ++ const char *list_name, const char *cells_name, int cell_count, ++ int index, struct of_phandle_args *out_args); + extern int of_parse_phandle_with_args_map(const struct device_node *np, + const char *list_name, const char *stem_name, int index, + struct of_phandle_args *out_args); +-extern int of_parse_phandle_with_fixed_args(const struct device_node *np, +- const char *list_name, int cells_count, int index, +- struct of_phandle_args *out_args); + extern int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name); + +@@ -864,18 +858,12 @@ static inline int of_property_read_strin + return -ENOSYS; + } + +-static inline struct device_node *of_parse_phandle(const struct device_node *np, +- const char *phandle_name, +- int index) +-{ +- return NULL; +-} +- +-static inline int of_parse_phandle_with_args(const struct device_node *np, +- const char *list_name, +- const char *cells_name, +- int index, +- struct of_phandle_args *out_args) ++static inline int __of_parse_phandle_with_args(const struct device_node *np, ++ const char *list_name, ++ const char *cells_name, ++ int cell_count, ++ int index, ++ struct of_phandle_args *out_args) + { + return -ENOSYS; + } +@@ -889,13 +877,6 @@ static inline int of_parse_phandle_with_ + return -ENOSYS; + } + +-static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, +- const char *list_name, int cells_count, int index, +- struct of_phandle_args *out_args) +-{ +- return -ENOSYS; +-} +- + static inline int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, + const char *cells_name) +@@ -1077,6 +1058,117 @@ static inline bool of_node_is_type(const + } + + /** ++ * of_parse_phandle - Resolve a phandle property to a device_node pointer ++ * @np: Pointer to device node holding phandle property ++ * @phandle_name: Name of property holding a phandle value ++ * @index: For properties holding a table of phandles, this is the index into ++ * the table ++ * ++ * Return: The device_node pointer with refcount incremented. Use ++ * of_node_put() on it when done. ++ */ ++static inline struct device_node *of_parse_phandle(const struct device_node *np, ++ const char *phandle_name, ++ int index) ++{ ++ struct of_phandle_args args; ++ ++ if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, ++ index, &args)) ++ return NULL; ++ ++ return args.np; ++} ++ ++/** ++ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list ++ * @np: pointer to a device tree node containing a list ++ * @list_name: property name that contains a list ++ * @cells_name: property name that specifies phandles' arguments count ++ * @index: index of a phandle to parse out ++ * @out_args: optional pointer to output arguments structure (will be filled) ++ * ++ * This function is useful to parse lists of phandles and their arguments. ++ * Returns 0 on success and fills out_args, on error returns appropriate ++ * errno value. ++ * ++ * Caller is responsible to call of_node_put() on the returned out_args->np ++ * pointer. ++ * ++ * Example:: ++ * ++ * phandle1: node1 { ++ * #list-cells = <2>; ++ * }; ++ * ++ * phandle2: node2 { ++ * #list-cells = <1>; ++ * }; ++ * ++ * node3 { ++ * list = <&phandle1 1 2 &phandle2 3>; ++ * }; ++ * ++ * To get a device_node of the ``node2`` node you may call this: ++ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); ++ */ ++static inline int of_parse_phandle_with_args(const struct device_node *np, ++ const char *list_name, ++ const char *cells_name, ++ int index, ++ struct of_phandle_args *out_args) ++{ ++ int cell_count = -1; ++ ++ /* If cells_name is NULL we assume a cell count of 0 */ ++ if (!cells_name) ++ cell_count = 0; ++ ++ return __of_parse_phandle_with_args(np, list_name, cells_name, ++ cell_count, index, out_args); ++} ++ ++/** ++ * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list ++ * @np: pointer to a device tree node containing a list ++ * @list_name: property name that contains a list ++ * @cell_count: number of argument cells following the phandle ++ * @index: index of a phandle to parse out ++ * @out_args: optional pointer to output arguments structure (will be filled) ++ * ++ * This function is useful to parse lists of phandles and their arguments. ++ * Returns 0 on success and fills out_args, on error returns appropriate ++ * errno value. ++ * ++ * Caller is responsible to call of_node_put() on the returned out_args->np ++ * pointer. ++ * ++ * Example:: ++ * ++ * phandle1: node1 { ++ * }; ++ * ++ * phandle2: node2 { ++ * }; ++ * ++ * node3 { ++ * list = <&phandle1 0 2 &phandle2 2 3>; ++ * }; ++ * ++ * To get a device_node of the ``node2`` node you may call this: ++ * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args); ++ */ ++static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, ++ const char *list_name, ++ int cell_count, ++ int index, ++ struct of_phandle_args *out_args) ++{ ++ return __of_parse_phandle_with_args(np, list_name, NULL, cell_count, ++ index, out_args); ++} ++ ++/** + * of_property_count_u8_elems - Count the number of u8 elements in a property + * + * @np: device node from which the property value is to be read. diff --git a/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch b/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch new file mode 100644 index 00000000000..2b2a60e096b --- /dev/null +++ b/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch @@ -0,0 +1,58 @@ +From c5d264d4b527c96ae8903376a4b195df47b05203 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:43 +0000 +Subject: [PATCH] of: base: add of_parse_phandle_with_optional_args() + +Add a new variant of the of_parse_phandle_with_args() which treats the +cells name as optional. If it's missing, it is assumed that the phandle +has no arguments. + +Up until now, a nvmem node didn't have any arguments, so all the device +trees haven't any '#*-cells' property. But there is a need for an +additional argument for the phandle, for which we need a '#*-cells' +property. Therefore, we need to support nvmem nodes with and without +this property. + +Signed-off-by: Michael Walle +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-10-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/of.h | 25 +++++++++++++++++++++++++ + 1 file changed, 25 insertions(+) + +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -1169,6 +1169,31 @@ static inline int of_parse_phandle_with_ + } + + /** ++ * of_parse_phandle_with_optional_args() - Find a node pointed by phandle in a list ++ * @np: pointer to a device tree node containing a list ++ * @list_name: property name that contains a list ++ * @cells_name: property name that specifies phandles' arguments count ++ * @index: index of a phandle to parse out ++ * @out_args: optional pointer to output arguments structure (will be filled) ++ * ++ * Same as of_parse_phandle_with_args() except that if the cells_name property ++ * is not found, cell_count of 0 is assumed. ++ * ++ * This is used to useful, if you have a phandle which didn't have arguments ++ * before and thus doesn't have a '#*-cells' property but is now migrated to ++ * having arguments while retaining backwards compatibility. ++ */ ++static inline int of_parse_phandle_with_optional_args(const struct device_node *np, ++ const char *list_name, ++ const char *cells_name, ++ int index, ++ struct of_phandle_args *out_args) ++{ ++ return __of_parse_phandle_with_args(np, list_name, cells_name, ++ 0, index, out_args); ++} ++ ++/** + * of_property_count_u8_elems - Count the number of u8 elements in a property + * + * @np: device node from which the property value is to be read. diff --git a/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch b/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch new file mode 100644 index 00000000000..39d9fae7239 --- /dev/null +++ b/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch @@ -0,0 +1,34 @@ +From ff24fed10ba414d19579e26e60b126fad2f2bb07 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:44 +0000 +Subject: [PATCH] of: property: make #.*-cells optional for simple props + +Sometimes, future bindings for phandles will get additional arguments. +Thus the target node of the phandle will need a new #.*-cells property. +To be backwards compatible, this needs to be optional. + +Prepare the DEFINE_SIMPLE_PROPS() to handle the cells name as optional. + +Signed-off-by: Michael Walle +Tested-by: Miquel Raynal +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-11-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/property.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -1173,8 +1173,8 @@ static struct device_node *parse_prop_ce + if (strcmp(prop_name, list_name)) + return NULL; + +- if (of_parse_phandle_with_args(np, list_name, cells_name, index, +- &sup_args)) ++ if (__of_parse_phandle_with_args(np, list_name, cells_name, 0, index, ++ &sup_args)) + return NULL; + + return sup_args.np; diff --git a/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch b/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch new file mode 100644 index 00000000000..774e793ca5a --- /dev/null +++ b/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch @@ -0,0 +1,30 @@ +From e2d8172043d2e50df19fcd59c11e5593de8188d7 Mon Sep 17 00:00:00 2001 +From: Michael Walle +Date: Mon, 6 Feb 2023 13:43:45 +0000 +Subject: [PATCH] of: property: add #nvmem-cell-cells property + +Bindings describe the new '#nvmem-cell-cells' property. Now that the +arguments count property is optional, we just add this property to the +nvmem-cells. + +Signed-off-by: Michael Walle +Tested-by: Miquel Raynal +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230206134356.839737-12-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/property.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/of/property.c ++++ b/drivers/of/property.c +@@ -1276,7 +1276,7 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-c + DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") + DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") + DEFINE_SIMPLE_PROP(extcon, "extcon", NULL) +-DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", NULL) ++DEFINE_SIMPLE_PROP(nvmem_cells, "nvmem-cells", "#nvmem-cell-cells") + DEFINE_SIMPLE_PROP(phys, "phys", "#phy-cells") + DEFINE_SIMPLE_PROP(wakeup_parent, "wakeup-parent", NULL) + DEFINE_SIMPLE_PROP(pinctrl0, "pinctrl-0", NULL) diff --git a/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch b/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch new file mode 100644 index 00000000000..37eefc4570f --- /dev/null +++ b/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch @@ -0,0 +1,37 @@ +From 553bd29700145e1849698985e9800f14e967da49 Mon Sep 17 00:00:00 2001 +From: Alexander Stein +Date: Tue, 7 Feb 2023 12:05:29 +0100 +Subject: [PATCH] of: device: Ignore modalias of reused nodes + +If of_node is reused, do not use that node's modalias. This will hide +the name of the actual device. This is rather prominent in USB glue +drivers creating a platform device for the host controller. + +Signed-off-by: Alexander Stein +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20230207110531.1060252-2-alexander.stein@ew.tq-group.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/device.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -249,7 +249,7 @@ static ssize_t of_device_get_modalias(st + ssize_t csize; + ssize_t tsize; + +- if ((!dev) || (!dev->of_node)) ++ if ((!dev) || (!dev->of_node) || dev->of_node_reused) + return -ENODEV; + + /* Name & Type */ +@@ -372,7 +372,7 @@ int of_device_uevent_modalias(struct dev + { + int sl; + +- if ((!dev) || (!dev->of_node)) ++ if ((!dev) || (!dev->of_node) || dev->of_node_reused) + return -ENODEV; + + /* Devicetree modalias is tricky, we add it in 2 steps */ diff --git a/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch b/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch new file mode 100644 index 00000000000..dd5820e94a5 --- /dev/null +++ b/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch @@ -0,0 +1,29 @@ +From 2295bed9bebe8d1eef276194fed5b5fbe89c5363 Mon Sep 17 00:00:00 2001 +From: Alexander Stein +Date: Tue, 7 Feb 2023 12:05:30 +0100 +Subject: [PATCH] of: device: Do not ignore error code in + of_device_uevent_modalias + +of_device_get_modalias might return an error code, propagate that one. +Otherwise the negative, signed integer is propagated to unsigned integer +for the comparison resulting in a huge 'sl' size. + +Signed-off-by: Alexander Stein +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20230207110531.1060252-3-alexander.stein@ew.tq-group.com +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/device.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -381,6 +381,8 @@ int of_device_uevent_modalias(struct dev + + sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); ++ if (sl < 0) ++ return sl; + if (sl >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += sl; diff --git a/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch b/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch new file mode 100644 index 00000000000..4713cc71b12 --- /dev/null +++ b/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch @@ -0,0 +1,103 @@ +From 5c3d15e127ebfc0754cd18def7124633b6d46672 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:15 +0100 +Subject: [PATCH] of: Update of_device_get_modalias() + +This function only needs a "struct device_node" to work, but for +convenience the author (and only user) of this helper did use a "struct +device" and put it in device.c. + +Let's convert this helper to take a "struct device node" instead. This +change asks for two additional changes: renaming it "of_modalias()" +to fit the current naming, and moving it outside of device.c which will +be done in a follow-up commit. + +Signed-off-by: Miquel Raynal +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-8-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/device.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -241,7 +241,7 @@ const void *of_device_get_match_data(con + } + EXPORT_SYMBOL(of_device_get_match_data); + +-static ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) ++static ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) + { + const char *compat; + char *c; +@@ -249,19 +249,16 @@ static ssize_t of_device_get_modalias(st + ssize_t csize; + ssize_t tsize; + +- if ((!dev) || (!dev->of_node) || dev->of_node_reused) +- return -ENODEV; +- + /* Name & Type */ + /* %p eats all alphanum characters, so %c must be used here */ +- csize = snprintf(str, len, "of:N%pOFn%c%s", dev->of_node, 'T', +- of_node_get_device_type(dev->of_node)); ++ csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', ++ of_node_get_device_type(np)); + tsize = csize; + len -= csize; + if (str) + str += csize; + +- of_property_for_each_string(dev->of_node, "compatible", p, compat) { ++ of_property_for_each_string(np, "compatible", p, compat) { + csize = strlen(compat) + 1; + tsize += csize; + if (csize > len) +@@ -286,7 +283,10 @@ int of_device_request_module(struct devi + ssize_t size; + int ret; + +- size = of_device_get_modalias(dev, NULL, 0); ++ if (!dev || !dev->of_node) ++ return -ENODEV; ++ ++ size = of_modalias(dev->of_node, NULL, 0); + if (size < 0) + return size; + +@@ -297,7 +297,7 @@ int of_device_request_module(struct devi + if (!str) + return -ENOMEM; + +- of_device_get_modalias(dev, str, size); ++ of_modalias(dev->of_node, str, size); + str[size - 1] = '\0'; + ret = request_module(str); + kfree(str); +@@ -314,7 +314,12 @@ EXPORT_SYMBOL_GPL(of_device_request_modu + */ + ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) + { +- ssize_t sl = of_device_get_modalias(dev, str, len - 2); ++ ssize_t sl; ++ ++ if (!dev || !dev->of_node || dev->of_node_reused) ++ return -ENODEV; ++ ++ sl = of_modalias(dev->of_node, str, len - 2); + if (sl < 0) + return sl; + if (sl > len - 2) +@@ -379,8 +384,8 @@ int of_device_uevent_modalias(struct dev + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + +- sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], +- sizeof(env->buf) - env->buflen); ++ sl = of_modalias(dev->of_node, &env->buf[env->buflen-1], ++ sizeof(env->buf) - env->buflen); + if (sl < 0) + return sl; + if (sl >= (sizeof(env->buf) - env->buflen)) diff --git a/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch new file mode 100644 index 00000000000..6c205217018 --- /dev/null +++ b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch @@ -0,0 +1,173 @@ +From 673aa1ed1c9b6710bf24e3f0957d85e2f46c77db Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:16 +0100 +Subject: [PATCH] of: Rename of_modalias_node() + +This helper does not produce a real modalias, but tries to get the +"product" compatible part of the "vendor,product" compatibles only. It +is far from creating a purely useful modalias string and does not seem +to be used like that directly anyway, so let's try to give this helper a +more meaningful name before moving there a real modalias helper (already +existing under of/device.c). + +Also update the various documentations to refer to the strings as +"aliases" rather than "modaliases" which has a real meaning in the Linux +kernel. + +There is no functional change. + +Cc: Rafael J. Wysocki +Cc: Len Brown +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Thomas Zimmermann +Cc: Sebastian Reichel +Cc: Wolfram Sang +Cc: Mark Brown +Signed-off-by: Miquel Raynal +Reviewed-by: Rob Herring +Acked-by: Mark Brown +Signed-off-by: Srinivas Kandagatla +Acked-by: Sebastian Reichel +Link: https://lore.kernel.org/r/20230404172148.82422-9-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/acpi/bus.c | 7 ++++--- + drivers/gpu/drm/drm_mipi_dsi.c | 2 +- + drivers/hsi/hsi_core.c | 2 +- + drivers/i2c/busses/i2c-powermac.c | 2 +- + drivers/i2c/i2c-core-of.c | 2 +- + drivers/of/base.c | 18 +++++++++++------- + drivers/spi/spi.c | 4 ++-- + include/linux/of.h | 3 ++- + 8 files changed, 23 insertions(+), 17 deletions(-) + +--- a/drivers/acpi/bus.c ++++ b/drivers/acpi/bus.c +@@ -785,9 +785,10 @@ static bool acpi_of_modalias(struct acpi + * @modalias: Pointer to buffer that modalias value will be copied into + * @len: Length of modalias buffer + * +- * This is a counterpart of of_modalias_node() for struct acpi_device objects. +- * If there is a compatible string for @adev, it will be copied to @modalias +- * with the vendor prefix stripped; otherwise, @default_id will be used. ++ * This is a counterpart of of_alias_from_compatible() for struct acpi_device ++ * objects. If there is a compatible string for @adev, it will be copied to ++ * @modalias with the vendor prefix stripped; otherwise, @default_id will be ++ * used. + */ + void acpi_set_modalias(struct acpi_device *adev, const char *default_id, + char *modalias, size_t len) +--- a/drivers/gpu/drm/drm_mipi_dsi.c ++++ b/drivers/gpu/drm/drm_mipi_dsi.c +@@ -160,7 +160,7 @@ of_mipi_dsi_device_add(struct mipi_dsi_h + int ret; + u32 reg; + +- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { ++ if (of_alias_from_compatible(node, info.type, sizeof(info.type)) < 0) { + drm_err(host, "modalias failure on %pOF\n", node); + return ERR_PTR(-EINVAL); + } +--- a/drivers/hsi/hsi_core.c ++++ b/drivers/hsi/hsi_core.c +@@ -207,7 +207,7 @@ static void hsi_add_client_from_dt(struc + if (!cl) + return; + +- err = of_modalias_node(client, name, sizeof(name)); ++ err = of_alias_from_compatible(client, name, sizeof(name)); + if (err) + goto err; + +--- a/drivers/i2c/busses/i2c-powermac.c ++++ b/drivers/i2c/busses/i2c-powermac.c +@@ -284,7 +284,7 @@ static bool i2c_powermac_get_type(struct + */ + + /* First try proper modalias */ +- if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) { ++ if (of_alias_from_compatible(node, tmp, sizeof(tmp)) >= 0) { + snprintf(type, type_size, "MAC,%s", tmp); + return true; + } +--- a/drivers/i2c/i2c-core-of.c ++++ b/drivers/i2c/i2c-core-of.c +@@ -27,7 +27,7 @@ int of_i2c_get_board_info(struct device + + memset(info, 0, sizeof(*info)); + +- if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) { ++ if (of_alias_from_compatible(node, info->type, sizeof(info->type)) < 0) { + dev_err(dev, "of_i2c: modalias failure on %pOF\n", node); + return -EINVAL; + } +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -1159,19 +1159,23 @@ struct device_node *of_find_matching_nod + EXPORT_SYMBOL(of_find_matching_node_and_match); + + /** +- * of_modalias_node - Lookup appropriate modalias for a device node ++ * of_alias_from_compatible - Lookup appropriate alias for a device node ++ * depending on compatible + * @node: pointer to a device tree node +- * @modalias: Pointer to buffer that modalias value will be copied into +- * @len: Length of modalias value ++ * @alias: Pointer to buffer that alias value will be copied into ++ * @len: Length of alias value + * + * Based on the value of the compatible property, this routine will attempt +- * to choose an appropriate modalias value for a particular device tree node. ++ * to choose an appropriate alias value for a particular device tree node. + * It does this by stripping the manufacturer prefix (as delimited by a ',') + * from the first entry in the compatible list property. + * ++ * Note: The matching on just the "product" side of the compatible is a relic ++ * from I2C and SPI. Please do not add any new user. ++ * + * Return: This routine returns 0 on success, <0 on failure. + */ +-int of_modalias_node(struct device_node *node, char *modalias, int len) ++int of_alias_from_compatible(const struct device_node *node, char *alias, int len) + { + const char *compatible, *p; + int cplen; +@@ -1180,10 +1184,10 @@ int of_modalias_node(struct device_node + if (!compatible || strlen(compatible) > cplen) + return -ENODEV; + p = strchr(compatible, ','); +- strlcpy(modalias, p ? p + 1 : compatible, len); ++ strlcpy(alias, p ? p + 1 : compatible, len); + return 0; + } +-EXPORT_SYMBOL_GPL(of_modalias_node); ++EXPORT_SYMBOL_GPL(of_alias_from_compatible); + + /** + * of_find_node_by_phandle - Find a node given a phandle +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -2128,8 +2128,8 @@ of_register_spi_device(struct spi_contro + } + + /* Select device driver */ +- rc = of_modalias_node(nc, spi->modalias, +- sizeof(spi->modalias)); ++ rc = of_alias_from_compatible(nc, spi->modalias, ++ sizeof(spi->modalias)); + if (rc < 0) { + dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc); + goto err_out; +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -361,7 +361,8 @@ extern int of_n_addr_cells(struct device + extern int of_n_size_cells(struct device_node *np); + extern const struct of_device_id *of_match_node( + const struct of_device_id *matches, const struct device_node *node); +-extern int of_modalias_node(struct device_node *node, char *modalias, int len); ++extern int of_alias_from_compatible(const struct device_node *node, char *alias, ++ int len); + extern void of_print_phandle_args(const char *msg, const struct of_phandle_args *args); + extern int __of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name, int cell_count, diff --git a/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch b/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch new file mode 100644 index 00000000000..a70c6f2eec8 --- /dev/null +++ b/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch @@ -0,0 +1,160 @@ +From bd7a7ed774afd1a4174df34227626c95573be517 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:17 +0100 +Subject: [PATCH] of: Move of_modalias() to module.c + +Create a specific .c file for OF related module handling. +Move of_modalias() inside as a first step. + +The helper is exposed through of.h even though it is only used by core +files because the users from device.c will soon be split into an OF-only +helper in module.c as well as a device-oriented inline helper in +of_device.h. Putting this helper in of_private.h would require to +include of_private.h from of_device.h, which is not acceptable. + +Suggested-by: Rob Herring +Signed-off-by: Miquel Raynal +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-10-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/Makefile | 2 +- + drivers/of/device.c | 37 ------------------------------------- + drivers/of/module.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ + include/linux/of.h | 9 +++++++++ + 4 files changed, 54 insertions(+), 38 deletions(-) + create mode 100644 drivers/of/module.c + +--- a/drivers/of/Makefile ++++ b/drivers/of/Makefile +@@ -1,5 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0 +-obj-y = base.o device.o platform.o property.o ++obj-y = base.o device.o module.o platform.o property.o + obj-$(CONFIG_OF_KOBJ) += kobj.o + obj-$(CONFIG_OF_DYNAMIC) += dynamic.o + obj-$(CONFIG_OF_FLATTREE) += fdt.o +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -1,5 +1,4 @@ + // SPDX-License-Identifier: GPL-2.0 +-#include + #include + #include + #include +@@ -241,42 +240,6 @@ const void *of_device_get_match_data(con + } + EXPORT_SYMBOL(of_device_get_match_data); + +-static ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) +-{ +- const char *compat; +- char *c; +- struct property *p; +- ssize_t csize; +- ssize_t tsize; +- +- /* Name & Type */ +- /* %p eats all alphanum characters, so %c must be used here */ +- csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', +- of_node_get_device_type(np)); +- tsize = csize; +- len -= csize; +- if (str) +- str += csize; +- +- of_property_for_each_string(np, "compatible", p, compat) { +- csize = strlen(compat) + 1; +- tsize += csize; +- if (csize > len) +- continue; +- +- csize = snprintf(str, len, "C%s", compat); +- for (c = str; c; ) { +- c = strchr(c, ' '); +- if (c) +- *c++ = '_'; +- } +- len -= csize; +- str += csize; +- } +- +- return tsize; +-} +- + int of_device_request_module(struct device *dev) + { + char *str; +--- /dev/null ++++ b/drivers/of/module.c +@@ -0,0 +1,44 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Linux kernel module helpers. ++ */ ++ ++#include ++#include ++#include ++ ++ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) ++{ ++ const char *compat; ++ char *c; ++ struct property *p; ++ ssize_t csize; ++ ssize_t tsize; ++ ++ /* Name & Type */ ++ /* %p eats all alphanum characters, so %c must be used here */ ++ csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', ++ of_node_get_device_type(np)); ++ tsize = csize; ++ len -= csize; ++ if (str) ++ str += csize; ++ ++ of_property_for_each_string(np, "compatible", p, compat) { ++ csize = strlen(compat) + 1; ++ tsize += csize; ++ if (csize > len) ++ continue; ++ ++ csize = snprintf(str, len, "C%s", compat); ++ for (c = str; c; ) { ++ c = strchr(c, ' '); ++ if (c) ++ *c++ = '_'; ++ } ++ len -= csize; ++ str += csize; ++ } ++ ++ return tsize; ++} +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -373,6 +373,9 @@ extern int of_parse_phandle_with_args_ma + extern int of_count_phandle_with_args(const struct device_node *np, + const char *list_name, const char *cells_name); + ++/* module functions */ ++extern ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len); ++ + /* phandle iterator functions */ + extern int of_phandle_iterator_init(struct of_phandle_iterator *it, + const struct device_node *np, +@@ -885,6 +888,12 @@ static inline int of_count_phandle_with_ + return -ENOSYS; + } + ++static inline ssize_t of_modalias(const struct device_node *np, char *str, ++ ssize_t len) ++{ ++ return -ENODEV; ++} ++ + static inline int of_phandle_iterator_init(struct of_phandle_iterator *it, + const struct device_node *np, + const char *list_name, diff --git a/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch b/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch new file mode 100644 index 00000000000..06bc24ca6e3 --- /dev/null +++ b/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch @@ -0,0 +1,131 @@ +From e6506f06d5e82765666902ccf9e9162f3e31d518 Mon Sep 17 00:00:00 2001 +From: Miquel Raynal +Date: Tue, 4 Apr 2023 18:21:18 +0100 +Subject: [PATCH] of: Move the request module helper logic to module.c + +Depending on device.c for pure OF handling is considered +backwards. Let's extract the content of of_device_request_module() to +have the real logic under module.c. + +The next step will be to convert users of of_device_request_module() to +use the new helper. + +Signed-off-by: Miquel Raynal +Reviewed-by: Rob Herring +Signed-off-by: Srinivas Kandagatla +Link: https://lore.kernel.org/r/20230404172148.82422-11-srinivas.kandagatla@linaro.org +Signed-off-by: Greg Kroah-Hartman +--- + drivers/of/device.c | 25 ++----------------------- + drivers/of/module.c | 30 ++++++++++++++++++++++++++++++ + include/linux/of.h | 6 ++++++ + 3 files changed, 38 insertions(+), 23 deletions(-) + +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -8,7 +8,6 @@ + #include /* for bus_dma_region */ + #include + #include +-#include + #include + #include + #include +@@ -242,30 +241,10 @@ EXPORT_SYMBOL(of_device_get_match_data); + + int of_device_request_module(struct device *dev) + { +- char *str; +- ssize_t size; +- int ret; +- +- if (!dev || !dev->of_node) ++ if (!dev) + return -ENODEV; + +- size = of_modalias(dev->of_node, NULL, 0); +- if (size < 0) +- return size; +- +- /* Reserve an additional byte for the trailing '\0' */ +- size++; +- +- str = kmalloc(size, GFP_KERNEL); +- if (!str) +- return -ENOMEM; +- +- of_modalias(dev->of_node, str, size); +- str[size - 1] = '\0'; +- ret = request_module(str); +- kfree(str); +- +- return ret; ++ return of_request_module(dev->of_node); + } + EXPORT_SYMBOL_GPL(of_device_request_module); + +--- a/drivers/of/module.c ++++ b/drivers/of/module.c +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #include + #include + +@@ -42,3 +43,32 @@ ssize_t of_modalias(const struct device_ + + return tsize; + } ++ ++int of_request_module(const struct device_node *np) ++{ ++ char *str; ++ ssize_t size; ++ int ret; ++ ++ if (!np) ++ return -ENODEV; ++ ++ size = of_modalias(np, NULL, 0); ++ if (size < 0) ++ return size; ++ ++ /* Reserve an additional byte for the trailing '\0' */ ++ size++; ++ ++ str = kmalloc(size, GFP_KERNEL); ++ if (!str) ++ return -ENOMEM; ++ ++ of_modalias(np, str, size); ++ str[size - 1] = '\0'; ++ ret = request_module(str); ++ kfree(str); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(of_request_module); +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -375,6 +375,7 @@ extern int of_count_phandle_with_args(co + + /* module functions */ + extern ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len); ++extern int of_request_module(const struct device_node *np); + + /* phandle iterator functions */ + extern int of_phandle_iterator_init(struct of_phandle_iterator *it, +@@ -893,6 +894,11 @@ static inline ssize_t of_modalias(const + { + return -ENODEV; + } ++ ++static inline int of_request_module(const struct device_node *np) ++{ ++ return -ENODEV; ++} + + static inline int of_phandle_iterator_init(struct of_phandle_iterator *it, + const struct device_node *np, diff --git a/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch b/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch new file mode 100644 index 00000000000..0d81d24e09c --- /dev/null +++ b/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch @@ -0,0 +1,348 @@ +From f07788079f515ca4a681c5f595bdad19cfbd7b1d Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Sat, 3 Dec 2022 11:54:25 +0100 +Subject: [PATCH] ata: ahci: fix enum constants for gcc-13 + +gcc-13 slightly changes the type of constant expressions that are defined +in an enum, which triggers a compile time sanity check in libata: + +linux/drivers/ata/libahci.c: In function 'ahci_led_store': +linux/include/linux/compiler_types.h:357:45: error: call to '__compiletime_assert_302' declared with attribute error: BUILD_BUG_ON failed: sizeof(_s) > sizeof(long) +357 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + +The new behavior is that sizeof() returns the same value for the +constant as it does for the enum type, which is generally more sensible +and consistent. + +The problem in libata is that it contains a single enum definition for +lots of unrelated constants, some of which are large positive (unsigned) +integers like 0xffffffff, while others like (1<<31) are interpreted as +negative integers, and this forces the enum type to become 64 bit wide +even though most constants would still fit into a signed 32-bit 'int'. + +Fix this by changing the entire enum definition to use BIT(x) in place +of (1< +Cc: linux-ide@vger.kernel.org +Cc: Damien Le Moal +Cc: stable@vger.kernel.org +Cc: Randy Dunlap +Signed-off-by: Arnd Bergmann +Tested-by: Luis Machado +Signed-off-by: Damien Le Moal +--- + drivers/ata/ahci.h | 245 +++++++++++++++++++++++---------------------- + 1 file changed, 123 insertions(+), 122 deletions(-) + +--- a/drivers/ata/ahci.h ++++ b/drivers/ata/ahci.h +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + /* Enclosure Management Control */ + #define EM_CTRL_MSG_TYPE 0x000f0000 +@@ -54,12 +55,12 @@ enum { + AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ + + AHCI_CMD_TBL_AR_SZ + + (AHCI_RX_FIS_SZ * 16), +- AHCI_IRQ_ON_SG = (1 << 31), +- AHCI_CMD_ATAPI = (1 << 5), +- AHCI_CMD_WRITE = (1 << 6), +- AHCI_CMD_PREFETCH = (1 << 7), +- AHCI_CMD_RESET = (1 << 8), +- AHCI_CMD_CLR_BUSY = (1 << 10), ++ AHCI_IRQ_ON_SG = BIT(31), ++ AHCI_CMD_ATAPI = BIT(5), ++ AHCI_CMD_WRITE = BIT(6), ++ AHCI_CMD_PREFETCH = BIT(7), ++ AHCI_CMD_RESET = BIT(8), ++ AHCI_CMD_CLR_BUSY = BIT(10), + + RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */ + RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ +@@ -77,37 +78,37 @@ enum { + HOST_CAP2 = 0x24, /* host capabilities, extended */ + + /* HOST_CTL bits */ +- HOST_RESET = (1 << 0), /* reset controller; self-clear */ +- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ +- HOST_MRSM = (1 << 2), /* MSI Revert to Single Message */ +- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ ++ HOST_RESET = BIT(0), /* reset controller; self-clear */ ++ HOST_IRQ_EN = BIT(1), /* global IRQ enable */ ++ HOST_MRSM = BIT(2), /* MSI Revert to Single Message */ ++ HOST_AHCI_EN = BIT(31), /* AHCI enabled */ + + /* HOST_CAP bits */ +- HOST_CAP_SXS = (1 << 5), /* Supports External SATA */ +- HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ +- HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */ +- HOST_CAP_PART = (1 << 13), /* Partial state capable */ +- HOST_CAP_SSC = (1 << 14), /* Slumber state capable */ +- HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */ +- HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */ +- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ +- HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */ +- HOST_CAP_CLO = (1 << 24), /* Command List Override support */ +- HOST_CAP_LED = (1 << 25), /* Supports activity LED */ +- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ +- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ +- HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */ +- HOST_CAP_SNTF = (1 << 29), /* SNotification register */ +- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ +- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ ++ HOST_CAP_SXS = BIT(5), /* Supports External SATA */ ++ HOST_CAP_EMS = BIT(6), /* Enclosure Management support */ ++ HOST_CAP_CCC = BIT(7), /* Command Completion Coalescing */ ++ HOST_CAP_PART = BIT(13), /* Partial state capable */ ++ HOST_CAP_SSC = BIT(14), /* Slumber state capable */ ++ HOST_CAP_PIO_MULTI = BIT(15), /* PIO multiple DRQ support */ ++ HOST_CAP_FBS = BIT(16), /* FIS-based switching support */ ++ HOST_CAP_PMP = BIT(17), /* Port Multiplier support */ ++ HOST_CAP_ONLY = BIT(18), /* Supports AHCI mode only */ ++ HOST_CAP_CLO = BIT(24), /* Command List Override support */ ++ HOST_CAP_LED = BIT(25), /* Supports activity LED */ ++ HOST_CAP_ALPM = BIT(26), /* Aggressive Link PM support */ ++ HOST_CAP_SSS = BIT(27), /* Staggered Spin-up */ ++ HOST_CAP_MPS = BIT(28), /* Mechanical presence switch */ ++ HOST_CAP_SNTF = BIT(29), /* SNotification register */ ++ HOST_CAP_NCQ = BIT(30), /* Native Command Queueing */ ++ HOST_CAP_64 = BIT(31), /* PCI DAC (64-bit DMA) support */ + + /* HOST_CAP2 bits */ +- HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ +- HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ +- HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ +- HOST_CAP2_SDS = (1 << 3), /* Support device sleep */ +- HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */ +- HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */ ++ HOST_CAP2_BOH = BIT(0), /* BIOS/OS handoff supported */ ++ HOST_CAP2_NVMHCI = BIT(1), /* NVMHCI supported */ ++ HOST_CAP2_APST = BIT(2), /* Automatic partial to slumber */ ++ HOST_CAP2_SDS = BIT(3), /* Support device sleep */ ++ HOST_CAP2_SADM = BIT(4), /* Support aggressive DevSlp */ ++ HOST_CAP2_DESO = BIT(5), /* DevSlp from slumber only */ + + /* registers for each SATA port */ + PORT_LST_ADDR = 0x00, /* command list DMA addr */ +@@ -129,24 +130,24 @@ enum { + PORT_DEVSLP = 0x44, /* device sleep */ + + /* PORT_IRQ_{STAT,MASK} bits */ +- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ +- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ +- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ +- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ +- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ +- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ +- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ +- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ +- +- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ +- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ +- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ +- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ +- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ +- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ +- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ +- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ +- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ ++ PORT_IRQ_COLD_PRES = BIT(31), /* cold presence detect */ ++ PORT_IRQ_TF_ERR = BIT(30), /* task file error */ ++ PORT_IRQ_HBUS_ERR = BIT(29), /* host bus fatal error */ ++ PORT_IRQ_HBUS_DATA_ERR = BIT(28), /* host bus data error */ ++ PORT_IRQ_IF_ERR = BIT(27), /* interface fatal error */ ++ PORT_IRQ_IF_NONFATAL = BIT(26), /* interface non-fatal error */ ++ PORT_IRQ_OVERFLOW = BIT(24), /* xfer exhausted available S/G */ ++ PORT_IRQ_BAD_PMP = BIT(23), /* incorrect port multiplier */ ++ ++ PORT_IRQ_PHYRDY = BIT(22), /* PhyRdy changed */ ++ PORT_IRQ_DEV_ILCK = BIT(7), /* device interlock */ ++ PORT_IRQ_CONNECT = BIT(6), /* port connect change status */ ++ PORT_IRQ_SG_DONE = BIT(5), /* descriptor processed */ ++ PORT_IRQ_UNK_FIS = BIT(4), /* unknown FIS rx'd */ ++ PORT_IRQ_SDB_FIS = BIT(3), /* Set Device Bits FIS rx'd */ ++ PORT_IRQ_DMAS_FIS = BIT(2), /* DMA Setup FIS rx'd */ ++ PORT_IRQ_PIOS_FIS = BIT(1), /* PIO Setup FIS rx'd */ ++ PORT_IRQ_D2H_REG_FIS = BIT(0), /* D2H Register FIS rx'd */ + + PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | + PORT_IRQ_IF_ERR | +@@ -162,34 +163,34 @@ enum { + PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, + + /* PORT_CMD bits */ +- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ +- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ +- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ +- PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */ +- PORT_CMD_ESP = (1 << 21), /* External Sata Port */ +- PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */ +- PORT_CMD_PMP = (1 << 17), /* PMP attached */ +- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ +- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ +- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ +- PORT_CMD_CLO = (1 << 3), /* Command list override */ +- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ +- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ +- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ +- +- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ +- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ +- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ +- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ ++ PORT_CMD_ASP = BIT(27), /* Aggressive Slumber/Partial */ ++ PORT_CMD_ALPE = BIT(26), /* Aggressive Link PM enable */ ++ PORT_CMD_ATAPI = BIT(24), /* Device is ATAPI */ ++ PORT_CMD_FBSCP = BIT(22), /* FBS Capable Port */ ++ PORT_CMD_ESP = BIT(21), /* External Sata Port */ ++ PORT_CMD_HPCP = BIT(18), /* HotPlug Capable Port */ ++ PORT_CMD_PMP = BIT(17), /* PMP attached */ ++ PORT_CMD_LIST_ON = BIT(15), /* cmd list DMA engine running */ ++ PORT_CMD_FIS_ON = BIT(14), /* FIS DMA engine running */ ++ PORT_CMD_FIS_RX = BIT(4), /* Enable FIS receive DMA engine */ ++ PORT_CMD_CLO = BIT(3), /* Command list override */ ++ PORT_CMD_POWER_ON = BIT(2), /* Power up device */ ++ PORT_CMD_SPIN_UP = BIT(1), /* Spin up device */ ++ PORT_CMD_START = BIT(0), /* Enable port DMA engine */ ++ ++ PORT_CMD_ICC_MASK = (0xfu << 28), /* i/f ICC state mask */ ++ PORT_CMD_ICC_ACTIVE = (0x1u << 28), /* Put i/f in active state */ ++ PORT_CMD_ICC_PARTIAL = (0x2u << 28), /* Put i/f in partial state */ ++ PORT_CMD_ICC_SLUMBER = (0x6u << 28), /* Put i/f in slumber state */ + + /* PORT_FBS bits */ + PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ + PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ + PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ + PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */ +- PORT_FBS_SDE = (1 << 2), /* FBS single device error */ +- PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ +- PORT_FBS_EN = (1 << 0), /* Enable FBS */ ++ PORT_FBS_SDE = BIT(2), /* FBS single device error */ ++ PORT_FBS_DEC = BIT(1), /* FBS device error clear */ ++ PORT_FBS_EN = BIT(0), /* Enable FBS */ + + /* PORT_DEVSLP bits */ + PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */ +@@ -197,50 +198,50 @@ enum { + PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */ + PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */ + PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */ +- PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */ +- PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */ ++ PORT_DEVSLP_DSP = BIT(1), /* DevSlp present */ ++ PORT_DEVSLP_ADSE = BIT(0), /* Aggressive DevSlp enable */ + + /* hpriv->flags bits */ + + #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) + +- AHCI_HFLAG_NO_NCQ = (1 << 0), +- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ +- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ +- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ +- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ +- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ +- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ +- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ +- AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ +- AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ +- AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as ++ AHCI_HFLAG_NO_NCQ = BIT(0), ++ AHCI_HFLAG_IGN_IRQ_IF_ERR = BIT(1), /* ignore IRQ_IF_ERR */ ++ AHCI_HFLAG_IGN_SERR_INTERNAL = BIT(2), /* ignore SERR_INTERNAL */ ++ AHCI_HFLAG_32BIT_ONLY = BIT(3), /* force 32bit */ ++ AHCI_HFLAG_MV_PATA = BIT(4), /* PATA port */ ++ AHCI_HFLAG_NO_MSI = BIT(5), /* no PCI MSI */ ++ AHCI_HFLAG_NO_PMP = BIT(6), /* no PMP */ ++ AHCI_HFLAG_SECT255 = BIT(8), /* max 255 sectors */ ++ AHCI_HFLAG_YES_NCQ = BIT(9), /* force NCQ cap on */ ++ AHCI_HFLAG_NO_SUSPEND = BIT(10), /* don't suspend */ ++ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = BIT(11), /* treat SRST timeout as + link offline */ +- AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ +- AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */ +- AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */ +- AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on ++ AHCI_HFLAG_NO_SNTF = BIT(12), /* no sntf */ ++ AHCI_HFLAG_NO_FPDMA_AA = BIT(13), /* no FPDMA AA */ ++ AHCI_HFLAG_YES_FBS = BIT(14), /* force FBS cap on */ ++ AHCI_HFLAG_DELAY_ENGINE = BIT(15), /* do not start engine on + port start (wait until + error-handling stage) */ +- AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ +- AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ ++ AHCI_HFLAG_NO_DEVSLP = BIT(17), /* no device sleep */ ++ AHCI_HFLAG_NO_FBS = BIT(18), /* no FBS */ + + #ifdef CONFIG_PCI_MSI +- AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */ ++ AHCI_HFLAG_MULTI_MSI = BIT(20), /* per-port MSI(-X) */ + #else + /* compile out MSI infrastructure */ + AHCI_HFLAG_MULTI_MSI = 0, + #endif +- AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ +- AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */ +- AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read ++ AHCI_HFLAG_WAKE_BEFORE_STOP = BIT(22), /* wake before DMA stop */ ++ AHCI_HFLAG_YES_ALPM = BIT(23), /* force ALPM cap on */ ++ AHCI_HFLAG_NO_WRITE_TO_RO = BIT(24), /* don't write to read + only registers */ +- AHCI_HFLAG_IS_MOBILE = (1 << 25), /* mobile chipset, use ++ AHCI_HFLAG_IS_MOBILE = BIT(25), /* mobile chipset, use + SATA_MOBILE_LPM_POLICY + as default lpm_policy */ +- AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during ++ AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during + suspend/resume */ +- AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */ ++ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ + + /* ap->flags bits */ + +@@ -256,22 +257,22 @@ enum { + EM_MAX_RETRY = 5, + + /* em_ctl bits */ +- EM_CTL_RST = (1 << 9), /* Reset */ +- EM_CTL_TM = (1 << 8), /* Transmit Message */ +- EM_CTL_MR = (1 << 0), /* Message Received */ +- EM_CTL_ALHD = (1 << 26), /* Activity LED */ +- EM_CTL_XMT = (1 << 25), /* Transmit Only */ +- EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ +- EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ +- EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ +- EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ +- EM_CTL_LED = (1 << 16), /* LED messages supported */ ++ EM_CTL_RST = BIT(9), /* Reset */ ++ EM_CTL_TM = BIT(8), /* Transmit Message */ ++ EM_CTL_MR = BIT(0), /* Message Received */ ++ EM_CTL_ALHD = BIT(26), /* Activity LED */ ++ EM_CTL_XMT = BIT(25), /* Transmit Only */ ++ EM_CTL_SMB = BIT(24), /* Single Message Buffer */ ++ EM_CTL_SGPIO = BIT(19), /* SGPIO messages supported */ ++ EM_CTL_SES = BIT(18), /* SES-2 messages supported */ ++ EM_CTL_SAFTE = BIT(17), /* SAF-TE messages supported */ ++ EM_CTL_LED = BIT(16), /* LED messages supported */ + + /* em message type */ +- EM_MSG_TYPE_LED = (1 << 0), /* LED */ +- EM_MSG_TYPE_SAFTE = (1 << 1), /* SAF-TE */ +- EM_MSG_TYPE_SES2 = (1 << 2), /* SES-2 */ +- EM_MSG_TYPE_SGPIO = (1 << 3), /* SGPIO */ ++ EM_MSG_TYPE_LED = BIT(0), /* LED */ ++ EM_MSG_TYPE_SAFTE = BIT(1), /* SAF-TE */ ++ EM_MSG_TYPE_SES2 = BIT(2), /* SES-2 */ ++ EM_MSG_TYPE_SGPIO = BIT(3), /* SGPIO */ + }; + + struct ahci_cmd_hdr { diff --git a/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch b/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch new file mode 100644 index 00000000000..e9d692b651a --- /dev/null +++ b/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch @@ -0,0 +1,49 @@ +From d3115128bdafb62628ab41861a4f06f6d02ac320 Mon Sep 17 00:00:00 2001 +From: Lech Perczak +Date: Mon, 10 Jan 2022 23:48:44 +0100 +Subject: MIPS: ath79: drop _machine_restart again + +Commit 81424d0ad0d4 ("MIPS: ath79: Use the reset controller to restart +OF machines") removed setup of _machine_restart on OF machines to use +reset handler in reset controller driver. +While removing remnants of non-OF machines in commit 3a77e0d75eed +("MIPS: ath79: drop machfiles"), this was introduced again, making it +impossible to use additional restart handlers registered through device +tree. Drop setting _machine_restart altogether, and ath79_restart +function, which is no longer used after this. + +Fixes: 3a77e0d75eed ("MIPS: ath79: drop machfiles") +Cc: John Crispin +Cc: Florian Fainelli +Signed-off-by: Lech Perczak +Signed-off-by: Thomas Bogendoerfer +--- + arch/mips/ath79/setup.c | 10 ---------- + 1 file changed, 10 deletions(-) + +--- a/arch/mips/ath79/setup.c ++++ b/arch/mips/ath79/setup.c +@@ -34,15 +34,6 @@ + + static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; + +-static void ath79_restart(char *command) +-{ +- local_irq_disable(); +- ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); +- for (;;) +- if (cpu_wait) +- cpu_wait(); +-} +- + static void ath79_halt(void) + { + while (1) +@@ -234,7 +225,6 @@ void __init plat_mem_setup(void) + + detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX); + +- _machine_restart = ath79_restart; + _machine_halt = ath79_halt; + pm_power_off = ath79_halt; + } diff --git a/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch b/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch new file mode 100644 index 00000000000..fabf177628f --- /dev/null +++ b/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch @@ -0,0 +1,71 @@ +From 31d8f414e1596ba54a4315418e4c0086fda9e428 Mon Sep 17 00:00:00 2001 +From: Christian Lamparter +Date: Fri, 18 Feb 2022 10:06:43 +0100 +Subject: hwmon: (lm70) Add ti,tmp125 support + +The TMP125 is a 2 degree Celsius accurate Digital +Temperature Sensor with a SPI interface. + +The temperature register is a 16-bit, read-only register. +The MSB (Bit 15) is a leading zero and never set. Bits 14 +to 5 are the 1+9 temperature data bits in a two's +complement format. Bits 4 to 0 are useless copies of +Bit 5 value and therefore ignored. + +Signed-off-by: Christian Lamparter +Link: https://lore.kernel.org/r/43b19cbd4e7f51e9509e561b02b5d8d0e7079fac.1645175187.git.chunkeey@gmail.com +Signed-off-by: Guenter Roeck +--- +--- a/drivers/hwmon/lm70.c ++++ b/drivers/hwmon/lm70.c +@@ -34,6 +34,7 @@ + #define LM70_CHIP_LM71 2 /* NS LM71 */ + #define LM70_CHIP_LM74 3 /* NS LM74 */ + #define LM70_CHIP_TMP122 4 /* TI TMP122/TMP124 */ ++#define LM70_CHIP_TMP125 5 /* TI TMP125 */ + + struct lm70 { + struct spi_device *spi; +@@ -87,6 +88,12 @@ static ssize_t temp1_input_show(struct d + * LM71: + * 14 bits of 2's complement data, discard LSB 2 bits, + * resolution 0.0312 degrees celsius. ++ * ++ * TMP125: ++ * MSB/D15 is a leading zero. D14 is the sign-bit. This is ++ * followed by 9 temperature bits (D13..D5) in 2's complement ++ * data format with a resolution of 0.25 degrees celsius per unit. ++ * LSB 5 bits (D4..D0) share the same value as D5 and get discarded. + */ + switch (p_lm70->chip) { + case LM70_CHIP_LM70: +@@ -102,6 +109,10 @@ static ssize_t temp1_input_show(struct d + case LM70_CHIP_LM71: + val = ((int)raw / 4) * 3125 / 100; + break; ++ ++ case LM70_CHIP_TMP125: ++ val = (sign_extend32(raw, 14) / 32) * 250; ++ break; + } + + status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ +@@ -136,6 +147,10 @@ static const struct of_device_id lm70_of + .data = (void *) LM70_CHIP_TMP122, + }, + { ++ .compatible = "ti,tmp125", ++ .data = (void *) LM70_CHIP_TMP125, ++ }, ++ { + .compatible = "ti,lm71", + .data = (void *) LM70_CHIP_LM71, + }, +@@ -184,6 +199,7 @@ static const struct spi_device_id lm70_i + { "lm70", LM70_CHIP_LM70 }, + { "tmp121", LM70_CHIP_TMP121 }, + { "tmp122", LM70_CHIP_TMP122 }, ++ { "tmp125", LM70_CHIP_TMP125 }, + { "lm71", LM70_CHIP_LM71 }, + { "lm74", LM70_CHIP_LM74 }, + { }, diff --git a/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch b/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch new file mode 100644 index 00000000000..39fdb327733 --- /dev/null +++ b/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch @@ -0,0 +1,58 @@ +From a79a5613e1907e1bf09bb6ba6fd5ff43b66c1afe Mon Sep 17 00:00:00 2001 +From: Lech Perczak +Date: Fri, 1 Apr 2022 22:03:55 +0200 +Subject: [PATCH 1/3] cdc_ether: export usbnet_cdc_zte_rx_fixup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit bfe9b9d2df66 ("cdc_ether: Improve ZTE MF823/831/910 handling") +introduces a workaround for certain ZTE modems reporting invalid MAC +addresses over CDC-ECM. +The same issue was present on their RNDIS interface,which was fixed in +commit a5a18bdf7453 ("rndis_host: Set valid random MAC on buggy devices"). + +However, internal modem of ZTE MF286R router, on its RNDIS interface, also +exhibits a second issue fixed already in CDC-ECM, of the device not +respecting configured random MAC address. In order to share the fixup for +this with rndis_host driver, export the workaround function, which will +be re-used in the following commit in rndis_host. + +Cc: Kristian Evensen +Cc: Bjørn Mork +Cc: Oliver Neukum +Signed-off-by: Lech Perczak +--- + drivers/net/usb/cdc_ether.c | 3 ++- + include/linux/usb/usbnet.h | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/usb/cdc_ether.c ++++ b/drivers/net/usb/cdc_ether.c +@@ -479,7 +479,7 @@ static int usbnet_cdc_zte_bind(struct us + * device MAC address has been updated). Always set MAC address to that of the + * device. + */ +-static int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb) ++int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + { + if (skb->len < ETH_HLEN || !(skb->data[0] & 0x02)) + return 1; +@@ -489,6 +489,7 @@ static int usbnet_cdc_zte_rx_fixup(struc + + return 1; + } ++EXPORT_SYMBOL_GPL(usbnet_cdc_zte_rx_fixup); + + /* Ensure correct link state + * +--- a/include/linux/usb/usbnet.h ++++ b/include/linux/usb/usbnet.h +@@ -214,6 +214,7 @@ extern int usbnet_ether_cdc_bind(struct + extern int usbnet_cdc_bind(struct usbnet *, struct usb_interface *); + extern void usbnet_cdc_unbind(struct usbnet *, struct usb_interface *); + extern void usbnet_cdc_status(struct usbnet *, struct urb *); ++extern int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb); + + /* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ + #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ diff --git a/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch b/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch new file mode 100644 index 00000000000..71a6df81020 --- /dev/null +++ b/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch @@ -0,0 +1,118 @@ +From aa8aff10e969aca0cb64f5e54ff7489355582667 Mon Sep 17 00:00:00 2001 +From: Lech Perczak +Date: Fri, 1 Apr 2022 22:04:01 +0200 +Subject: [PATCH 2/3] rndis_host: enable the bogus MAC fixup for ZTE devices + from cdc_ether +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Certain ZTE modems, namely: MF823. MF831, MF910, built-in modem from +MF286R, expose both CDC-ECM and RNDIS network interfaces. +They have a trait of ignoring the locally-administered MAC address +configured on the interface both in CDC-ECM and RNDIS part, +and this leads to dropping of incoming traffic by the host. +However, the workaround was only present in CDC-ECM, and MF286R +explicitly requires it in RNDIS mode. + +Re-use the workaround in rndis_host as well, to fix operation of MF286R +module, some versions of which expose only the RNDIS interface. Do so by +introducing new flag, RNDIS_DRIVER_DATA_DST_MAC_FIXUP, and testing for it +in rndis_rx_fixup. This is required, as RNDIS uses frame batching, and all +of the packets inside the batch need the fixup. This might introduce a +performance penalty, because test is done for every returned Ethernet +frame. + +Apply the workaround to both "flavors" of RNDIS interfaces, as older ZTE +modems, like MF823 found in the wild, report the USB_CLASS_COMM class +interfaces, while MF286R reports USB_CLASS_WIRELESS_CONTROLLER. + +Suggested-by: Bjørn Mork +Cc: Kristian Evensen +Cc: Oliver Neukum +Signed-off-by: Lech Perczak +--- + drivers/net/usb/rndis_host.c | 32 ++++++++++++++++++++++++++++++++ + include/linux/usb/rndis_host.h | 1 + + 2 files changed, 33 insertions(+) + +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -486,10 +486,14 @@ EXPORT_SYMBOL_GPL(rndis_unbind); + */ + int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) + { ++ bool dst_mac_fixup; ++ + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + ++ dst_mac_fixup = !!(dev->driver_info->data & RNDIS_DRIVER_DATA_DST_MAC_FIXUP); ++ + /* peripheral may have batched packets to us... */ + while (likely(skb->len)) { + struct rndis_data_hdr *hdr = (void *)skb->data; +@@ -524,10 +528,17 @@ int rndis_rx_fixup(struct usbnet *dev, s + break; + skb_pull(skb, msg_len - sizeof *hdr); + skb_trim(skb2, data_len); ++ ++ if (unlikely(dst_mac_fixup)) ++ usbnet_cdc_zte_rx_fixup(dev, skb2); ++ + usbnet_skb_return(dev, skb2); + } + + /* caller will usbnet_skb_return the remaining packet */ ++ if (unlikely(dst_mac_fixup)) ++ usbnet_cdc_zte_rx_fixup(dev, skb); ++ + return 1; + } + EXPORT_SYMBOL_GPL(rndis_rx_fixup); +@@ -601,6 +612,17 @@ static const struct driver_info rndis_po + .tx_fixup = rndis_tx_fixup, + }; + ++static const struct driver_info zte_rndis_info = { ++ .description = "ZTE RNDIS device", ++ .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, ++ .data = RNDIS_DRIVER_DATA_DST_MAC_FIXUP, ++ .bind = rndis_bind, ++ .unbind = rndis_unbind, ++ .status = rndis_status, ++ .rx_fixup = rndis_rx_fixup, ++ .tx_fixup = rndis_tx_fixup, ++}; ++ + /*-------------------------------------------------------------------------*/ + + static const struct usb_device_id products [] = { +@@ -615,6 +637,16 @@ static const struct usb_device_id produc + USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long)&rndis_info, + }, { ++ /* ZTE WWAN modules */ ++ USB_VENDOR_AND_INTERFACE_INFO(0x19d2, ++ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), ++ .driver_info = (unsigned long)&zte_rndis_info, ++}, { ++ /* ZTE WWAN modules, ACM flavour */ ++ USB_VENDOR_AND_INTERFACE_INFO(0x19d2, ++ USB_CLASS_COMM, 2 /* ACM */, 0x0ff), ++ .driver_info = (unsigned long)&zte_rndis_info, ++}, { + /* RNDIS is MSFT's un-official variant of CDC ACM */ + USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), + .driver_info = (unsigned long) &rndis_info, +--- a/include/linux/usb/rndis_host.h ++++ b/include/linux/usb/rndis_host.h +@@ -197,6 +197,7 @@ struct rndis_keepalive_c { /* IN (option + + /* Flags for driver_info::data */ + #define RNDIS_DRIVER_DATA_POLL_STATUS 1 /* poll status before control */ ++#define RNDIS_DRIVER_DATA_DST_MAC_FIXUP 2 /* device ignores configured MAC address */ + + extern void rndis_status(struct usbnet *dev, struct urb *urb); + extern int diff --git a/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch b/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch new file mode 100644 index 00000000000..bdd812cc906 --- /dev/null +++ b/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch @@ -0,0 +1,63 @@ +From 9bfb4bcda7ba32d73ea322ea56a8ebe32e9247f6 Mon Sep 17 00:00:00 2001 +From: Lech Perczak +Date: Sat, 2 Apr 2022 02:19:57 +0200 +Subject: [PATCH 3/3] rndis_host: limit scope of bogus MAC address detection to + ZTE devices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reporting of bogus MAC addresses and ignoring configuration of new +destination address wasn't observed outside of a range of ZTE devices, +among which this seems to be the common bug. Align rndis_host driver +with implementation found in cdc_ether, which also limits this workaround +to ZTE devices. + +Suggested-by: Bjørn Mork +Cc: Kristian Evensen +Cc: Oliver Neukum +Signed-off-by: Lech Perczak +--- + drivers/net/usb/rndis_host.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -419,10 +419,7 @@ generic_rndis_bind(struct usbnet *dev, s + goto halt_fail_and_release; + } + +- if (bp[0] & 0x02) +- eth_hw_addr_random(net); +- else +- ether_addr_copy(net->dev_addr, bp); ++ ether_addr_copy(net->dev_addr, bp); + + /* set a nonzero filter to enable data transfers */ + memset(u.set, 0, sizeof *u.set); +@@ -464,6 +461,16 @@ static int rndis_bind(struct usbnet *dev + return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); + } + ++static int zte_rndis_bind(struct usbnet *dev, struct usb_interface *intf) ++{ ++ int status = rndis_bind(dev, intf); ++ ++ if (!status && (dev->net->dev_addr[0] & 0x02)) ++ eth_hw_addr_random(dev->net); ++ ++ return status; ++} ++ + void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) + { + struct rndis_halt *halt; +@@ -616,7 +623,7 @@ static const struct driver_info zte_rndi + .description = "ZTE RNDIS device", + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .data = RNDIS_DRIVER_DATA_DST_MAC_FIXUP, +- .bind = rndis_bind, ++ .bind = zte_rndis_bind, + .unbind = rndis_unbind, + .status = rndis_status, + .rx_fixup = rndis_rx_fixup, diff --git a/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch b/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch new file mode 100644 index 00000000000..38fbc3a3d73 --- /dev/null +++ b/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch @@ -0,0 +1,40 @@ +From dbf70fc204d2fbb0d8ad8f42038a60846502efda Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Oct 2022 13:51:09 +0300 +Subject: [PATCH] mtd: spinand: winbond: fix flash identification + +Winbond uses 3 bytes to identify flash: vendor_id, dev_id_0, dev_id_1, +but current driver uses only first 2 bytes of it for devices +identification. As result Winbond W25N02KV flash (id_bytes: EF, AA, 22) +is identified as W25N01GV (id_bytes: EF, AA, 21). + +Fix this by adding missed identification bytes. + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Frieder Schrempf +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-1-mikhail.kshevetskiy@iopsys.eu +--- + drivers/mtd/nand/spi/winbond.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct + + static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO("W25M02GV", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, +@@ -86,7 +86,7 @@ static const struct spinand_info winbond + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_SELECT_TARGET(w25m02gv_select_target)), + SPINAND_INFO("W25N01GV", +- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, diff --git a/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch b/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch new file mode 100644 index 00000000000..d75a1acc57c --- /dev/null +++ b/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch @@ -0,0 +1,106 @@ +From 6154c7a583483d7b69f53bea868efdc369edd563 Mon Sep 17 00:00:00 2001 +From: Mikhail Kshevetskiy +Date: Mon, 10 Oct 2022 13:51:10 +0300 +Subject: [PATCH] mtd: spinand: winbond: add Winbond W25N02KV flash support + +Add support of Winbond W25N02KV flash + +Signed-off-by: Mikhail Kshevetskiy +Reviewed-by: Frieder Schrempf +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-2-mikhail.kshevetskiy@iopsys.eu +--- + drivers/mtd/nand/spi/winbond.c | 75 ++++++++++++++++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +--- a/drivers/mtd/nand/spi/winbond.c ++++ b/drivers/mtd/nand/spi/winbond.c +@@ -74,6 +74,72 @@ static int w25m02gv_select_target(struct + return spi_mem_exec_op(spinand->spimem, &op); + } + ++static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = 64 + (16 * section); ++ region->length = 13; ++ ++ return 0; ++} ++ ++static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = (16 * section) + 2; ++ region->length = 14; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { ++ .ecc = w25n02kv_ooblayout_ecc, ++ .free = w25n02kv_ooblayout_free, ++}; ++ ++static int w25n02kv_ecc_get_status(struct spinand_device *spinand, ++ u8 status) ++{ ++ struct nand_device *nand = spinand_to_nand(spinand); ++ u8 mbf = 0; ++ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); ++ ++ switch (status & STATUS_ECC_MASK) { ++ case STATUS_ECC_NO_BITFLIPS: ++ return 0; ++ ++ case STATUS_ECC_UNCOR_ERROR: ++ return -EBADMSG; ++ ++ case STATUS_ECC_HAS_BITFLIPS: ++ /* ++ * Let's try to retrieve the real maximum number of bitflips ++ * in order to avoid forcing the wear-leveling layer to move ++ * data around if it's not necessary. ++ */ ++ if (spi_mem_exec_op(spinand->spimem, &op)) ++ return nanddev_get_ecc_conf(nand)->strength; ++ ++ mbf >>= 4; ++ ++ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) ++ return nanddev_get_ecc_conf(nand)->strength; ++ ++ return mbf; ++ ++ default: ++ break; ++ } ++ ++ return -EINVAL; ++} ++ + static const struct spinand_info winbond_spinand_table[] = { + SPINAND_INFO("W25M02GV", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), +@@ -94,6 +160,15 @@ static const struct spinand_info winbond + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), ++ SPINAND_INFO("W25N02KV", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + }; + + static int winbond_spinand_init(struct spinand_device *spinand) diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 new file mode 100644 index 00000000000..f13af8ba268 --- /dev/null +++ b/target/linux/generic/config-6.1 @@ -0,0 +1,7591 @@ +# CONFIG_104_QUAD_8 is not set +CONFIG_32BIT=y +CONFIG_64BIT_TIME=y +# CONFIG_6LOWPAN is not set +# CONFIG_6LOWPAN_DEBUGFS is not set +# CONFIG_6PACK is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_9P_FS is not set +# CONFIG_AB3100_CORE is not set +# CONFIG_AB8500_CORE is not set +# CONFIG_ABP060MG is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_ACENIC is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_ACORN_PARTITION is not set +# CONFIG_ACPI_ALS is not set +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_APEI_PCIEAER is not set +# CONFIG_ACPI_BUTTON is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +# CONFIG_ACPI_EXTLOG is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_NFIT is not set +# CONFIG_ACPI_REDUCED_HARDWARE_ONLY is not set +# CONFIG_ACPI_TABLE_UPGRADE is not set +# CONFIG_ACPI_VIDEO is not set +# CONFIG_AD2S1200 is not set +# CONFIG_AD2S1210 is not set +# CONFIG_AD2S90 is not set +# CONFIG_AD5064 is not set +# CONFIG_AD5110 is not set +# CONFIG_AD525X_DPOT is not set +# CONFIG_AD5272 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_AD5686 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5766 is not set +# CONFIG_AD5770R is not set +# CONFIG_AD5791 is not set +# CONFIG_AD5933 is not set +# CONFIG_AD7091R5 is not set +# CONFIG_AD7124 is not set +# CONFIG_AD7150 is not set +# CONFIG_AD7152 is not set +# CONFIG_AD7192 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7280 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7292 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606 is not set +# CONFIG_AD7606_IFACE_PARALLEL is not set +# CONFIG_AD7606_IFACE_SPI is not set +# CONFIG_AD7746 is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7768_1 is not set +# CONFIG_AD7780 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7816 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7949 is not set +# CONFIG_AD799X is not set +# CONFIG_AD8366 is not set +# CONFIG_AD8801 is not set +# CONFIG_AD9467 is not set +# CONFIG_AD9523 is not set +# CONFIG_AD9832 is not set +# CONFIG_AD9834 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_ADE7854 is not set +# CONFIG_ADF4350 is not set +# CONFIG_ADF4371 is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16203 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADIS16240 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16460 is not set +# CONFIG_ADIS16475 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_ADI_AXI_ADC is not set +# CONFIG_ADJD_S311 is not set +# CONFIG_ADM6996_PHY is not set +# CONFIG_ADM8211 is not set +# CONFIG_ADT7316 is not set +# CONFIG_ADUX1020 is not set +CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXL372_I2C is not set +# CONFIG_ADXL372_SPI is not set +# CONFIG_ADXRS290 is not set +# CONFIG_ADXRS450 is not set +CONFIG_AEABI=y +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_AFFS_FS is not set +# CONFIG_AFS_DEBUG_CURSOR is not set +# CONFIG_AFS_FS is not set +# CONFIG_AF_KCM is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_RXRPC_INJECT_LOSS is not set +# CONFIG_AF_RXRPC_IPV6 is not set +CONFIG_AF_UNIX_OOB=y +# CONFIG_AGP is not set +# CONFIG_AHCI_BRCM is not set +# CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_IMX is not set +# CONFIG_AHCI_MVEBU is not set +# CONFIG_AHCI_QORIQ is not set +# CONFIG_AHCI_XGENE is not set +CONFIG_AIO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_AK09911 is not set +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AL3010 is not set +# CONFIG_AL3320A is not set +# CONFIG_ALIM7101_WDT is not set +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_ALTERA_MBOX is not set +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_ALX is not set +# CONFIG_AL_FIC is not set +# CONFIG_AM2315 is not set +# CONFIG_AM335X_PHY_USB is not set +# CONFIG_AMBA_PL08X is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +# CONFIG_AMD_PHY is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_AMD_XGBE_HAVE_ECC is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_ANDROID is not set +CONFIG_ANON_INODES=y +# CONFIG_APDS9300 is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_APDS9960 is not set +# CONFIG_APM8018X is not set +# CONFIG_APM_EMULATION is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_APPLICOM is not set +# CONFIG_AQTION is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AR5523 is not set +# CONFIG_AR7 is not set +# CONFIG_AR8216_PHY is not set +# CONFIG_AR8216_PHY_LEDS is not set +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_APPLE is not set +# CONFIG_ARCH_ARTPEC is not set +# CONFIG_ARCH_ASPEED is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_AXXIA is not set +# CONFIG_ARCH_BCM is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM4908 is not set +# CONFIG_ARCH_BCM_21664 is not set +# CONFIG_ARCH_BCM_23550 is not set +# CONFIG_ARCH_BCM_281XX is not set +# CONFIG_ARCH_BCM_5301X is not set +# CONFIG_ARCH_BCM_53573 is not set +# CONFIG_ARCH_BCM_63XX is not set +# CONFIG_ARCH_BCM_CYGNUS is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BCM_NSP is not set +# CONFIG_ARCH_BERLIN is not set +CONFIG_ARCH_BINFMT_ELF_STATE=y +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_DIGICOLOR is not set +# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_EXYNOS is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_HI3xxx is not set +# CONFIG_ARCH_HIGHBANK is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_INTEL_SOCFPGA is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_KEEMBAY is not set +# CONFIG_ARCH_KEYSTONE is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MEDIATEK is not set +# CONFIG_ARCH_MESON is not set +# CONFIG_ARCH_MILBEAUT is not set +CONFIG_ARCH_MMAP_RND_BITS=8 +CONFIG_ARCH_MMAP_RND_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_MSTARV7 is not set +# CONFIG_ARCH_MULTIPLATFORM is not set +# CONFIG_ARCH_MULTI_V6 is not set +# CONFIG_ARCH_MULTI_V7 is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_NPCM is not set +# CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_OMAP1 is not set +# CONFIG_ARCH_OMAP2 is not set +# CONFIG_ARCH_OMAP2PLUS is not set +# CONFIG_ARCH_OMAP3 is not set +# CONFIG_ARCH_OMAP4 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_OXNAS is not set +# CONFIG_ARCH_PICOXCELL is not set +# CONFIG_ARCH_PRIMA2 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_RANDOM is not set +# CONFIG_ARCH_RDA is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_S32 is not set +# CONFIG_ARCH_S3C24XX is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_SIRF is not set +# CONFIG_ARCH_SOCFPGA is not set +# CONFIG_ARCH_SPARX5 is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_STI is not set +# CONFIG_ARCH_STM32 is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TANGO is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_VIRT is not set +# CONFIG_ARCH_VISCONTI is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_ARCH_VULCAN is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_WANTS_THP_SWAP is not set +# CONFIG_ARCH_WM8505 is not set +# CONFIG_ARCH_WM8750 is not set +# CONFIG_ARCH_WM8850 is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQ is not set +# CONFIG_ARCH_ZYNQMP is not set +# CONFIG_ARCNET is not set +# CONFIG_ARC_EMAC is not set +# CONFIG_ARC_IRQ_NO_AUTOSAVE is not set +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_ARM64_AMU_EXTN is not set +# CONFIG_ARM64_BTI is not set +# CONFIG_ARM64_CRYPTO is not set +# CONFIG_ARM64_E0PD is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_ARM64_ERRATUM_1319367 is not set +# CONFIG_ARM64_ERRATUM_1418040 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1508412 is not set +# CONFIG_ARM64_ERRATUM_1530923 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_1742098 is not set +# CONFIG_ARM64_ERRATUM_2441007 is not set +# CONFIG_ARM64_ERRATUM_2441009 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_MODULE_PLTS is not set +# CONFIG_ARM64_MTE is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_ARM64_PTR_AUTH is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_RELOC_TEST is not set +# CONFIG_ARM64_SVE is not set +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_TLB_RANGE is not set +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_USE_LSE_ATOMICS is not set +# CONFIG_ARM64_VA_BITS_48 is not set +# CONFIG_ARM64_VHE is not set +# CONFIG_ARM_APPENDED_DTB is not set +# CONFIG_ARM_ARCH_TIMER is not set +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set +# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set +# CONFIG_ARM_CCI is not set +# CONFIG_ARM_CCI400_PMU is not set +# CONFIG_ARM_CCI5xx_PMU is not set +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +# CONFIG_ARM_CMN is not set +# CONFIG_ARM_CPUIDLE is not set +CONFIG_ARM_CPU_TOPOLOGY=y +# CONFIG_ARM_CRYPTO is not set +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_ERRATA_326103 is not set +# CONFIG_ARM_ERRATA_364296 is not set +# CONFIG_ARM_ERRATA_411920 is not set +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_643719 is not set +# CONFIG_ARM_ERRATA_720789 is not set +# CONFIG_ARM_ERRATA_742230 is not set +# CONFIG_ARM_ERRATA_742231 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_751472 is not set +# CONFIG_ARM_ERRATA_754322 is not set +# CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764369 is not set +# CONFIG_ARM_ERRATA_773022 is not set +# CONFIG_ARM_ERRATA_775420 is not set +# CONFIG_ARM_ERRATA_798181 is not set +# CONFIG_ARM_ERRATA_814220 is not set +# CONFIG_ARM_ERRATA_818325_852422 is not set +# CONFIG_ARM_ERRATA_821420 is not set +# CONFIG_ARM_ERRATA_825619 is not set +# CONFIG_ARM_ERRATA_852421 is not set +# CONFIG_ARM_ERRATA_852423 is not set +# CONFIG_ARM_ERRATA_857271 is not set +# CONFIG_ARM_ERRATA_857272 is not set +# CONFIG_ARM_FFA_TRANSPORT is not set +CONFIG_ARM_GIC_MAX_NR=1 +# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set +# CONFIG_ARM_KPROBES_TEST is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_ARM_MEDIATEK_CPUFREQ_HW is not set +# CONFIG_ARM_MHU is not set +# CONFIG_ARM_MODULE_PLTS is not set +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +# CONFIG_ARM_PSCI is not set +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_PSCI_CPUIDLE is not set +# CONFIG_ARM_PTDUMP_DEBUGFS is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_ARM_SCMI_PROTOCOL is not set +# CONFIG_ARM_SCPI_PROTOCOL is not set +# CONFIG_ARM_SDE_INTERFACE is not set +# CONFIG_ARM_SMCCC_SOC_ID is not set +# CONFIG_ARM_SMC_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SPE_PMU is not set +# CONFIG_ARM_THUMBEE is not set +# CONFIG_ARM_TIMER_SP804 is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_ARM_VIRT_EXT is not set +# CONFIG_AS3935 is not set +# CONFIG_AS73211 is not set +# CONFIG_ASM9260_TIMER is not set +# CONFIG_ASN1 is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASYMMETRIC_KEY_TYPE is not set +# CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE is not set +# CONFIG_ASYNC_RAID6_TEST is not set +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_AT76C50X_USB is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_AT91_SAMA5D2_ADC is not set +# CONFIG_ATA is not set +# CONFIG_ATAGS is not set +CONFIG_ATAGS_PROC=y +# CONFIG_ATALK is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_ATA_ACPI is not set +CONFIG_ATA_BMDMA=y +# CONFIG_ATA_FORCE is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_ATA_LEDS is not set +# CONFIG_ATA_NONSTANDARD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_ATA_PIIX is not set +CONFIG_ATA_SFF=y +# CONFIG_ATA_VERBOSE_ERROR is not set +# CONFIG_ATH10K is not set +# CONFIG_ATH25 is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH6KL is not set +# CONFIG_ATH79 is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1C is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL2 is not set +# CONFIG_ATLAS_EZO_SENSOR is not set +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_ATM is not set +# CONFIG_ATMEL is not set +# CONFIG_ATMEL_PIT is not set +# CONFIG_ATMEL_SSC is not set +# CONFIG_ATM_AMBASSADOR is not set +# CONFIG_ATM_BR2684 is not set +CONFIG_ATM_BR2684_IPFILTER=y +# CONFIG_ATM_CLIP is not set +CONFIG_ATM_CLIP_NO_ICMP=y +# CONFIG_ATM_DRIVERS is not set +# CONFIG_ATM_DUMMY is not set +# CONFIG_ATM_ENI is not set +# CONFIG_ATM_FIRESTREAM is not set +# CONFIG_ATM_FORE200E is not set +# CONFIG_ATM_HE is not set +# CONFIG_ATM_HORIZON is not set +# CONFIG_ATM_IA is not set +# CONFIG_ATM_IDT77252 is not set +# CONFIG_ATM_LANAI is not set +# CONFIG_ATM_LANE is not set +# CONFIG_ATM_MPOA is not set +# CONFIG_ATM_NICSTAR is not set +# CONFIG_ATM_SOLOS is not set +# CONFIG_ATM_TCP is not set +# CONFIG_ATM_ZATM is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_ATP is not set +# CONFIG_AUDIT is not set +# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set +# CONFIG_AURORA_NB8800 is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTO_ZRELADDR is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_AX25 is not set +# CONFIG_AX25_DAMA_SLAVE is not set +# CONFIG_AX88796 is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_AXP20X_ADC is not set +# CONFIG_AXP20X_POWER is not set +# CONFIG_AXP288_ADC is not set +# CONFIG_AXP288_FUEL_GAUGE is not set +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_B44 is not set +# CONFIG_B53 is not set +# CONFIG_B53_MDIO_DRIVER is not set +# CONFIG_B53_MMAP_DRIVER is not set +# CONFIG_B53_SERDES is not set +# CONFIG_B53_SPI_DRIVER is not set +# CONFIG_B53_SRAB_DRIVER is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_GPIO is not set +# CONFIG_BACKLIGHT_KTD253 is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +# CONFIG_BACKLIGHT_LED is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_PANDORA is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_RPI is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_BAREUDP is not set +CONFIG_BASE_FULL=y +CONFIG_BASE_SMALL=0 +# CONFIG_BATMAN_ADV is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_BQ27XXX_HDQ is not set +# CONFIG_BATTERY_CW2015 is not set +# CONFIG_BATTERY_DS2760 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1721X is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_BAYCOM_EPP is not set +# CONFIG_BAYCOM_PAR is not set +# CONFIG_BAYCOM_SER_FDX is not set +# CONFIG_BAYCOM_SER_HDX is not set +# CONFIG_BCACHE is not set +# CONFIG_BCM47XX is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM63XX is not set +# CONFIG_BCM63XX_PHY is not set +# CONFIG_BCM7038_WDT is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BCMA is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMGENET is not set +# CONFIG_BCM_IPROC_ADC is not set +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_BCM_SBA_RAID is not set +# CONFIG_BCM_VK is not set +# CONFIG_BDI_SWITCH is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BE2NET is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_BGMAC is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_BIG_LITTLE is not set +CONFIG_BINARY_PRINTF=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_ELF_FDPIC is not set +# CONFIG_BINFMT_FLAT is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_SCRIPT=y +CONFIG_BITREVERSE=y +# CONFIG_BLK_CGROUP_IOCOST is not set +# CONFIG_BLK_CGROUP_IOLATENCY is not set +# CONFIG_BLK_CGROUP_IOPRIO is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_DEBUG_FS is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_BLK_DEV_4DRIVES is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI14XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_ATIIXP is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_CS5535 is not set +# CONFIG_BLK_DEV_CS5536 is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_DELKIN is not set +# CONFIG_BLK_DEV_DM is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_DTC2278 is not set +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_GENERIC is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_HT6560B is not set +# CONFIG_BLK_DEV_IDEACPI is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDECS is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_IDEPNP is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDE_AU1XXX is not set +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_BLK_DEV_IT8172 is not set +# CONFIG_BLK_DEV_IT8213 is not set +# CONFIG_BLK_DEV_IT821X is not set +# CONFIG_BLK_DEV_JMICRON is not set +# CONFIG_BLK_DEV_LOOP is not set +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_MD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_BLK_DEV_OFFBOARD is not set +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_PLATFORM is not set +# CONFIG_BLK_DEV_PMEM is not set +# CONFIG_BLK_DEV_QD65XX is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_RSXX is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_SD is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SIS5513 is not set +# CONFIG_BLK_DEV_SKD is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_TC86C001 is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UMC8672 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLOCK=y +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMA400 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_BMC150_MAGN is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_BME680 is not set +# CONFIG_BMG160 is not set +# CONFIG_BMI088_ACCEL is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_BMIPS_GENERIC is not set +# CONFIG_BMP280 is not set +# CONFIG_BNA is not set +# CONFIG_BNX2 is not set +# CONFIG_BNX2X is not set +# CONFIG_BNX2X_SRIOV is not set +# CONFIG_BNXT is not set +# CONFIG_BONDING is not set +# CONFIG_BOOKE_WDT is not set +CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 +# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set +# CONFIG_BOOTTIME_TRACING is not set +# CONFIG_BOOT_CONFIG is not set +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_BOOT_RAW=y +# CONFIG_BOUNCE is not set +CONFIG_BPF=y +# CONFIG_BPFILTER is not set +CONFIG_BPF_JIT=y +# CONFIG_BPF_JIT_ALWAYS_ON is not set +CONFIG_BPF_JIT_DEFAULT_ON=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_UNPRIV_DEFAULT_OFF=y +# CONFIG_BPQETHER is not set +CONFIG_BQL=y +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_BRCMFMAC is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMSTB_GISB_ARB is not set +CONFIG_BRIDGE=y +# CONFIG_BRIDGE_CFM is not set +# CONFIG_BRIDGE_EBT_802_3 is not set +# CONFIG_BRIDGE_EBT_AMONG is not set +# CONFIG_BRIDGE_EBT_ARP is not set +# CONFIG_BRIDGE_EBT_ARPREPLY is not set +# CONFIG_BRIDGE_EBT_BROUTE is not set +# CONFIG_BRIDGE_EBT_DNAT is not set +# CONFIG_BRIDGE_EBT_IP is not set +# CONFIG_BRIDGE_EBT_IP6 is not set +# CONFIG_BRIDGE_EBT_LIMIT is not set +# CONFIG_BRIDGE_EBT_LOG is not set +# CONFIG_BRIDGE_EBT_MARK is not set +# CONFIG_BRIDGE_EBT_MARK_T is not set +# CONFIG_BRIDGE_EBT_NFLOG is not set +# CONFIG_BRIDGE_EBT_PKTTYPE is not set +# CONFIG_BRIDGE_EBT_REDIRECT is not set +# CONFIG_BRIDGE_EBT_SNAT is not set +# CONFIG_BRIDGE_EBT_STP is not set +# CONFIG_BRIDGE_EBT_T_FILTER is not set +# CONFIG_BRIDGE_EBT_T_NAT is not set +# CONFIG_BRIDGE_EBT_VLAN is not set +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_MRP is not set +# CONFIG_BRIDGE_NETFILTER is not set +# CONFIG_BRIDGE_NF_EBTABLES is not set +CONFIG_BRIDGE_VLAN_FILTERING=y +# CONFIG_BROADCOM_PHY is not set +CONFIG_BROKEN_ON_SMP=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +# CONFIG_BT is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BT_AOSPEXT is not set +# CONFIG_BT_ATH3K is not set +# CONFIG_BT_BNEP is not set +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_CMTP is not set +# CONFIG_BT_FEATURE_DEBUG is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIBLUECARD is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBT3C is not set +# CONFIG_BT_HCIBTSDIO is not set +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +# CONFIG_BT_HCIBTUSB_MTK is not set +# CONFIG_BT_HCIBTUSB_RTL is not set +# CONFIG_BT_HCIDTL1 is not set +# CONFIG_BT_HCIUART is not set +# CONFIG_BT_HCIUART_3WIRE is not set +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_ATH3K is not set +CONFIG_BT_HCIUART_BCSP=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIUART_MRVL is not set +# CONFIG_BT_HCIUART_QCA is not set +# CONFIG_BT_HCIUART_RTL is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_HIDP is not set +# CONFIG_BT_HS is not set +# CONFIG_BT_LE is not set +# CONFIG_BT_LEDS is not set +# CONFIG_BT_MRVL is not set +# CONFIG_BT_MSFTEXT is not set +# CONFIG_BT_MTKSDIO is not set +# CONFIG_BT_MTKUART is not set +# CONFIG_BT_RFCOMM is not set +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_VIRTIO is not set +CONFIG_BUG=y +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +CONFIG_BUILDTIME_EXTABLE_SORT=y +CONFIG_BUILDTIME_TABLE_SORT=y +# CONFIG_BUILD_BIN2C is not set +CONFIG_BUILD_SALT="" +# CONFIG_C2PORT is not set +CONFIG_CACHE_L2X0_PMU=y +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_CAIF is not set +# CONFIG_CAN is not set +# CONFIG_CAN_BCM is not set +# CONFIG_CAN_DEBUG_DEVICES is not set +# CONFIG_CAN_DEV is not set +# CONFIG_CAN_ETAS_ES58X is not set +# CONFIG_CAN_GS_USB is not set +# CONFIG_CAN_GW is not set +# CONFIG_CAN_HI311X is not set +# CONFIG_CAN_IFI_CANFD is not set +# CONFIG_CAN_ISOTP is not set +# CONFIG_CAN_J1939 is not set +# CONFIG_CAN_KVASER_PCIEFD is not set +# CONFIG_CAN_MCBA_USB is not set +# CONFIG_CAN_MCP251XFD is not set +# CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_PEAK_PCIEFD is not set +# CONFIG_CAN_RAW is not set +# CONFIG_CAN_RCAR is not set +# CONFIG_CAN_RCAR_CANFD is not set +# CONFIG_CAN_SLCAN is not set +# CONFIG_CAN_SUN4I is not set +# CONFIG_CAN_UCAN is not set +# CONFIG_CAN_VCAN is not set +# CONFIG_CAN_VXCAN is not set +# CONFIG_CAPI_AVM is not set +# CONFIG_CAPI_EICON is not set +# CONFIG_CAPI_TRACE is not set +CONFIG_CARDBUS=y +# CONFIG_CARDMAN_4000 is not set +# CONFIG_CARDMAN_4040 is not set +# CONFIG_CARL9170 is not set +# CONFIG_CASSINI is not set +# CONFIG_CAVIUM_CPT is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23144 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_OCTEON_SOC is not set +# CONFIG_CAVIUM_PTP is not set +# CONFIG_CAVIUM_TX2_ERRATUM_219 is not set +# CONFIG_CB710_CORE is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_CCS811 is not set +CONFIG_CC_CAN_LINK=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_CFG80211 is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +# CONFIG_CGROUPS is not set +# CONFIG_CGROUP_MISC is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_CHARGER_BD99954 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ2515X is not set +# CONFIG_CHARGER_BQ256XX is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_BQ25980 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_ISP1704 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LT3651 is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_LTC4162L is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_QCOM_SMBB is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_CHARGER_TWL4030 is not set +# CONFIG_CHARGER_UCS1002 is not set +# CONFIG_CHASH_SELFTEST is not set +# CONFIG_CHASH_STATS is not set +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CIFS is not set +# CONFIG_CIFS_ACL is not set +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_CIFS_FSCACHE is not set +# CONFIG_CIFS_NFSD_EXPORT is not set +CONFIG_CIFS_POSIX=y +# CONFIG_CIFS_SMB2 is not set +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_STATS2 is not set +# CONFIG_CIFS_SWN_UPCALL is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +CONFIG_CIFS_XATTR=y +# CONFIG_CIO_DAC is not set +# CONFIG_CLEANCACHE is not set +# CONFIG_CLKSRC_PISTACHIO is not set +# CONFIG_CLKSRC_VERSATILE is not set +# CONFIG_CLK_GFM_LPASS_SM8250 is not set +# CONFIG_CLK_HSDK is not set +# CONFIG_CLK_QORIQ is not set +# CONFIG_CLK_SP810 is not set +# CONFIG_CLOCK_THERMAL is not set +CONFIG_CLS_U32_MARK=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_CMA is not set +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_BOOL is not set +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_CMDLINE_FROM_BOOTLOADER is not set +# CONFIG_CMDLINE_PARTITION is not set +# CONFIG_CNIC is not set +# CONFIG_CODA_FS is not set +# CONFIG_CODE_PATCHING_SELFTEST is not set +# CONFIG_COMEDI is not set +# CONFIG_COMMON_CLK_AXI_CLKGEN is not set +# CONFIG_COMMON_CLK_BOSTON is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +# CONFIG_COMMON_CLK_CS2000_CP is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +# CONFIG_COMMON_CLK_IPROC is not set +# CONFIG_COMMON_CLK_MAX9485 is not set +# CONFIG_COMMON_CLK_MT6765 is not set +# CONFIG_COMMON_CLK_MT8167 is not set +# CONFIG_COMMON_CLK_MT8167_AUDSYS is not set +# CONFIG_COMMON_CLK_MT8167_IMGSYS is not set +# CONFIG_COMMON_CLK_MT8167_MFGCFG is not set +# CONFIG_COMMON_CLK_MT8167_MMSYS is not set +# CONFIG_COMMON_CLK_MT8167_VDECSYS is not set +# CONFIG_COMMON_CLK_MT8192 is not set +# CONFIG_COMMON_CLK_NXP is not set +# CONFIG_COMMON_CLK_PIC32 is not set +# CONFIG_COMMON_CLK_PISTACHIO is not set +# CONFIG_COMMON_CLK_PWM is not set +# CONFIG_COMMON_CLK_PXA is not set +# CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI5341 is not set +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_XGENE is not set +# CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set +CONFIG_COMPACTION=y +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_COMPAT is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_COMPILE_TEST is not set +# CONFIG_CONFIGFS_FS is not set +# CONFIG_CONNECTOR is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_CONSTRUCTORS=y +# CONFIG_CONTEXT_SWITCH_TRACER is not set +# CONFIG_COPS is not set +# CONFIG_CORDIC is not set +# CONFIG_COREDUMP is not set +# CONFIG_CORESIGHT is not set +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_COUNTER is not set +# CONFIG_CPA_DEBUG is not set +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_FREQ is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_FREQ_THERMAL is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND is not set +# CONFIG_CPU_IDLE is not set +# CONFIG_CPU_IDLE_GOV_LADDER is not set +# CONFIG_CPU_IDLE_GOV_MENU is not set +# CONFIG_CPU_IDLE_GOV_TEO is not set +# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set +# CONFIG_CPU_ISOLATION is not set +# CONFIG_CPU_LITTLE_ENDIAN is not set +# CONFIG_CPU_NO_EFFICIENT_FFS is not set +CONFIG_CPU_SW_DOMAIN_PAN=y +# CONFIG_CPU_THERMAL is not set +# CONFIG_CRAMFS is not set +CONFIG_CRAMFS_BLOCKDEV=y +# CONFIG_CRAMFS_MTD is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_CRC16 is not set +CONFIG_CRC32=y +# CONFIG_CRC32_BIT is not set +CONFIG_CRC32_SARWATE=y +# CONFIG_CRC32_SELFTEST is not set +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SLICEBY8 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC7 is not set +# CONFIG_CRC8 is not set +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC_ITU_T is not set +# CONFIG_CRC_T10DIF is not set +CONFIG_CROSS_COMPILE="" +# CONFIG_CROSS_MEMORY_ATTACH is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_842 is not set +CONFIG_CRYPTO_ACOMP2=y +# CONFIG_CRYPTO_ADIANTUM is not set +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS128L_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_AEGIS256_AESNI_SSE2 is not set +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_586 is not set +# CONFIG_CRYPTO_AES_ARM is not set +# CONFIG_CRYPTO_AES_ARM64 is not set +# CONFIG_CRYPTO_AES_ARM64_BS is not set +# CONFIG_CRYPTO_AES_ARM64_CE is not set +# CONFIG_CRYPTO_AES_ARM64_CE_BLK is not set +# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set +# CONFIG_CRYPTO_AES_ARM64_NEON_BLK is not set +# CONFIG_CRYPTO_AES_ARM_BS is not set +# CONFIG_CRYPTO_AES_ARM_CE is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_AES_TI is not set +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_BLAKE2B is not set +# CONFIG_CRYPTO_BLAKE2B_NEON is not set +# CONFIG_CRYPTO_BLAKE2S is not set +# CONFIG_CRYPTO_BLAKE2S_ARM is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_CBC is not set +CONFIG_CRYPTO_CCM=y +# CONFIG_CRYPTO_CFB is not set +# CONFIG_CRYPTO_CHACHA20 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_CHACHA20_NEON is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_CHACHA_MIPS is not set +# CONFIG_CRYPTO_CMAC is not set +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32_ARM_CE is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set +# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# CONFIG_CRYPTO_CURVE25519_NEON is not set +# CONFIG_CRYPTO_CURVE25519_X86 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +# CONFIG_CRYPTO_DEV_ATMEL_AES is not set +# CONFIG_CRYPTO_DEV_ATMEL_AUTHENC is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_ATMEL_TDES is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCP_DEBUGFS is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM is not set +# CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is not set +# CONFIG_CRYPTO_DEV_HIFN_795X is not set +# CONFIG_CRYPTO_DEV_HISI_SEC is not set +# CONFIG_CRYPTO_DEV_HISI_ZIP is not set +# CONFIG_CRYPTO_DEV_IMGTEC_HASH is not set +# CONFIG_CRYPTO_DEV_MARVELL_CESA is not set +# CONFIG_CRYPTO_DEV_MEDIATEK is not set +# CONFIG_CRYPTO_DEV_MV_CESA is not set +# CONFIG_CRYPTO_DEV_MXC_SCC is not set +# CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_OCTEONTX_CPT is not set +# CONFIG_CRYPTO_DEV_QAT_4XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QCE is not set +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_SAHARA is not set +# CONFIG_CRYPTO_DEV_SP_PSP is not set +# CONFIG_CRYPTO_DEV_TALITOS is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_MENU is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECDSA is not set +# CONFIG_CRYPTO_ECHAINIV is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_ESSIV is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_FIPS is not set +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_GHASH=y +# CONFIG_CRYPTO_GHASH_ARM64_CE is not set +# CONFIG_CRYPTO_GHASH_ARM_CE is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_CRYPTO_JITTERENTROPY is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_KHAZAD is not set +CONFIG_CRYPTO_KPP=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=y +# CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC is not set +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +# CONFIG_CRYPTO_LIB_POLY1305 is not set +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9 +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_MCRYPTD is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_MORUS1280 is not set +# CONFIG_CRYPTO_MORUS1280_AVX2 is not set +# CONFIG_CRYPTO_MORUS1280_SSE2 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS640_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_PCOMP is not set +# CONFIG_CRYPTO_PCOMP2 is not set +CONFIG_CRYPTO_PCRYPT=y +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_POLY1305_ARM is not set +# CONFIG_CRYPTO_POLY1305_MIPS is not set +# CONFIG_CRYPTO_POLY1305_NEON is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RNG is not set +# CONFIG_CRYPTO_RSA is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA1_ARM is not set +# CONFIG_CRYPTO_SHA1_ARM64_CE is not set +# CONFIG_CRYPTO_SHA1_ARM_CE is not set +# CONFIG_CRYPTO_SHA1_ARM_NEON is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA256_ARM is not set +# CONFIG_CRYPTO_SHA256_ARM64 is not set +# CONFIG_CRYPTO_SHA2_ARM64_CE is not set +# CONFIG_CRYPTO_SHA2_ARM_CE is not set +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SHA3_ARM64 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_SHA512_ARM is not set +# CONFIG_CRYPTO_SHA512_ARM64 is not set +# CONFIG_CRYPTO_SHA512_ARM64_CE is not set +# CONFIG_CRYPTO_SIMD is not set +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_SM4_ARM64_CE is not set +# CONFIG_CRYPTO_SPECK is not set +# CONFIG_CRYPTO_STATS is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_TWOFISH_586 is not set +# CONFIG_CRYPTO_TWOFISH_COMMON is not set +# CONFIG_CRYPTO_USER is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE is not set +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_XXHASH is not set +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_ZSTD is not set +# CONFIG_CS5535_MFGPT is not set +# CONFIG_CS89x0 is not set +# CONFIG_CS89x0_PLATFORM is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# CONFIG_CUSE is not set +# CONFIG_CW1200 is not set +# CONFIG_CXD2880_SPI_DRV is not set +# CONFIG_CXL_AFU_DRIVER_OPS is not set +# CONFIG_CXL_BASE is not set +# CONFIG_CXL_BUS is not set +# CONFIG_CXL_EEH is not set +# CONFIG_CXL_KERNEL_API is not set +# CONFIG_CXL_LIB is not set +# CONFIG_CYPRESS_FIRMWARE is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DAMON is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DAX is not set +# CONFIG_DCB is not set +# CONFIG_DDR is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_CREDENTIALS is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_EFI is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_32B is not set +# CONFIG_DEBUG_FORCE_FUNCTION_ALIGN_64B is not set +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_GPIO is not set +# CONFIG_DEBUG_HIGHMEM is not set +# CONFIG_DEBUG_ICEDCC is not set +# CONFIG_DEBUG_INFO is not set +# CONFIG_DEBUG_INFO_BTF is not set +# CONFIG_DEBUG_INFO_COMPRESSED is not set +# CONFIG_DEBUG_INFO_DWARF4 is not set +# CONFIG_DEBUG_INFO_DWARF5 is not set +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +# CONFIG_DEBUG_INFO_REDUCED is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +# CONFIG_DEBUG_IRQFLAGS is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_KMAP_LOCAL is not set +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_KOBJECT is not set +# CONFIG_DEBUG_KOBJECT_RELEASE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_LL is not set +# CONFIG_DEBUG_LL_UART_8250 is not set +# CONFIG_DEBUG_LL_UART_PL01X is not set +# CONFIG_DEBUG_LOCKDEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_MISC is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_NX_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_RSEQ is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_SEMIHOSTING is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_SHIRQ is not set +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_STACKOVERFLOW is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_UART_8250_PALMCHIP is not set +# CONFIG_DEBUG_UART_8250_WORD is not set +# CONFIG_DEBUG_UART_BCM63XX is not set +# CONFIG_DEBUG_UART_FLOW_CONTROL is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGFLAGS is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +# CONFIG_DEBUG_VM_RB is not set +# CONFIG_DEBUG_VM_VMACACHE is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ZBOOT is not set +# CONFIG_DECNET is not set +# CONFIG_DEFAULT_CODEL is not set +CONFIG_DEFAULT_CUBIC=y +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_FQ is not set +CONFIG_DEFAULT_FQ_CODEL=y +# CONFIG_DEFAULT_FQ_PIE is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_DEFAULT_NET_SCH="fq_codel" +# CONFIG_DEFAULT_NOOP is not set +# CONFIG_DEFAULT_PFIFO_FAST is not set +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_DAC=y +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SFQ is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_DELL_LAPTOP is not set +# CONFIG_DELL_RBTN is not set +# CONFIG_DELL_SMBIOS is not set +# CONFIG_DELL_SMO8800 is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_DEVKMEM is not set +# CONFIG_DEVMEM is not set +CONFIG_DEVPORT=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_DEVTMPFS is not set +# CONFIG_DEVTMPFS_MOUNT is not set +# CONFIG_DEV_DAX is not set +# CONFIG_DGAP is not set +# CONFIG_DGNC is not set +# CONFIG_DHT11 is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_DISPLAY_CONNECTOR_ANALOG_TV is not set +# CONFIG_DISPLAY_CONNECTOR_DVI is not set +# CONFIG_DISPLAY_CONNECTOR_HDMI is not set +# CONFIG_DISPLAY_ENCODER_TFP410 is not set +# CONFIG_DISPLAY_ENCODER_TPD12S015 is not set +# CONFIG_DISPLAY_PANEL_DPI is not set +# CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DL2K is not set +# CONFIG_DLHL60D is not set +# CONFIG_DLM is not set +# CONFIG_DM9000 is not set +# CONFIG_DMABUF_DEBUG is not set +# CONFIG_DMABUF_HEAPS is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_SYSFS_STATS is not set +# CONFIG_DMADEVICES is not set +# CONFIG_DMADEVICES_DEBUG is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_DMASCC is not set +# CONFIG_DMATEST is not set +# CONFIG_DMA_API_DEBUG is not set +CONFIG_DMA_COHERENT_POOL=y +CONFIG_DMA_DECLARE_COHERENT=y +# CONFIG_DMA_ENGINE is not set +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_DMA_JZ4780 is not set +# CONFIG_DMA_MAP_BENCHMARK is not set +CONFIG_DMA_NONCOHERENT_MMAP=y +# CONFIG_DMA_NOOP_OPS is not set +# CONFIG_DMA_PERNUMA_CMA is not set +# CONFIG_DMA_RESTRICTED_POOL is not set +# CONFIG_DMA_SHARED_BUFFER is not set +# CONFIG_DMA_VIRT_OPS is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_CLONE is not set +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_MQ_DEFAULT is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DNET is not set +# CONFIG_DNOTIFY is not set +# CONFIG_DNS_RESOLVER is not set +CONFIG_DOUBLEFAULT=y +# CONFIG_DP83640_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DPOT_DAC is not set +# CONFIG_DPS310 is not set +CONFIG_DQL=y +# CONFIG_DRAGONRISE_FF is not set +# CONFIG_DRM is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_AMDGPU_CIK is not set +# CONFIG_DRM_AMDGPU_GART_DEBUGFS is not set +# CONFIG_DRM_AMDGPU_SI is not set +# CONFIG_DRM_AMDGPU_USERPTR is not set +# CONFIG_DRM_AMD_ACP is not set +# CONFIG_DRM_AMD_DC_DCN2_0 is not set +# CONFIG_DRM_AMD_DC_DCN3_0 is not set +# CONFIG_DRM_AMD_DC_HDCP is not set +# CONFIG_DRM_AMD_DC_SI is not set +# CONFIG_DRM_AMD_SECURE_DISPLAY is not set +# CONFIG_DRM_ANALOGIX_ANX6345 is not set +# CONFIG_DRM_ANALOGIX_ANX7625 is not set +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_ARMADA is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_ATMEL_HLCDC is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_CDNS_MHDP8546 is not set +# CONFIG_DRM_CHIPONE_ICN6211 is not set +# CONFIG_DRM_CHRONTEL_CH7033 is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +# CONFIG_DRM_DISPLAY_CONNECTOR is not set +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DP_CEC is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_EXYNOS is not set +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +# CONFIG_DRM_FSL_DCU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_GUD is not set +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_HISI_HIBMC is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_I2C_ADV7511 is not set +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I915 is not set +# CONFIG_DRM_ITE_IT66121 is not set +# CONFIG_DRM_KOMEDA is not set +# CONFIG_DRM_LEGACY is not set +# CONFIG_DRM_LIB_RANDOM is not set +# CONFIG_DRM_LIMA is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +# CONFIG_DRM_LONTIUM_LT8912B is not set +# CONFIG_DRM_LONTIUM_LT9611 is not set +# CONFIG_DRM_LONTIUM_LT9611UXC is not set +# CONFIG_DRM_LVDS_CODEC is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_MCDE is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_MXSFB is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_NWL_MIPI_DSI is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_OMAP is not set +# CONFIG_DRM_PANEL_ABT_Y030XX067A is not set +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596 is not set +# CONFIG_DRM_PANEL_BOE_HIMAX8279D is not set +# CONFIG_DRM_PANEL_BOE_TV101WUM_NL6 is not set +# CONFIG_DRM_PANEL_DSI_CM is not set +# CONFIG_DRM_PANEL_ELIDA_KD35T133 is not set +# CONFIG_DRM_PANEL_FEIXIN_K101_IM2BA02 is not set +# CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9806E is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set +# CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set +# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set +# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set +# CONFIG_DRM_PANEL_KHADAS_TS050 is not set +# CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04 is not set +# CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W is not set +# CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829 is not set +# CONFIG_DRM_PANEL_LG_LB035Q02 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set +# CONFIG_DRM_PANEL_MIPI_DBI is not set +# CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT35510 is not set +# CONFIG_DRM_PANEL_NOVATEK_NT36672A is not set +# CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set +# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set +# CONFIG_DRM_PANEL_ORISETECH_OTM8009A is not set +# CONFIG_DRM_PANEL_OSD_OSD101T2587_53TS is not set +# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM67191 is not set +# CONFIG_DRM_PANEL_RAYDIUM_RM68200 is not set +# CONFIG_DRM_PANEL_ROCKTECH_JH057N00900 is not set +# CONFIG_DRM_PANEL_RONBO_RB070D30 is not set +# CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20 is not set +# CONFIG_DRM_PANEL_SAMSUNG_DB7430 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6D16D0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SAMSUNG_SOFEF00 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set +# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set +# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7701 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7703 is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_SONY_ACX424AKP is not set +# CONFIG_DRM_PANEL_SONY_ACX565AKM is not set +# CONFIG_DRM_PANEL_TDO_TL070WSH30 is not set +# CONFIG_DRM_PANEL_TPO_TD028TTEC1 is not set +# CONFIG_DRM_PANEL_TPO_TD043MTEA1 is not set +# CONFIG_DRM_PANEL_TPO_TPG110 is not set +# CONFIG_DRM_PANEL_TPO_Y17P is not set +# CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA is not set +# CONFIG_DRM_PANEL_VISIONOX_RM69299 is not set +# CONFIG_DRM_PANEL_WIDECHIPS_WS2401 is not set +# CONFIG_DRM_PANEL_XINPENG_XPP055C272 is not set +# CONFIG_DRM_PANFROST is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_PARADE_PS8640 is not set +# CONFIG_DRM_PL111 is not set +# CONFIG_DRM_QXL is not set +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_RADEON_USERPTR is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +# CONFIG_DRM_ROCKCHIP is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_SIMPLEDRM is not set +# CONFIG_DRM_SIMPLE_BRIDGE is not set +# CONFIG_DRM_STI is not set +# CONFIG_DRM_STM is not set +# CONFIG_DRM_SUN4I is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TIDSS is not set +# CONFIG_DRM_TILCDC is not set +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_TI_SN65DSI83 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_TPD12S015 is not set +# CONFIG_DRM_TOSHIBA_TC358762 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TOSHIBA_TC358768 is not set +# CONFIG_DRM_TOSHIBA_TC358775 is not set +# CONFIG_DRM_TVE200 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_VC4_HDMI_CEC is not set +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VIRTIO_GPU is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_XEN is not set +# CONFIG_DRM_XEN_FRONTEND is not set +# CONFIG_DS1682 is not set +# CONFIG_DS1803 is not set +# CONFIG_DS4424 is not set +# CONFIG_DST_CACHE is not set +# CONFIG_DTLK is not set +# CONFIG_DUMMY is not set +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# CONFIG_DUMMY_IRQ is not set +# CONFIG_DVB_A8293 is not set +# CONFIG_DVB_AF9013 is not set +# CONFIG_DVB_AF9033 is not set +# CONFIG_DVB_AS102 is not set +# CONFIG_DVB_ASCOT2E is not set +# CONFIG_DVB_ATBM8830 is not set +# CONFIG_DVB_AU8522_DTV is not set +# CONFIG_DVB_AU8522_V4L is not set +# CONFIG_DVB_B2C2_FLEXCOP_USB is not set +# CONFIG_DVB_BCM3510 is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DVB_CX22700 is not set +# CONFIG_DVB_CX22702 is not set +# CONFIG_DVB_CX24110 is not set +# CONFIG_DVB_CX24116 is not set +# CONFIG_DVB_CX24117 is not set +# CONFIG_DVB_CX24120 is not set +# CONFIG_DVB_CX24123 is not set +# CONFIG_DVB_CXD2099 is not set +# CONFIG_DVB_CXD2820R is not set +# CONFIG_DVB_CXD2841ER is not set +# CONFIG_DVB_CXD2880 is not set +# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set +# CONFIG_DVB_DIB3000MB is not set +# CONFIG_DVB_DIB3000MC is not set +# CONFIG_DVB_DIB7000M is not set +# CONFIG_DVB_DIB7000P is not set +# CONFIG_DVB_DIB8000 is not set +# CONFIG_DVB_DIB9000 is not set +# CONFIG_DVB_DRX39XYJ is not set +# CONFIG_DVB_DRXD is not set +# CONFIG_DVB_DRXK is not set +# CONFIG_DVB_DS3000 is not set +# CONFIG_DVB_DUMMY_FE is not set +# CONFIG_DVB_DYNAMIC_MINORS is not set +# CONFIG_DVB_EC100 is not set +# CONFIG_DVB_FIREDTV is not set +# CONFIG_DVB_HELENE is not set +# CONFIG_DVB_HORUS3A is not set +# CONFIG_DVB_ISL6405 is not set +# CONFIG_DVB_ISL6421 is not set +# CONFIG_DVB_ISL6423 is not set +# CONFIG_DVB_IX2505V is not set +# CONFIG_DVB_L64781 is not set +# CONFIG_DVB_LG2160 is not set +# CONFIG_DVB_LGDT3305 is not set +# CONFIG_DVB_LGDT3306A is not set +# CONFIG_DVB_LGDT330X is not set +# CONFIG_DVB_LGS8GL5 is not set +# CONFIG_DVB_LGS8GXX is not set +# CONFIG_DVB_LNBH25 is not set +# CONFIG_DVB_LNBH29 is not set +# CONFIG_DVB_LNBP21 is not set +# CONFIG_DVB_LNBP22 is not set +# CONFIG_DVB_M88DS3103 is not set +# CONFIG_DVB_M88RS2000 is not set +CONFIG_DVB_MAX_ADAPTERS=16 +# CONFIG_DVB_MB86A16 is not set +# CONFIG_DVB_MB86A20S is not set +# CONFIG_DVB_MMAP is not set +# CONFIG_DVB_MN88443X is not set +# CONFIG_DVB_MN88472 is not set +# CONFIG_DVB_MN88473 is not set +# CONFIG_DVB_MT312 is not set +# CONFIG_DVB_MT352 is not set +# CONFIG_DVB_MXL5XX is not set +# CONFIG_DVB_MXL692 is not set +# CONFIG_DVB_NET is not set +# CONFIG_DVB_NXT200X is not set +# CONFIG_DVB_NXT6000 is not set +# CONFIG_DVB_OR51132 is not set +# CONFIG_DVB_OR51211 is not set +# CONFIG_DVB_PLATFORM_DRIVERS is not set +# CONFIG_DVB_PLL is not set +# CONFIG_DVB_RTL2830 is not set +# CONFIG_DVB_RTL2832 is not set +# CONFIG_DVB_RTL2832_SDR is not set +# CONFIG_DVB_S5H1409 is not set +# CONFIG_DVB_S5H1411 is not set +# CONFIG_DVB_S5H1420 is not set +# CONFIG_DVB_S5H1432 is not set +# CONFIG_DVB_S921 is not set +# CONFIG_DVB_SI2165 is not set +# CONFIG_DVB_SI2168 is not set +# CONFIG_DVB_SI21XX is not set +# CONFIG_DVB_SP2 is not set +# CONFIG_DVB_SP8870 is not set +# CONFIG_DVB_SP887X is not set +# CONFIG_DVB_STB0899 is not set +# CONFIG_DVB_STB6000 is not set +# CONFIG_DVB_STB6100 is not set +# CONFIG_DVB_STV0288 is not set +# CONFIG_DVB_STV0297 is not set +# CONFIG_DVB_STV0299 is not set +# CONFIG_DVB_STV0367 is not set +# CONFIG_DVB_STV0900 is not set +# CONFIG_DVB_STV090x is not set +# CONFIG_DVB_STV0910 is not set +# CONFIG_DVB_STV6110 is not set +# CONFIG_DVB_STV6110x is not set +# CONFIG_DVB_STV6111 is not set +# CONFIG_DVB_TC90522 is not set +# CONFIG_DVB_TDA10021 is not set +# CONFIG_DVB_TDA10023 is not set +# CONFIG_DVB_TDA10048 is not set +# CONFIG_DVB_TDA1004X is not set +# CONFIG_DVB_TDA10071 is not set +# CONFIG_DVB_TDA10086 is not set +# CONFIG_DVB_TDA18271C2DD is not set +# CONFIG_DVB_TDA665x is not set +# CONFIG_DVB_TDA8083 is not set +# CONFIG_DVB_TDA8261 is not set +# CONFIG_DVB_TDA826X is not set +# CONFIG_DVB_TEST_DRIVERS is not set +# CONFIG_DVB_TS2020 is not set +# CONFIG_DVB_TTUSB_BUDGET is not set +# CONFIG_DVB_TTUSB_DEC is not set +# CONFIG_DVB_TUA6100 is not set +# CONFIG_DVB_TUNER_CX24113 is not set +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_DVB_TUNER_ITD1000 is not set +# CONFIG_DVB_ULE_DEBUG is not set +# CONFIG_DVB_USB is not set +# CONFIG_DVB_USB_V2 is not set +# CONFIG_DVB_VES1820 is not set +# CONFIG_DVB_VES1X93 is not set +# CONFIG_DVB_ZD1301_DEMOD is not set +# CONFIG_DVB_ZL10036 is not set +# CONFIG_DVB_ZL10039 is not set +# CONFIG_DVB_ZL10353 is not set +# CONFIG_DWC_XLGMAC is not set +# CONFIG_DWMAC_DWC_QOS_ETH is not set +# CONFIG_DWMAC_INTEL_PLAT is not set +# CONFIG_DWMAC_IPQ806X is not set +# CONFIG_DWMAC_LOONGSON is not set +# CONFIG_DWMAC_LPC18XX is not set +# CONFIG_DWMAC_MESON is not set +# CONFIG_DWMAC_ROCKCHIP is not set +# CONFIG_DWMAC_SOCFPGA is not set +# CONFIG_DWMAC_STI is not set +# CONFIG_DW_AXI_DMAC is not set +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +# CONFIG_DW_EDMA_PCIE is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_DW_XDATA_PCIE is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +# CONFIG_E100 is not set +# CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_HWTS is not set +# CONFIG_EARLY_PRINTK_8250 is not set +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_ECHO is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_EDAC is not set +# CONFIG_EEEPC_LAPTOP is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_DIGSY_MTC_CFG is not set +# CONFIG_EEPROM_EE1004 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EFI is not set +CONFIG_EFI_PARTITION=y +# CONFIG_EFI_VARS_PSTORE is not set +# CONFIG_EFS_FS is not set +CONFIG_ELFCORE=y +# CONFIG_ELF_CORE is not set +# CONFIG_EMAC_ROCKCHIP is not set +CONFIG_EMBEDDED=y +# CONFIG_EM_TIMER_STI is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +# CONFIG_ENA_ETHERNET is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_ENCX24J600 is not set +# CONFIG_ENERGY_MODEL is not set +# CONFIG_ENIC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_EPAPR_PARAVIRT is not set +# CONFIG_EPIC100 is not set +CONFIG_EPOLL=y +# CONFIG_EQUALIZER is not set +# CONFIG_EROFS_FS is not set +# CONFIG_ET131X is not set +CONFIG_ETHERNET=y +# CONFIG_ETHOC is not set +CONFIG_ETHTOOL_NETLINK=y +CONFIG_EVENTFD=y +# CONFIG_EVM is not set +# CONFIG_EXFAT_FS is not set +CONFIG_EXPERT=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +# CONFIG_EXT2_FS is not set +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4_DEBUG is not set +# CONFIG_EXT4_ENCRYPTION is not set +# CONFIG_EXT4_FS is not set +# CONFIG_EXT4_FS_POSIX_ACL is not set +# CONFIG_EXT4_FS_SECURITY is not set +CONFIG_EXT4_USE_FOR_EXT2=y +# CONFIG_EXTCON is not set +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set +# CONFIG_EXTCON_AXP288 is not set +# CONFIG_EXTCON_FSA9480 is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_INTEL_INT3496 is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_PTN5150 is not set +# CONFIG_EXTCON_QCOM_SPMI_MISC is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +# CONFIG_EXTCON_USBC_TUSB320 is not set +# CONFIG_EXTCON_USB_GPIO is not set +CONFIG_EXTRA_FIRMWARE="" +CONFIG_EXTRA_TARGETS="" +# CONFIG_EXYNOS_ADC is not set +# CONFIG_EXYNOS_VIDEO is not set +# CONFIG_EZCHIP_NPS_MANAGEMENT_ENET is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_F2FS_CHECK_FS is not set +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_F2FS_FS is not set +# CONFIG_F2FS_FS_COMPRESSION is not set +# CONFIG_F2FS_FS_ENCRYPTION is not set +# CONFIG_F2FS_FS_POSIX_ACL is not set +# CONFIG_F2FS_FS_SECURITY is not set +CONFIG_F2FS_FS_XATTR=y +# CONFIG_F2FS_IOSTAT is not set +# CONFIG_F2FS_IO_TRACE is not set +CONFIG_F2FS_STAT_FS=y +# CONFIG_FAILOVER is not set +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_FANOTIFY is not set +# CONFIG_FANOTIFY_ACCESS_PERMISSIONS is not set +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_FAT_FS is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_FB is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_ARC is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_ATMEL is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_AUO_K190X is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_BIG_ENDIAN is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +# CONFIG_FB_BOTH_ENDIAN is not set +# CONFIG_FB_BROADSHEET is not set +# CONFIG_FB_CARMINE is not set +# CONFIG_FB_CFB_COPYAREA is not set +# CONFIG_FB_CFB_FILLRECT is not set +# CONFIG_FB_CFB_IMAGEBLIT is not set +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_DA8XX is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_FLEX is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_FSL_DIU is not set +# CONFIG_FB_GEODE is not set +# CONFIG_FB_GOLDFISH is not set +# CONFIG_FB_HGA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_IMX is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_LE80578 is not set +# CONFIG_FB_LITTLE_ENDIAN is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_MXS is not set +# CONFIG_FB_N411 is not set +# CONFIG_FB_NEOMAGIC is not set +CONFIG_FB_NOTIFY=y +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_OF is not set +# CONFIG_FB_OMAP2 is not set +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_PS3 is not set +# CONFIG_FB_PXA is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_SM712 is not set +# CONFIG_FB_SM750 is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_TFT is not set +# CONFIG_FB_TFT_AGM1264K_FL is not set +# CONFIG_FB_TFT_BD663474 is not set +# CONFIG_FB_TFT_FBTFT_DEVICE is not set +# CONFIG_FB_TFT_HX8340BN is not set +# CONFIG_FB_TFT_HX8347D is not set +# CONFIG_FB_TFT_HX8353D is not set +# CONFIG_FB_TFT_HX8357D is not set +# CONFIG_FB_TFT_ILI9163 is not set +# CONFIG_FB_TFT_ILI9320 is not set +# CONFIG_FB_TFT_ILI9325 is not set +# CONFIG_FB_TFT_ILI9340 is not set +# CONFIG_FB_TFT_ILI9341 is not set +# CONFIG_FB_TFT_ILI9481 is not set +# CONFIG_FB_TFT_ILI9486 is not set +# CONFIG_FB_TFT_PCD8544 is not set +# CONFIG_FB_TFT_RA8875 is not set +# CONFIG_FB_TFT_S6D02A1 is not set +# CONFIG_FB_TFT_S6D1121 is not set +# CONFIG_FB_TFT_SEPS525 is not set +# CONFIG_FB_TFT_SH1106 is not set +# CONFIG_FB_TFT_SSD1289 is not set +# CONFIG_FB_TFT_SSD1305 is not set +# CONFIG_FB_TFT_SSD1306 is not set +# CONFIG_FB_TFT_SSD1325 is not set +# CONFIG_FB_TFT_SSD1331 is not set +# CONFIG_FB_TFT_SSD1351 is not set +# CONFIG_FB_TFT_ST7735R is not set +# CONFIG_FB_TFT_ST7789V is not set +# CONFIG_FB_TFT_TINYLCD is not set +# CONFIG_FB_TFT_TLS8204 is not set +# CONFIG_FB_TFT_UC1611 is not set +# CONFIG_FB_TFT_UC1701 is not set +# CONFIG_FB_TFT_UPD161704 is not set +# CONFIG_FB_TFT_WATTEROTT is not set +# CONFIG_FB_TILEBLITTING is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_UVESA is not set +# CONFIG_FB_VGA16 is not set +# CONFIG_FB_VIA is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_XGI is not set +# CONFIG_FCOE is not set +# CONFIG_FCOE_FNIC is not set +# CONFIG_FDDI is not set +# CONFIG_FEALNX is not set +# CONFIG_FENCE_TRACE is not set +# CONFIG_FHANDLE is not set +CONFIG_FIB_RULES=y +# CONFIG_FIELDBUS_DEV is not set +CONFIG_FILE_LOCKING=y +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# CONFIG_FIREWIRE_SERIAL is not set +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FIRMWARE_IN_KERNEL is not set +# CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FIT_PARTITION is not set +# CONFIG_FIXED_PHY is not set +CONFIG_FLATMEM=y +CONFIG_FLATMEM_MANUAL=y +CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_FM10K is not set +# CONFIG_FMC is not set +# CONFIG_FONTS is not set +# CONFIG_FONT_6x8 is not set +# CONFIG_FONT_TER16x32 is not set +# CONFIG_FORCEDETH is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_FORTIFY_SOURCE=y +# CONFIG_FPGA is not set +# CONFIG_FRAMEBUFFER_CONSOLE is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION is not set +# CONFIG_FRAME_POINTER is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_FREEZER is not set +# CONFIG_FRONTSWAP is not set +# CONFIG_FSCACHE is not set +# CONFIG_FSI is not set +# CONFIG_FSL_EDMA is not set +# CONFIG_FSL_ENETC is not set +# CONFIG_FSL_ENETC_IERB is not set +# CONFIG_FSL_ENETC_MDIO is not set +# CONFIG_FSL_ENETC_VF is not set +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_FSL_MC_BUS is not set +# CONFIG_FSL_PQ_MDIO is not set +# CONFIG_FSL_QDMA is not set +# CONFIG_FSL_RCPM is not set +# CONFIG_FSL_XGMAC_MDIO is not set +CONFIG_FSNOTIFY=y +# CONFIG_FS_DAX is not set +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_FS_VERITY is not set +# CONFIG_FTGMAC100 is not set +# CONFIG_FTL is not set +# CONFIG_FTMAC100 is not set +# CONFIG_FTRACE is not set +# CONFIG_FTRACE_RECORD_RECURSION is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_FTR_FIXUP_SELFTEST is not set +# CONFIG_FTWDT010_WATCHDOG is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_FUNCTION_ERROR_INJECTION is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUSE_FS is not set +# CONFIG_FUSION is not set +# CONFIG_FUSION_FC is not set +# CONFIG_FUSION_SAS is not set +# CONFIG_FUSION_SPI is not set +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +# CONFIG_FW_CFG_SYSFS is not set +CONFIG_FW_LOADER=y +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FXAS21002C is not set +# CONFIG_FXLS8962AF_I2C is not set +# CONFIG_FXLS8962AF_SPI is not set +# CONFIG_FXOS8700_I2C is not set +# CONFIG_FXOS8700_SPI is not set +CONFIG_GACT_PROB=y +# CONFIG_GADGET_UAC1 is not set +# CONFIG_GAMEPORT is not set +# CONFIG_GATEWORKS_GW16083 is not set +# CONFIG_GCC_PLUGINS is not set +# CONFIG_GCOV is not set +# CONFIG_GCOV_KERNEL is not set +# CONFIG_GDB_SCRIPTS is not set +# CONFIG_GEMINI_ETHERNET is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_GENERIC_CALIBRATE_DELAY=y +# CONFIG_GENERIC_CPU_DEVICES is not set +CONFIG_GENERIC_HWEIGHT=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_IPI=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_GENERIC_PHY is not set +CONFIG_GENERIC_PTDUMP=y +CONFIG_GENERIC_VDSO_TIME_NS=y +# CONFIG_GENEVE is not set +# CONFIG_GENWQE is not set +# CONFIG_GFS2_FS is not set +# CONFIG_GIGASET_CAPI is not set +# CONFIG_GIGASET_DEBUG is not set +# CONFIG_GIGASET_DUMMYLL is not set +# CONFIG_GLOB_SELFTEST is not set +# CONFIG_GNSS is not set +# CONFIG_GOLDFISH is not set +# CONFIG_GOOGLE_FIRMWARE is not set +# CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT is not set +# CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY is not set +# CONFIG_GOOGLE_SMI is not set +# CONFIG_GP2AP002 is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_GPD_POCKET_FAN is not set +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +# CONFIG_GPIO_104_DIO_48E is not set +# CONFIG_GPIO_104_IDIO_16 is not set +# CONFIG_GPIO_104_IDI_48 is not set +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_AGGREGATOR is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_AMD8111 is not set +# CONFIG_GPIO_AMDPT is not set +# CONFIG_GPIO_AMD_FCH is not set +# CONFIG_GPIO_BCM_KONA is not set +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_CADENCE is not set +# CONFIG_GPIO_CASCADE is not set +# CONFIG_GPIO_CDEV is not set +# CONFIG_GPIO_CDEV_V1 is not set +# CONFIG_GPIO_CS5535 is not set +# CONFIG_GPIO_DWAPB is not set +# CONFIG_GPIO_EM is not set +# CONFIG_GPIO_EXAR is not set +# CONFIG_GPIO_F7188X is not set +# CONFIG_GPIO_FTGPIO010 is not set +# CONFIG_GPIO_GENERIC_PLATFORM is not set +# CONFIG_GPIO_GPIO_MM is not set +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_ICH is not set +# CONFIG_GPIO_IT87 is not set +# CONFIG_GPIO_LOGICVC is not set +# CONFIG_GPIO_LYNXPOINT is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_ML_IOH is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_MPC8XXX is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCA953X_IRQ is not set +# CONFIG_GPIO_PCA9570 is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_PCH is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_PWM is not set +# CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_RDC321X is not set +# CONFIG_GPIO_SAMA5D2_PIOBU is not set +# CONFIG_GPIO_SCH is not set +# CONFIG_GPIO_SCH311X is not set +# CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_SYSCON is not set +CONFIG_GPIO_SYSFS=y +# CONFIG_GPIO_TPIC2810 is not set +# CONFIG_GPIO_TS4900 is not set +# CONFIG_GPIO_TS5500 is not set +# CONFIG_GPIO_VIRTIO is not set +# CONFIG_GPIO_VX855 is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_GPIO_WINBOND is not set +# CONFIG_GPIO_WS16C48 is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_XRA1403 is not set +# CONFIG_GPIO_ZEVIO is not set +# CONFIG_GPIO_ZX is not set +# CONFIG_GREENASIA_FF is not set +# CONFIG_GREYBUS is not set +# CONFIG_GS_FPGABOOT is not set +# CONFIG_GTP is not set +# CONFIG_GUP_BENCHMARK is not set +# CONFIG_GUP_TEST is not set +# CONFIG_GVE is not set +# CONFIG_HABANA_AI is not set +# CONFIG_HAMACHI is not set +# CONFIG_HAMRADIO is not set +# CONFIG_HAPPYMEAL is not set +CONFIG_HARDENED_USERCOPY=y +# CONFIG_HARDENED_USERCOPY_FALLBACK is not set +# CONFIG_HARDENED_USERCOPY_PAGESPAN is not set +CONFIG_HARDEN_BRANCH_HISTORY=y +CONFIG_HARDEN_EL2_VECTORS=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_HAVE_ARM_ARCH_TIMER is not set +# CONFIG_HCALL_STATS is not set +# CONFIG_HDC100X is not set +# CONFIG_HDC2010 is not set +# CONFIG_HDLC is not set +# CONFIG_HDLC_CISCO is not set +# CONFIG_HDLC_FR is not set +# CONFIG_HDLC_PPP is not set +# CONFIG_HDLC_RAW is not set +# CONFIG_HDLC_RAW_ETH is not set +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_HDQ_MASTER_OMAP is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_HEADER_TEST is not set +# CONFIG_HERMES is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_HFSPLUS_FS_POSIX_ACL is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFS_FS_POSIX_ACL is not set +# CONFIG_HI6421V600_IRQ is not set +# CONFIG_HI8435 is not set +# CONFIG_HIBERNATION is not set +# CONFIG_HID is not set +# CONFIG_HIDRAW is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +# CONFIG_HID_ACRUX_FF is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +# CONFIG_HID_BATTERY_STRENGTH is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_BIGBEN_FF is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_CP2112 is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_FT260 is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GENERIC is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_GOOGLE_HAMMER is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MCP2221 is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PENMOUNT is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PID is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PLAYSTATION is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_REDRAGON is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_RMI is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SEMITEK is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEAM is not set +# CONFIG_HID_STEELSERIES is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HIGHMEM is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_HINIC is not set +# CONFIG_HIP04_ETH is not set +# CONFIG_HIPPI is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_HISI_DMA is not set +# CONFIG_HISI_FEMAC is not set +# CONFIG_HISI_HIKEY_USB is not set +# CONFIG_HIST_TRIGGERS_DEBUG is not set +# CONFIG_HIX5HD2_GMAC is not set +# CONFIG_HMC425 is not set +# CONFIG_HMC6352 is not set +# CONFIG_HNS is not set +# CONFIG_HNS3 is not set +# CONFIG_HNS_DSAF is not set +# CONFIG_HNS_ENET is not set +# CONFIG_HOSTAP is not set +# CONFIG_HOSTAP_CS is not set +# CONFIG_HOSTAP_PCI is not set +# CONFIG_HOSTAP_PLX is not set +# CONFIG_HOTPLUG_CPU is not set +# CONFIG_HOTPLUG_PCI is not set +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set +# CONFIG_HOTPLUG_PCI_COMPAQ is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_IBM is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set +# CONFIG_HP03 is not set +# CONFIG_HP100 is not set +# CONFIG_HP206C is not set +CONFIG_HPET_MMAP_DEFAULT=y +# CONFIG_HPFS_FS is not set +# CONFIG_HP_ILO is not set +# CONFIG_HP_WIRELESS is not set +# CONFIG_HSA_AMD is not set +# CONFIG_HSI is not set +# CONFIG_HSR is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_HVC_DCC is not set +# CONFIG_HVC_UDBG is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_HWMON is not set +# CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_HWMON_VID is not set +# CONFIG_HWSPINLOCK is not set +# CONFIG_HWSPINLOCK_OMAP is not set +CONFIG_HW_PERF_EVENTS=y +# CONFIG_HW_RANDOM is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_ARM_SMCCC_TRNG is not set +# CONFIG_HW_RANDOM_ATMEL is not set +# CONFIG_HW_RANDOM_BA431 is not set +# CONFIG_HW_RANDOM_BCM2835 is not set +# CONFIG_HW_RANDOM_CAVIUM is not set +# CONFIG_HW_RANDOM_CCTRNG is not set +# CONFIG_HW_RANDOM_EXYNOS is not set +# CONFIG_HW_RANDOM_GEODE is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_IPROC_RNG200 is not set +# CONFIG_HW_RANDOM_MTK is not set +# CONFIG_HW_RANDOM_OMAP is not set +# CONFIG_HW_RANDOM_OMAP3_ROM is not set +# CONFIG_HW_RANDOM_PPC4XX is not set +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_TPM=y +# CONFIG_HW_RANDOM_VIA is not set +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HW_RANDOM_XIPHERA is not set +# CONFIG_HX711 is not set +# CONFIG_HYPERV is not set +# CONFIG_HYPERV_TSCPAGE is not set +# CONFIG_HYSDN is not set +CONFIG_HZ=100 +CONFIG_HZ_100=y +# CONFIG_HZ_1000 is not set +# CONFIG_HZ_1024 is not set +# CONFIG_HZ_128 is not set +# CONFIG_HZ_200 is not set +# CONFIG_HZ_24 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_256 is not set +# CONFIG_HZ_300 is not set +# CONFIG_HZ_48 is not set +# CONFIG_HZ_500 is not set +# CONFIG_HZ_PERIODIC is not set +# CONFIG_I2C is not set +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCA is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_AU1550 is not set +# CONFIG_I2C_BCM2835 is not set +# CONFIG_I2C_BCM_IPROC is not set +# CONFIG_I2C_BRCMSTB is not set +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_CP2615 is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_DESIGNWARE_PLATFORM is not set +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_EG20T is not set +# CONFIG_I2C_ELEKTOR is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_HID is not set +# CONFIG_I2C_HID_OF is not set +# CONFIG_I2C_HID_OF_GOODIX is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_IBM_IIC is not set +# CONFIG_I2C_IMG is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_JZ4780 is not set +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_MPC is not set +# CONFIG_I2C_MT65XX is not set +# CONFIG_I2C_MUX is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_MV64XXX is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_OCTEON is not set +# CONFIG_I2C_PARPORT is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PCA_ISA is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_PXA_PCI is not set +# CONFIG_I2C_PXA_SLAVE is not set +# CONFIG_I2C_RCAR is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_S3C2410 is not set +# CONFIG_I2C_SCMI is not set +# CONFIG_I2C_SH_MOBILE is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_SLAVE_EEPROM is not set +# CONFIG_I2C_SMBUS is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_THUNDERX is not set +# CONFIG_I2C_TINY_USB is not set +# CONFIG_I2C_VERSATILE is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VIRTIO is not set +# CONFIG_I2C_XILINX is not set +# CONFIG_I3C is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_IAQCORE is not set +# CONFIG_IBM_ASM is not set +# CONFIG_IBM_EMAC_DEBUG is not set +# CONFIG_IBM_EMAC_EMAC4 is not set +# CONFIG_IBM_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_EMAC_MAL_COMMON_ERR is not set +# CONFIG_IBM_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_EMAC_RGMII is not set +# CONFIG_IBM_EMAC_TAH is not set +# CONFIG_IBM_EMAC_ZMII is not set +# CONFIG_ICE is not set +# CONFIG_ICP10100 is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ICST is not set +# CONFIG_IDE is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_IDE_GD is not set +# CONFIG_IDE_PROC_FS is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +# CONFIG_IEEE802154 is not set +# CONFIG_IEEE802154_ADF7242 is not set +# CONFIG_IEEE802154_ATUSB is not set +# CONFIG_IEEE802154_CA8210 is not set +# CONFIG_IEEE802154_HWSIM is not set +# CONFIG_IEEE802154_MCR20A is not set +# CONFIG_IFB is not set +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IGC is not set +# CONFIG_IIO is not set +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_BUFFER_CB is not set +# CONFIG_IIO_BUFFER_DMA is not set +# CONFIG_IIO_BUFFER_DMAENGINE is not set +# CONFIG_IIO_BUFFER_HDC2010 is not set +# CONFIG_IIO_BUFFER_HW_CONSUMER is not set +# CONFIG_IIO_CONFIGFS is not set +CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_INTERRUPT_TRIGGER is not set +# CONFIG_IIO_MUX is not set +# CONFIG_IIO_PERIODIC_RTC_TRIGGER is not set +# CONFIG_IIO_RESCALE is not set +# CONFIG_IIO_SIMPLE_DUMMY is not set +# CONFIG_IIO_SSP_SENSORHUB is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_IIO_ST_LSM6DSX is not set +# CONFIG_IIO_ST_LSM9DS0 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set +# CONFIG_IIO_SYSFS_TRIGGER is not set +# CONFIG_IIO_TRIGGER is not set +# CONFIG_IIO_TRIGGERED_EVENT is not set +# CONFIG_IKCONFIG is not set +# CONFIG_IKCONFIG_PROC is not set +# CONFIG_IKHEADERS is not set +# CONFIG_IMA is not set +# CONFIG_IMGPDC_WDT is not set +# CONFIG_IMG_MDC_DMA is not set +# CONFIG_IMX7D_ADC is not set +# CONFIG_IMX_IPUV3_CORE is not set +# CONFIG_IMX_THERMAL is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_INDIRECT_PIO is not set +CONFIG_INET=y +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_ESPINTCP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_DIAG is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_ESPINTCP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_TABLE_PERTURB_ORDER=16 +# CONFIG_INET_TCP_DIAG is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INFINIBAND is not set +# CONFIG_INFTL is not set +# CONFIG_INGENIC_ADC is not set +# CONFIG_INGENIC_CGU_JZ4725B is not set +# CONFIG_INGENIC_CGU_JZ4740 is not set +# CONFIG_INGENIC_CGU_JZ4760 is not set +# CONFIG_INGENIC_CGU_JZ4770 is not set +# CONFIG_INGENIC_CGU_JZ4780 is not set +# CONFIG_INGENIC_CGU_X1000 is not set +# CONFIG_INGENIC_CGU_X1830 is not set +# CONFIG_INGENIC_OST is not set +# CONFIG_INGENIC_SYSOST is not set +# CONFIG_INGENIC_TCU_CLK is not set +# CONFIG_INGENIC_TCU_IRQ is not set +# CONFIG_INGENIC_TIMER is not set +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +# CONFIG_INIT_STACK_ALL_PATTERN is not set +# CONFIG_INIT_STACK_ALL_ZERO is not set +CONFIG_INIT_STACK_NONE=y +CONFIG_INOTIFY_USER=y +# CONFIG_INPUT is not set +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_AXP20X_PEK is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_DA7280_HAPTICS is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_GPIO_TILT_POLLED is not set +# CONFIG_INPUT_GPIO_VIBRA is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_IQS269A is not set +# CONFIG_INPUT_IQS626A is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_LEDS is not set +# CONFIG_INPUT_MATRIXKMAP is not set +# CONFIG_INPUT_MAX8997_HAPTIC is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MPU3050 is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set +# CONFIG_INPUT_PALMAS_PWRBUTTON is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_PM8941_PWRKEY is not set +# CONFIG_INPUT_PM8XXX_VIBRATOR is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_TPS65218_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_PWRBUTTON is not set +# CONFIG_INPUT_TWL4030_VIBRA is not set +# CONFIG_INPUT_TWL6040_VIBRA is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_WISTRON_BTNS is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INT340X_THERMAL is not set +# CONFIG_INTEGRITY is not set +# CONFIG_INTEGRITY_AUDIT is not set +# CONFIG_INTEGRITY_SIGNATURE is not set +# CONFIG_INTEL_ATOMISP2_LED is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_CHT_INT33FE is not set +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_IDLE is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IDXD_COMPAT is not set +# CONFIG_INTEL_INT0002_VGPIO is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_INTEL_ISH_HID is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MIC_CARD is not set +# CONFIG_INTEL_MIC_HOST is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PMC_CORE is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_SOC_PMIC is not set +# CONFIG_INTEL_SOC_PMIC_CHTDC_TI is not set +# CONFIG_INTEL_SOC_PMIC_CHTWC is not set +# CONFIG_INTEL_TH is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_INV_ICM42600_I2C is not set +# CONFIG_INV_ICM42600_SPI is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_IIO is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set +# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +# CONFIG_IOMMU_SUPPORT is not set +# CONFIG_IONIC is not set +# CONFIG_IOSCHED_BFQ is not set +# CONFIG_IOSM is not set +CONFIG_IO_STRICT_DEVMEM=y +# CONFIG_IO_URING is not set +CONFIG_IO_WQ=y +# CONFIG_IP17XX_PHY is not set +# CONFIG_IP6_NF_FILTER is not set +# CONFIG_IP6_NF_IPTABLES is not set +# CONFIG_IP6_NF_MANGLE is not set +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_NAT is not set +# CONFIG_IP6_NF_RAW is not set +# CONFIG_IP6_NF_SECURITY is not set +# CONFIG_IP6_NF_TARGET_HL is not set +# CONFIG_IP6_NF_TARGET_MASQUERADE is not set +# CONFIG_IP6_NF_TARGET_REJECT is not set +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +# CONFIG_IPACK_BUS is not set +# CONFIG_IPC_NS is not set +# CONFIG_IPMB_DEVICE_INTERFACE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPV6 is not set +# CONFIG_IPV6_FOU is not set +# CONFIG_IPV6_FOU_TUNNEL is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_IOAM6_LWTUNNEL is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_ROUTE_INFO is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SIT is not set +# CONFIG_IPV6_SIT_6RD is not set +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_VTI is not set +# CONFIG_IPVLAN is not set +# CONFIG_IPVTAP is not set +# CONFIG_IPW2100 is not set +# CONFIG_IPW2100_DEBUG is not set +CONFIG_IPW2100_MONITOR=y +# CONFIG_IPW2200 is not set +# CONFIG_IPW2200_DEBUG is not set +CONFIG_IPW2200_MONITOR=y +# CONFIG_IPW2200_PROMISCUOUS is not set +# CONFIG_IPW2200_QOS is not set +# CONFIG_IPW2200_RADIOTAP is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_IPX is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_FILTER is not set +# CONFIG_IP_NF_IPTABLES is not set +# CONFIG_IP_NF_MANGLE is not set +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_SECURITY is not set +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_MASQUERADE is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_REJECT is not set +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_IP_PNP is not set +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +# CONFIG_IP_SCTP is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_SET_HASH_IPMAC is not set +# CONFIG_IP_VS is not set +# CONFIG_IP_VS_MH is not set +CONFIG_IP_VS_MH_TAB_INDEX=10 +# CONFIG_IP_VS_TWOS is not set +# CONFIG_IRDA is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_IRQ_ALL_CPUS is not set +# CONFIG_IRQ_DOMAIN_DEBUG is not set +# CONFIG_IRQ_POLL is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_IR_GPIO_CIR is not set +# CONFIG_IR_HIX5HD2 is not set +# CONFIG_IR_IGORPLUGUSB is not set +# CONFIG_IR_IGUANA is not set +# CONFIG_IR_IMG is not set +# CONFIG_IR_IMON is not set +# CONFIG_IR_IMON_RAW is not set +# CONFIG_IR_JVC_DECODER is not set +# CONFIG_IR_LIRC_CODEC is not set +# CONFIG_IR_MCEUSB is not set +# CONFIG_IR_NEC_DECODER is not set +# CONFIG_IR_RC5_DECODER is not set +# CONFIG_IR_RC6_DECODER is not set +# CONFIG_IR_REDRAT3 is not set +# CONFIG_IR_SERIAL is not set +# CONFIG_IR_SIR is not set +# CONFIG_IR_SONY_DECODER is not set +# CONFIG_IR_STREAMZAP is not set +# CONFIG_IR_TOY is not set +# CONFIG_IR_TTUSBIR is not set +# CONFIG_ISA_BUS is not set +# CONFIG_ISA_BUS_API is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_ISCSI_TCP is not set +CONFIG_ISDN=y +# CONFIG_ISDN_AUDIO is not set +# CONFIG_ISDN_CAPI is not set +# CONFIG_ISDN_CAPI_CAPIDRV is not set +# CONFIG_ISDN_DIVERSION is not set +# CONFIG_ISDN_DRV_ACT2000 is not set +# CONFIG_ISDN_DRV_GIGASET is not set +# CONFIG_ISDN_DRV_HISAX is not set +# CONFIG_ISDN_DRV_ICN is not set +# CONFIG_ISDN_DRV_LOOP is not set +# CONFIG_ISDN_DRV_PCBIT is not set +# CONFIG_ISDN_DRV_SC is not set +# CONFIG_ISDN_I4L is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_ISL29125 is not set +# CONFIG_ISL29501 is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_ISS4xx is not set +# CONFIG_ITG3200 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +# CONFIG_IXGB is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_JBD2_DEBUG is not set +# CONFIG_JFFS2_CMODE_FAVOURLZO is not set +# CONFIG_JFFS2_CMODE_NONE is not set +CONFIG_JFFS2_CMODE_PRIORITY=y +# CONFIG_JFFS2_CMODE_SIZE is not set +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# CONFIG_JFFS2_FS_POSIX_ACL is not set +# CONFIG_JFFS2_FS_SECURITY is not set +# CONFIG_JFFS2_FS_WBUF_VERIFY is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y +CONFIG_JFFS2_FS_XATTR=y +CONFIG_JFFS2_LZMA=y +# CONFIG_JFFS2_LZO is not set +CONFIG_JFFS2_RTIME=y +# CONFIG_JFFS2_RUBIN is not set +CONFIG_JFFS2_SUMMARY=y +# CONFIG_JFFS2_ZLIB is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_JME is not set +CONFIG_JOLIET=y +# CONFIG_JSA1212 is not set +# CONFIG_JUMP_LABEL is not set +# CONFIG_JZ4740_WDT is not set +# CONFIG_JZ4770_PHY is not set +# CONFIG_KALLSYMS is not set +# CONFIG_KALLSYMS_ABSOLUTE_PERCPU is not set +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +# CONFIG_KALLSYMS_UNCOMPRESSED is not set +# CONFIG_KARMA_PARTITION is not set +# CONFIG_KASAN is not set +# CONFIG_KASAN_MODULE_TEST is not set +CONFIG_KASAN_STACK=y +# CONFIG_KCMP is not set +# CONFIG_KCOV is not set +CONFIG_KCOV_IRQ_AREA_SIZE=0x40000 +# CONFIG_KCSAN is not set +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_CAT is not set +# CONFIG_KERNEL_GZIP is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +CONFIG_KERNEL_MODE_NEON=y +CONFIG_KERNEL_XZ=y +# CONFIG_KERNEL_ZSTD is not set +CONFIG_KERNFS=y +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEXEC_SIG is not set +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_APPLESPI is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_BCM is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PXA27x is not set +# CONFIG_KEYBOARD_QT1050 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_SH_KEYSC is not set +# CONFIG_KEYBOARD_SNVS_PWRKEY is not set +# CONFIG_KEYBOARD_STMPE is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_TEGRA is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_TWL4030 is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYS is not set +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_KFENCE is not set +# CONFIG_KGDB is not set +# CONFIG_KMEMCHECK is not set +# CONFIG_KMX61 is not set +# CONFIG_KPC2000 is not set +# CONFIG_KPROBES is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_KPROBE_EVENTS_ON_NOTRACE is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_KS7010 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSM is not set +# CONFIG_KSZ884X_PCI is not set +# CONFIG_KUNIT is not set +CONFIG_KUSER_HELPERS=y +# CONFIG_KVM_AMD is not set +# CONFIG_KVM_AMD_SEV is not set +# CONFIG_KVM_GUEST is not set +# CONFIG_KVM_INTEL is not set +# CONFIG_KVM_WERROR is not set +# CONFIG_KVM_XEN is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_KXSD9 is not set +# CONFIG_L2TP is not set +# CONFIG_L2TP_ETH is not set +# CONFIG_L2TP_IP is not set +# CONFIG_L2TP_V3 is not set +# CONFIG_LAN743X is not set +# CONFIG_LANMEDIA is not set +# CONFIG_LANTIQ is not set +# CONFIG_LAPB is not set +# CONFIG_LASAT is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +CONFIG_LBDAF=y +# CONFIG_LCD_AMS369FG06 is not set +# CONFIG_LCD_CLASS_DEVICE is not set +# CONFIG_LCD_HX8357 is not set +# CONFIG_LCD_ILI922X is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LD9040 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LMS501KF03 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_OTM3225A is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +CONFIG_LDISC_AUTOLOAD=y +# CONFIG_LDM_PARTITION is not set +CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y +# CONFIG_LD_HEAD_STUB_CATCH is not set +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW2013 is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_BRIGHTNESS_HW_CHANGED=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +CONFIG_LEDS_CLASS_MULTICOLOR=y +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_EL15203000 is not set +# CONFIG_LEDS_GPIO is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP50XX is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP55XX_COMMON is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_NIC78BX is not set +# CONFIG_LEDS_NS2 is not set +# CONFIG_LEDS_OT200 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_SPI_BYTE is not set +# CONFIG_LEDS_SYSCON is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TI_LMU_COMMON is not set +# CONFIG_LEDS_TLC591XX is not set +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_MTD is not set +CONFIG_LEDS_TRIGGER_NETDEV=y +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +CONFIG_LEDS_TRIGGER_TIMER=y +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_TTY is not set +# CONFIG_LEDS_TURRIS_OMNIA is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LED_TRIGGER_PHY is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LGUEST is not set +# CONFIG_LIB80211 is not set +# CONFIG_LIB80211_CRYPT_CCMP is not set +# CONFIG_LIB80211_CRYPT_TKIP is not set +# CONFIG_LIB80211_CRYPT_WEP is not set +# CONFIG_LIB80211_DEBUG is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_LIBERTAS_USB is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_LIBIPW_DEBUG is not set +# CONFIG_LIBNVDIMM is not set +CONFIG_LIB_MEMNEQ=y +# CONFIG_LIDAR_LITE_V2 is not set +CONFIG_LINEAR_RANGES=y +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +# CONFIG_LIRC is not set +# CONFIG_LIS3L02DQ is not set +# CONFIG_LITEX_LITEETH is not set +# CONFIG_LITEX_SOC_CONTROLLER is not set +# CONFIG_LIVEPATCH is not set +# CONFIG_LKDTM is not set +CONFIG_LLC=y +# CONFIG_LLC2 is not set +# CONFIG_LMK04832 is not set +# CONFIG_LMP91000 is not set +# CONFIG_LNET is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_LOCKD is not set +CONFIG_LOCKDEP_BITS=15 +CONFIG_LOCKDEP_CHAINS_BITS=16 +CONFIG_LOCKDEP_CIRCULAR_QUEUE_BITS=12 +CONFIG_LOCKDEP_STACK_TRACE_BITS=19 +CONFIG_LOCKDEP_STACK_TRACE_HASH_BITS=14 +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_LOCKD_V4=y +# CONFIG_LOCKUP_DETECTOR is not set +# CONFIG_LOCK_EVENT_COUNTS is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_LOGFS is not set +# CONFIG_LOGIG940_FF is not set +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGITECH_FF is not set +# CONFIG_LOGIWHEELS_FF is not set +# CONFIG_LOGO is not set +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_LOONGSON_MC146818 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_LP_CONSOLE is not set +CONFIG_LRU_GEN=y +CONFIG_LRU_GEN_ENABLED=y +# CONFIG_LRU_GEN_STATS is not set +# CONFIG_LSI_ET1011C_PHY is not set +CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity" +CONFIG_LSM_MMAP_MIN_ADDR=65536 +# CONFIG_LTC1660 is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2496 is not set +# CONFIG_LTC2497 is not set +# CONFIG_LTC2632 is not set +# CONFIG_LTC2983 is not set +# CONFIG_LTE_GDM724X is not set +CONFIG_LTO_NONE=y +# CONFIG_LTPC is not set +# CONFIG_LTR501 is not set +# CONFIG_LUSTRE_FS is not set +# CONFIG_LV0104CS is not set +# CONFIG_LWTUNNEL is not set +# CONFIG_LXT_PHY is not set +# CONFIG_LZ4HC_COMPRESS is not set +# CONFIG_LZ4_COMPRESS is not set +# CONFIG_LZ4_DECOMPRESS is not set +CONFIG_LZMA_COMPRESS=y +CONFIG_LZMA_DECOMPRESS=y +# CONFIG_LZO_COMPRESS is not set +# CONFIG_LZO_DECOMPRESS is not set +# CONFIG_M62332 is not set +# CONFIG_MAC80211 is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_MACB is not set +# CONFIG_MACH_ASM9260 is not set +# CONFIG_MACH_DECSTATION is not set +# CONFIG_MACH_INGENIC is not set +# CONFIG_MACH_INGENIC_SOC is not set +# CONFIG_MACH_JAZZ is not set +# CONFIG_MACH_JZ4740 is not set +# CONFIG_MACH_LOONGSON2EF is not set +# CONFIG_MACH_LOONGSON32 is not set +# CONFIG_MACH_LOONGSON64 is not set +# CONFIG_MACH_NINTENDO64 is not set +# CONFIG_MACH_PIC32 is not set +# CONFIG_MACH_PISTACHIO is not set +# CONFIG_MACH_REALTEK_RTL is not set +# CONFIG_MACH_TX39XX is not set +# CONFIG_MACH_TX49XX is not set +# CONFIG_MACH_VR41XX is not set +# CONFIG_MACH_XILFPGA is not set +# CONFIG_MACINTOSH_DRIVERS is not set +# CONFIG_MACSEC is not set +# CONFIG_MACVLAN is not set +# CONFIG_MACVTAP is not set +# CONFIG_MAC_EMUMOUSEBTN is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MAG3110 is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +# CONFIG_MAGIC_SYSRQ_SERIAL is not set +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +# CONFIG_MAILBOX is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_MANDATORY_FILE_LOCKING is not set +# CONFIG_MANGLE_BOOTARGS is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_88X2222_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1241 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set +# CONFIG_MAX31856 is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX44009 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5432 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_MAX9611 is not set +# CONFIG_MAXIM_THERMOCOUPLE is not set +# CONFIG_MAXLINEAR_GPHY is not set +CONFIG_MAY_USE_DEVLINK=y +# CONFIG_MB1232 is not set +# CONFIG_MC3230 is not set +# CONFIG_MCB is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP3911 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP41010 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_MCPM is not set +# CONFIG_MCTP is not set +# CONFIG_MD is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BUS_MUX_GPIO is not set +# CONFIG_MDIO_BUS_MUX_MMIOREG is not set +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_DEVICE is not set +# CONFIG_MDIO_DEVRES is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_IPQ4019 is not set +# CONFIG_MDIO_IPQ8064 is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_THUNDER is not set +# CONFIG_MDIO_XPCS is not set +# CONFIG_MDM_GCC_9607 is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_MEDIATEK_GE_PHY is not set +# CONFIG_MEDIATEK_MT6577_AUXADC is not set +# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set +# CONFIG_MEDIA_ATTACH is not set +# CONFIG_MEDIA_CAMERA_SUPPORT is not set +# CONFIG_MEDIA_CEC_SUPPORT is not set +# CONFIG_MEDIA_CONTROLLER is not set +# CONFIG_MEDIA_CONTROLLER_DVB is not set +# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_PLATFORM_SUPPORT is not set +# CONFIG_MEDIA_RADIO_SUPPORT is not set +# CONFIG_MEDIA_RC_SUPPORT is not set +# CONFIG_MEDIA_SDR_SUPPORT is not set +# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set +# CONFIG_MEDIA_SUPPORT is not set +# CONFIG_MEDIA_SUPPORT_FILTER is not set +# CONFIG_MEDIA_TEST_SUPPORT is not set +# CONFIG_MEDIA_TUNER_E4000 is not set +# CONFIG_MEDIA_TUNER_FC0011 is not set +# CONFIG_MEDIA_TUNER_FC0012 is not set +# CONFIG_MEDIA_TUNER_FC0013 is not set +# CONFIG_MEDIA_TUNER_FC2580 is not set +# CONFIG_MEDIA_TUNER_IT913X is not set +# CONFIG_MEDIA_TUNER_M88RS6000T is not set +# CONFIG_MEDIA_TUNER_MAX2165 is not set +# CONFIG_MEDIA_TUNER_MC44S803 is not set +# CONFIG_MEDIA_TUNER_MSI001 is not set +# CONFIG_MEDIA_TUNER_MT2060 is not set +# CONFIG_MEDIA_TUNER_MT2063 is not set +# CONFIG_MEDIA_TUNER_MT20XX is not set +# CONFIG_MEDIA_TUNER_MT2131 is not set +# CONFIG_MEDIA_TUNER_MT2266 is not set +# CONFIG_MEDIA_TUNER_MXL301RF is not set +# CONFIG_MEDIA_TUNER_MXL5005S is not set +# CONFIG_MEDIA_TUNER_MXL5007T is not set +# CONFIG_MEDIA_TUNER_QM1D1B0004 is not set +# CONFIG_MEDIA_TUNER_QM1D1C0042 is not set +# CONFIG_MEDIA_TUNER_QT1010 is not set +# CONFIG_MEDIA_TUNER_R820T is not set +# CONFIG_MEDIA_TUNER_SI2157 is not set +# CONFIG_MEDIA_TUNER_SIMPLE is not set +# CONFIG_MEDIA_TUNER_TDA18212 is not set +# CONFIG_MEDIA_TUNER_TDA18218 is not set +# CONFIG_MEDIA_TUNER_TDA18250 is not set +# CONFIG_MEDIA_TUNER_TDA18271 is not set +# CONFIG_MEDIA_TUNER_TDA827X is not set +# CONFIG_MEDIA_TUNER_TDA8290 is not set +# CONFIG_MEDIA_TUNER_TDA9887 is not set +# CONFIG_MEDIA_TUNER_TEA5761 is not set +# CONFIG_MEDIA_TUNER_TEA5767 is not set +# CONFIG_MEDIA_TUNER_TUA9001 is not set +# CONFIG_MEDIA_TUNER_XC2028 is not set +# CONFIG_MEDIA_TUNER_XC4000 is not set +# CONFIG_MEDIA_TUNER_XC5000 is not set +# CONFIG_MEDIA_USB_SUPPORT is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_MEMBARRIER=y +# CONFIG_MEMORY is not set +# CONFIG_MEMORY_FAILURE is not set +# CONFIG_MEMORY_HOTPLUG is not set +# CONFIG_MEMSTICK is not set +# CONFIG_MEMTEST is not set +# CONFIG_MEN_A21_WDT is not set +# CONFIG_MESON_SM is not set +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_AC100 is not set +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_ARIZONA_SPI is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_MFD_ATC260X_I2C is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_AXP20X is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_CORE is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_CROS_EC is not set +# CONFIG_MFD_CS5535 is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_EXYNOS_LPASS is not set +# CONFIG_MFD_GATEWORKS_GSC is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_MFD_INTEL_M10_BMC is not set +# CONFIG_MFD_INTEL_PMT is not set +# CONFIG_MFD_INTEL_QUARK_I2C_GPIO is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_LOCHNAGAR is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77650 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_MFD_MT6360 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_NTXEC is not set +# CONFIG_MFD_OMAP_USB_HOST is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_PM8921_CORE is not set +# CONFIG_MFD_PM8XXX is not set +# CONFIG_MFD_QCOM_PM8008 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_RK808 is not set +# CONFIG_MFD_RN5T618 is not set +# CONFIG_MFD_ROHM_BD70528 is not set +# CONFIG_MFD_ROHM_BD71828 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_ROHM_BD957XMUF is not set +# CONFIG_MFD_RSMU_I2C is not set +# CONFIG_MFD_RSMU_SPI is not set +# CONFIG_MFD_RT4831 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RTSX_PCI is not set +# CONFIG_MFD_RTSX_USB is not set +# CONFIG_MFD_SEC_CORE is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SL28CPLD is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_MFD_STMFX is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_MFD_TIMBERDALE is not set +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS68470 is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_WM831X is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MG_DISK is not set +# CONFIG_MHI_BUS is not set +# CONFIG_MHI_BUS_DEBUG is not set +# CONFIG_MHI_BUS_PCI_GENERIC is not set +# CONFIG_MHI_NET is not set +# CONFIG_MHI_WWAN_CTRL is not set +# CONFIG_MHI_WWAN_MBIM is not set +# CONFIG_MICREL_KS8995MA is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_KSZ is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_PIT64B is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MIGRATION is not set +CONFIG_MII=y +# CONFIG_MIKROTIK is not set +# CONFIG_MIKROTIK_RB532 is not set +# CONFIG_MINIX_FS is not set +# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_MIPS32_N32 is not set +# CONFIG_MIPS32_O32 is not set +# CONFIG_MIPS_ALCHEMY is not set +# CONFIG_MIPS_CDMM is not set +# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set +# CONFIG_MIPS_CMDLINE_FROM_DTB is not set +# CONFIG_MIPS_CMP is not set +# CONFIG_MIPS_COBALT is not set +# CONFIG_MIPS_CPS is not set +# CONFIG_MIPS_ELF_APPENDED_DTB is not set +# CONFIG_MIPS_FPU_EMULATOR is not set +# CONFIG_MIPS_FP_SUPPORT is not set +# CONFIG_MIPS_GENERIC is not set +# CONFIG_MIPS_GENERIC_KERNEL is not set +# CONFIG_MIPS_MALTA is not set +# CONFIG_MIPS_O32_FP64_SUPPORT is not set +# CONFIG_MIPS_PARAVIRT is not set +# CONFIG_MIPS_PLATFORM_DEVICES is not set +# CONFIG_MIPS_RAW_APPENDED_DTB is not set +# CONFIG_MIPS_SEAD3 is not set +# CONFIG_MIPS_VA_BITS_48 is not set +# CONFIG_MIPS_VPE_LOADER is not set +# CONFIG_MISC_ALCOR_PCI is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_MISDN is not set +# CONFIG_MISDN_AVMFRITZ is not set +# CONFIG_MISDN_HFCPCI is not set +# CONFIG_MISDN_HFCUSB is not set +# CONFIG_MISDN_INFINEON is not set +# CONFIG_MISDN_NETJET is not set +# CONFIG_MISDN_SPEEDFAX is not set +# CONFIG_MISDN_W6692 is not set +CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y +# CONFIG_MKISS is not set +# CONFIG_MLX4_CORE is not set +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLX5_SF is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_MLXFW is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLX_CPLD_PLATFORM is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MMC is not set +# CONFIG_MMC35240 is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_AU1X is not set +# CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_MINORS=8 +# CONFIG_MMC_CAVIUM_THUNDERX is not set +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_CQHCI is not set +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_HSQ is not set +# CONFIG_MMC_JZ4740 is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MMC_MVSDIO is not set +# CONFIG_MMC_S3C is not set +# CONFIG_MMC_SDHCI is not set +# CONFIG_MMC_SDHCI_ACPI is not set +# CONFIG_MMC_SDHCI_AM654 is not set +# CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_BRCMSTB is not set +# CONFIG_MMC_SDHCI_CADENCE is not set +# CONFIG_MMC_SDHCI_F_SDH30 is not set +# CONFIG_MMC_SDHCI_IPROC is not set +# CONFIG_MMC_SDHCI_MILBEAUT is not set +# CONFIG_MMC_SDHCI_MSM is not set +# CONFIG_MMC_SDHCI_OF_ARASAN is not set +# CONFIG_MMC_SDHCI_OF_ASPEED is not set +# CONFIG_MMC_SDHCI_OF_AT91 is not set +# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set +# CONFIG_MMC_SDHCI_OF_ESDHC is not set +# CONFIG_MMC_SDHCI_OF_HLWD is not set +# CONFIG_MMC_SDHCI_OMAP is not set +# CONFIG_MMC_SDHCI_PXAV2 is not set +# CONFIG_MMC_SDHCI_PXAV3 is not set +# CONFIG_MMC_SDHCI_S3C is not set +# CONFIG_MMC_SDHCI_XENON is not set +# CONFIG_MMC_SDRICOH_CS is not set +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_STM32_SDMMC is not set +# CONFIG_MMC_TEST is not set +# CONFIG_MMC_TIFM_SD is not set +# CONFIG_MMC_TOSHIBA_PCI is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_VIA_SDMMC is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMIOTRACE is not set +CONFIG_MMU=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MODPROBE_PATH="/sbin/modprobe" +CONFIG_MODULES=y +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_MODULE_COMPRESS_GZIP is not set +CONFIG_MODULE_COMPRESS_NONE=y +# CONFIG_MODULE_COMPRESS_XZ is not set +# CONFIG_MODULE_COMPRESS_ZSTD is not set +# CONFIG_MODULE_FORCE_LOAD is not set +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_MODULE_STRIPPED=y +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MOST is not set +# CONFIG_MOTORCOMM_PHY is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_PS2_FOCALTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +# CONFIG_MOXTET is not set +# CONFIG_MPL115 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MPLS is not set +# CONFIG_MPLS_IPTUNNEL is not set +# CONFIG_MPLS_ROUTING is not set +# CONFIG_MPTCP is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_MQ_IOSCHED_DEADLINE is not set +# CONFIG_MQ_IOSCHED_KYBER is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_MSCC_OCELOT_SWITCH is not set +# CONFIG_MSDOS_FS is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_MSI_BITMAP_SELFTEST is not set +# CONFIG_MSI_LAPTOP is not set +# CONFIG_MSM_GCC_8953 is not set +# CONFIG_MSM_MMCC_8994 is not set +# CONFIG_MST_IRQ is not set +CONFIG_MTD=y +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_MTD_BLOCK2MTD is not set +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_AMDSTD=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_STAA is not set +CONFIG_MTD_CFI_UTIL=y +# CONFIG_MTD_CMDLINE_PARTS is not set +CONFIG_MTD_COMPLEX_MAPPINGS=y +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_DOCG3 is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_GPIO_ADDR is not set +# CONFIG_MTD_HYPERBUS is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_INTEL_VR_NOR is not set +# CONFIG_MTD_JEDECPROBE is not set +# CONFIG_MTD_LATCH_ADDR is not set +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_LPDDR2_NVM is not set +# CONFIG_MTD_M25P80 is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +CONFIG_MTD_MAP_BANK_WIDTH_2=y +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MCHP23K256 is not set +# CONFIG_MTD_MCHP48L640 is not set +# CONFIG_MTD_MT81xx_NOR is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_MYLOADER_PARTS is not set +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_AMS_DELTA is not set +# CONFIG_MTD_NAND_AR934X is not set +# CONFIG_MTD_NAND_AR934X_HW_ECC is not set +# CONFIG_MTD_NAND_ARASAN is not set +# CONFIG_MTD_NAND_ATMEL is not set +# CONFIG_MTD_NAND_AU1550 is not set +# CONFIG_MTD_NAND_BCH is not set +# CONFIG_MTD_NAND_BF5XX is not set +# CONFIG_MTD_NAND_BRCMNAND is not set +# CONFIG_MTD_NAND_CADENCE is not set +# CONFIG_MTD_NAND_CAFE is not set +# CONFIG_MTD_NAND_CM_X270 is not set +# CONFIG_MTD_NAND_CS553X is not set +# CONFIG_MTD_NAND_DAVINCI is not set +# CONFIG_MTD_NAND_DENALI is not set +# CONFIG_MTD_NAND_DENALI_DT is not set +# CONFIG_MTD_NAND_DENALI_PCI is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_DOCG4 is not set +# CONFIG_MTD_NAND_ECC is not set +# CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +# CONFIG_MTD_NAND_ECC_SW_BCH is not set +# CONFIG_MTD_NAND_ECC_SW_HAMMING is not set +# CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC is not set +# CONFIG_MTD_NAND_FSL_ELBC is not set +# CONFIG_MTD_NAND_FSL_IFC is not set +# CONFIG_MTD_NAND_FSL_UPM is not set +# CONFIG_MTD_NAND_FSMC is not set +# CONFIG_MTD_NAND_GPIO is not set +# CONFIG_MTD_NAND_GPMI_NAND is not set +# CONFIG_MTD_NAND_HISI504 is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_INTEL_LGM is not set +# CONFIG_MTD_NAND_JZ4740 is not set +# CONFIG_MTD_NAND_MPC5121_NFC is not set +# CONFIG_MTD_NAND_MTK is not set +# CONFIG_MTD_NAND_MTK_BMT is not set +# CONFIG_MTD_NAND_MXC is not set +# CONFIG_MTD_NAND_MXIC is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_NDFC is not set +# CONFIG_MTD_NAND_NUC900 is not set +# CONFIG_MTD_NAND_OMAP2 is not set +# CONFIG_MTD_NAND_OMAP_BCH_BUILD is not set +# CONFIG_MTD_NAND_ORION is not set +# CONFIG_MTD_NAND_PASEMI is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_NAND_PXA3xx is not set +# CONFIG_MTD_NAND_RB4XX is not set +# CONFIG_MTD_NAND_RB750 is not set +# CONFIG_MTD_NAND_RB91X is not set +# CONFIG_MTD_NAND_RICOH is not set +# CONFIG_MTD_NAND_S3C2410 is not set +# CONFIG_MTD_NAND_SHARPSL is not set +# CONFIG_MTD_NAND_SH_FLCTL is not set +# CONFIG_MTD_NAND_SOCRATES is not set +# CONFIG_MTD_NAND_TMIO is not set +# CONFIG_MTD_NAND_TXX9NDFMC is not set +CONFIG_MTD_OF_PARTS=y +# CONFIG_MTD_ONENAND is not set +# CONFIG_MTD_OOPS is not set +# CONFIG_MTD_OTP is not set +# CONFIG_MTD_PARSER_TRX is not set +# CONFIG_MTD_PARTITIONED_MASTER is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PHYSMAP_COMPAT is not set +# CONFIG_MTD_PHYSMAP_GEMINI is not set +# CONFIG_MTD_PHYSMAP_GPIO_ADDR is not set +# CONFIG_MTD_PHYSMAP_IXP4XX is not set +CONFIG_MTD_PHYSMAP_OF=y +# CONFIG_MTD_PHYSMAP_OF_GEMINI is not set +# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set +# CONFIG_MTD_PHYSMAP_VERSATILE is not set +# CONFIG_MTD_PLATRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_RAW_NAND is not set +CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1 +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set +# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set +# CONFIG_MTD_ROM is not set +CONFIG_MTD_ROOTFS_ROOT_DEV=y +# CONFIG_MTD_ROUTERBOOT_PARTS is not set +# CONFIG_MTD_SERCOMM_PARTS is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_SPINAND_MT29F is not set +# CONFIG_MTD_SPI_NAND is not set +# CONFIG_MTD_SPI_NOR is not set +# CONFIG_MTD_SPI_NOR_SWP_DISABLE is not set +CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y +# CONFIG_MTD_SPI_NOR_SWP_KEEP is not set +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +# CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE is not set +CONFIG_MTD_SPLIT=y +# CONFIG_MTD_SPLIT_BCM63XX_FW is not set +# CONFIG_MTD_SPLIT_BCM_WFI_FW is not set +# CONFIG_MTD_SPLIT_BRNIMAGE_FW is not set +# CONFIG_MTD_SPLIT_ELF_FW is not set +# CONFIG_MTD_SPLIT_EVA_FW is not set +# CONFIG_MTD_SPLIT_FIRMWARE is not set +CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" +# CONFIG_MTD_SPLIT_FIT_FW is not set +# CONFIG_MTD_SPLIT_H3C_VFS is not set +# CONFIG_MTD_SPLIT_JIMAGE_FW is not set +# CONFIG_MTD_SPLIT_LZMA_FW is not set +# CONFIG_MTD_SPLIT_MINOR_FW is not set +# CONFIG_MTD_SPLIT_SEAMA_FW is not set +CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +CONFIG_MTD_SPLIT_SUPPORT=y +# CONFIG_MTD_SPLIT_TPLINK_FW is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set +# CONFIG_MTD_SPLIT_UIMAGE_FW is not set +# CONFIG_MTD_SPLIT_WRGG_FW is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SWAP is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_UBI is not set +# CONFIG_MTD_UBI_FASTMAP is not set +# CONFIG_MTD_UBI_GLUEBI is not set +# CONFIG_MTD_UIMAGE_SPLIT is not set +# CONFIG_MTD_VIRT_CONCAT is not set +# CONFIG_MTK_DEVAPC is not set +# CONFIG_MTK_MMC is not set +# CONFIG_MTK_MMSYS is not set +# CONFIG_MTK_THERMAL is not set +# CONFIG_MULTIPLEXER is not set +CONFIG_MULTIUSER=y +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +# CONFIG_MUX_ADG792A is not set +# CONFIG_MUX_ADGS1408 is not set +# CONFIG_MUX_GPIO is not set +# CONFIG_MUX_MMIO is not set +# CONFIG_MV643XX_ETH is not set +# CONFIG_MVMDIO is not set +# CONFIG_MVNETA_BM is not set +# CONFIG_MVSW61XX_PHY is not set +# CONFIG_MV_XOR_V2 is not set +# CONFIG_MWAVE is not set +# CONFIG_MWL8K is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_MYRI10GE is not set +# CONFIG_NAMESPACES is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NATSEMI is not set +# CONFIG_NAU7802 is not set +# CONFIG_NBPFAXI_DMA is not set +# CONFIG_NCP_FS is not set +# CONFIG_NE2000 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NEC_MARKEINS is not set +CONFIG_NET=y +# CONFIG_NETCONSOLE is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVSIM is not set +# CONFIG_NETFILTER is not set +# CONFIG_NETFILTER_ADVANCED is not set +# CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_INGRESS is not set +# CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +# CONFIG_NETFILTER_NETLINK_HOOK is not set +# CONFIG_NETFILTER_NETLINK_LOG is not set +# CONFIG_NETFILTER_NETLINK_OSF is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +# CONFIG_NETFILTER_XTABLES is not set +# CONFIG_NETFILTER_XTABLES_COMPAT is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +# CONFIG_NETFILTER_XT_MATCH_STATE is not set +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_SECMARK is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TRACE is not set +# CONFIG_NETLABEL is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_NETLINK_MMAP is not set +# CONFIG_NETPOLL is not set +# CONFIG_NETROM is not set +CONFIG_NETWORK_FILESYSTEMS=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_NET_9P is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_CT is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_GATE is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_MPLS is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_VLAN is not set +CONFIG_NET_CADENCE=y +# CONFIG_NET_CALXEDA_XGMAC is not set +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_ACT is not set +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_IND=y +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_U32 is not set +CONFIG_NET_CORE=y +# CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DROP_MONITOR is not set +# CONFIG_NET_DSA is not set +# CONFIG_NET_DSA_AR9331 is not set +# CONFIG_NET_DSA_BCM_SF2 is not set +# CONFIG_NET_DSA_LANTIQ_GSWIP is not set +# CONFIG_NET_DSA_LEGACY is not set +# CONFIG_NET_DSA_LOOP is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MSCC_FELIX is not set +# CONFIG_NET_DSA_MSCC_SEVILLE is not set +# CONFIG_NET_DSA_MT7530 is not set +# CONFIG_NET_DSA_MV88E6060 is not set +# CONFIG_NET_DSA_MV88E6123_61_65 is not set +# CONFIG_NET_DSA_MV88E6131 is not set +# CONFIG_NET_DSA_MV88E6171 is not set +# CONFIG_NET_DSA_MV88E6352 is not set +# CONFIG_NET_DSA_MV88E6XXX is not set +# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set +# CONFIG_NET_DSA_MV88E6XXX_PTP is not set +# CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_REALTEK_SMI is not set +# CONFIG_NET_DSA_SJA1105 is not set +# CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set +# CONFIG_NET_DSA_SMSC_LAN9303_MDIO is not set +# CONFIG_NET_DSA_TAG_8021Q is not set +# CONFIG_NET_DSA_TAG_AR9331 is not set +# CONFIG_NET_DSA_TAG_BRCM is not set +# CONFIG_NET_DSA_TAG_BRCM_LEGACY is not set +# CONFIG_NET_DSA_TAG_BRCM_PREPEND is not set +# CONFIG_NET_DSA_TAG_DSA is not set +# CONFIG_NET_DSA_TAG_EDSA is not set +# CONFIG_NET_DSA_TAG_GSWIP is not set +# CONFIG_NET_DSA_TAG_HELLCREEK is not set +# CONFIG_NET_DSA_TAG_KSZ is not set +# CONFIG_NET_DSA_TAG_LAN9303 is not set +# CONFIG_NET_DSA_TAG_MTK is not set +# CONFIG_NET_DSA_TAG_OCELOT is not set +# CONFIG_NET_DSA_TAG_OCELOT_8021Q is not set +# CONFIG_NET_DSA_TAG_QCA is not set +# CONFIG_NET_DSA_TAG_RTL4_A is not set +# CONFIG_NET_DSA_TAG_SJA1105 is not set +# CONFIG_NET_DSA_TAG_TRAILER is not set +# CONFIG_NET_DSA_TAG_XRS700X is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM is not set +# CONFIG_NET_DSA_VITESSE_VSC73XX_SPI is not set +# CONFIG_NET_DSA_XRS700X_I2C is not set +# CONFIG_NET_DSA_XRS700X_MDIO is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_EMATCH_CANID is not set +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_IPT is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_NET_IFE is not set +# CONFIG_NET_IPGRE is not set +CONFIG_NET_IPGRE_BROADCAST=y +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_IP_TUNNEL is not set +# CONFIG_NET_KEY is not set +# CONFIG_NET_KEY_MIGRATE is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_MEDIATEK_STAR_EMAC is not set +# CONFIG_NET_MPLS_GSO is not set +# CONFIG_NET_NCSI is not set +# CONFIG_NET_NSH is not set +# CONFIG_NET_PACKET_ENGINE is not set +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_NET_PTP_CLASSIFY is not set +CONFIG_NET_RX_BUSY_POLL=y +# CONFIG_NET_SB1000 is not set +CONFIG_NET_SCHED=y +# CONFIG_NET_SCH_ATM is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_CODEL is not set +CONFIG_NET_SCH_DEFAULT=y +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_ETS is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_NET_SCH_FQ is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_FQ_PIE is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCTPPROBE is not set +# CONFIG_NET_SELFTESTS is not set +CONFIG_NET_SOCK_MSG=y +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_TCPPROBE is not set +# CONFIG_NET_TC_SKB_EXT is not set +# CONFIG_NET_TEAM is not set +# CONFIG_NET_TULIP is not set +# CONFIG_NET_UDP_TUNNEL is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_NET_VENDOR_8390=y +CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_AGERE=y +CONFIG_NET_VENDOR_ALACRITECH=y +CONFIG_NET_VENDOR_ALTEON=y +CONFIG_NET_VENDOR_AMAZON=y +CONFIG_NET_VENDOR_AMD=y +CONFIG_NET_VENDOR_AQUANTIA=y +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ATHEROS=y +CONFIG_NET_VENDOR_AURORA=y +CONFIG_NET_VENDOR_BROADCOM=y +CONFIG_NET_VENDOR_BROCADE=y +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_NET_VENDOR_CAVIUM=y +CONFIG_NET_VENDOR_CHELSIO=y +CONFIG_NET_VENDOR_CIRRUS=y +CONFIG_NET_VENDOR_CISCO=y +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_VENDOR_DLINK=y +CONFIG_NET_VENDOR_EMULEX=y +CONFIG_NET_VENDOR_EXAR=y +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FARADAY=y +CONFIG_NET_VENDOR_FREESCALE=y +CONFIG_NET_VENDOR_FUJITSU=y +CONFIG_NET_VENDOR_GOOGLE=y +CONFIG_NET_VENDOR_HISILICON=y +CONFIG_NET_VENDOR_HP=y +CONFIG_NET_VENDOR_HUAWEI=y +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_IBM=y +CONFIG_NET_VENDOR_INTEL=y +# CONFIG_NET_VENDOR_LITEX is not set +CONFIG_NET_VENDOR_MARVELL=y +CONFIG_NET_VENDOR_MELLANOX=y +CONFIG_NET_VENDOR_MICREL=y +CONFIG_NET_VENDOR_MICROCHIP=y +CONFIG_NET_VENDOR_MICROSEMI=y +# CONFIG_NET_VENDOR_MICROSOFT is not set +CONFIG_NET_VENDOR_MYRI=y +CONFIG_NET_VENDOR_NATSEMI=y +CONFIG_NET_VENDOR_NETERION=y +CONFIG_NET_VENDOR_NETRONOME=y +CONFIG_NET_VENDOR_NI=y +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_NET_VENDOR_OKI=y +CONFIG_NET_VENDOR_PACKET_ENGINES=y +CONFIG_NET_VENDOR_PENSANDO=y +CONFIG_NET_VENDOR_QLOGIC=y +CONFIG_NET_VENDOR_QUALCOMM=y +CONFIG_NET_VENDOR_RDC=y +CONFIG_NET_VENDOR_REALTEK=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +CONFIG_NET_VENDOR_SIS=y +CONFIG_NET_VENDOR_SMSC=y +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_SOLARFLARE=y +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_NET_VENDOR_SUN=y +CONFIG_NET_VENDOR_SYNOPSYS=y +CONFIG_NET_VENDOR_TEHUTI=y +CONFIG_NET_VENDOR_TI=y +CONFIG_NET_VENDOR_TOSHIBA=y +CONFIG_NET_VENDOR_VIA=y +CONFIG_NET_VENDOR_WIZNET=y +CONFIG_NET_VENDOR_XILINX=y +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_NET_VRF is not set +# CONFIG_NET_XGENE is not set +CONFIG_NEW_LEDS=y +# CONFIG_NFC is not set +# CONFIG_NFP is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V2_ACL is not set +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V3_ACL is not set +# CONFIG_NFSD_V4 is not set +# CONFIG_NFS_ACL_SUPPORT is not set +CONFIG_NFS_COMMON=y +# CONFIG_NFS_DISABLE_UDP_SUPPORT is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_FSCACHE is not set +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V2 is not set +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +# CONFIG_NFS_V4_1 is not set +# CONFIG_NFTL is not set +# CONFIG_NFT_BRIDGE_META is not set +# CONFIG_NFT_BRIDGE_REJECT is not set +# CONFIG_NFT_CONNLIMIT is not set +# CONFIG_NFT_DUP_IPV4 is not set +# CONFIG_NFT_DUP_IPV6 is not set +# CONFIG_NFT_FIB_IPV4 is not set +# CONFIG_NFT_FIB_IPV6 is not set +# CONFIG_NFT_FIB_NETDEV is not set +# CONFIG_NFT_FLOW_OFFLOAD is not set +# CONFIG_NFT_OBJREF is not set +# CONFIG_NFT_OSF is not set +# CONFIG_NFT_REJECT_NETDEV is not set +# CONFIG_NFT_RT is not set +# CONFIG_NFT_SET_BITMAP is not set +# CONFIG_NFT_SOCKET is not set +# CONFIG_NFT_SYNPROXY is not set +# CONFIG_NFT_TPROXY is not set +# CONFIG_NFT_TUNNEL is not set +# CONFIG_NFT_XFRM is not set +# CONFIG_NF_CONNTRACK is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_NF_CONNTRACK_EVENTS is not set +# CONFIG_NF_CONNTRACK_FTP is not set +# CONFIG_NF_CONNTRACK_H323 is not set +# CONFIG_NF_CONNTRACK_IRC is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +CONFIG_NF_CONNTRACK_PROCFS=y +# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set +# CONFIG_NF_CONNTRACK_SANE is not set +# CONFIG_NF_CONNTRACK_SECMARK is not set +# CONFIG_NF_CONNTRACK_SIP is not set +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_TFTP is not set +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +# CONFIG_NF_CT_NETLINK is not set +# CONFIG_NF_CT_NETLINK_HELPER is not set +# CONFIG_NF_CT_NETLINK_TIMEOUT is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_GRE is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_DEFRAG_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_DUP_IPV6 is not set +# CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_BRIDGE is not set +# CONFIG_NF_LOG_IPV4 is not set +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_LOG_SYSLOG is not set +# CONFIG_NF_NAT is not set +# CONFIG_NF_NAT_AMANDA is not set +# CONFIG_NF_NAT_FTP is not set +# CONFIG_NF_NAT_H323 is not set +# CONFIG_NF_NAT_IRC is not set +# CONFIG_NF_NAT_NEEDED is not set +# CONFIG_NF_NAT_PPTP is not set +# CONFIG_NF_NAT_PROTO_GRE is not set +# CONFIG_NF_NAT_SIP is not set +# CONFIG_NF_NAT_SNMP_BASIC is not set +# CONFIG_NF_NAT_TFTP is not set +# CONFIG_NF_REJECT_IPV4 is not set +# CONFIG_NF_REJECT_IPV6 is not set +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TABLES is not set +CONFIG_NF_TABLES_ARP=y +CONFIG_NF_TABLES_BRIDGE=y +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_IPV4=y +CONFIG_NF_TABLES_IPV6=y +CONFIG_NF_TABLES_NETDEV=y +# CONFIG_NF_TABLES_SET is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NI65 is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_NIU is not set +# CONFIG_NI_XGE_MANAGEMENT_ENET is not set +CONFIG_NLATTR=y +# CONFIG_NLMON is not set +# CONFIG_NLM_XLP_BOARD is not set +# CONFIG_NLM_XLR_BOARD is not set +# CONFIG_NLS is not set +# CONFIG_NLS_ASCII is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +# CONFIG_NLS_UTF8 is not set +CONFIG_NMI_LOG_BUF_SHIFT=13 +# CONFIG_NOA1305 is not set +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_NORTEL_HERMES is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT is not set +# CONFIG_NOZOMI is not set +# CONFIG_NO_BOOTMEM is not set +# CONFIG_NO_HZ is not set +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ_IDLE is not set +# CONFIG_NS83820 is not set +# CONFIG_NTB is not set +# CONFIG_NTFS3_64BIT_CLUSTER is not set +# CONFIG_NTFS3_FS is not set +# CONFIG_NTFS3_FS_POSIX_ACL is not set +# CONFIG_NTFS3_LZX_XPRESS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_NTP_PPS is not set +# CONFIG_NULL_TTY is not set +# CONFIG_NUMA is not set +# CONFIG_NVIDIA_CARMEL_CNP_ERRATUM is not set +# CONFIG_NVM is not set +# CONFIG_NVMEM is not set +# CONFIG_NVMEM_BCM_OCOTP is not set +# CONFIG_NVMEM_IMX_OCOTP is not set +# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set +# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set +# CONFIG_NVMEM_REBOOT_MODE is not set +# CONFIG_NVMEM_RMEM is not set +# CONFIG_NVMEM_SYSFS is not set +# CONFIG_NVMEM_U_BOOT_ENV is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set +# CONFIG_NVME_TCP is not set +# CONFIG_NVRAM is not set +# CONFIG_NV_TCO is not set +# CONFIG_NXP_C45_TJA11XX_PHY is not set +# CONFIG_NXP_STB220 is not set +# CONFIG_NXP_STB225 is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_N_GSM is not set +# CONFIG_OABI_COMPAT is not set +# CONFIG_OBS600 is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_OCTEONTX2_AF is not set +# CONFIG_OCTEONTX2_PF is not set +# CONFIG_OF_OVERLAY is not set +CONFIG_OF_RESERVED_MEM=y +# CONFIG_OF_UNITTEST is not set +# CONFIG_OID_REGISTRY is not set +# CONFIG_OMAP2_DSS_DEBUG is not set +# CONFIG_OMAP2_DSS_DEBUGFS is not set +# CONFIG_OMAP2_DSS_SDI is not set +# CONFIG_OMAP_OCP2SCP is not set +# CONFIG_OMAP_USB2 is not set +# CONFIG_OMFS_FS is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_OPROFILE is not set +# CONFIG_OPROFILE_EVENT_MULTIPLEX is not set +# CONFIG_OPT3001 is not set +CONFIG_OPTIMIZE_INLINING=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ORION_WATCHDOG is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_OSNOISE_TRACER is not set +CONFIG_OVERLAY_FS=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_METACOPY is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_XINO_AUTO=y +# CONFIG_OWL_LOADER is not set +# CONFIG_P54_COMMON is not set +# CONFIG_PA12203001 is not set +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +# CONFIG_PACKING is not set +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_PAGE_POOL is not set +# CONFIG_PAGE_POOL_STATS is not set +# CONFIG_PAGE_REPORTING is not set +# CONFIG_PAGE_SIZE_16KB is not set +# CONFIG_PAGE_SIZE_32KB is not set +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_64KB is not set +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PALMAS_GPADC is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_PANEL is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_ON_OOPS_VALUE=1 +CONFIG_PANIC_TIMEOUT=1 +# CONFIG_PANTHERLORD_FF is not set +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_PARPORT is not set +# CONFIG_PARPORT_1284 is not set +# CONFIG_PARPORT_AX88796 is not set +# CONFIG_PARPORT_GSC is not set +# CONFIG_PARPORT_PC is not set +CONFIG_PARTITION_ADVANCED=y +# CONFIG_PATA_ALI is not set +# CONFIG_PATA_AMD is not set +# CONFIG_PATA_ARASAN_CF is not set +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CS5520 is not set +# CONFIG_PATA_CS5530 is not set +# CONFIG_PATA_CS5535 is not set +# CONFIG_PATA_CS5536 is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IMX is not set +# CONFIG_PATA_ISAPNP is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_LEGACY is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set +# CONFIG_PATA_OCTEON_CF is not set +# CONFIG_PATA_OF_PLATFORM is not set +# CONFIG_PATA_OLDPIIX is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_PLATFORM is not set +# CONFIG_PATA_QDI is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +# CONFIG_PATA_RZ1000 is not set +# CONFIG_PATA_SC1200 is not set +# CONFIG_PATA_SCH is not set +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set +# CONFIG_PATA_WINBOND_VLB is not set +# CONFIG_PC104 is not set +# CONFIG_PC300TOO is not set +# CONFIG_PCCARD is not set +# CONFIG_PCH_DMA is not set +# CONFIG_PCH_GBE is not set +# CONFIG_PCH_PHUB is not set +# CONFIG_PCI is not set +# CONFIG_PCI200SYN is not set +# CONFIG_PCIEAER is not set +# CONFIG_PCIEAER_INJECT is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIE_AL is not set +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCIE_ARMADA_8K is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_TUNE_OFF is not set +# CONFIG_PCIE_BW is not set +# CONFIG_PCIE_CADENCE_HOST is not set +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# CONFIG_PCIE_DPC is not set +# CONFIG_PCIE_DW_PLAT is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# CONFIG_PCIE_ECRC is not set +# CONFIG_PCIE_IPROC is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_LAYERSCAPE_GEN4 is not set +# CONFIG_PCIE_MEDIATEK_GEN3 is not set +# CONFIG_PCIE_MICROCHIP_HOST is not set +# CONFIG_PCIE_PTM is not set +# CONFIG_PCIE_XILINX is not set +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_PCI_ATMEL is not set +# CONFIG_PCI_CNB20LE_QUIRK is not set +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_DISABLE_COMMON_QUIRKS is not set +# CONFIG_PCI_ENDPOINT is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HERMES is not set +# CONFIG_PCI_HISI is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_J721E_HOST is not set +# CONFIG_PCI_LAYERSCAPE is not set +# CONFIG_PCI_MESON is not set +# CONFIG_PCI_MSI is not set +# CONFIG_PCI_PASID is not set +# CONFIG_PCI_PF_STUB is not set +# CONFIG_PCI_PRI is not set +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_SW_SWITCHTEC is not set +CONFIG_PCI_SYSCALL=y +# CONFIG_PCI_V3_SEMI is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCMCIA is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_AHA152X is not set +# CONFIG_PCMCIA_ATMEL is not set +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_DEBUG is not set +# CONFIG_PCMCIA_FDOMAIN is not set +# CONFIG_PCMCIA_FMVJ18X is not set +# CONFIG_PCMCIA_HERMES is not set +# CONFIG_PCMCIA_LOAD_CIS is not set +# CONFIG_PCMCIA_NINJA_SCSI is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_PCNET is not set +# CONFIG_PCMCIA_QLOGIC is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_SPECTRUM is not set +# CONFIG_PCMCIA_SYM53C500 is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_PCMCIA_XIRCOM is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCPU_DEV_REFCNT is not set +# CONFIG_PCSPKR_PLATFORM is not set +# CONFIG_PCS_XPCS is not set +# CONFIG_PD6729 is not set +# CONFIG_PDA_POWER is not set +# CONFIG_PDC_ADMA is not set +# CONFIG_PERCPU_STATS is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_EVENTS_AMD_POWER is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_PHANTOM is not set +# CONFIG_PHONET is not set +# CONFIG_PHYLIB is not set +# CONFIG_PHYS_ADDR_T_64BIT is not set +# CONFIG_PHY_CADENCE_DP is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_PHY_CADENCE_TORRENT is not set +# CONFIG_PHY_CAN_TRANSCEIVER is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_EXYNOS_DP_VIDEO is not set +# CONFIG_PHY_EXYNOS_MIPI_VIDEO is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_INGENIC_USB is not set +# CONFIG_PHY_INTEL_KEEMBAY_EMMC is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_MIXEL_MIPI_DPHY is not set +# CONFIG_PHY_MTK_HDMI is not set +# CONFIG_PHY_MTK_MIPI_DSI is not set +# CONFIG_PHY_MVEBU_CP110_UTMI is not set +# CONFIG_PHY_OCELOT_SERDES is not set +# CONFIG_PHY_PISTACHIO_USB is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_QCOM_DWC3 is not set +# CONFIG_PHY_QCOM_USB_HS is not set +# CONFIG_PHY_QCOM_USB_HSIC is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_PHY_TUSB1210 is not set +# CONFIG_PHY_XGENE is not set +# CONFIG_PI433 is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_PID_NS is not set +CONFIG_PINCONF=y +# CONFIG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_AXP209 is not set +# CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_EXYNOS is not set +# CONFIG_PINCTRL_EXYNOS5440 is not set +# CONFIG_PINCTRL_ICELAKE is not set +# CONFIG_PINCTRL_INGENIC is not set +# CONFIG_PINCTRL_LPASS_LPI is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_MDM9607 is not set +# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set +# CONFIG_PINCTRL_MSM8953 is not set +# CONFIG_PINCTRL_MSM8X74 is not set +# CONFIG_PINCTRL_MT6779 is not set +# CONFIG_PINCTRL_MT8167 is not set +# CONFIG_PINCTRL_MT8192 is not set +# CONFIG_PINCTRL_MT8195 is not set +# CONFIG_PINCTRL_MT8365 is not set +# CONFIG_PINCTRL_MTK_V2 is not set +# CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_PISTACHIO is not set +# CONFIG_PINCTRL_SC7280 is not set +# CONFIG_PINCTRL_SC8180X is not set +# CONFIG_PINCTRL_SDX55 is not set +CONFIG_PINCTRL_SINGLE=y +# CONFIG_PINCTRL_SM6115 is not set +# CONFIG_PINCTRL_SM6125 is not set +# CONFIG_PINCTRL_SM8350 is not set +# CONFIG_PINCTRL_STMFX is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PING is not set +CONFIG_PINMUX=y +# CONFIG_PKCS7_MESSAGE_PARSER is not set +# CONFIG_PL310_ERRATA_588369 is not set +# CONFIG_PL310_ERRATA_727915 is not set +# CONFIG_PL310_ERRATA_753970 is not set +# CONFIG_PL310_ERRATA_769419 is not set +# CONFIG_PL320_MBOX is not set +# CONFIG_PL330_DMA is not set +# CONFIG_PLATFORM_MHU is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_PLIP is not set +# CONFIG_PLX_DMA is not set +# CONFIG_PLX_HERMES is not set +# CONFIG_PM is not set +# CONFIG_PMBUS is not set +# CONFIG_PMC_MSP is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMS7003 is not set +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_DEBUG is not set +# CONFIG_PM_DEVFREQ is not set +# CONFIG_PM_WAKELOCKS is not set +# CONFIG_POSIX_MQUEUE is not set +CONFIG_POSIX_TIMERS=y +# CONFIG_POWERCAP is not set +# CONFIG_POWER_AVS is not set +# CONFIG_POWER_RESET is not set +# CONFIG_POWER_RESET_BRCMKONA is not set +# CONFIG_POWER_RESET_BRCMSTB is not set +# CONFIG_POWER_RESET_GPIO is not set +# CONFIG_POWER_RESET_GPIO_RESTART is not set +# CONFIG_POWER_RESET_LINKSTATION is not set +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_PIIX4_POWEROFF is not set +# CONFIG_POWER_RESET_QNAP is not set +# CONFIG_POWER_RESET_REGULATOR is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_SYSCON is not set +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_POWER_RESET_VERSATILE is not set +# CONFIG_POWER_RESET_XGENE is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_POWER_SUPPLY_HWMON is not set +# CONFIG_PPC4xx_GPIO is not set +# CONFIG_PPC_16K_PAGES is not set +# CONFIG_PPC_256K_PAGES is not set +CONFIG_PPC_4K_PAGES=y +# CONFIG_PPC_64K_PAGES is not set +# CONFIG_PPC_DISABLE_WERROR is not set +# CONFIG_PPC_EMULATED_STATS is not set +# CONFIG_PPC_EPAPR_HV_BYTECHAN is not set +# CONFIG_PPC_QUEUED_SPINLOCKS is not set +# CONFIG_PPP is not set +# CONFIG_PPPOATM is not set +# CONFIG_PPPOE is not set +# CONFIG_PPPOL2TP is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_FILTER=y +# CONFIG_PPP_MPPE is not set +CONFIG_PPP_MULTILINK=y +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPS is not set +# CONFIG_PPS_CLIENT_GPIO is not set +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_PARPORT is not set +# CONFIG_PPS_DEBUG is not set +# CONFIG_PPTP is not set +# CONFIG_PREEMPT is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_PREEMPTIRQ_EVENTS is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PRESTERA is not set +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_PRIME_NUMBERS is not set +CONFIG_PRINTK=y +# CONFIG_PRINTK_CALLER is not set +# CONFIG_PRINTK_INDEX is not set +CONFIG_PRINTK_NMI=y +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +# CONFIG_PRINTK_TIME is not set +CONFIG_PRINT_STACK_DEPTH=64 +# CONFIG_PRISM2_USB is not set +# CONFIG_PRISM54 is not set +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +# CONFIG_PROC_PAGE_MONITOR is not set +# CONFIG_PROC_STRIPPED is not set +CONFIG_PROC_SYSCTL=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILING is not set +# CONFIG_PROVE_LOCKING is not set +# CONFIG_PROVE_RAW_LOCK_NESTING is not set +# CONFIG_PROVE_RCU is not set +# CONFIG_PROVE_RCU_LIST is not set +# CONFIG_PROVE_RCU_REPEATEDLY is not set +# CONFIG_PSAMPLE is not set +# CONFIG_PSB6970_PHY is not set +# CONFIG_PSI is not set +# CONFIG_PSTORE is not set +# CONFIG_PSTORE_842_COMPRESS is not set +# CONFIG_PSTORE_BLK is not set +# CONFIG_PSTORE_COMPRESS is not set +# CONFIG_PSTORE_CONSOLE is not set +CONFIG_PSTORE_DEFAULT_KMSG_BYTES=10240 +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +# CONFIG_PSTORE_DEFLATE_COMPRESS_DEFAULT is not set +# CONFIG_PSTORE_FTRACE is not set +# CONFIG_PSTORE_LZ4HC_COMPRESS is not set +# CONFIG_PSTORE_LZ4_COMPRESS is not set +# CONFIG_PSTORE_LZO_COMPRESS is not set +# CONFIG_PSTORE_PMSG is not set +# CONFIG_PSTORE_RAM is not set +# CONFIG_PSTORE_ZSTD_COMPRESS is not set +# CONFIG_PTDUMP_DEBUGFS is not set +# CONFIG_PTP_1588_CLOCK is not set +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_IXP46X is not set +# CONFIG_PTP_1588_CLOCK_KVM is not set +# CONFIG_PTP_1588_CLOCK_OCP is not set +# CONFIG_PTP_1588_CLOCK_PCH is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# CONFIG_PUBLIC_KEY_ALGO_RSA is not set +# CONFIG_PVPANIC is not set +# CONFIG_PWM is not set +# CONFIG_PWM_ATMEL_TCB is not set +# CONFIG_PWM_DEBUG is not set +# CONFIG_PWM_DWC is not set +# CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_IMG is not set +# CONFIG_PWM_JZ4740 is not set +# CONFIG_PWM_MEDIATEK is not set +# CONFIG_PWM_PCA9685 is not set +# CONFIG_PWM_RASPBERRYPI_POE is not set +CONFIG_PWRSEQ_EMMC=y +# CONFIG_PWRSEQ_SD8787 is not set +CONFIG_PWRSEQ_SIMPLE=y +# CONFIG_QCA7000 is not set +# CONFIG_QCA7000_SPI is not set +# CONFIG_QCA7000_UART is not set +# CONFIG_QCOM_A7PLL is not set +# CONFIG_QCOM_EMAC is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_QCOM_GPI_DMA is not set +# CONFIG_QCOM_HIDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_LMH is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_SPMI_ADC5 is not set +# CONFIG_QCOM_SPMI_ADC_TM5 is not set +# CONFIG_QCOM_SPMI_IADC is not set +# CONFIG_QCOM_SPMI_TEMP_ALARM is not set +# CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QED is not set +# CONFIG_QFMT_V1 is not set +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_QLGE is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_QORIQ_CPUFREQ is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_QRTR is not set +# CONFIG_QRTR_MHI is not set +# CONFIG_QRTR_TUN is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_QUEUED_LOCK_STAT is not set +# CONFIG_QUICC_ENGINE is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_QUOTA_DEBUG is not set +# CONFIG_QUOTA_NETLINK_INTERFACE is not set +# CONFIG_R3964 is not set +# CONFIG_R6040 is not set +# CONFIG_R8169 is not set +# CONFIG_R8188EU is not set +# CONFIG_R8712U is not set +# CONFIG_R8723AU is not set +# CONFIG_RADIO_ADAPTERS is not set +# CONFIG_RADIO_AZTECH is not set +# CONFIG_RADIO_CADET is not set +# CONFIG_RADIO_GEMTEK is not set +# CONFIG_RADIO_MAXIRADIO is not set +# CONFIG_RADIO_RTRACK is not set +# CONFIG_RADIO_RTRACK2 is not set +# CONFIG_RADIO_SF16FMI is not set +# CONFIG_RADIO_SF16FMR2 is not set +# CONFIG_RADIO_TERRATEC is not set +# CONFIG_RADIO_TRUST is not set +# CONFIG_RADIO_TYPHOON is not set +# CONFIG_RADIO_ZOLTRIX is not set +# CONFIG_RAID6_PQ_BENCHMARK is not set +# CONFIG_RAID_ATTRS is not set +# CONFIG_RALINK is not set +# CONFIG_RANDOM32_SELFTEST is not set +# CONFIG_RANDOMIZE_BASE is not set +# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set +CONFIG_RANDOM_TRUST_BOOTLOADER=y +CONFIG_RANDOM_TRUST_CPU=y +# CONFIG_RAPIDIO is not set +# CONFIG_RAS is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_RCU_BOOST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_RCU_EXPEDITE_BOOT is not set +# CONFIG_RCU_EXPERT is not set +CONFIG_RCU_KTHREAD_PRIO=0 +CONFIG_RCU_NEED_SEGCBLIST=y +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +# CONFIG_RCU_SCALE_TEST is not set +CONFIG_RCU_STALL_COMMON=y +# CONFIG_RCU_STRICT_GRACE_PERIOD is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 +# CONFIG_RCU_TRACE is not set +# CONFIG_RC_ATI_REMOTE is not set +# CONFIG_RC_CORE is not set +# CONFIG_RC_DECODERS is not set +# CONFIG_RC_LOOPBACK is not set +# CONFIG_RC_MAP is not set +# CONFIG_RC_XBOX_DVD is not set +# CONFIG_RDS is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_GZIP is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_ZSTD is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_READ_ONLY_THP_FOR_FS is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_REDWOOD is not set +# CONFIG_REED_SOLOMON is not set +# CONFIG_REED_SOLOMON_DEC8 is not set +# CONFIG_REED_SOLOMON_ENC8 is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_REGMAP is not set +# CONFIG_REGMAP_I2C is not set +# CONFIG_REGMAP_MMIO is not set +# CONFIG_REGMAP_SPI is not set +# CONFIG_REGULATOR is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_DA9121 is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_FAN53555 is not set +# CONFIG_REGULATOR_FAN53880 is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_GPIO is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX77620 is not set +# CONFIG_REGULATOR_MAX77826 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8893 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MP5416 is not set +# CONFIG_REGULATOR_MP8859 is not set +# CONFIG_REGULATOR_MP886X is not set +# CONFIG_REGULATOR_MPQ7920 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_MT6315 is not set +# CONFIG_REGULATOR_MT6359 is not set +# CONFIG_REGULATOR_PCA9450 is not set +# CONFIG_REGULATOR_PF8X00 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set +# CONFIG_REGULATOR_RT4801 is not set +# CONFIG_REGULATOR_RT6160 is not set +# CONFIG_REGULATOR_RT6245 is not set +# CONFIG_REGULATOR_RTMV20 is not set +# CONFIG_REGULATOR_RTQ2134 is not set +# CONFIG_REGULATOR_RTQ6752 is not set +# CONFIG_REGULATOR_SLG51000 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_SY8824X is not set +# CONFIG_REGULATOR_SY8827N is not set +# CONFIG_REGULATOR_TI_ABB is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_VCTRL is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_FS_POSIX_ACL is not set +# CONFIG_REISERFS_FS_SECURITY is not set +CONFIG_REISERFS_FS_XATTR=y +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_RELAY is not set +# CONFIG_RELOCATABLE is not set +# CONFIG_REMOTEPROC is not set +# CONFIG_RENESAS_PHY is not set +# CONFIG_RESET_ATH79 is not set +# CONFIG_RESET_BERLIN is not set +# CONFIG_RESET_BRCMSTB_RESCAL is not set +# CONFIG_RESET_CONTROLLER is not set +# CONFIG_RESET_IMX7 is not set +# CONFIG_RESET_INTEL_GW is not set +# CONFIG_RESET_LANTIQ is not set +# CONFIG_RESET_LPC18XX is not set +# CONFIG_RESET_MESON is not set +# CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SOCFPGA is not set +# CONFIG_RESET_STM32 is not set +# CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TEGRA_BPMP is not set +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_ZYNQ is not set +# CONFIG_RFD77402 is not set +# CONFIG_RFD_FTL is not set +CONFIG_RFKILL=y +# CONFIG_RFKILL_FULL is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_RFKILL_INPUT is not set +# CONFIG_RFKILL_LEDS is not set +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set +# CONFIG_RMI4_CORE is not set +# CONFIG_RMNET is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_ROCKER is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_ROSE is not set +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_RPMSG_WWAN_CTRL is not set +# CONFIG_RPR0521 is not set +# CONFIG_RSEQ is not set +# CONFIG_RT2X00 is not set +# CONFIG_RTC_CLASS is not set +# CONFIG_RTC_DEBUG is not set +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_ARMADA38X is not set +# CONFIG_RTC_DRV_AU1XXX is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_CADENCE is not set +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1307_CENTURY is not set +# CONFIG_RTC_DRV_DS1307_HWMON is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_EP93XX is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_GENERIC is not set +# CONFIG_RTC_DRV_GOLDFISH is not set +# CONFIG_RTC_DRV_HID_SENSOR_TIME is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_ISL12057 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_JZ4740 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_MAX77686 is not set +# CONFIG_RTC_DRV_MCP795 is not set +# CONFIG_RTC_DRV_MOXART is not set +# CONFIG_RTC_DRV_MPC5121 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_MT2712 is not set +# CONFIG_RTC_DRV_OMAP is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_PL030 is not set +# CONFIG_RTC_DRV_PL031 is not set +# CONFIG_RTC_DRV_PS3 is not set +# CONFIG_RTC_DRV_PT7C4338 is not set +# CONFIG_RTC_DRV_R7301 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_RTC7301 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_SD3078 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_SUN6I is not set +# CONFIG_RTC_DRV_TEGRA is not set +# CONFIG_RTC_DRV_TEST is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_XGENE is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_LIB=y +# CONFIG_RTC_NVMEM is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +# CONFIG_RTL8192E is not set +# CONFIG_RTL8192U is not set +# CONFIG_RTL8306_PHY is not set +# CONFIG_RTL8366RB_PHY is not set +# CONFIG_RTL8366S_PHY is not set +# CONFIG_RTL8366_SMI is not set +# CONFIG_RTL8366_SMI_DEBUG_FS is not set +# CONFIG_RTL8367B_PHY is not set +# CONFIG_RTL8367_PHY is not set +# CONFIG_RTLLIB is not set +# CONFIG_RTL_CARDS is not set +# CONFIG_RTS5208 is not set +CONFIG_RT_MUTEXES=y +# CONFIG_RUNTIME_DEBUG is not set +CONFIG_RUNTIME_TESTING_MENU=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_RXKAD=y +# CONFIG_S2IO is not set +# CONFIG_SAMPLES is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_AHCI is not set +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_FSL is not set +# CONFIG_SATA_HIGHBANK is not set +# CONFIG_SATA_HOST is not set +# CONFIG_SATA_INIC162X is not set +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PMP is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_RCAR is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIL24 is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_SX4 is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +CONFIG_SBITMAP=y +# CONFIG_SC92031 is not set +# CONFIG_SCA3000 is not set +# CONFIG_SCA3300 is not set +# CONFIG_SCACHE_DEBUGFS is not set +# CONFIG_SCC is not set +# CONFIG_SCD30_CORE is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_HRTICK=y +# CONFIG_SCHED_MC is not set +CONFIG_SCHED_OMIT_FRAME_POINTER=y +# CONFIG_SCHED_SMT is not set +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_SCHED_TRACER is not set +# CONFIG_SCR24X is not set +# CONFIG_SCSI is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_BFA_FC is not set +# CONFIG_SCSI_BNX2X_FCOE is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CHELSIO_FCOE is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DPT_I2O is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_HISI_SAS is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_LOGGING is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_LPFC is not set +CONFIG_SCSI_MOD=y +# CONFIG_SCSI_MPI3MR is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MQ_DEFAULT is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVSAS_DEBUG is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_NETLINK is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PM8001 is not set +# CONFIG_SCSI_PMCRAID is not set +CONFIG_SCSI_PROC_FS=y +# CONFIG_SCSI_QLA_FC is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_ULTRASTOR is not set +# CONFIG_SCSI_VIRTIO is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SC_CAMCC_7180 is not set +# CONFIG_SC_DISPCC_7280 is not set +# CONFIG_SC_GCC_7280 is not set +# CONFIG_SC_GCC_8180X is not set +# CONFIG_SC_GPUCC_7280 is not set +# CONFIG_SC_VIDEOCC_7280 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_SDIO_UART is not set +# CONFIG_SDM_GPUCC_660 is not set +# CONFIG_SDM_MMCC_660 is not set +# CONFIG_SDR_MAX2175 is not set +# CONFIG_SDR_PLATFORM_DRIVERS is not set +# CONFIG_SDX_GCC_55 is not set +# CONFIG_SD_ADC_MODULATOR is not set +# CONFIG_SECCOMP is not set +# CONFIG_SECCOMP_CACHE_DEBUG is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_SECURITY_APPARMOR is not set +CONFIG_SECURITY_DMESG_RESTRICT=y +# CONFIG_SECURITY_LANDLOCK is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_SELINUX_AVC_STATS is not set +# CONFIG_SECURITY_SELINUX_BOOTPARAM is not set +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 +# CONFIG_SECURITY_SELINUX_DEVELOP is not set +# CONFIG_SECURITY_SELINUX_DISABLE is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_YAMA is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSIRION_SGP30 is not set +# CONFIG_SENSIRION_SGP40 is not set +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1177 is not set +# CONFIG_SENSORS_ADM1266 is not set +# CONFIG_SENSORS_ADM1275 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AHT10 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_BEL_PFE is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BPA_RS600 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_CORSAIR_PSU is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_DPS920AB is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC2305 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FSP_3Y is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_GPIO_FAN is not set +# CONFIG_SENSORS_GSC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HMC5843 is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_HTU21 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_IBM_CFFPS is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_INSPUR_IPSPS is not set +# CONFIG_SENSORS_IR35221 is not set +# CONFIG_SENSORS_IR36021 is not set +# CONFIG_SENSORS_IR38064 is not set +# CONFIG_SENSORS_IRPS5401 is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_SENSORS_ISL68137 is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LIS3LV02D is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LM25066 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2947_SPI is not set +# CONFIG_SENSORS_LTC2978 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC2992 is not set +# CONFIG_SENSORS_LTC3815 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_LTQ_CPUTEMP is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX127 is not set +# CONFIG_SENSORS_MAX15301 is not set +# CONFIG_SENSORS_MAX16064 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX16601 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX20730 is not set +# CONFIG_SENSORS_MAX20751 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX31730 is not set +# CONFIG_SENSORS_MAX31785 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX8688 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_MP2888 is not set +# CONFIG_SENSORS_MP2975 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_NSA320 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NZXT_KRAKEN2 is not set +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_PIM4328 is not set +# CONFIG_SENSORS_PM6764TR is not set +# CONFIG_SENSORS_PMBUS is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_PWM_FAN is not set +# CONFIG_SENSORS_PXE1610 is not set +# CONFIG_SENSORS_Q54SJ108A2 is not set +# CONFIG_SENSORS_RM3100_I2C is not set +# CONFIG_SENSORS_RM3100_SPI is not set +# CONFIG_SENSORS_SBRMI is not set +# CONFIG_SENSORS_SBTSI is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_SCH56XX_COMMON is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHT4x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_STPDDC60 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TMP513 is not set +# CONFIG_SENSORS_TPS23861 is not set +# CONFIG_SENSORS_TPS40422 is not set +# CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_SENSORS_UCD9000 is not set +# CONFIG_SENSORS_UCD9200 is not set +# CONFIG_SENSORS_VEXPRESS is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_XDPE122 is not set +# CONFIG_SENSORS_XGENE is not set +# CONFIG_SENSORS_ZL6100 is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_16550A_VARIANTS=y +# CONFIG_SERIAL_8250_ACCENT is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +# CONFIG_SERIAL_8250_BOCA is not set +CONFIG_SERIAL_8250_CONSOLE=y +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_EM is not set +# CONFIG_SERIAL_8250_EXAR is not set +# CONFIG_SERIAL_8250_EXAR_ST16C554 is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_FINTEK is not set +# CONFIG_SERIAL_8250_FOURPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +# CONFIG_SERIAL_8250_INGENIC is not set +# CONFIG_SERIAL_8250_LPSS is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_MID is not set +# CONFIG_SERIAL_8250_MOXA is not set +CONFIG_SERIAL_8250_NR_UARTS=2 +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_BCM63XX is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_SERIAL_EARLYCON=y +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_SERIAL_OF_PLATFORM is not set +# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set +# CONFIG_SERIAL_PCH_UART is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SH_SCI is not set +# CONFIG_SERIAL_SIFIVE is not set +# CONFIG_SERIAL_SPRD is not set +# CONFIG_SERIAL_STM32 is not set +# CONFIG_SERIAL_ST_ASC is not set +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_UARTLITE is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_PCIPS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_SUN4I_PS2 is not set +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFI is not set +# CONFIG_SFP is not set +# CONFIG_SF_PDMA is not set +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SGI_IOC4 is not set +# CONFIG_SGI_IP22 is not set +# CONFIG_SGI_IP27 is not set +# CONFIG_SGI_IP28 is not set +# CONFIG_SGI_IP30 is not set +# CONFIG_SGI_IP32 is not set +# CONFIG_SGI_MFD_IOC3 is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_SG_POOL is not set +# CONFIG_SG_SPLIT is not set +CONFIG_SHMEM=y +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_SH_ETH is not set +# CONFIG_SH_TIMER_CMT is not set +# CONFIG_SH_TIMER_MTU2 is not set +# CONFIG_SH_TIMER_TMU is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set +# CONFIG_SIBYTE_BIGSUR is not set +# CONFIG_SIBYTE_CARMEL is not set +# CONFIG_SIBYTE_CRHINE is not set +# CONFIG_SIBYTE_CRHONE is not set +# CONFIG_SIBYTE_LITTLESUR is not set +# CONFIG_SIBYTE_RHONE is not set +# CONFIG_SIBYTE_SENTOSA is not set +# CONFIG_SIBYTE_SWARM is not set +CONFIG_SIGNALFD=y +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_SIMPLE_GPIO is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_SIOX is not set +# CONFIG_SIS190 is not set +# CONFIG_SIS900 is not set +# CONFIG_SKGE is not set +# CONFIG_SKY2 is not set +# CONFIG_SKY2_DEBUG is not set +# CONFIG_SLAB is not set +CONFIG_SLABINFO=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLHC is not set +# CONFIG_SLICOSS is not set +# CONFIG_SLIMBUS is not set +# CONFIG_SLIP is not set +# CONFIG_SLOB is not set +CONFIG_SLUB=y +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SMARTJOYPLUS_FF is not set +# CONFIG_SMB_SERVER is not set +# CONFIG_SMC911X is not set +# CONFIG_SMC9194 is not set +# CONFIG_SMC91X is not set +# CONFIG_SMP is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_SMS_SDIO_DRV is not set +# CONFIG_SMS_USB_DRV is not set +# CONFIG_SM_CAMCC_8250 is not set +# CONFIG_SM_FTL is not set +# CONFIG_SM_GCC_6115 is not set +# CONFIG_SM_GCC_6125 is not set +# CONFIG_SM_GCC_6350 is not set +# CONFIG_SM_GCC_8350 is not set +# CONFIG_SND is not set +# CONFIG_SND_AC97_POWER_SAVE is not set +# CONFIG_SND_AD1816A is not set +# CONFIG_SND_AD1848 is not set +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ADLIB is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_ALS100 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_ATMEL_AC97C is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT2320 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_BCM63XX_I2S_WHISTLER is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMI8330 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_CS4231 is not set +# CONFIG_SND_CS4236 is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS5530 is not set +# CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_DESIGNWARE_I2S is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_EDMA_SOC is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1688 is not set +# CONFIG_SND_ES18XX is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FIREWIRE is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_GUSCLASSIC is not set +# CONFIG_SND_GUSEXTREME is not set +# CONFIG_SND_GUSMAX is not set +# CONFIG_SND_HDA_CODEC_CS8409 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDA_INTEL_DETECT_DMIC is not set +# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +CONFIG_SND_HDA_PREALLOC_SIZE=64 +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_HWDEP is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_INTERWAVE is not set +# CONFIG_SND_INTERWAVE_STB is not set +# CONFIG_SND_ISA is not set +# CONFIG_SND_JZ4740_SOC_I2S is not set +# CONFIG_SND_KIRKWOOD_SOC is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_MAX_CARDS=16 +# CONFIG_SND_MIA is not set +# CONFIG_SND_MIPS is not set +# CONFIG_SND_MIRO is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MPC52xx_SOC_EFIKA is not set +# CONFIG_SND_MPU401 is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_MTS64 is not set +# CONFIG_SND_MXS_SOC is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_OPL3SA2 is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_OPTI92X_AD1848 is not set +# CONFIG_SND_OPTI92X_CS4231 is not set +# CONFIG_SND_OPTI93X is not set +CONFIG_SND_OSSEMUL=y +# CONFIG_SND_OXYGEN is not set +CONFIG_SND_PCI=y +# CONFIG_SND_PCM is not set +# CONFIG_SND_PCMCIA is not set +# CONFIG_SND_PCM_OSS is not set +CONFIG_SND_PCM_OSS_PLUGINS=y +# CONFIG_SND_PCM_TIMER is not set +# CONFIG_SND_PCM_XRUN_DEBUG is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_PORTMAN2X4 is not set +# CONFIG_SND_POWERPC_SOC is not set +# CONFIG_SND_PPC is not set +CONFIG_SND_PROC_FS=y +# CONFIG_SND_RAWMIDI is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_RTCTIMER is not set +# CONFIG_SND_SB16 is not set +# CONFIG_SND_SB8 is not set +# CONFIG_SND_SBAWE is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_SIMPLE_CARD is not set +# CONFIG_SND_SIMPLE_SCU_CARD is not set +# CONFIG_SND_SIS7019 is not set +# CONFIG_SND_SOC is not set +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_AD193X_I2C is not set +# CONFIG_SND_SOC_AD193X_SPI is not set +# CONFIG_SND_SOC_ADAU1372_I2C is not set +# CONFIG_SND_SOC_ADAU1372_SPI is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_ADAU7118_HW is not set +# CONFIG_SND_SOC_ADAU7118_I2C is not set +# CONFIG_SND_SOC_ADI is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_SOC_AMD_ACP3x is not set +# CONFIG_SND_SOC_AMD_ACP5x is not set +# CONFIG_SND_SOC_AMD_RENOIR is not set +# CONFIG_SND_SOC_AU1XAUDIO is not set +# CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS35L36 is not set +# CONFIG_SND_SOC_CS4234 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4341 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_CX2072X is not set +# CONFIG_SND_SOC_DA7213 is not set +# CONFIG_SND_SOC_DIO2125 is not set +# CONFIG_SND_SOC_DMIC is not set +# CONFIG_SND_SOC_ES7134 is not set +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_EUKREA_TLV320 is not set +# CONFIG_SND_SOC_FSL_ASOC_CARD is not set +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_AUD2HTX is not set +# CONFIG_SND_SOC_FSL_AUDMIX is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_FSL_RPMSG is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_XCVR is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_ICS43432 is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_IMX_AUDMIX is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_SOC_IMX_CARD is not set +# CONFIG_SND_SOC_IMX_ES8328 is not set +# CONFIG_SND_SOC_IMX_HDMI is not set +# CONFIG_SND_SOC_IMX_RPMSG is not set +# CONFIG_SND_SOC_IMX_SPDIF is not set +# CONFIG_SND_SOC_IMX_WM8962 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_INTEL_APL is not set +# CONFIG_SND_SOC_INTEL_BAYTRAIL is not set +# CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_BXT_RT298_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH is not set +# CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH is not set +# CONFIG_SND_SOC_INTEL_CATPT is not set +# CONFIG_SND_SOC_INTEL_CFL is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_NAU8824_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH is not set +# CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH is not set +# CONFIG_SND_SOC_INTEL_CML_H is not set +# CONFIG_SND_SOC_INTEL_CML_LP is not set +# CONFIG_SND_SOC_INTEL_CNL is not set +# CONFIG_SND_SOC_INTEL_GLK is not set +# CONFIG_SND_SOC_INTEL_HASWELL is not set +# CONFIG_SND_SOC_INTEL_KBL is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH is not set +# CONFIG_SND_SOC_INTEL_KEEMBAY is not set +# CONFIG_SND_SOC_INTEL_SKL is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH is not set +# CONFIG_SND_SOC_INTEL_SKL_RT286_MACH is not set +# CONFIG_SND_SOC_INTEL_SKYLAKE is not set +# CONFIG_SND_SOC_INTEL_SST is not set +CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y +# CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES is not set +# CONFIG_SND_SOC_JZ4725B_CODEC is not set +# CONFIG_SND_SOC_JZ4740_CODEC is not set +# CONFIG_SND_SOC_JZ4770_CODEC is not set +# CONFIG_SND_SOC_LPASS_RX_MACRO is not set +# CONFIG_SND_SOC_LPASS_TX_MACRO is not set +# CONFIG_SND_SOC_LPASS_VA_MACRO is not set +# CONFIG_SND_SOC_LPASS_WSA_MACRO is not set +# CONFIG_SND_SOC_MA120X0P is not set +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MAX98088 is not set +# CONFIG_SND_SOC_MAX98357A is not set +# CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX98373_I2C is not set +# CONFIG_SND_SOC_MAX98390 is not set +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MAX9867 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MEDIATEK is not set +# CONFIG_SND_SOC_MPC5200_AC97 is not set +# CONFIG_SND_SOC_MPC5200_I2S is not set +# CONFIG_SND_SOC_MSM8916_WCD_ANALOG is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_MT2701 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT6358 is not set +# CONFIG_SND_SOC_MT6359 is not set +# CONFIG_SND_SOC_MT6359_ACCDET is not set +# CONFIG_SND_SOC_MT6660 is not set +# CONFIG_SND_SOC_MT6797 is not set +# CONFIG_SND_SOC_MT8173 is not set +# CONFIG_SND_SOC_MT8183 is not set +# CONFIG_SND_SOC_MT8192 is not set +# CONFIG_SND_SOC_MT8195 is not set +# CONFIG_SND_SOC_MTK_BTCVSD is not set +# CONFIG_SND_SOC_NAU8315 is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8822 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM1792A is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3060_I2C is not set +# CONFIG_SND_SOC_PCM3060_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM5102A is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_QCOM is not set +# CONFIG_SND_SOC_RK3328 is not set +# CONFIG_SND_SOC_RK817 is not set +# CONFIG_SND_SOC_ROCKCHIP is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_RT5640 is not set +# CONFIG_SND_SOC_RT5659 is not set +# CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIMPLE_MUX is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +# CONFIG_SND_SOC_SOF_TOPLEVEL is not set +# CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2518 is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS2562 is not set +# CONFIG_SND_SOC_TAS2764 is not set +# CONFIG_SND_SOC_TAS2770 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TFA989X is not set +# CONFIG_SND_SOC_TLV320ADCX140 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TLV320AIC3X_I2C is not set +# CONFIG_SND_SOC_TLV320AIC3X_SPI is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_UDA1334 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8782 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set +# CONFIG_SND_SOC_XILINX_I2S is not set +# CONFIG_SND_SOC_XILINX_SPDIF is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_SND_SOC_ZL38060 is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_SSCAPE is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_ACPI is not set +# CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set +# CONFIG_SND_SUN4I_CODEC is not set +# CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TIMER is not set +# CONFIG_SND_TRIDENT is not set +CONFIG_SND_USB=y +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_VARIAX is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTIO is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_WAVEFRONT is not set +CONFIG_SND_X86=y +# CONFIG_SND_XEN_FRONTEND is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SNI_RM is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_SOCK_CGROUP_DATA is not set +# CONFIG_SOC_AM33XX is not set +# CONFIG_SOC_AM43XX is not set +# CONFIG_SOC_BRCMSTB is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_SOC_DRA7XX is not set +# CONFIG_SOC_HAS_OMAP2_SDRC is not set +# CONFIG_SOC_OMAP5 is not set +# CONFIG_SOC_TI is not set +# CONFIG_SOFTLOCKUP_DETECTOR is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_SONYPI is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SOUND is not set +# CONFIG_SOUNDWIRE is not set +# CONFIG_SOUND_OSS_CORE is not set +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +# CONFIG_SOUND_PRIME is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SPARSEMEM_MANUAL is not set +# CONFIG_SPARSEMEM_STATIC is not set +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_SPARSE_IRQ is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_SPEAKUP is not set +# CONFIG_SPI is not set +# CONFIG_SPINLOCK_TEST is not set +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AMD is not set +# CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BCM2835 is not set +# CONFIG_SPI_BCM_QSPI is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_BUTTERFLY is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_DEBUG is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_FSL_DSPI is not set +# CONFIG_SPI_FSL_ESPI is not set +# CONFIG_SPI_FSL_SPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_GPIO_OLD is not set +# CONFIG_SPI_IMG_SPFI is not set +# CONFIG_SPI_LANTIQ_SSC is not set +# CONFIG_SPI_LM70_LLP is not set +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_SPI_MEM is not set +# CONFIG_SPI_MPC52xx is not set +# CONFIG_SPI_MPC52xx_PSC is not set +# CONFIG_SPI_MTK_QUADSPI is not set +# CONFIG_SPI_MUX is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_OCTEON is not set +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_ORION is not set +# CONFIG_SPI_PL022 is not set +# CONFIG_SPI_PPC4xx is not set +# CONFIG_SPI_PXA2XX is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_QCOM_QSPI is not set +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_S3C64XX is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_THUNDERX is not set +# CONFIG_SPI_TI_QSPI is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_TOPCLIFF_PCH is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_XWAY is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_SPMI is not set +# CONFIG_SPS30 is not set +# CONFIG_SPS30_I2C is not set +# CONFIG_SPS30_SERIAL is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +CONFIG_SQUASHFS_EMBEDDED=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_SQUASHFS_LZ4 is not set +# CONFIG_SQUASHFS_LZO is not set +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_XZ=y +# CONFIG_SQUASHFS_ZLIB is not set +# CONFIG_SQUASHFS_ZSTD is not set +# CONFIG_SRAM is not set +# CONFIG_SRF04 is not set +# CONFIG_SRF08 is not set +# CONFIG_SSB is not set +# CONFIG_SSB_DEBUG is not set +# CONFIG_SSB_DRIVER_GPIO is not set +# CONFIG_SSB_HOST_SOC is not set +# CONFIG_SSB_PCMCIAHOST is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_SILENT is not set +# CONFIG_SSFDC is not set +# CONFIG_STACKPROTECTOR is not set +# CONFIG_STACKPROTECTOR_STRONG is not set +# CONFIG_STACKTRACE is not set +# CONFIG_STACKTRACE_BUILD_ID is not set +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_STACK_HASH_ORDER=20 +# CONFIG_STACK_TRACER is not set +# CONFIG_STACK_VALIDATION is not set +CONFIG_STAGING=y +# CONFIG_STAGING_BOARD is not set +# CONFIG_STAGING_GASKET_FRAMEWORK is not set +# CONFIG_STAGING_MEDIA is not set +CONFIG_STANDALONE=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_STDBINUTILS=y +# CONFIG_STE10XP is not set +# CONFIG_STE_MODEM_RPROC is not set +# CONFIG_STK3310 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set +# CONFIG_STM is not set +# CONFIG_STMMAC_ETH is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_STMMAC_PLATFORM is not set +# CONFIG_STMMAC_SELFTESTS is not set +# CONFIG_STM_DUMMY is not set +# CONFIG_STM_SOURCE_CONSOLE is not set +CONFIG_STP=y +# CONFIG_STREAM_PARSER is not set +# CONFIG_STRICT_DEVMEM is not set +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_STRICT_MODULE_RWX=y +# CONFIG_STRING_SELFTEST is not set +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_STX104 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_SUN4I_GPADC is not set +# CONFIG_SUN50I_DE2_BUS is not set +# CONFIG_SUN50I_ERRATUM_UNKNOWN1 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNGEM is not set +# CONFIG_SUNRPC is not set +# CONFIG_SUNRPC_DEBUG is not set +CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y +# CONFIG_SUNRPC_GSS is not set +# CONFIG_SUNXI_SRAM is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SUSPEND is not set +# CONFIG_SUSPEND_SKIP_SYNC is not set +CONFIG_SWAP=y +# CONFIG_SWCONFIG is not set +# CONFIG_SWCONFIG_B53 is not set +# CONFIG_SWCONFIG_B53_MDIO_DRIVER is not set +# CONFIG_SWCONFIG_B53_MMAP_DRIVER is not set +# CONFIG_SWCONFIG_B53_SPI_DRIVER is not set +# CONFIG_SWCONFIG_B53_SRAB_DRIVER is not set +# CONFIG_SWCONFIG_LEDS is not set +# CONFIG_SW_SYNC is not set +# CONFIG_SX9310 is not set +# CONFIG_SX9500 is not set +# CONFIG_SXGBE_ETH is not set +CONFIG_SYMBOLIC_ERRNAME=y +# CONFIG_SYNCLINK_CS is not set +# CONFIG_SYNC_FILE is not set +# CONFIG_SYNOPSYS_DWC_ETH_QOS is not set +# CONFIG_SYNTH_EVENTS is not set +# CONFIG_SYNTH_EVENT_GEN_TEST is not set +CONFIG_SYN_COOKIES=y +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_SYSCTL=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_SYSFS=y +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_SYSFS_SYSCALL is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# CONFIG_SYSTEM_DATA_VERIFICATION is not set +# CONFIG_SYSTEM_TRUSTED_KEYRING is not set +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSV68_PARTITION is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_SYSV_FS is not set +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_T5403 is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_TASKS_RCU is not set +# CONFIG_TASK_XACCT is not set +# CONFIG_TC35815 is not set +# CONFIG_TCG_ATMEL is not set +# CONFIG_TCG_CRB is not set +# CONFIG_TCG_FTPM_TEE is not set +# CONFIG_TCG_INFINEON is not set +# CONFIG_TCG_NSC is not set +# CONFIG_TCG_ST33_I2C is not set +# CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C_ATMEL is not set +# CONFIG_TCG_TIS_I2C_CR50 is not set +# CONFIG_TCG_TIS_I2C_INFINEON is not set +# CONFIG_TCG_TIS_I2C_NUVOTON is not set +# CONFIG_TCG_TIS_SPI is not set +# CONFIG_TCG_TIS_ST33ZP24_I2C is not set +# CONFIG_TCG_TIS_ST33ZP24_SPI is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TCG_VTPM_PROXY is not set +# CONFIG_TCG_XEN is not set +# CONFIG_TCIC is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BBR is not set +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CDG is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_MD5SIG is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_TEE is not set +# CONFIG_TEGRA_AHB is not set +# CONFIG_TEGRA_HOST1X is not set +# CONFIG_TEHUTI is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +# CONFIG_TEST_BITFIELD is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set +# CONFIG_TEST_DEBUG_VIRTUAL is not set +# CONFIG_TEST_DIV64 is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_HASH is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_KASAN_MODULE is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_LIST_SORT is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_LOCKUP is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_OVERFLOW is not set +# CONFIG_TEST_POWER is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_SCANF is not set +# CONFIG_TEST_SORT is not set +# CONFIG_TEST_STACKINIT is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_STRSCPY is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UBSAN is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_XARRAY is not set +CONFIG_TEXTSEARCH=y +# CONFIG_TEXTSEARCH_BM is not set +# CONFIG_TEXTSEARCH_FSM is not set +# CONFIG_TEXTSEARCH_KMP is not set +# CONFIG_THERMAL is not set +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_HWMON is not set +# CONFIG_THERMAL_MMIO is not set +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +# CONFIG_THINKPAD_ACPI is not set +CONFIG_THIN_ARCHIVES=y +# CONFIG_THRUSTMASTER_FF is not set +# CONFIG_THUMB2_KERNEL is not set +# CONFIG_THUNDERBOLT is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_TICK_CPU_ACCOUNTING is not set +CONFIG_TICK_ONESHOT=y +# CONFIG_TIFM_CORE is not set +# CONFIG_TIGON3 is not set +# CONFIG_TIMB_DMA is not set +CONFIG_TIMERFD=y +# CONFIG_TIMERLAT_TRACER is not set +# CONFIG_TIMER_STATS is not set +# CONFIG_TIME_NS is not set +# CONFIG_TINYDRM_HX8357D is not set +# CONFIG_TINYDRM_ILI9225 is not set +# CONFIG_TINYDRM_ILI9341 is not set +# CONFIG_TINYDRM_ILI9486 is not set +# CONFIG_TINYDRM_MI0283QT is not set +# CONFIG_TINYDRM_REPAPER is not set +# CONFIG_TINYDRM_ST7586 is not set +# CONFIG_TINYDRM_ST7735R is not set +CONFIG_TINY_RCU=y +# CONFIG_TIPC is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS124S08 is not set +# CONFIG_TI_ADS131E08 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8344 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_AM335X_ADC is not set +# CONFIG_TI_CPSW is not set +# CONFIG_TI_CPSW_ALE is not set +# CONFIG_TI_CPSW_PHY_SEL is not set +# CONFIG_TI_CPTS is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_TI_DAC7612 is not set +# CONFIG_TI_DAVINCI_CPDMA is not set +# CONFIG_TI_DAVINCI_MDIO is not set +# CONFIG_TI_ST is not set +# CONFIG_TI_SYSCON_RESET is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_TI_TSC2046 is not set +# CONFIG_TLAN is not set +# CONFIG_TLS is not set +# CONFIG_TLS_DEVICE is not set +# CONFIG_TLS_TOE is not set +# CONFIG_TMD_HERMES is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +# CONFIG_TMP117 is not set +CONFIG_TMPFS=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_TMPFS_POSIX_ACL is not set +CONFIG_TMPFS_XATTR=y +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_TORTURE_TEST is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOUCHSCREEN_88PM860X is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_AD7879_I2C is not set +# CONFIG_TOUCHSCREEN_AD7879_SPI is not set +# CONFIG_TOUCHSCREEN_ADC is not set +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AR1021_I2C is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT_T37 is not set +# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_BU21029 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8318 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +# CONFIG_TOUCHSCREEN_COLIBRI_VF50 is not set +# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_SPI is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP_I2C is not set +# CONFIG_TOUCHSCREEN_CYTTSP_SPI is not set +# CONFIG_TOUCHSCREEN_DA9034 is not set +# CONFIG_TOUCHSCREEN_DA9052 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GOODIX is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_HIDEEP is not set +# CONFIG_TOUCHSCREEN_HP600 is not set +# CONFIG_TOUCHSCREEN_HP7XX is not set +# CONFIG_TOUCHSCREEN_HTCPEN is not set +# CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_ILITEK is not set +# CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set +# CONFIG_TOUCHSCREEN_IPROC is not set +# CONFIG_TOUCHSCREEN_IQS5XX is not set +# CONFIG_TOUCHSCREEN_LPC32XX is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MC13783 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MIGOR is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MSG2638 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_MX25 is not set +# CONFIG_TOUCHSCREEN_MXS_LRADC is not set +# CONFIG_TOUCHSCREEN_PCAP is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_PROPERTIES is not set +# CONFIG_TOUCHSCREEN_RASPBERRYPI_FW is not set +# CONFIG_TOUCHSCREEN_RM_TS is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_RPI_FT5406 is not set +# CONFIG_TOUCHSCREEN_S3C2410 is not set +# CONFIG_TOUCHSCREEN_S6SY761 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_SIS_I2C is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_STMPE is not set +# CONFIG_TOUCHSCREEN_SUN4I is not set +# CONFIG_TOUCHSCREEN_SUR40 is not set +# CONFIG_TOUCHSCREEN_SURFACE3_SPI is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TI_AM335X_TSC is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_TS4800 is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_TSC2007_IIO is not set +# CONFIG_TOUCHSCREEN_TSC200X_CORE is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_UCB1400 is not set +# CONFIG_TOUCHSCREEN_USB_3M is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set +# CONFIG_TOUCHSCREEN_USB_E2I is not set +# CONFIG_TOUCHSCREEN_USB_EASYTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_EGALAX is not set +# CONFIG_TOUCHSCREEN_USB_ELO is not set +# CONFIG_TOUCHSCREEN_USB_ETT_TC45USB is not set +# CONFIG_TOUCHSCREEN_USB_ETURBO is not set +# CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH is not set +# CONFIG_TOUCHSCREEN_USB_GOTOP is not set +# CONFIG_TOUCHSCREEN_USB_GUNZE is not set +# CONFIG_TOUCHSCREEN_USB_IDEALTEK is not set +# CONFIG_TOUCHSCREEN_USB_IRTOUCH is not set +# CONFIG_TOUCHSCREEN_USB_ITM is not set +# CONFIG_TOUCHSCREEN_USB_JASTEC is not set +# CONFIG_TOUCHSCREEN_USB_NEXIO is not set +# CONFIG_TOUCHSCREEN_USB_PANJIT is not set +# CONFIG_TOUCHSCREEN_USB_ZYTRONIC is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_WM831X is not set +# CONFIG_TOUCHSCREEN_WM9705 is not set +# CONFIG_TOUCHSCREEN_WM9712 is not set +# CONFIG_TOUCHSCREEN_WM9713 is not set +# CONFIG_TOUCHSCREEN_WM97XX is not set +# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set +# CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ZFORCE is not set +# CONFIG_TOUCHSCREEN_ZINITIX is not set +# CONFIG_TPL0102 is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_TRACER_SNAPSHOT is not set +# CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP is not set +# CONFIG_TRACE_BRANCH_PROFILING is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_TRACE_EVENT_INJECT is not set +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_TRACE_SINK is not set +# CONFIG_TRACING_EVENTS_GPIO is not set +CONFIG_TRACING_SUPPORT=y +CONFIG_TRAD_SIGNALS=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +# CONFIG_TRUSTED_FOUNDATIONS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2591 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL2x7x is not set +# CONFIG_TSL4531 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +# CONFIG_TTPCI_EEPROM is not set +CONFIG_TTY=y +# CONFIG_TTY_PRINTK is not set +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL4030_MADC is not set +# CONFIG_TWL6030_GPADC is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_TYPEC is not set +# CONFIG_TYPEC_TCPM is not set +# CONFIG_TYPEC_UCSI is not set +# CONFIG_TYPHOON is not set +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_UBIFS_ATIME_SUPPORT is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +# CONFIG_UBIFS_FS_AUTHENTICATION is not set +# CONFIG_UBIFS_FS_ENCRYPTION is not set +CONFIG_UBIFS_FS_LZO=y +# CONFIG_UBIFS_FS_SECURITY is not set +CONFIG_UBIFS_FS_XATTR=y +CONFIG_UBIFS_FS_ZLIB=y +CONFIG_UBIFS_FS_ZSTD=y +# CONFIG_UBSAN is not set +CONFIG_UBSAN_ALIGNMENT=y +CONFIG_UBSAN_BOOL=y +# CONFIG_UBSAN_DIV_ZERO is not set +CONFIG_UBSAN_ENUM=y +# CONFIG_UBSAN_MISC is not set +CONFIG_UBSAN_SHIFT=y +# CONFIG_UBSAN_UNREACHABLE is not set +# CONFIG_UCB1400_CORE is not set +# CONFIG_UCSI is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDMABUF is not set +CONFIG_UEVENT_HELPER=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +# CONFIG_UFS_FS is not set +# CONFIG_UHID is not set +CONFIG_UID16=y +# CONFIG_UIO is not set +# CONFIG_ULTRA is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_UNICODE is not set +# CONFIG_UNISYSSPAR is not set +# CONFIG_UNISYS_VISORBUS is not set +CONFIG_UNIX=y +CONFIG_UNIX98_PTYS=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_UNIX_DIAG is not set +CONFIG_UNIX_SCM=y +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_UNWINDER_FRAME_POINTER is not set +# CONFIG_UPROBES is not set +# CONFIG_UPROBE_EVENTS is not set +# CONFIG_US5182D is not set +# CONFIG_USB is not set +# CONFIG_USB4 is not set +# CONFIG_USBIP_CORE is not set +CONFIG_USBIP_VHCI_HC_PORTS=8 +CONFIG_USBIP_VHCI_NR_HCS=1 +# CONFIG_USBIP_VUDC is not set +# CONFIG_USBPCWATCHDOG is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AIRSPY is not set +CONFIG_USB_ALI_M5632=y +# CONFIG_USB_AMD5536UDC is not set +CONFIG_USB_AN2720=y +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set +# CONFIG_USB_APPLEDISPLAY is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB_ARMLINUX=y +# CONFIG_USB_ATM is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +# CONFIG_USB_BDC_UDC is not set +CONFIG_USB_BELKIN=y +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_CATC is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_CDNS3 is not set +# CONFIG_USB_CDNS_SUPPORT is not set +# CONFIG_USB_CHAOSKEY is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_CHIPIDEA_GENERIC is not set +# CONFIG_USB_CHIPIDEA_IMX is not set +# CONFIG_USB_CHIPIDEA_MSM is not set +# CONFIG_USB_CHIPIDEA_PCI is not set +# CONFIG_USB_CHIPIDEA_TEGRA is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_USB_CONN_GPIO is not set +# CONFIG_USB_CXACRU is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DSBR is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_DUAL_ROLE is not set +# CONFIG_USB_DWC2_HOST is not set +# CONFIG_USB_DWC2_PERIPHERAL is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC3_EXYNOS is not set +# CONFIG_USB_DWC3_HAPS is not set +# CONFIG_USB_DWC3_KEYSTONE is not set +# CONFIG_USB_DWC3_OF_SIMPLE is not set +# CONFIG_USB_DWC3_PCI is not set +# CONFIG_USB_DWC3_QCOM is not set +# CONFIG_USB_DWC3_ULPI is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_EG20T is not set +# CONFIG_USB_EHCI_ATH79 is not set +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_EHCI_HCD_AT91 is not set +# CONFIG_USB_EHCI_HCD_OMAP is not set +# CONFIG_USB_EHCI_HCD_PPC_OF is not set +# CONFIG_USB_EHCI_MSM is not set +# CONFIG_USB_EHCI_MV is not set +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EPSON2888 is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_FSL_USB2 is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FUSB300 is not set +# CONFIG_USB_GADGET is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 +CONFIG_USB_GADGET_VBUS_DRAW=2 +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_GL860 is not set +# CONFIG_USB_GOKU is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_GSPCA_BENQ is not set +# CONFIG_USB_GSPCA_CONEX is not set +# CONFIG_USB_GSPCA_CPIA1 is not set +# CONFIG_USB_GSPCA_DTCS033 is not set +# CONFIG_USB_GSPCA_ETOMS is not set +# CONFIG_USB_GSPCA_FINEPIX is not set +# CONFIG_USB_GSPCA_JEILINJ is not set +# CONFIG_USB_GSPCA_JL2005BCD is not set +# CONFIG_USB_GSPCA_KINECT is not set +# CONFIG_USB_GSPCA_KONICA is not set +# CONFIG_USB_GSPCA_MARS is not set +# CONFIG_USB_GSPCA_MR97310A is not set +# CONFIG_USB_GSPCA_NW80X is not set +# CONFIG_USB_GSPCA_OV519 is not set +# CONFIG_USB_GSPCA_OV534 is not set +# CONFIG_USB_GSPCA_OV534_9 is not set +# CONFIG_USB_GSPCA_PAC207 is not set +# CONFIG_USB_GSPCA_PAC7302 is not set +# CONFIG_USB_GSPCA_PAC7311 is not set +# CONFIG_USB_GSPCA_SE401 is not set +# CONFIG_USB_GSPCA_SN9C2028 is not set +# CONFIG_USB_GSPCA_SN9C20X is not set +# CONFIG_USB_GSPCA_SONIXB is not set +# CONFIG_USB_GSPCA_SONIXJ is not set +# CONFIG_USB_GSPCA_SPCA1528 is not set +# CONFIG_USB_GSPCA_SPCA500 is not set +# CONFIG_USB_GSPCA_SPCA501 is not set +# CONFIG_USB_GSPCA_SPCA505 is not set +# CONFIG_USB_GSPCA_SPCA506 is not set +# CONFIG_USB_GSPCA_SPCA508 is not set +# CONFIG_USB_GSPCA_SPCA561 is not set +# CONFIG_USB_GSPCA_SQ905 is not set +# CONFIG_USB_GSPCA_SQ905C is not set +# CONFIG_USB_GSPCA_SQ930X is not set +# CONFIG_USB_GSPCA_STK014 is not set +# CONFIG_USB_GSPCA_STK1135 is not set +# CONFIG_USB_GSPCA_STV0680 is not set +# CONFIG_USB_GSPCA_SUNPLUS is not set +# CONFIG_USB_GSPCA_T613 is not set +# CONFIG_USB_GSPCA_TOPRO is not set +# CONFIG_USB_GSPCA_TOUPTEK is not set +# CONFIG_USB_GSPCA_TV8532 is not set +# CONFIG_USB_GSPCA_VC032X is not set +# CONFIG_USB_GSPCA_VICAM is not set +# CONFIG_USB_GSPCA_XIRLINK_CIT is not set +# CONFIG_USB_GSPCA_ZC3XX is not set +# CONFIG_USB_G_ACM_MS is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_G_WEBCAM is not set +# CONFIG_USB_HACKRF is not set +# CONFIG_USB_HCD_TEST_MODE is not set +# CONFIG_USB_HID is not set +# CONFIG_USB_HIDDEV is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_IMX21_HCD is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1301 is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_ISP1760 is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_KBD is not set +# CONFIG_USB_KC2190 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LGM_PHY is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_M5602 is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_MAX3420_UDC is not set +# CONFIG_USB_MAX3421_HCD is not set +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_MSI2500 is not set +# CONFIG_USB_MSM_OTG is not set +# CONFIG_USB_MTU3 is not set +# CONFIG_USB_MUSB_GADGET is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_MUSB_HOST is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MXS_PHY is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_NET2280 is not set +# CONFIG_USB_NET_AQC111 is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_DM9601 is not set +# CONFIG_USB_NET_DRIVERS is not set +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_INT51X1 is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_MCS7830 is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +# CONFIG_USB_NET_QMI_WWAN is not set +# CONFIG_USB_NET_RNDIS_HOST is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_USB_NET_SMSC75XX is not set +# CONFIG_USB_NET_SMSC95XX is not set +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_USB_OHCI_HCD is not set +# CONFIG_USB_OHCI_HCD_PCI is not set +# CONFIG_USB_OHCI_HCD_PPC_OF is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_BE is not set +# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set +# CONFIG_USB_OHCI_HCD_SSB is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_PCI is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_PHY is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_PWC_INPUT_EVDEV is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_RAW_GADGET is not set +# CONFIG_USB_RCAR_PHY is not set +# CONFIG_USB_RENESAS_USBHS is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_ROLES_INTEL_XHCI is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_RTL8153_ECM is not set +# CONFIG_USB_S2255 is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +# CONFIG_USB_SERIAL_CH341 is not set +# CONFIG_USB_SERIAL_CP210X is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_DEBUG is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_GARMIN is not set +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IPW is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_IUU is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +CONFIG_USB_SERIAL_KEYSPAN_MPR=y +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +CONFIG_USB_SERIAL_KEYSPAN_USA18X=y +CONFIG_USB_SERIAL_KEYSPAN_USA19=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y +CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y +CONFIG_USB_SERIAL_KEYSPAN_USA19W=y +CONFIG_USB_SERIAL_KEYSPAN_USA28=y +CONFIG_USB_SERIAL_KEYSPAN_USA28X=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y +CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y +CONFIG_USB_SERIAL_KEYSPAN_USA49W=y +CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7715_PARPORT is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SAFE is not set +CONFIG_USB_SERIAL_SAFE_PADDED=y +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_XR is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_SPEEDTOUCH is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STV06XX is not set +# CONFIG_USB_SUPPORT is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_TMC is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_UEAGLEATM is not set +# CONFIG_USB_ULPI is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_VIDEO_CLASS is not set +CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y +# CONFIG_USB_VL600 is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_WHCI_HCD is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XHCI_DBGCAP is not set +# CONFIG_USB_XHCI_HCD is not set +# CONFIG_USB_XHCI_MVEBU is not set +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XUSBATM is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_ZD1201 is not set +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USELIB is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_USERIO is not set +# CONFIG_USE_OF is not set +# CONFIG_UTS_NS is not set +# CONFIG_UWB is not set +# CONFIG_U_SERIAL_CONSOLE is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_V4L_PLATFORM_DRIVERS is not set +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_VALIDATE_FS_PARSER is not set +# CONFIG_VBOXGUEST is not set +# CONFIG_VCNL3020 is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VCNL4035 is not set +# CONFIG_VDPA is not set +CONFIG_VDSO=y +# CONFIG_VEML6030 is not set +# CONFIG_VEML6070 is not set +# CONFIG_VETH is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_VF610_ADC is not set +# CONFIG_VF610_DAC is not set +# CONFIG_VFAT_FS is not set +# CONFIG_VFIO is not set +# CONFIG_VGASTATE is not set +# CONFIG_VGA_ARB is not set +# CONFIG_VGA_CONSOLE is not set +# CONFIG_VGA_SWITCHEROO is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_VSOCK is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +# CONFIG_VIDEO_AD5398 is not set +# CONFIG_VIDEO_AD5820 is not set +# CONFIG_VIDEO_AD9389B is not set +# CONFIG_VIDEO_ADP1653 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_ADV7183 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_ADV7393 is not set +# CONFIG_VIDEO_ADV748X is not set +# CONFIG_VIDEO_ADV7511 is not set +# CONFIG_VIDEO_ADV7604 is not set +# CONFIG_VIDEO_ADV7842 is not set +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_AK7375 is not set +# CONFIG_VIDEO_AK881X is not set +# CONFIG_VIDEO_AM437X_VPFE is not set +# CONFIG_VIDEO_ASPEED is not set +# CONFIG_VIDEO_ATMEL_ISC is not set +# CONFIG_VIDEO_ATMEL_ISI is not set +# CONFIG_VIDEO_AU0828 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT848 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_CAFE_CCIC is not set +# CONFIG_VIDEO_CCS is not set +# CONFIG_VIDEO_CODA is not set +# CONFIG_VIDEO_CS3308 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_CX231XX is not set +# CONFIG_VIDEO_CX2341X is not set +# CONFIG_VIDEO_CX25840 is not set +# CONFIG_VIDEO_CX88 is not set +# CONFIG_VIDEO_DEV is not set +# CONFIG_VIDEO_DM6446_CCDC is not set +# CONFIG_VIDEO_DT3155 is not set +# CONFIG_VIDEO_DW9714 is not set +# CONFIG_VIDEO_DW9768 is not set +# CONFIG_VIDEO_DW9807_VCM is not set +# CONFIG_VIDEO_EM28XX is not set +# CONFIG_VIDEO_ET8EK8 is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +# CONFIG_VIDEO_GO7007 is not set +# CONFIG_VIDEO_GS1662 is not set +# CONFIG_VIDEO_HDPVR is not set +# CONFIG_VIDEO_HEXIUM_GEMINI is not set +# CONFIG_VIDEO_HEXIUM_ORION is not set +# CONFIG_VIDEO_HI556 is not set +# CONFIG_VIDEO_I2C is not set +# CONFIG_VIDEO_IMX_PXP is not set +# CONFIG_VIDEO_IMX208 is not set +# CONFIG_VIDEO_IMX214 is not set +# CONFIG_VIDEO_IMX219 is not set +# CONFIG_VIDEO_IMX258 is not set +# CONFIG_VIDEO_IMX274 is not set +# CONFIG_VIDEO_IMX290 is not set +# CONFIG_VIDEO_IMX319 is not set +# CONFIG_VIDEO_IMX334 is not set +# CONFIG_VIDEO_IMX335 is not set +# CONFIG_VIDEO_IMX355 is not set +# CONFIG_VIDEO_IMX412 is not set +# CONFIG_VIDEO_IMX477 is not set +# CONFIG_VIDEO_IMX8_JPEG is not set +# CONFIG_VIDEO_IRS1125 is not set +# CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_IVTV is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_LM3560 is not set +# CONFIG_VIDEO_LM3646 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_M5MOLS is not set +# CONFIG_VIDEO_MAX9286 is not set +# CONFIG_VIDEO_MEM2MEM_DEINTERLACE is not set +# CONFIG_VIDEO_ML86V7667 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_MT9M001 is not set +# CONFIG_VIDEO_MT9M032 is not set +# CONFIG_VIDEO_MT9M111 is not set +# CONFIG_VIDEO_MT9P031 is not set +# CONFIG_VIDEO_MT9T001 is not set +# CONFIG_VIDEO_MT9T112 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_MT9V032 is not set +# CONFIG_VIDEO_MT9V111 is not set +# CONFIG_VIDEO_MUX is not set +# CONFIG_VIDEO_MXB is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OMAP2_VOUT is not set +# CONFIG_VIDEO_OV02A10 is not set +# CONFIG_VIDEO_OV13858 is not set +# CONFIG_VIDEO_OV2311 is not set +# CONFIG_VIDEO_OV2640 is not set +# CONFIG_VIDEO_OV2659 is not set +# CONFIG_VIDEO_OV2680 is not set +# CONFIG_VIDEO_OV2685 is not set +# CONFIG_VIDEO_OV2740 is not set +# CONFIG_VIDEO_OV5640 is not set +# CONFIG_VIDEO_OV5645 is not set +# CONFIG_VIDEO_OV5647 is not set +# CONFIG_VIDEO_OV5648 is not set +# CONFIG_VIDEO_OV5670 is not set +# CONFIG_VIDEO_OV5675 is not set +# CONFIG_VIDEO_OV5695 is not set +# CONFIG_VIDEO_OV6650 is not set +# CONFIG_VIDEO_OV7251 is not set +# CONFIG_VIDEO_OV7640 is not set +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_OV772X is not set +# CONFIG_VIDEO_OV7740 is not set +# CONFIG_VIDEO_OV8856 is not set +# CONFIG_VIDEO_OV8865 is not set +# CONFIG_VIDEO_OV9281 is not set +# CONFIG_VIDEO_OV9282 is not set +# CONFIG_VIDEO_OV9640 is not set +# CONFIG_VIDEO_OV9650 is not set +# CONFIG_VIDEO_OV9734 is not set +# CONFIG_VIDEO_PVRUSB2 is not set +# CONFIG_VIDEO_RDACM20 is not set +# CONFIG_VIDEO_RDACM21 is not set +# CONFIG_VIDEO_RJ54N1 is not set +# CONFIG_VIDEO_ROCKCHIP_ISP1 is not set +# CONFIG_VIDEO_S5C73M3 is not set +# CONFIG_VIDEO_S5K4ECGX is not set +# CONFIG_VIDEO_S5K5BAF is not set +# CONFIG_VIDEO_S5K6A3 is not set +# CONFIG_VIDEO_S5K6AA is not set +# CONFIG_VIDEO_SAA6588 is not set +# CONFIG_VIDEO_SAA6752HS is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7134 is not set +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_SH_MOBILE_CEU is not set +# CONFIG_VIDEO_SMIAPP is not set +# CONFIG_VIDEO_SONY_BTF_MPX is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_STK1160_COMMON is not set +# CONFIG_VIDEO_ST_MIPID02 is not set +# CONFIG_VIDEO_TC358743 is not set +# CONFIG_VIDEO_TDA1997X is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_THS8200 is not set +# CONFIG_VIDEO_TIMBERDALE is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_TM6000 is not set +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_TW2804 is not set +# CONFIG_VIDEO_TW9903 is not set +# CONFIG_VIDEO_TW9906 is not set +# CONFIG_VIDEO_TW9910 is not set +# CONFIG_VIDEO_UDA1342 is not set +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set +# CONFIG_VIDEO_USBTV is not set +# CONFIG_VIDEO_USBVISION is not set +# CONFIG_VIDEO_V4L2 is not set +# CONFIG_VIDEO_VP27SMPX is not set +# CONFIG_VIDEO_VPX3220 is not set +# CONFIG_VIDEO_VS6624 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_XILINX is not set +# CONFIG_VIDEO_ZORAN is not set +# CONFIG_VIRTIO_BALLOON is not set +# CONFIG_VIRTIO_BLK_SCSI is not set +# CONFIG_VIRTIO_CONSOLE is not set +# CONFIG_VIRTIO_FS is not set +# CONFIG_VIRTIO_INPUT is not set +# CONFIG_VIRTIO_IOMMU is not set +CONFIG_VIRTIO_MENU=y +# CONFIG_VIRTIO_MMIO is not set +# CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set +# CONFIG_VIRTIO_PCI is not set +# CONFIG_VIRTUALIZATION is not set +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRT_TO_BUS=y +# CONFIG_VITESSE_PHY is not set +# CONFIG_VL53L0X_I2C is not set +# CONFIG_VL6180 is not set +CONFIG_VLAN_8021Q=y +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VME_BUS is not set +# CONFIG_VMLINUX_MAP is not set +# CONFIG_VMSPLIT_1G is not set +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_2G_OPT is not set +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_3G_OPT is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMXNET3 is not set +# CONFIG_VM_EVENT_COUNTERS is not set +# CONFIG_VOP_BUS is not set +# CONFIG_VORTEX is not set +# CONFIG_VSOCKETS is not set +# CONFIG_VSOCKETS_DIAG is not set +# CONFIG_VT is not set +# CONFIG_VT6655 is not set +# CONFIG_VT6656 is not set +# CONFIG_VXFS_FS is not set +# CONFIG_VXGE is not set +# CONFIG_VXLAN is not set +# CONFIG_VZ89X is not set +# CONFIG_W1 is not set +# CONFIG_W1_CON is not set +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_DS2482 is not set +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_GPIO is not set +# CONFIG_W1_MASTER_MATROX is not set +# CONFIG_W1_MASTER_SGI is not set +# CONFIG_W1_SLAVE_DS2405 is not set +# CONFIG_W1_SLAVE_DS2406 is not set +# CONFIG_W1_SLAVE_DS2408 is not set +# CONFIG_W1_SLAVE_DS2413 is not set +# CONFIG_W1_SLAVE_DS2423 is not set +# CONFIG_W1_SLAVE_DS2430 is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2438 is not set +# CONFIG_W1_SLAVE_DS250X is not set +# CONFIG_W1_SLAVE_DS2780 is not set +# CONFIG_W1_SLAVE_DS2781 is not set +# CONFIG_W1_SLAVE_DS2805 is not set +# CONFIG_W1_SLAVE_DS28E04 is not set +# CONFIG_W1_SLAVE_DS28E17 is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_WAN is not set +# CONFIG_WANXL is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WATCH_QUEUE is not set +# CONFIG_WD80x3 is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_WDTPCI is not set +CONFIG_WERROR=y +# CONFIG_WEXT_CORE is not set +# CONFIG_WEXT_PRIV is not set +# CONFIG_WEXT_PROC is not set +# CONFIG_WEXT_SPY is not set +CONFIG_WILINK_PLATFORM_DATA=y +# CONFIG_WIMAX is not set +# CONFIG_WIREGUARD is not set +CONFIG_WIRELESS=y +# CONFIG_WIRELESS_EXT is not set +# CONFIG_WIRELESS_WDS is not set +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +CONFIG_WLAN=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_MICROCHIP is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +# CONFIG_WLCORE is not set +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WWAN is not set +# CONFIG_WWAN_HWSIM is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_X25 is not set +# CONFIG_X509_CERTIFICATE_PARSER is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_X86_SYSFB=y +# CONFIG_XDP_SOCKETS is not set +# CONFIG_XEN is not set +# CONFIG_XEN_GRANT_DMA_ALLOC is not set +# CONFIG_XEN_PVCALLS_FRONTEND is not set +CONFIG_XEN_SCRUB_PAGES_DEFAULT=y +CONFIG_XFRM=y +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_IPCOMP is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_USER is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_XFS_FS is not set +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_SUPPORT_V4 is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_XILINX_VCU is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_XILINX_XADC is not set +# CONFIG_XILINX_ZYNQMP_DMA is not set +# CONFIG_XILINX_ZYNQMP_DPDMA is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XILLYUSB is not set +# CONFIG_XIL_AXIS_FIFO is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_XMON is not set +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_BCJ is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_YAM is not set +# CONFIG_YAMAHA_YAS530 is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_YENTA is not set +# CONFIG_YENTA_O2 is not set +# CONFIG_YENTA_RICOH is not set +# CONFIG_YENTA_TI is not set +# CONFIG_YENTA_TOSHIBA is not set +# CONFIG_ZBUD is not set +# CONFIG_ZD1211RW is not set +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_ZEROPLUS_FF is not set +# CONFIG_ZERO_CALL_USED_REGS is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ZISOFS is not set +# CONFIG_ZLIB_DEFLATE is not set +# CONFIG_ZLIB_INFLATE is not set +CONFIG_ZONE_DMA=y +# CONFIG_ZOPT2201 is not set +# CONFIG_ZPA2326 is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZRAM is not set +# CONFIG_ZRAM_DEF_COMP_842 is not set +# CONFIG_ZRAM_DEF_COMP_LZ4 is not set +# CONFIG_ZRAM_DEF_COMP_LZ4HC is not set +# CONFIG_ZRAM_DEF_COMP_LZO is not set +# CONFIG_ZRAM_DEF_COMP_LZORLE is not set +# CONFIG_ZRAM_DEF_COMP_ZSTD is not set +# CONFIG_ZRAM_MEMORY_TRACKING is not set +# CONFIG_ZSMALLOC is not set +# CONFIG_ZX_TDM is not set diff --git a/target/linux/generic/hack-6.1/204-module_strip.patch b/target/linux/generic/hack-6.1/204-module_strip.patch new file mode 100644 index 00000000000..dd5d93e2267 --- /dev/null +++ b/target/linux/generic/hack-6.1/204-module_strip.patch @@ -0,0 +1,212 @@ +From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 16:56:48 +0200 +Subject: build: add a hack for removing non-essential module info + +Signed-off-by: Felix Fietkau +--- + include/linux/module.h | 13 ++++++++----- + include/linux/moduleparam.h | 15 ++++++++++++--- + init/Kconfig | 7 +++++++ + kernel/module.c | 5 ++++- + scripts/mod/modpost.c | 12 ++++++++++++ + 5 files changed, 43 insertions(+), 9 deletions(-) + +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -164,6 +164,7 @@ extern void cleanup_module(void); + + /* Generic info of form tag = "info" */ + #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) ++#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info) + + /* For userspace: you can also call me... */ + #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) +@@ -233,12 +234,12 @@ extern void cleanup_module(void); + * Author(s), use "Name " or just "Name", for multiple + * authors use multiple MODULE_AUTHOR() statements/lines. + */ +-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) ++#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author) + + /* What your module does. */ +-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) ++#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description) + +-#ifdef MODULE ++#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED) + /* Creates an alias so file2alias.c can find device table. */ + #define MODULE_DEVICE_TABLE(type, name) \ + extern typeof(name) __mod_##type##__##name##_device_table \ +@@ -265,7 +266,9 @@ extern typeof(name) __mod_##type##__##na + */ + + #if defined(MODULE) || !defined(CONFIG_SYSFS) +-#define MODULE_VERSION(_version) MODULE_INFO(version, _version) ++#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version) ++#elif defined(CONFIG_MODULE_STRIPPED) ++#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version) + #else + #define MODULE_VERSION(_version) \ + MODULE_INFO(version, _version); \ +@@ -288,7 +291,7 @@ extern typeof(name) __mod_##type##__##na + /* Optional firmware file (or files) needed by the module + * format is simply firmware file name. Multiple firmware + * files require multiple MODULE_FIRMWARE() specifiers */ +-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) ++#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) + + #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) + +--- a/include/linux/moduleparam.h ++++ b/include/linux/moduleparam.h +@@ -20,6 +20,16 @@ + /* Chosen so that structs with an unsigned long line up. */ + #define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) + ++/* This struct is here for syntactic coherency, it is not used */ ++#define __MODULE_INFO_DISABLED(name) \ ++ struct __UNIQUE_ID(name) {} ++ ++#ifdef CONFIG_MODULE_STRIPPED ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name) ++#else ++#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info) ++#endif ++ + #define __MODULE_INFO(tag, name, info) \ + static const char __UNIQUE_ID(name)[] \ + __used __section(".modinfo") __aligned(1) \ +@@ -31,7 +41,7 @@ + /* One for each parameter, describing how to use it. Some files do + multiple of these per line, so can't just use MODULE_INFO. */ + #define MODULE_PARM_DESC(_parm, desc) \ +- __MODULE_INFO(parm, _parm, #_parm ":" desc) ++ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc) + + struct kernel_param; + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -2356,6 +2356,13 @@ config UNUSED_KSYMS_WHITELIST + one per line. The path can be absolute, or relative to the kernel + source tree. + ++config MODULE_STRIPPED ++ bool "Reduce module size" ++ depends on MODULES ++ help ++ Remove module parameter descriptions, author info, version, aliases, ++ device tables, etc. ++ + endif # MODULES + + config MODULES_TREE_LOOKUP +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -1218,6 +1218,7 @@ static struct module_attribute *modinfo_ + + static const char vermagic[] = VERMAGIC_STRING; + ++#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED) + static int try_to_force_load(struct module *mod, const char *reason) + { + #ifdef CONFIG_MODULE_FORCE_LOAD +@@ -1229,6 +1230,7 @@ static int try_to_force_load(struct modu + return -ENOEXEC; + #endif + } ++#endif + + #ifdef CONFIG_MODVERSIONS + +@@ -3266,9 +3268,11 @@ static int setup_load_info(struct load_i + + static int check_modinfo(struct module *mod, struct load_info *info, int flags) + { +- const char *modmagic = get_modinfo(info, "vermagic"); + int err; + ++#ifndef CONFIG_MODULE_STRIPPED ++ const char *modmagic = get_modinfo(info, "vermagic"); ++ + if (flags & MODULE_INIT_IGNORE_VERMAGIC) + modmagic = NULL; + +@@ -3289,6 +3293,7 @@ static int check_modinfo(struct module * + mod->name); + add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK); + } ++#endif + + check_modinfo_retpoline(mod, info); + +--- a/scripts/mod/modpost.c ++++ b/scripts/mod/modpost.c +@@ -2036,7 +2036,9 @@ static void read_symbols(const char *mod + symname = remove_dot(info.strtab + sym->st_name); + + handle_symbol(mod, &info, sym, symname); ++#ifndef CONFIG_MODULE_STRIPPED + handle_moddevtable(mod, &info, sym, symname); ++#endif + } + + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { +@@ -2215,8 +2217,10 @@ static void add_header(struct buffer *b, + buf_printf(b, "BUILD_SALT;\n"); + buf_printf(b, "BUILD_LTO_INFO;\n"); + buf_printf(b, "\n"); ++#ifndef CONFIG_MODULE_STRIPPED + buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); + buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n"); ++#endif + buf_printf(b, "\n"); + buf_printf(b, "__visible struct module __this_module\n"); + buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); +@@ -2233,8 +2237,10 @@ static void add_header(struct buffer *b, + + static void add_intree_flag(struct buffer *b, int is_intree) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (is_intree) + buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); ++#endif + } + + /* Cannot check for assembler */ +@@ -2247,8 +2253,10 @@ static void add_retpoline(struct buffer + + static void add_staging_flag(struct buffer *b, const char *name) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (strstarts(name, "drivers/staging")) + buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); ++#endif + } + + /** +@@ -2328,11 +2336,13 @@ static void add_depends(struct buffer *b + + static void add_srcversion(struct buffer *b, struct module *mod) + { ++#ifndef CONFIG_MODULE_STRIPPED + if (mod->srcversion[0]) { + buf_printf(b, "\n"); + buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", + mod->srcversion); + } ++#endif + } + + static void write_buf(struct buffer *b, const char *fname) +@@ -2581,7 +2591,9 @@ int main(int argc, char **argv) + add_staging_flag(&buf, mod->name); + add_versions(&buf, mod); + add_depends(&buf, mod); ++#ifndef CONFIG_MODULE_STRIPPED + add_moddevtable(&buf, mod); ++#endif + add_srcversion(&buf, mod); + + sprintf(fname, "%s.mod.c", mod->name); diff --git a/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch b/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch new file mode 100644 index 00000000000..a87c7a51169 --- /dev/null +++ b/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch @@ -0,0 +1,41 @@ +From 310e8e04a05d9eb43fa9dd7f00143300afcaa37a Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Fri, 11 Nov 2022 13:33:44 +0100 +Subject: [PATCH] kconfig: abort configuration on unset symbol + +When a target configuration has unset Kconfig symbols, the build will +fail when OpenWrt is compiled with V=s and stdin is connected to a tty. + +In case OpenWrt is compiled without either of these preconditions, the +build will succeed with the symbols in question being unset. + +Modify the kernel configuration in a way it fails on unset symbols +regardless of the aforementioned preconditions. + +Signed-off-by: David Bauer +--- + scripts/kconfig/conf.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/scripts/kconfig/conf.c ++++ b/scripts/kconfig/conf.c +@@ -341,6 +341,9 @@ static int conf_askvalue(struct symbol * + } + /* fall through */ + default: ++ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { ++ exit(1); ++ } + fflush(stdout); + xfgets(line, sizeof(line), stdin); + break; +@@ -523,6 +526,9 @@ static int conf_choice(struct menu *menu + } + /* fall through */ + case oldaskconfig: ++ if (!tty_stdio && getenv("FAIL_ON_UNCONFIGURED")) { ++ exit(1); ++ } + fflush(stdout); + xfgets(line, sizeof(line), stdin); + strip(line); diff --git a/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch b/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch new file mode 100644 index 00000000000..be6adc0d11a --- /dev/null +++ b/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch @@ -0,0 +1,3053 @@ +From db7c30dcd9a0391bf13b62c9f91e144d762ef43a Mon Sep 17 00:00:00 2001 +From: Florian Fainelli +Date: Fri, 7 Jul 2017 17:00:49 +0200 +Subject: Add an OSX specific patch to make the kernel be compiled + +lede-commit: 3fc2a24f0422b2f55f9ed43f116db3111f700526 +Signed-off-by: Florian Fainelli +--- + scripts/kconfig/Makefile | 3 + + scripts/mod/elf.h | 3007 ++++++++++++++++++++++++++++++++++++++++++++ + scripts/mod/mk_elfconfig.c | 4 + + scripts/mod/modpost.h | 4 + + 4 files changed, 3018 insertions(+) + create mode 100644 scripts/mod/elf.h + +--- /dev/null ++++ b/scripts/mod/elf.h +@@ -0,0 +1,3007 @@ ++/* This file defines standard ELF types, structures, and macros. ++ Copyright (C) 1995-2012 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#ifndef _ELF_H ++#define _ELF_H 1 ++ ++/* Standard ELF types. */ ++ ++#include ++ ++/* Type for a 16-bit quantity. */ ++typedef uint16_t Elf32_Half; ++typedef uint16_t Elf64_Half; ++ ++/* Types for signed and unsigned 32-bit quantities. */ ++typedef uint32_t Elf32_Word; ++typedef int32_t Elf32_Sword; ++typedef uint32_t Elf64_Word; ++typedef int32_t Elf64_Sword; ++ ++/* Types for signed and unsigned 64-bit quantities. */ ++typedef uint64_t Elf32_Xword; ++typedef int64_t Elf32_Sxword; ++typedef uint64_t Elf64_Xword; ++typedef int64_t Elf64_Sxword; ++ ++/* Type of addresses. */ ++typedef uint32_t Elf32_Addr; ++typedef uint64_t Elf64_Addr; ++ ++/* Type of file offsets. */ ++typedef uint32_t Elf32_Off; ++typedef uint64_t Elf64_Off; ++ ++/* Type for section indices, which are 16-bit quantities. */ ++typedef uint16_t Elf32_Section; ++typedef uint16_t Elf64_Section; ++ ++/* Type for version symbol information. */ ++typedef Elf32_Half Elf32_Versym; ++typedef Elf64_Half Elf64_Versym; ++ ++ ++/* The ELF file header. This appears at the start of every ELF file. */ ++ ++#define EI_NIDENT (16) ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf32_Half e_type; /* Object file type */ ++ Elf32_Half e_machine; /* Architecture */ ++ Elf32_Word e_version; /* Object file version */ ++ Elf32_Addr e_entry; /* Entry point virtual address */ ++ Elf32_Off e_phoff; /* Program header table file offset */ ++ Elf32_Off e_shoff; /* Section header table file offset */ ++ Elf32_Word e_flags; /* Processor-specific flags */ ++ Elf32_Half e_ehsize; /* ELF header size in bytes */ ++ Elf32_Half e_phentsize; /* Program header table entry size */ ++ Elf32_Half e_phnum; /* Program header table entry count */ ++ Elf32_Half e_shentsize; /* Section header table entry size */ ++ Elf32_Half e_shnum; /* Section header table entry count */ ++ Elf32_Half e_shstrndx; /* Section header string table index */ ++} Elf32_Ehdr; ++ ++typedef struct ++{ ++ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ ++ Elf64_Half e_type; /* Object file type */ ++ Elf64_Half e_machine; /* Architecture */ ++ Elf64_Word e_version; /* Object file version */ ++ Elf64_Addr e_entry; /* Entry point virtual address */ ++ Elf64_Off e_phoff; /* Program header table file offset */ ++ Elf64_Off e_shoff; /* Section header table file offset */ ++ Elf64_Word e_flags; /* Processor-specific flags */ ++ Elf64_Half e_ehsize; /* ELF header size in bytes */ ++ Elf64_Half e_phentsize; /* Program header table entry size */ ++ Elf64_Half e_phnum; /* Program header table entry count */ ++ Elf64_Half e_shentsize; /* Section header table entry size */ ++ Elf64_Half e_shnum; /* Section header table entry count */ ++ Elf64_Half e_shstrndx; /* Section header string table index */ ++} Elf64_Ehdr; ++ ++/* Fields in the e_ident array. The EI_* macros are indices into the ++ array. The macros under each EI_* macro are the values the byte ++ may have. */ ++ ++#define EI_MAG0 0 /* File identification byte 0 index */ ++#define ELFMAG0 0x7f /* Magic number byte 0 */ ++ ++#define EI_MAG1 1 /* File identification byte 1 index */ ++#define ELFMAG1 'E' /* Magic number byte 1 */ ++ ++#define EI_MAG2 2 /* File identification byte 2 index */ ++#define ELFMAG2 'L' /* Magic number byte 2 */ ++ ++#define EI_MAG3 3 /* File identification byte 3 index */ ++#define ELFMAG3 'F' /* Magic number byte 3 */ ++ ++/* Conglomeration of the identification bytes, for easy testing as a word. */ ++#define ELFMAG "\177ELF" ++#define SELFMAG 4 ++ ++#define EI_CLASS 4 /* File class byte index */ ++#define ELFCLASSNONE 0 /* Invalid class */ ++#define ELFCLASS32 1 /* 32-bit objects */ ++#define ELFCLASS64 2 /* 64-bit objects */ ++#define ELFCLASSNUM 3 ++ ++#define EI_DATA 5 /* Data encoding byte index */ ++#define ELFDATANONE 0 /* Invalid data encoding */ ++#define ELFDATA2LSB 1 /* 2's complement, little endian */ ++#define ELFDATA2MSB 2 /* 2's complement, big endian */ ++#define ELFDATANUM 3 ++ ++#define EI_VERSION 6 /* File version byte index */ ++ /* Value must be EV_CURRENT */ ++ ++#define EI_OSABI 7 /* OS ABI identification */ ++#define ELFOSABI_NONE 0 /* UNIX System V ABI */ ++#define ELFOSABI_SYSV 0 /* Alias. */ ++#define ELFOSABI_HPUX 1 /* HP-UX */ ++#define ELFOSABI_NETBSD 2 /* NetBSD. */ ++#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ ++#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ ++#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ ++#define ELFOSABI_AIX 7 /* IBM AIX. */ ++#define ELFOSABI_IRIX 8 /* SGI Irix. */ ++#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ ++#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ ++#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ ++#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ ++#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ ++#define ELFOSABI_ARM 97 /* ARM */ ++#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ ++ ++#define EI_ABIVERSION 8 /* ABI version */ ++ ++#define EI_PAD 9 /* Byte index of padding bytes */ ++ ++/* Legal values for e_type (object file type). */ ++ ++#define ET_NONE 0 /* No file type */ ++#define ET_REL 1 /* Relocatable file */ ++#define ET_EXEC 2 /* Executable file */ ++#define ET_DYN 3 /* Shared object file */ ++#define ET_CORE 4 /* Core file */ ++#define ET_NUM 5 /* Number of defined types */ ++#define ET_LOOS 0xfe00 /* OS-specific range start */ ++#define ET_HIOS 0xfeff /* OS-specific range end */ ++#define ET_LOPROC 0xff00 /* Processor-specific range start */ ++#define ET_HIPROC 0xffff /* Processor-specific range end */ ++ ++/* Legal values for e_machine (architecture). */ ++ ++#define EM_NONE 0 /* No machine */ ++#define EM_M32 1 /* AT&T WE 32100 */ ++#define EM_SPARC 2 /* SUN SPARC */ ++#define EM_386 3 /* Intel 80386 */ ++#define EM_68K 4 /* Motorola m68k family */ ++#define EM_88K 5 /* Motorola m88k family */ ++#define EM_860 7 /* Intel 80860 */ ++#define EM_MIPS 8 /* MIPS R3000 big-endian */ ++#define EM_S370 9 /* IBM System/370 */ ++#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ ++ ++#define EM_PARISC 15 /* HPPA */ ++#define EM_VPP500 17 /* Fujitsu VPP500 */ ++#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ ++#define EM_960 19 /* Intel 80960 */ ++#define EM_PPC 20 /* PowerPC */ ++#define EM_PPC64 21 /* PowerPC 64-bit */ ++#define EM_S390 22 /* IBM S390 */ ++ ++#define EM_V800 36 /* NEC V800 series */ ++#define EM_FR20 37 /* Fujitsu FR20 */ ++#define EM_RH32 38 /* TRW RH-32 */ ++#define EM_RCE 39 /* Motorola RCE */ ++#define EM_ARM 40 /* ARM */ ++#define EM_FAKE_ALPHA 41 /* Digital Alpha */ ++#define EM_SH 42 /* Hitachi SH */ ++#define EM_SPARCV9 43 /* SPARC v9 64-bit */ ++#define EM_TRICORE 44 /* Siemens Tricore */ ++#define EM_ARC 45 /* Argonaut RISC Core */ ++#define EM_H8_300 46 /* Hitachi H8/300 */ ++#define EM_H8_300H 47 /* Hitachi H8/300H */ ++#define EM_H8S 48 /* Hitachi H8S */ ++#define EM_H8_500 49 /* Hitachi H8/500 */ ++#define EM_IA_64 50 /* Intel Merced */ ++#define EM_MIPS_X 51 /* Stanford MIPS-X */ ++#define EM_COLDFIRE 52 /* Motorola Coldfire */ ++#define EM_68HC12 53 /* Motorola M68HC12 */ ++#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ ++#define EM_PCP 55 /* Siemens PCP */ ++#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ ++#define EM_NDR1 57 /* Denso NDR1 microprocessor */ ++#define EM_STARCORE 58 /* Motorola Start*Core processor */ ++#define EM_ME16 59 /* Toyota ME16 processor */ ++#define EM_ST100 60 /* STMicroelectronic ST100 processor */ ++#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ ++#define EM_X86_64 62 /* AMD x86-64 architecture */ ++#define EM_PDSP 63 /* Sony DSP Processor */ ++ ++#define EM_FX66 66 /* Siemens FX66 microcontroller */ ++#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ ++#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ ++#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ ++#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ ++#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ ++#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ ++#define EM_SVX 73 /* Silicon Graphics SVx */ ++#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ ++#define EM_VAX 75 /* Digital VAX */ ++#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ ++#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ ++#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ ++#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ ++#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ ++#define EM_HUANY 81 /* Harvard University machine-independent object files */ ++#define EM_PRISM 82 /* SiTera Prism */ ++#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ ++#define EM_FR30 84 /* Fujitsu FR30 */ ++#define EM_D10V 85 /* Mitsubishi D10V */ ++#define EM_D30V 86 /* Mitsubishi D30V */ ++#define EM_V850 87 /* NEC v850 */ ++#define EM_M32R 88 /* Mitsubishi M32R */ ++#define EM_MN10300 89 /* Matsushita MN10300 */ ++#define EM_MN10200 90 /* Matsushita MN10200 */ ++#define EM_PJ 91 /* picoJava */ ++#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ ++#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ ++#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ ++#define EM_TILEPRO 188 /* Tilera TILEPro */ ++#define EM_TILEGX 191 /* Tilera TILE-Gx */ ++#define EM_NUM 192 ++ ++/* If it is necessary to assign new unofficial EM_* values, please ++ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the ++ chances of collision with official or non-GNU unofficial values. */ ++ ++#define EM_ALPHA 0x9026 ++ ++/* Legal values for e_version (version). */ ++ ++#define EV_NONE 0 /* Invalid ELF version */ ++#define EV_CURRENT 1 /* Current version */ ++#define EV_NUM 2 ++ ++/* Section header. */ ++ ++typedef struct ++{ ++ Elf32_Word sh_name; /* Section name (string tbl index) */ ++ Elf32_Word sh_type; /* Section type */ ++ Elf32_Word sh_flags; /* Section flags */ ++ Elf32_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf32_Off sh_offset; /* Section file offset */ ++ Elf32_Word sh_size; /* Section size in bytes */ ++ Elf32_Word sh_link; /* Link to another section */ ++ Elf32_Word sh_info; /* Additional section information */ ++ Elf32_Word sh_addralign; /* Section alignment */ ++ Elf32_Word sh_entsize; /* Entry size if section holds table */ ++} Elf32_Shdr; ++ ++typedef struct ++{ ++ Elf64_Word sh_name; /* Section name (string tbl index) */ ++ Elf64_Word sh_type; /* Section type */ ++ Elf64_Xword sh_flags; /* Section flags */ ++ Elf64_Addr sh_addr; /* Section virtual addr at execution */ ++ Elf64_Off sh_offset; /* Section file offset */ ++ Elf64_Xword sh_size; /* Section size in bytes */ ++ Elf64_Word sh_link; /* Link to another section */ ++ Elf64_Word sh_info; /* Additional section information */ ++ Elf64_Xword sh_addralign; /* Section alignment */ ++ Elf64_Xword sh_entsize; /* Entry size if section holds table */ ++} Elf64_Shdr; ++ ++/* Special section indices. */ ++ ++#define SHN_UNDEF 0 /* Undefined section */ ++#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ ++#define SHN_LOPROC 0xff00 /* Start of processor-specific */ ++#define SHN_BEFORE 0xff00 /* Order section before all others ++ (Solaris). */ ++#define SHN_AFTER 0xff01 /* Order section after all others ++ (Solaris). */ ++#define SHN_HIPROC 0xff1f /* End of processor-specific */ ++#define SHN_LOOS 0xff20 /* Start of OS-specific */ ++#define SHN_HIOS 0xff3f /* End of OS-specific */ ++#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ ++#define SHN_COMMON 0xfff2 /* Associated symbol is common */ ++#define SHN_XINDEX 0xffff /* Index is in extra table. */ ++#define SHN_HIRESERVE 0xffff /* End of reserved indices */ ++ ++/* Legal values for sh_type (section type). */ ++ ++#define SHT_NULL 0 /* Section header table entry unused */ ++#define SHT_PROGBITS 1 /* Program data */ ++#define SHT_SYMTAB 2 /* Symbol table */ ++#define SHT_STRTAB 3 /* String table */ ++#define SHT_RELA 4 /* Relocation entries with addends */ ++#define SHT_HASH 5 /* Symbol hash table */ ++#define SHT_DYNAMIC 6 /* Dynamic linking information */ ++#define SHT_NOTE 7 /* Notes */ ++#define SHT_NOBITS 8 /* Program space with no data (bss) */ ++#define SHT_REL 9 /* Relocation entries, no addends */ ++#define SHT_SHLIB 10 /* Reserved */ ++#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ ++#define SHT_INIT_ARRAY 14 /* Array of constructors */ ++#define SHT_FINI_ARRAY 15 /* Array of destructors */ ++#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ ++#define SHT_GROUP 17 /* Section group */ ++#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ ++#define SHT_NUM 19 /* Number of defined types. */ ++#define SHT_LOOS 0x60000000 /* Start OS-specific. */ ++#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ ++#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ ++#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ ++#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ ++#define SHT_SUNW_move 0x6ffffffa ++#define SHT_SUNW_COMDAT 0x6ffffffb ++#define SHT_SUNW_syminfo 0x6ffffffc ++#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ ++#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ ++#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ ++#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ ++#define SHT_HIOS 0x6fffffff /* End OS-specific type */ ++#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define SHT_LOUSER 0x80000000 /* Start of application-specific */ ++#define SHT_HIUSER 0x8fffffff /* End of application-specific */ ++ ++/* Legal values for sh_flags (section flags). */ ++ ++#define SHF_WRITE (1 << 0) /* Writable */ ++#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ ++#define SHF_EXECINSTR (1 << 2) /* Executable */ ++#define SHF_MERGE (1 << 4) /* Might be merged */ ++#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ ++#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ ++#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ ++#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling ++ required */ ++#define SHF_GROUP (1 << 9) /* Section is member of a group. */ ++#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ ++#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ ++#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ ++#define SHF_ORDERED (1 << 30) /* Special ordering requirement ++ (Solaris). */ ++#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless ++ referenced or allocated (Solaris).*/ ++ ++/* Section group handling. */ ++#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ ++ ++/* Symbol table entry. */ ++ ++typedef struct ++{ ++ Elf32_Word st_name; /* Symbol name (string tbl index) */ ++ Elf32_Addr st_value; /* Symbol value */ ++ Elf32_Word st_size; /* Symbol size */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf32_Section st_shndx; /* Section index */ ++} Elf32_Sym; ++ ++typedef struct ++{ ++ Elf64_Word st_name; /* Symbol name (string tbl index) */ ++ unsigned char st_info; /* Symbol type and binding */ ++ unsigned char st_other; /* Symbol visibility */ ++ Elf64_Section st_shndx; /* Section index */ ++ Elf64_Addr st_value; /* Symbol value */ ++ Elf64_Xword st_size; /* Symbol size */ ++} Elf64_Sym; ++ ++/* The syminfo section if available contains additional information about ++ every dynamic symbol. */ ++ ++typedef struct ++{ ++ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf32_Half si_flags; /* Per symbol flags */ ++} Elf32_Syminfo; ++ ++typedef struct ++{ ++ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ ++ Elf64_Half si_flags; /* Per symbol flags */ ++} Elf64_Syminfo; ++ ++/* Possible values for si_boundto. */ ++#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ ++#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ ++#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ ++ ++/* Possible bitmasks for si_flags. */ ++#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ ++#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ ++#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ ++#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy ++ loaded */ ++/* Syminfo version values. */ ++#define SYMINFO_NONE 0 ++#define SYMINFO_CURRENT 1 ++#define SYMINFO_NUM 2 ++ ++ ++/* How to extract and insert information held in the st_info field. */ ++ ++#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) ++#define ELF32_ST_TYPE(val) ((val) & 0xf) ++#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) ++ ++/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ ++#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) ++#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) ++#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) ++ ++/* Legal values for ST_BIND subfield of st_info (symbol binding). */ ++ ++#define STB_LOCAL 0 /* Local symbol */ ++#define STB_GLOBAL 1 /* Global symbol */ ++#define STB_WEAK 2 /* Weak symbol */ ++#define STB_NUM 3 /* Number of defined types. */ ++#define STB_LOOS 10 /* Start of OS-specific */ ++#define STB_GNU_UNIQUE 10 /* Unique symbol. */ ++#define STB_HIOS 12 /* End of OS-specific */ ++#define STB_LOPROC 13 /* Start of processor-specific */ ++#define STB_HIPROC 15 /* End of processor-specific */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_NOTYPE 0 /* Symbol type is unspecified */ ++#define STT_OBJECT 1 /* Symbol is a data object */ ++#define STT_FUNC 2 /* Symbol is a code object */ ++#define STT_SECTION 3 /* Symbol associated with a section */ ++#define STT_FILE 4 /* Symbol's name is file name */ ++#define STT_COMMON 5 /* Symbol is a common data object */ ++#define STT_TLS 6 /* Symbol is thread-local data object*/ ++#define STT_NUM 7 /* Number of defined types. */ ++#define STT_LOOS 10 /* Start of OS-specific */ ++#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ ++#define STT_HIOS 12 /* End of OS-specific */ ++#define STT_LOPROC 13 /* Start of processor-specific */ ++#define STT_HIPROC 15 /* End of processor-specific */ ++ ++ ++/* Symbol table indices are found in the hash buckets and chain table ++ of a symbol hash table section. This special index value indicates ++ the end of a chain, meaning no further symbols are found in that bucket. */ ++ ++#define STN_UNDEF 0 /* End of a chain. */ ++ ++ ++/* How to extract and insert information held in the st_other field. */ ++ ++#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) ++ ++/* For ELF64 the definitions are the same. */ ++#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) ++ ++/* Symbol visibility specification encoded in the st_other field. */ ++#define STV_DEFAULT 0 /* Default symbol visibility rules */ ++#define STV_INTERNAL 1 /* Processor specific hidden class */ ++#define STV_HIDDEN 2 /* Sym unavailable in other modules */ ++#define STV_PROTECTED 3 /* Not preemptible, not exported */ ++ ++ ++/* Relocation table entry without addend (in section of type SHT_REL). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++} Elf32_Rel; ++ ++/* I have seen two different definitions of the Elf64_Rel and ++ Elf64_Rela structures, so we'll leave them out until Novell (or ++ whoever) gets their act together. */ ++/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++} Elf64_Rel; ++ ++/* Relocation table entry with addend (in section of type SHT_RELA). */ ++ ++typedef struct ++{ ++ Elf32_Addr r_offset; /* Address */ ++ Elf32_Word r_info; /* Relocation type and symbol index */ ++ Elf32_Sword r_addend; /* Addend */ ++} Elf32_Rela; ++ ++typedef struct ++{ ++ Elf64_Addr r_offset; /* Address */ ++ Elf64_Xword r_info; /* Relocation type and symbol index */ ++ Elf64_Sxword r_addend; /* Addend */ ++} Elf64_Rela; ++ ++/* How to extract and insert information held in the r_info field. */ ++ ++#define ELF32_R_SYM(val) ((val) >> 8) ++#define ELF32_R_TYPE(val) ((val) & 0xff) ++#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) ++ ++#define ELF64_R_SYM(i) ((i) >> 32) ++#define ELF64_R_TYPE(i) ((i) & 0xffffffff) ++#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) ++ ++/* Program segment header. */ ++ ++typedef struct ++{ ++ Elf32_Word p_type; /* Segment type */ ++ Elf32_Off p_offset; /* Segment file offset */ ++ Elf32_Addr p_vaddr; /* Segment virtual address */ ++ Elf32_Addr p_paddr; /* Segment physical address */ ++ Elf32_Word p_filesz; /* Segment size in file */ ++ Elf32_Word p_memsz; /* Segment size in memory */ ++ Elf32_Word p_flags; /* Segment flags */ ++ Elf32_Word p_align; /* Segment alignment */ ++} Elf32_Phdr; ++ ++typedef struct ++{ ++ Elf64_Word p_type; /* Segment type */ ++ Elf64_Word p_flags; /* Segment flags */ ++ Elf64_Off p_offset; /* Segment file offset */ ++ Elf64_Addr p_vaddr; /* Segment virtual address */ ++ Elf64_Addr p_paddr; /* Segment physical address */ ++ Elf64_Xword p_filesz; /* Segment size in file */ ++ Elf64_Xword p_memsz; /* Segment size in memory */ ++ Elf64_Xword p_align; /* Segment alignment */ ++} Elf64_Phdr; ++ ++/* Special value for e_phnum. This indicates that the real number of ++ program headers is too large to fit into e_phnum. Instead the real ++ value is in the field sh_info of section 0. */ ++ ++#define PN_XNUM 0xffff ++ ++/* Legal values for p_type (segment type). */ ++ ++#define PT_NULL 0 /* Program header table entry unused */ ++#define PT_LOAD 1 /* Loadable program segment */ ++#define PT_DYNAMIC 2 /* Dynamic linking information */ ++#define PT_INTERP 3 /* Program interpreter */ ++#define PT_NOTE 4 /* Auxiliary information */ ++#define PT_SHLIB 5 /* Reserved */ ++#define PT_PHDR 6 /* Entry for header table itself */ ++#define PT_TLS 7 /* Thread-local storage segment */ ++#define PT_NUM 8 /* Number of defined types */ ++#define PT_LOOS 0x60000000 /* Start of OS-specific */ ++#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ ++#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ ++#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ ++#define PT_LOSUNW 0x6ffffffa ++#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ ++#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ ++#define PT_HISUNW 0x6fffffff ++#define PT_HIOS 0x6fffffff /* End of OS-specific */ ++#define PT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define PT_HIPROC 0x7fffffff /* End of processor-specific */ ++ ++/* Legal values for p_flags (segment flags). */ ++ ++#define PF_X (1 << 0) /* Segment is executable */ ++#define PF_W (1 << 1) /* Segment is writable */ ++#define PF_R (1 << 2) /* Segment is readable */ ++#define PF_MASKOS 0x0ff00000 /* OS-specific */ ++#define PF_MASKPROC 0xf0000000 /* Processor-specific */ ++ ++/* Legal values for note segment descriptor types for core files. */ ++ ++#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ ++#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ ++#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ ++#define NT_PRXREG 4 /* Contains copy of prxregset struct */ ++#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ ++#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ ++#define NT_AUXV 6 /* Contains copy of auxv array */ ++#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ ++#define NT_ASRS 8 /* Contains copy of asrset struct */ ++#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ ++#define NT_PSINFO 13 /* Contains copy of psinfo struct */ ++#define NT_PRCRED 14 /* Contains copy of prcred struct */ ++#define NT_UTSNAME 15 /* Contains copy of utsname struct */ ++#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ ++#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ ++#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ ++#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ ++#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ ++#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ ++#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ ++#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ ++#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ ++#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ ++ ++/* Legal values for the note segment descriptor types for object files. */ ++ ++#define NT_VERSION 1 /* Contains a version string. */ ++ ++ ++/* Dynamic section entry. */ ++ ++typedef struct ++{ ++ Elf32_Sword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf32_Word d_val; /* Integer value */ ++ Elf32_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf32_Dyn; ++ ++typedef struct ++{ ++ Elf64_Sxword d_tag; /* Dynamic entry type */ ++ union ++ { ++ Elf64_Xword d_val; /* Integer value */ ++ Elf64_Addr d_ptr; /* Address value */ ++ } d_un; ++} Elf64_Dyn; ++ ++/* Legal values for d_tag (dynamic entry type). */ ++ ++#define DT_NULL 0 /* Marks end of dynamic section */ ++#define DT_NEEDED 1 /* Name of needed library */ ++#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ ++#define DT_PLTGOT 3 /* Processor defined value */ ++#define DT_HASH 4 /* Address of symbol hash table */ ++#define DT_STRTAB 5 /* Address of string table */ ++#define DT_SYMTAB 6 /* Address of symbol table */ ++#define DT_RELA 7 /* Address of Rela relocs */ ++#define DT_RELASZ 8 /* Total size of Rela relocs */ ++#define DT_RELAENT 9 /* Size of one Rela reloc */ ++#define DT_STRSZ 10 /* Size of string table */ ++#define DT_SYMENT 11 /* Size of one symbol table entry */ ++#define DT_INIT 12 /* Address of init function */ ++#define DT_FINI 13 /* Address of termination function */ ++#define DT_SONAME 14 /* Name of shared object */ ++#define DT_RPATH 15 /* Library search path (deprecated) */ ++#define DT_SYMBOLIC 16 /* Start symbol search here */ ++#define DT_REL 17 /* Address of Rel relocs */ ++#define DT_RELSZ 18 /* Total size of Rel relocs */ ++#define DT_RELENT 19 /* Size of one Rel reloc */ ++#define DT_PLTREL 20 /* Type of reloc in PLT */ ++#define DT_DEBUG 21 /* For debugging; unspecified */ ++#define DT_TEXTREL 22 /* Reloc might modify .text */ ++#define DT_JMPREL 23 /* Address of PLT relocs */ ++#define DT_BIND_NOW 24 /* Process relocations of object */ ++#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ ++#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ ++#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ ++#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ ++#define DT_RUNPATH 29 /* Library search path */ ++#define DT_FLAGS 30 /* Flags for the object being loaded */ ++#define DT_ENCODING 32 /* Start of encoded range */ ++#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ ++#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ ++#define DT_NUM 34 /* Number used */ ++#define DT_LOOS 0x6000000d /* Start of OS-specific */ ++#define DT_HIOS 0x6ffff000 /* End of OS-specific */ ++#define DT_LOPROC 0x70000000 /* Start of processor-specific */ ++#define DT_HIPROC 0x7fffffff /* End of processor-specific */ ++#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ ++ ++/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the ++ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's ++ approach. */ ++#define DT_VALRNGLO 0x6ffffd00 ++#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ ++#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ ++#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ ++#define DT_CHECKSUM 0x6ffffdf8 ++#define DT_PLTPADSZ 0x6ffffdf9 ++#define DT_MOVEENT 0x6ffffdfa ++#define DT_MOVESZ 0x6ffffdfb ++#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ ++#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting ++ the following DT_* entry. */ ++#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ ++#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ ++#define DT_VALRNGHI 0x6ffffdff ++#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ ++#define DT_VALNUM 12 ++ ++/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the ++ Dyn.d_un.d_ptr field of the Elf*_Dyn structure. ++ ++ If any adjustment is made to the ELF object after it has been ++ built these entries will need to be adjusted. */ ++#define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ ++#define DT_TLSDESC_PLT 0x6ffffef6 ++#define DT_TLSDESC_GOT 0x6ffffef7 ++#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ ++#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ ++#define DT_CONFIG 0x6ffffefa /* Configuration information. */ ++#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ ++#define DT_AUDIT 0x6ffffefc /* Object auditing. */ ++#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ ++#define DT_MOVETAB 0x6ffffefe /* Move table. */ ++#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ ++#define DT_ADDRRNGHI 0x6ffffeff ++#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ ++#define DT_ADDRNUM 11 ++ ++/* The versioning entry types. The next are defined as part of the ++ GNU extension. */ ++#define DT_VERSYM 0x6ffffff0 ++ ++#define DT_RELACOUNT 0x6ffffff9 ++#define DT_RELCOUNT 0x6ffffffa ++ ++/* These were chosen by Sun. */ ++#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ ++#define DT_VERDEF 0x6ffffffc /* Address of version definition ++ table */ ++#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ ++#define DT_VERNEED 0x6ffffffe /* Address of table with needed ++ versions */ ++#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ ++#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ ++#define DT_VERSIONTAGNUM 16 ++ ++/* Sun added these machine-independent extensions in the "processor-specific" ++ range. Be compatible. */ ++#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ ++#define DT_FILTER 0x7fffffff /* Shared object to get values from */ ++#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) ++#define DT_EXTRANUM 3 ++ ++/* Values of `d_un.d_val' in the DT_FLAGS entry. */ ++#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ ++#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ ++#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ ++#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ ++#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ ++ ++/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 ++ entry in the dynamic section. */ ++#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ ++#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ ++#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ ++#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ ++#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ ++#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ ++#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ ++#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ ++#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ ++#define DF_1_TRANS 0x00000200 ++#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ ++#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ ++#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ ++#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ ++#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ ++#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ ++#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ ++ ++/* Flags for the feature selection in DT_FEATURE_1. */ ++#define DTF_1_PARINIT 0x00000001 ++#define DTF_1_CONFEXP 0x00000002 ++ ++/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ ++#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ ++#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not ++ generally available. */ ++ ++/* Version definition sections. */ ++ ++typedef struct ++{ ++ Elf32_Half vd_version; /* Version revision */ ++ Elf32_Half vd_flags; /* Version information */ ++ Elf32_Half vd_ndx; /* Version Index */ ++ Elf32_Half vd_cnt; /* Number of associated aux entries */ ++ Elf32_Word vd_hash; /* Version name hash value */ ++ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf32_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf32_Verdef; ++ ++typedef struct ++{ ++ Elf64_Half vd_version; /* Version revision */ ++ Elf64_Half vd_flags; /* Version information */ ++ Elf64_Half vd_ndx; /* Version Index */ ++ Elf64_Half vd_cnt; /* Number of associated aux entries */ ++ Elf64_Word vd_hash; /* Version name hash value */ ++ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ ++ Elf64_Word vd_next; /* Offset in bytes to next verdef ++ entry */ ++} Elf64_Verdef; ++ ++ ++/* Legal values for vd_version (version revision). */ ++#define VER_DEF_NONE 0 /* No version */ ++#define VER_DEF_CURRENT 1 /* Current version */ ++#define VER_DEF_NUM 2 /* Given version number */ ++ ++/* Legal values for vd_flags (version information flags). */ ++#define VER_FLG_BASE 0x1 /* Version definition of file itself */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++/* Versym symbol index values. */ ++#define VER_NDX_LOCAL 0 /* Symbol is local. */ ++#define VER_NDX_GLOBAL 1 /* Symbol is global. */ ++#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ ++#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ ++ ++/* Auxialiary version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vda_name; /* Version or dependency names */ ++ Elf32_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf32_Verdaux; ++ ++typedef struct ++{ ++ Elf64_Word vda_name; /* Version or dependency names */ ++ Elf64_Word vda_next; /* Offset in bytes to next verdaux ++ entry */ ++} Elf64_Verdaux; ++ ++ ++/* Version dependency section. */ ++ ++typedef struct ++{ ++ Elf32_Half vn_version; /* Version of structure */ ++ Elf32_Half vn_cnt; /* Number of associated aux entries */ ++ Elf32_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf32_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf32_Verneed; ++ ++typedef struct ++{ ++ Elf64_Half vn_version; /* Version of structure */ ++ Elf64_Half vn_cnt; /* Number of associated aux entries */ ++ Elf64_Word vn_file; /* Offset of filename for this ++ dependency */ ++ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ ++ Elf64_Word vn_next; /* Offset in bytes to next verneed ++ entry */ ++} Elf64_Verneed; ++ ++ ++/* Legal values for vn_version (version revision). */ ++#define VER_NEED_NONE 0 /* No version */ ++#define VER_NEED_CURRENT 1 /* Current version */ ++#define VER_NEED_NUM 2 /* Given version number */ ++ ++/* Auxiliary needed version information. */ ++ ++typedef struct ++{ ++ Elf32_Word vna_hash; /* Hash value of dependency name */ ++ Elf32_Half vna_flags; /* Dependency specific information */ ++ Elf32_Half vna_other; /* Unused */ ++ Elf32_Word vna_name; /* Dependency name string offset */ ++ Elf32_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf32_Vernaux; ++ ++typedef struct ++{ ++ Elf64_Word vna_hash; /* Hash value of dependency name */ ++ Elf64_Half vna_flags; /* Dependency specific information */ ++ Elf64_Half vna_other; /* Unused */ ++ Elf64_Word vna_name; /* Dependency name string offset */ ++ Elf64_Word vna_next; /* Offset in bytes to next vernaux ++ entry */ ++} Elf64_Vernaux; ++ ++ ++/* Legal values for vna_flags. */ ++#define VER_FLG_WEAK 0x2 /* Weak version identifier */ ++ ++ ++/* Auxiliary vector. */ ++ ++/* This vector is normally only used by the program interpreter. The ++ usual definition in an ABI supplement uses the name auxv_t. The ++ vector is not usually defined in a standard file, but it ++ can't hurt. We rename it to avoid conflicts. The sizes of these ++ types are an arrangement between the exec server and the program ++ interpreter, so we don't fully specify them here. */ ++ ++typedef struct ++{ ++ uint32_t a_type; /* Entry type */ ++ union ++ { ++ uint32_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf32_auxv_t; ++ ++typedef struct ++{ ++ uint64_t a_type; /* Entry type */ ++ union ++ { ++ uint64_t a_val; /* Integer value */ ++ /* We use to have pointer elements added here. We cannot do that, ++ though, since it does not work when using 32-bit definitions ++ on 64-bit platforms and vice versa. */ ++ } a_un; ++} Elf64_auxv_t; ++ ++/* Legal values for a_type (entry type). */ ++ ++#define AT_NULL 0 /* End of vector */ ++#define AT_IGNORE 1 /* Entry should be ignored */ ++#define AT_EXECFD 2 /* File descriptor of program */ ++#define AT_PHDR 3 /* Program headers for program */ ++#define AT_PHENT 4 /* Size of program header entry */ ++#define AT_PHNUM 5 /* Number of program headers */ ++#define AT_PAGESZ 6 /* System page size */ ++#define AT_BASE 7 /* Base address of interpreter */ ++#define AT_FLAGS 8 /* Flags */ ++#define AT_ENTRY 9 /* Entry point of program */ ++#define AT_NOTELF 10 /* Program is not ELF */ ++#define AT_UID 11 /* Real uid */ ++#define AT_EUID 12 /* Effective uid */ ++#define AT_GID 13 /* Real gid */ ++#define AT_EGID 14 /* Effective gid */ ++#define AT_CLKTCK 17 /* Frequency of times() */ ++ ++/* Some more special a_type values describing the hardware. */ ++#define AT_PLATFORM 15 /* String identifying platform. */ ++#define AT_HWCAP 16 /* Machine dependent hints about ++ processor capabilities. */ ++ ++/* This entry gives some information about the FPU initialization ++ performed by the kernel. */ ++#define AT_FPUCW 18 /* Used FPU control word. */ ++ ++/* Cache block sizes. */ ++#define AT_DCACHEBSIZE 19 /* Data cache block size. */ ++#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ ++#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ ++ ++/* A special ignored value for PPC, used by the kernel to control the ++ interpretation of the AUXV. Must be > 16. */ ++#define AT_IGNOREPPC 22 /* Entry should be ignored. */ ++ ++#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ ++ ++#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ ++ ++#define AT_RANDOM 25 /* Address of 16 random bytes. */ ++ ++#define AT_EXECFN 31 /* Filename of executable. */ ++ ++/* Pointer to the global system page used for system calls and other ++ nice things. */ ++#define AT_SYSINFO 32 ++#define AT_SYSINFO_EHDR 33 ++ ++/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains ++ log2 of line size; mask those to get cache size. */ ++#define AT_L1I_CACHESHAPE 34 ++#define AT_L1D_CACHESHAPE 35 ++#define AT_L2_CACHESHAPE 36 ++#define AT_L3_CACHESHAPE 37 ++ ++/* Note section contents. Each entry in the note section begins with ++ a header of a fixed form. */ ++ ++typedef struct ++{ ++ Elf32_Word n_namesz; /* Length of the note's name. */ ++ Elf32_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf32_Word n_type; /* Type of the note. */ ++} Elf32_Nhdr; ++ ++typedef struct ++{ ++ Elf64_Word n_namesz; /* Length of the note's name. */ ++ Elf64_Word n_descsz; /* Length of the note's descriptor. */ ++ Elf64_Word n_type; /* Type of the note. */ ++} Elf64_Nhdr; ++ ++/* Known names of notes. */ ++ ++/* Solaris entries in the note section have this name. */ ++#define ELF_NOTE_SOLARIS "SUNW Solaris" ++ ++/* Note entries for GNU systems have this name. */ ++#define ELF_NOTE_GNU "GNU" ++ ++ ++/* Defined types of notes for Solaris. */ ++ ++/* Value of descriptor (one word) is desired pagesize for the binary. */ ++#define ELF_NOTE_PAGESIZE_HINT 1 ++ ++ ++/* Defined note types for GNU systems. */ ++ ++/* ABI information. The descriptor consists of words: ++ word 0: OS descriptor ++ word 1: major version of the ABI ++ word 2: minor version of the ABI ++ word 3: subminor version of the ABI ++*/ ++#define NT_GNU_ABI_TAG 1 ++#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ ++ ++/* Known OSes. These values can appear in word 0 of an ++ NT_GNU_ABI_TAG note section entry. */ ++#define ELF_NOTE_OS_LINUX 0 ++#define ELF_NOTE_OS_GNU 1 ++#define ELF_NOTE_OS_SOLARIS2 2 ++#define ELF_NOTE_OS_FREEBSD 3 ++ ++/* Synthetic hwcap information. The descriptor begins with two words: ++ word 0: number of entries ++ word 1: bitmask of enabled entries ++ Then follow variable-length entries, one byte followed by a ++ '\0'-terminated hwcap name string. The byte gives the bit ++ number to test if enabled, (1U << bit) & bitmask. */ ++#define NT_GNU_HWCAP 2 ++ ++/* Build ID bits as generated by ld --build-id. ++ The descriptor consists of any nonzero number of bytes. */ ++#define NT_GNU_BUILD_ID 3 ++ ++/* Version note generated by GNU gold containing a version string. */ ++#define NT_GNU_GOLD_VERSION 4 ++ ++ ++/* Move records. */ ++typedef struct ++{ ++ Elf32_Xword m_value; /* Symbol value. */ ++ Elf32_Word m_info; /* Size and index. */ ++ Elf32_Word m_poffset; /* Symbol offset. */ ++ Elf32_Half m_repeat; /* Repeat count. */ ++ Elf32_Half m_stride; /* Stride info. */ ++} Elf32_Move; ++ ++typedef struct ++{ ++ Elf64_Xword m_value; /* Symbol value. */ ++ Elf64_Xword m_info; /* Size and index. */ ++ Elf64_Xword m_poffset; /* Symbol offset. */ ++ Elf64_Half m_repeat; /* Repeat count. */ ++ Elf64_Half m_stride; /* Stride info. */ ++} Elf64_Move; ++ ++/* Macro to construct move records. */ ++#define ELF32_M_SYM(info) ((info) >> 8) ++#define ELF32_M_SIZE(info) ((unsigned char) (info)) ++#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) ++ ++#define ELF64_M_SYM(info) ELF32_M_SYM (info) ++#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) ++#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) ++ ++ ++/* Motorola 68k specific definitions. */ ++ ++/* Values for Elf32_Ehdr.e_flags. */ ++#define EF_CPU32 0x00810000 ++ ++/* m68k relocs. */ ++ ++#define R_68K_NONE 0 /* No reloc */ ++#define R_68K_32 1 /* Direct 32 bit */ ++#define R_68K_16 2 /* Direct 16 bit */ ++#define R_68K_8 3 /* Direct 8 bit */ ++#define R_68K_PC32 4 /* PC relative 32 bit */ ++#define R_68K_PC16 5 /* PC relative 16 bit */ ++#define R_68K_PC8 6 /* PC relative 8 bit */ ++#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ ++#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ ++#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ ++#define R_68K_GOT32O 10 /* 32 bit GOT offset */ ++#define R_68K_GOT16O 11 /* 16 bit GOT offset */ ++#define R_68K_GOT8O 12 /* 8 bit GOT offset */ ++#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ ++#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ ++#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ ++#define R_68K_PLT32O 16 /* 32 bit PLT offset */ ++#define R_68K_PLT16O 17 /* 16 bit PLT offset */ ++#define R_68K_PLT8O 18 /* 8 bit PLT offset */ ++#define R_68K_COPY 19 /* Copy symbol at runtime */ ++#define R_68K_GLOB_DAT 20 /* Create GOT entry */ ++#define R_68K_JMP_SLOT 21 /* Create PLT entry */ ++#define R_68K_RELATIVE 22 /* Adjust by program base */ ++#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ ++#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ ++#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ ++#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ ++#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ ++#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ ++#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ ++#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ ++#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ ++#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ ++#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ ++#define R_68K_TLS_LE32 37 /* 32 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE16 38 /* 16 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_LE8 39 /* 8 bit offset relative to ++ static TLS block */ ++#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ ++#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ ++#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ ++/* Keep this the last entry. */ ++#define R_68K_NUM 43 ++ ++/* Intel 80386 specific definitions. */ ++ ++/* i386 relocs. */ ++ ++#define R_386_NONE 0 /* No reloc */ ++#define R_386_32 1 /* Direct 32 bit */ ++#define R_386_PC32 2 /* PC relative 32 bit */ ++#define R_386_GOT32 3 /* 32 bit GOT entry */ ++#define R_386_PLT32 4 /* 32 bit PLT address */ ++#define R_386_COPY 5 /* Copy symbol at runtime */ ++#define R_386_GLOB_DAT 6 /* Create GOT entry */ ++#define R_386_JMP_SLOT 7 /* Create PLT entry */ ++#define R_386_RELATIVE 8 /* Adjust by program base */ ++#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ ++#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ ++#define R_386_32PLT 11 ++#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ ++#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS ++ block offset */ ++#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block ++ offset */ ++#define R_386_TLS_LE 17 /* Offset relative to static TLS ++ block */ ++#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of ++ general dynamic thread local data */ ++#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of ++ local dynamic thread local data ++ in LE code */ ++#define R_386_16 20 ++#define R_386_PC16 21 ++#define R_386_8 22 ++#define R_386_PC8 23 ++#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic ++ thread local data */ ++#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ ++#define R_386_TLS_GD_CALL 26 /* Relocation for call to ++ __tls_get_addr() */ ++#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ ++#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic ++ thread local data in LE code */ ++#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ ++#define R_386_TLS_LDM_CALL 30 /* Relocation for call to ++ __tls_get_addr() in LDM code */ ++#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ ++#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ ++#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS ++ block offset */ ++#define R_386_TLS_LE_32 34 /* Negated offset relative to static ++ TLS block */ ++#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ ++#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ ++#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ ++/* 38? */ ++#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ ++#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS ++ descriptor for ++ relaxation. */ ++#define R_386_TLS_DESC 41 /* TLS descriptor containing ++ pointer to code and to ++ argument, returning the TLS ++ offset for the symbol. */ ++#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ ++/* Keep this the last entry. */ ++#define R_386_NUM 43 ++ ++/* SUN SPARC specific definitions. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ ++ ++/* Values for Elf64_Ehdr.e_flags. */ ++ ++#define EF_SPARCV9_MM 3 ++#define EF_SPARCV9_TSO 0 ++#define EF_SPARCV9_PSO 1 ++#define EF_SPARCV9_RMO 2 ++#define EF_SPARC_LEDATA 0x800000 /* little endian data */ ++#define EF_SPARC_EXT_MASK 0xFFFF00 ++#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ ++#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ ++#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ ++#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ ++ ++/* SPARC relocs. */ ++ ++#define R_SPARC_NONE 0 /* No reloc */ ++#define R_SPARC_8 1 /* Direct 8 bit */ ++#define R_SPARC_16 2 /* Direct 16 bit */ ++#define R_SPARC_32 3 /* Direct 32 bit */ ++#define R_SPARC_DISP8 4 /* PC relative 8 bit */ ++#define R_SPARC_DISP16 5 /* PC relative 16 bit */ ++#define R_SPARC_DISP32 6 /* PC relative 32 bit */ ++#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ ++#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ ++#define R_SPARC_HI22 9 /* High 22 bit */ ++#define R_SPARC_22 10 /* Direct 22 bit */ ++#define R_SPARC_13 11 /* Direct 13 bit */ ++#define R_SPARC_LO10 12 /* Truncated 10 bit */ ++#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ ++#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ ++#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ ++#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ ++#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ ++#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ ++#define R_SPARC_COPY 19 /* Copy symbol at runtime */ ++#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ ++#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ ++#define R_SPARC_RELATIVE 22 /* Adjust by program base */ ++#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ ++ ++/* Additional Sparc64 relocs. */ ++ ++#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ ++#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ ++#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ ++#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ ++#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ ++#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ ++#define R_SPARC_10 30 /* Direct 10 bit */ ++#define R_SPARC_11 31 /* Direct 11 bit */ ++#define R_SPARC_64 32 /* Direct 64 bit */ ++#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ ++#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ ++#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ ++#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ ++#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ ++#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ ++#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ ++#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ ++#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ ++#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ ++#define R_SPARC_7 43 /* Direct 7 bit */ ++#define R_SPARC_5 44 /* Direct 5 bit */ ++#define R_SPARC_6 45 /* Direct 6 bit */ ++#define R_SPARC_DISP64 46 /* PC relative 64 bit */ ++#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ ++#define R_SPARC_HIX22 48 /* High 22 bit complemented */ ++#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ ++#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ ++#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ ++#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ ++#define R_SPARC_REGISTER 53 /* Global register usage */ ++#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ ++#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ ++#define R_SPARC_TLS_GD_HI22 56 ++#define R_SPARC_TLS_GD_LO10 57 ++#define R_SPARC_TLS_GD_ADD 58 ++#define R_SPARC_TLS_GD_CALL 59 ++#define R_SPARC_TLS_LDM_HI22 60 ++#define R_SPARC_TLS_LDM_LO10 61 ++#define R_SPARC_TLS_LDM_ADD 62 ++#define R_SPARC_TLS_LDM_CALL 63 ++#define R_SPARC_TLS_LDO_HIX22 64 ++#define R_SPARC_TLS_LDO_LOX10 65 ++#define R_SPARC_TLS_LDO_ADD 66 ++#define R_SPARC_TLS_IE_HI22 67 ++#define R_SPARC_TLS_IE_LO10 68 ++#define R_SPARC_TLS_IE_LD 69 ++#define R_SPARC_TLS_IE_LDX 70 ++#define R_SPARC_TLS_IE_ADD 71 ++#define R_SPARC_TLS_LE_HIX22 72 ++#define R_SPARC_TLS_LE_LOX10 73 ++#define R_SPARC_TLS_DTPMOD32 74 ++#define R_SPARC_TLS_DTPMOD64 75 ++#define R_SPARC_TLS_DTPOFF32 76 ++#define R_SPARC_TLS_DTPOFF64 77 ++#define R_SPARC_TLS_TPOFF32 78 ++#define R_SPARC_TLS_TPOFF64 79 ++#define R_SPARC_GOTDATA_HIX22 80 ++#define R_SPARC_GOTDATA_LOX10 81 ++#define R_SPARC_GOTDATA_OP_HIX22 82 ++#define R_SPARC_GOTDATA_OP_LOX10 83 ++#define R_SPARC_GOTDATA_OP 84 ++#define R_SPARC_H34 85 ++#define R_SPARC_SIZE32 86 ++#define R_SPARC_SIZE64 87 ++#define R_SPARC_WDISP10 88 ++#define R_SPARC_JMP_IREL 248 ++#define R_SPARC_IRELATIVE 249 ++#define R_SPARC_GNU_VTINHERIT 250 ++#define R_SPARC_GNU_VTENTRY 251 ++#define R_SPARC_REV32 252 ++/* Keep this the last entry. */ ++#define R_SPARC_NUM 253 ++ ++/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ ++ ++#define DT_SPARC_REGISTER 0x70000001 ++#define DT_SPARC_NUM 2 ++ ++/* MIPS R3000 specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ ++#define EF_MIPS_PIC 2 /* Contains PIC code */ ++#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ ++#define EF_MIPS_XGOT 8 ++#define EF_MIPS_64BIT_WHIRL 16 ++#define EF_MIPS_ABI2 32 ++#define EF_MIPS_ABI_ON32 64 ++#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ ++ ++/* Legal values for MIPS architecture level. */ ++ ++#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* The following are non-official names and should not be used. */ ++ ++#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ ++#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ ++#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ ++#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ ++#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ ++#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ ++#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ ++ ++/* Special section indices. */ ++ ++#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ ++#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ ++#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ ++#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ ++#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ ++#define SHT_MIPS_MSYM 0x70000001 ++#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ ++#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ ++#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ ++#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ ++#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ ++#define SHT_MIPS_PACKAGE 0x70000007 ++#define SHT_MIPS_PACKSYM 0x70000008 ++#define SHT_MIPS_RELD 0x70000009 ++#define SHT_MIPS_IFACE 0x7000000b ++#define SHT_MIPS_CONTENT 0x7000000c ++#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ ++#define SHT_MIPS_SHDR 0x70000010 ++#define SHT_MIPS_FDESC 0x70000011 ++#define SHT_MIPS_EXTSYM 0x70000012 ++#define SHT_MIPS_DENSE 0x70000013 ++#define SHT_MIPS_PDESC 0x70000014 ++#define SHT_MIPS_LOCSYM 0x70000015 ++#define SHT_MIPS_AUXSYM 0x70000016 ++#define SHT_MIPS_OPTSYM 0x70000017 ++#define SHT_MIPS_LOCSTR 0x70000018 ++#define SHT_MIPS_LINE 0x70000019 ++#define SHT_MIPS_RFDESC 0x7000001a ++#define SHT_MIPS_DELTASYM 0x7000001b ++#define SHT_MIPS_DELTAINST 0x7000001c ++#define SHT_MIPS_DELTACLASS 0x7000001d ++#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ ++#define SHT_MIPS_DELTADECL 0x7000001f ++#define SHT_MIPS_SYMBOL_LIB 0x70000020 ++#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ ++#define SHT_MIPS_TRANSLATE 0x70000022 ++#define SHT_MIPS_PIXIE 0x70000023 ++#define SHT_MIPS_XLATE 0x70000024 ++#define SHT_MIPS_XLATE_DEBUG 0x70000025 ++#define SHT_MIPS_WHIRL 0x70000026 ++#define SHT_MIPS_EH_REGION 0x70000027 ++#define SHT_MIPS_XLATE_OLD 0x70000028 ++#define SHT_MIPS_PDR_EXCEPTION 0x70000029 ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ ++#define SHF_MIPS_MERGE 0x20000000 ++#define SHF_MIPS_ADDR 0x40000000 ++#define SHF_MIPS_STRINGS 0x80000000 ++#define SHF_MIPS_NOSTRIP 0x08000000 ++#define SHF_MIPS_LOCAL 0x04000000 ++#define SHF_MIPS_NAMES 0x02000000 ++#define SHF_MIPS_NODUPE 0x01000000 ++ ++ ++/* Symbol tables. */ ++ ++/* MIPS specific values for `st_other'. */ ++#define STO_MIPS_DEFAULT 0x0 ++#define STO_MIPS_INTERNAL 0x1 ++#define STO_MIPS_HIDDEN 0x2 ++#define STO_MIPS_PROTECTED 0x3 ++#define STO_MIPS_PLT 0x8 ++#define STO_MIPS_SC_ALIGN_UNUSED 0xff ++ ++/* MIPS specific values for `st_info'. */ ++#define STB_MIPS_SPLIT_COMMON 13 ++ ++/* Entries found in sections of type SHT_MIPS_GPTAB. */ ++ ++typedef union ++{ ++ struct ++ { ++ Elf32_Word gt_current_g_value; /* -G value used for compilation */ ++ Elf32_Word gt_unused; /* Not used */ ++ } gt_header; /* First entry in section */ ++ struct ++ { ++ Elf32_Word gt_g_value; /* If this value were used for -G */ ++ Elf32_Word gt_bytes; /* This many bytes would be used */ ++ } gt_entry; /* Subsequent entries in section */ ++} Elf32_gptab; ++ ++/* Entry found in sections of type SHT_MIPS_REGINFO. */ ++ ++typedef struct ++{ ++ Elf32_Word ri_gprmask; /* General registers used */ ++ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ ++ Elf32_Sword ri_gp_value; /* $gp register value */ ++} Elf32_RegInfo; ++ ++/* Entries found in sections of type SHT_MIPS_OPTIONS. */ ++ ++typedef struct ++{ ++ unsigned char kind; /* Determines interpretation of the ++ variable part of descriptor. */ ++ unsigned char size; /* Size of descriptor, including header. */ ++ Elf32_Section section; /* Section header index of section affected, ++ 0 for global options. */ ++ Elf32_Word info; /* Kind-specific information. */ ++} Elf_Options; ++ ++/* Values for `kind' field in Elf_Options. */ ++ ++#define ODK_NULL 0 /* Undefined. */ ++#define ODK_REGINFO 1 /* Register usage information. */ ++#define ODK_EXCEPTIONS 2 /* Exception processing options. */ ++#define ODK_PAD 3 /* Section padding options. */ ++#define ODK_HWPATCH 4 /* Hardware workarounds performed */ ++#define ODK_FILL 5 /* record the fill value used by the linker. */ ++#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ ++#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ ++#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ ++ ++/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ ++ ++#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ ++#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ ++#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ ++#define OEX_SMM 0x20000 /* Force sequential memory mode? */ ++#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ ++#define OEX_PRECISEFP OEX_FPDBUG ++#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ ++ ++#define OEX_FPU_INVAL 0x10 ++#define OEX_FPU_DIV0 0x08 ++#define OEX_FPU_OFLO 0x04 ++#define OEX_FPU_UFLO 0x02 ++#define OEX_FPU_INEX 0x01 ++ ++/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ ++ ++#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ ++#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ ++#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ ++#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ ++ ++#define OPAD_PREFIX 0x1 ++#define OPAD_POSTFIX 0x2 ++#define OPAD_SYMBOL 0x4 ++ ++/* Entry found in `.options' section. */ ++ ++typedef struct ++{ ++ Elf32_Word hwp_flags1; /* Extra flags. */ ++ Elf32_Word hwp_flags2; /* Extra flags. */ ++} Elf_Options_Hw; ++ ++/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ ++ ++#define OHWA0_R4KEOP_CHECKED 0x00000001 ++#define OHWA1_R4KEOP_CLEAN 0x00000002 ++ ++/* MIPS relocs. */ ++ ++#define R_MIPS_NONE 0 /* No reloc */ ++#define R_MIPS_16 1 /* Direct 16 bit */ ++#define R_MIPS_32 2 /* Direct 32 bit */ ++#define R_MIPS_REL32 3 /* PC relative 32 bit */ ++#define R_MIPS_26 4 /* Direct 26 bit shifted */ ++#define R_MIPS_HI16 5 /* High 16 bit */ ++#define R_MIPS_LO16 6 /* Low 16 bit */ ++#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ ++#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ ++#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ ++#define R_MIPS_PC16 10 /* PC relative 16 bit */ ++#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ ++#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ ++ ++#define R_MIPS_SHIFT5 16 ++#define R_MIPS_SHIFT6 17 ++#define R_MIPS_64 18 ++#define R_MIPS_GOT_DISP 19 ++#define R_MIPS_GOT_PAGE 20 ++#define R_MIPS_GOT_OFST 21 ++#define R_MIPS_GOT_HI16 22 ++#define R_MIPS_GOT_LO16 23 ++#define R_MIPS_SUB 24 ++#define R_MIPS_INSERT_A 25 ++#define R_MIPS_INSERT_B 26 ++#define R_MIPS_DELETE 27 ++#define R_MIPS_HIGHER 28 ++#define R_MIPS_HIGHEST 29 ++#define R_MIPS_CALL_HI16 30 ++#define R_MIPS_CALL_LO16 31 ++#define R_MIPS_SCN_DISP 32 ++#define R_MIPS_REL16 33 ++#define R_MIPS_ADD_IMMEDIATE 34 ++#define R_MIPS_PJUMP 35 ++#define R_MIPS_RELGOT 36 ++#define R_MIPS_JALR 37 ++#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ ++#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ ++#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ ++#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ ++#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ ++#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ ++#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ ++#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ ++#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ ++#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ ++#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ ++#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ ++#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ ++#define R_MIPS_GLOB_DAT 51 ++#define R_MIPS_COPY 126 ++#define R_MIPS_JUMP_SLOT 127 ++/* Keep this the last entry. */ ++#define R_MIPS_NUM 128 ++ ++/* Legal values for p_type field of Elf32_Phdr. */ ++ ++#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ ++#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ ++#define PT_MIPS_OPTIONS 0x70000002 ++ ++/* Special program header types. */ ++ ++#define PF_MIPS_LOCAL 0x10000000 ++ ++/* Legal values for d_tag field of Elf32_Dyn. */ ++ ++#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ ++#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ ++#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ ++#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ ++#define DT_MIPS_FLAGS 0x70000005 /* Flags */ ++#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ ++#define DT_MIPS_MSYM 0x70000007 ++#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ ++#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ ++#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ ++#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ ++#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ ++#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ ++#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ ++#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ ++#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ ++#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ ++#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ ++#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in ++ DT_MIPS_DELTA_CLASS. */ ++#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ ++#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in ++ DT_MIPS_DELTA_INSTANCE. */ ++#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ ++#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in ++ DT_MIPS_DELTA_RELOC. */ ++#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta ++ relocations refer to. */ ++#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in ++ DT_MIPS_DELTA_SYM. */ ++#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the ++ class declaration. */ ++#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in ++ DT_MIPS_DELTA_CLASSSYM. */ ++#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ ++#define DT_MIPS_PIXIE_INIT 0x70000023 ++#define DT_MIPS_SYMBOL_LIB 0x70000024 ++#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 ++#define DT_MIPS_LOCAL_GOTIDX 0x70000026 ++#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 ++#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 ++#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ ++#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ ++#define DT_MIPS_DYNSTR_ALIGN 0x7000002b ++#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ ++#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve ++ function stored in GOT. */ ++#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added ++ by rld on dlopen() calls. */ ++#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ ++#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ ++#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ ++/* The address of .got.plt in an executable using the new non-PIC ABI. */ ++#define DT_MIPS_PLTGOT 0x70000032 ++/* The base of the PLT in an executable using the new non-PIC ABI if that ++ PLT is writable. For a non-writable PLT, this is omitted or has a zero ++ value. */ ++#define DT_MIPS_RWPLT 0x70000034 ++#define DT_MIPS_NUM 0x35 ++ ++/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ ++ ++#define RHF_NONE 0 /* No flags */ ++#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ ++#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ ++#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ ++#define RHF_NO_MOVE (1 << 3) ++#define RHF_SGI_ONLY (1 << 4) ++#define RHF_GUARANTEE_INIT (1 << 5) ++#define RHF_DELTA_C_PLUS_PLUS (1 << 6) ++#define RHF_GUARANTEE_START_INIT (1 << 7) ++#define RHF_PIXIE (1 << 8) ++#define RHF_DEFAULT_DELAY_LOAD (1 << 9) ++#define RHF_REQUICKSTART (1 << 10) ++#define RHF_REQUICKSTARTED (1 << 11) ++#define RHF_CORD (1 << 12) ++#define RHF_NO_UNRES_UNDEF (1 << 13) ++#define RHF_RLD_ORDER_SAFE (1 << 14) ++ ++/* Entries found in sections of type SHT_MIPS_LIBLIST. */ ++ ++typedef struct ++{ ++ Elf32_Word l_name; /* Name (string table index) */ ++ Elf32_Word l_time_stamp; /* Timestamp */ ++ Elf32_Word l_checksum; /* Checksum */ ++ Elf32_Word l_version; /* Interface version */ ++ Elf32_Word l_flags; /* Flags */ ++} Elf32_Lib; ++ ++typedef struct ++{ ++ Elf64_Word l_name; /* Name (string table index) */ ++ Elf64_Word l_time_stamp; /* Timestamp */ ++ Elf64_Word l_checksum; /* Checksum */ ++ Elf64_Word l_version; /* Interface version */ ++ Elf64_Word l_flags; /* Flags */ ++} Elf64_Lib; ++ ++ ++/* Legal values for l_flags. */ ++ ++#define LL_NONE 0 ++#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ ++#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ ++#define LL_REQUIRE_MINOR (1 << 2) ++#define LL_EXPORTS (1 << 3) ++#define LL_DELAY_LOAD (1 << 4) ++#define LL_DELTA (1 << 5) ++ ++/* Entries found in sections of type SHT_MIPS_CONFLICT. */ ++ ++typedef Elf32_Addr Elf32_Conflict; ++ ++ ++/* HPPA specific definitions. */ ++ ++/* Legal values for e_flags field of Elf32_Ehdr. */ ++ ++#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ ++#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ ++#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ ++#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ ++#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch ++ prediction. */ ++#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ ++#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ ++ ++/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ ++ ++#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ ++#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ ++#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ ++ ++/* Additional section indeces. */ ++ ++#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared ++ symbols in ANSI C. */ ++#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ ++ ++/* Legal values for sh_type field of Elf32_Shdr. */ ++ ++#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ ++#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ ++#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ ++ ++/* Legal values for sh_flags field of Elf32_Shdr. */ ++ ++#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ ++#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ ++#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ ++ ++/* Legal values for ST_TYPE subfield of st_info (symbol type). */ ++ ++#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ ++ ++#define STT_HP_OPAQUE (STT_LOOS + 0x1) ++#define STT_HP_STUB (STT_LOOS + 0x2) ++ ++/* HPPA relocs. */ ++ ++#define R_PARISC_NONE 0 /* No reloc. */ ++#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ ++#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ ++#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ ++#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ ++#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ ++#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ ++#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ ++#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ ++#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ ++#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ ++#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ ++#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ ++#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ ++#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ ++#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ ++#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ ++#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ ++#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ ++#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ ++#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ ++#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ ++#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ ++#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ ++#define R_PARISC_FPTR64 64 /* 64 bits function address. */ ++#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ ++#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ ++#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ ++#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ ++#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ ++#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ ++#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ ++#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ ++#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ ++#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ ++#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ ++#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ ++#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ ++#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ ++#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ ++#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ ++#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ ++#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ ++#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ ++#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ ++#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ ++#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ ++#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ ++#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ ++#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ ++#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ ++#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ ++#define R_PARISC_LORESERVE 128 ++#define R_PARISC_COPY 128 /* Copy relocation. */ ++#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ ++#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ ++#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ ++#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ ++#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ ++#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ ++#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ ++#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ ++#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ ++#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ ++#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ ++#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ ++#define R_PARISC_GNU_VTENTRY 232 ++#define R_PARISC_GNU_VTINHERIT 233 ++#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ ++#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ ++#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ ++#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ ++#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ ++#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ ++#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ ++#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ ++#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ ++#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ ++#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ ++#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L ++#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R ++#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L ++#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R ++#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 ++#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 ++#define R_PARISC_HIRESERVE 255 ++ ++/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PT_HP_TLS (PT_LOOS + 0x0) ++#define PT_HP_CORE_NONE (PT_LOOS + 0x1) ++#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) ++#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) ++#define PT_HP_CORE_COMM (PT_LOOS + 0x4) ++#define PT_HP_CORE_PROC (PT_LOOS + 0x5) ++#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) ++#define PT_HP_CORE_STACK (PT_LOOS + 0x7) ++#define PT_HP_CORE_SHM (PT_LOOS + 0x8) ++#define PT_HP_CORE_MMF (PT_LOOS + 0x9) ++#define PT_HP_PARALLEL (PT_LOOS + 0x10) ++#define PT_HP_FASTBIND (PT_LOOS + 0x11) ++#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) ++#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) ++#define PT_HP_STACK (PT_LOOS + 0x14) ++ ++#define PT_PARISC_ARCHEXT 0x70000000 ++#define PT_PARISC_UNWIND 0x70000001 ++ ++/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ ++ ++#define PF_PARISC_SBP 0x08000000 ++ ++#define PF_HP_PAGE_SIZE 0x00100000 ++#define PF_HP_FAR_SHARED 0x00200000 ++#define PF_HP_NEAR_SHARED 0x00400000 ++#define PF_HP_CODE 0x01000000 ++#define PF_HP_MODIFY 0x02000000 ++#define PF_HP_LAZYSWAP 0x04000000 ++#define PF_HP_SBP 0x08000000 ++ ++ ++/* Alpha specific definitions. */ ++ ++/* Legal values for e_flags field of Elf64_Ehdr. */ ++ ++#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ ++#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ ++ ++/* Legal values for sh_type field of Elf64_Shdr. */ ++ ++/* These two are primerily concerned with ECOFF debugging info. */ ++#define SHT_ALPHA_DEBUG 0x70000001 ++#define SHT_ALPHA_REGINFO 0x70000002 ++ ++/* Legal values for sh_flags field of Elf64_Shdr. */ ++ ++#define SHF_ALPHA_GPREL 0x10000000 ++ ++/* Legal values for st_other field of Elf64_Sym. */ ++#define STO_ALPHA_NOPV 0x80 /* No PV required. */ ++#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ ++ ++/* Alpha relocs. */ ++ ++#define R_ALPHA_NONE 0 /* No reloc */ ++#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ ++#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ ++#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ ++#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ ++#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ ++#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ ++#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ ++#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ ++#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ ++#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ ++#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ ++#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ ++#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ ++#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ ++#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ ++#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ ++#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ ++#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ ++#define R_ALPHA_TLS_GD_HI 28 ++#define R_ALPHA_TLSGD 29 ++#define R_ALPHA_TLS_LDM 30 ++#define R_ALPHA_DTPMOD64 31 ++#define R_ALPHA_GOTDTPREL 32 ++#define R_ALPHA_DTPREL64 33 ++#define R_ALPHA_DTPRELHI 34 ++#define R_ALPHA_DTPRELLO 35 ++#define R_ALPHA_DTPREL16 36 ++#define R_ALPHA_GOTTPREL 37 ++#define R_ALPHA_TPREL64 38 ++#define R_ALPHA_TPRELHI 39 ++#define R_ALPHA_TPRELLO 40 ++#define R_ALPHA_TPREL16 41 ++/* Keep this the last entry. */ ++#define R_ALPHA_NUM 46 ++ ++/* Magic values of the LITUSE relocation addend. */ ++#define LITUSE_ALPHA_ADDR 0 ++#define LITUSE_ALPHA_BASE 1 ++#define LITUSE_ALPHA_BYTOFF 2 ++#define LITUSE_ALPHA_JSR 3 ++#define LITUSE_ALPHA_TLS_GD 4 ++#define LITUSE_ALPHA_TLS_LDM 5 ++ ++/* Legal values for d_tag of Elf64_Dyn. */ ++#define DT_ALPHA_PLTRO (DT_LOPROC + 0) ++#define DT_ALPHA_NUM 1 ++ ++/* PowerPC specific declarations */ ++ ++/* Values for Elf32/64_Ehdr.e_flags. */ ++#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ ++ ++/* Cygnus local bits below */ ++#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ ++#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib ++ flag */ ++ ++/* PowerPC relocations defined by the ABIs */ ++#define R_PPC_NONE 0 ++#define R_PPC_ADDR32 1 /* 32bit absolute address */ ++#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ ++#define R_PPC_ADDR16 3 /* 16bit absolute address */ ++#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ ++#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ ++#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ ++#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ ++#define R_PPC_ADDR14_BRTAKEN 8 ++#define R_PPC_ADDR14_BRNTAKEN 9 ++#define R_PPC_REL24 10 /* PC relative 26 bit */ ++#define R_PPC_REL14 11 /* PC relative 16 bit */ ++#define R_PPC_REL14_BRTAKEN 12 ++#define R_PPC_REL14_BRNTAKEN 13 ++#define R_PPC_GOT16 14 ++#define R_PPC_GOT16_LO 15 ++#define R_PPC_GOT16_HI 16 ++#define R_PPC_GOT16_HA 17 ++#define R_PPC_PLTREL24 18 ++#define R_PPC_COPY 19 ++#define R_PPC_GLOB_DAT 20 ++#define R_PPC_JMP_SLOT 21 ++#define R_PPC_RELATIVE 22 ++#define R_PPC_LOCAL24PC 23 ++#define R_PPC_UADDR32 24 ++#define R_PPC_UADDR16 25 ++#define R_PPC_REL32 26 ++#define R_PPC_PLT32 27 ++#define R_PPC_PLTREL32 28 ++#define R_PPC_PLT16_LO 29 ++#define R_PPC_PLT16_HI 30 ++#define R_PPC_PLT16_HA 31 ++#define R_PPC_SDAREL16 32 ++#define R_PPC_SECTOFF 33 ++#define R_PPC_SECTOFF_LO 34 ++#define R_PPC_SECTOFF_HI 35 ++#define R_PPC_SECTOFF_HA 36 ++ ++/* PowerPC relocations defined for the TLS access ABI. */ ++#define R_PPC_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ ++#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ ++#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ ++#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ ++#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ ++#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ ++#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ ++#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ ++#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ ++ ++/* The remaining relocs are from the Embedded ELF ABI, and are not ++ in the SVR4 ELF ABI. */ ++#define R_PPC_EMB_NADDR32 101 ++#define R_PPC_EMB_NADDR16 102 ++#define R_PPC_EMB_NADDR16_LO 103 ++#define R_PPC_EMB_NADDR16_HI 104 ++#define R_PPC_EMB_NADDR16_HA 105 ++#define R_PPC_EMB_SDAI16 106 ++#define R_PPC_EMB_SDA2I16 107 ++#define R_PPC_EMB_SDA2REL 108 ++#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ ++#define R_PPC_EMB_MRKREF 110 ++#define R_PPC_EMB_RELSEC16 111 ++#define R_PPC_EMB_RELST_LO 112 ++#define R_PPC_EMB_RELST_HI 113 ++#define R_PPC_EMB_RELST_HA 114 ++#define R_PPC_EMB_BIT_FLD 115 ++#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ ++ ++/* Diab tool relocations. */ ++#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ ++#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ ++#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ ++#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ ++#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ ++#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC_IRELATIVE 248 ++ ++/* GNU relocs used in PIC code sequences. */ ++#define R_PPC_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* This is a phony reloc to handle any old fashioned TOC16 references ++ that may still be in object files. */ ++#define R_PPC_TOC16 255 ++ ++/* PowerPC specific values for the Dyn d_tag field. */ ++#define DT_PPC_GOT (DT_LOPROC + 0) ++#define DT_PPC_NUM 1 ++ ++/* PowerPC64 relocations defined by the ABIs */ ++#define R_PPC64_NONE R_PPC_NONE ++#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ ++#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ ++#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ ++#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ ++#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ ++#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ ++#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ ++#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN ++#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN ++#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ ++#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ ++#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN ++#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN ++#define R_PPC64_GOT16 R_PPC_GOT16 ++#define R_PPC64_GOT16_LO R_PPC_GOT16_LO ++#define R_PPC64_GOT16_HI R_PPC_GOT16_HI ++#define R_PPC64_GOT16_HA R_PPC_GOT16_HA ++ ++#define R_PPC64_COPY R_PPC_COPY ++#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT ++#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT ++#define R_PPC64_RELATIVE R_PPC_RELATIVE ++ ++#define R_PPC64_UADDR32 R_PPC_UADDR32 ++#define R_PPC64_UADDR16 R_PPC_UADDR16 ++#define R_PPC64_REL32 R_PPC_REL32 ++#define R_PPC64_PLT32 R_PPC_PLT32 ++#define R_PPC64_PLTREL32 R_PPC_PLTREL32 ++#define R_PPC64_PLT16_LO R_PPC_PLT16_LO ++#define R_PPC64_PLT16_HI R_PPC_PLT16_HI ++#define R_PPC64_PLT16_HA R_PPC_PLT16_HA ++ ++#define R_PPC64_SECTOFF R_PPC_SECTOFF ++#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO ++#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI ++#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA ++#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ ++#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ ++#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ ++#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ ++#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ ++#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ ++#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ ++#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ ++#define R_PPC64_PLT64 45 /* doubleword64 L + A */ ++#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ ++#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ ++#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ ++#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ ++#define R_PPC64_TOC 51 /* doubleword64 .TOC */ ++#define R_PPC64_PLTGOT16 52 /* half16* M + A */ ++#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ ++#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ ++#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ ++ ++#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ ++#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ ++#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ ++#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ ++#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ ++#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ ++#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ ++#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ ++#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ ++#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ ++#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ ++ ++/* PowerPC64 relocations defined for the TLS access ABI. */ ++#define R_PPC64_TLS 67 /* none (sym+add)@tls */ ++#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ ++#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ ++#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ ++#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ ++#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ ++#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ ++#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ ++#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ ++#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ ++#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ ++#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ ++#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ ++#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ ++#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ ++#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ ++#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ ++#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ ++#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ ++#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ ++#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ ++#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ ++#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ ++#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ ++#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ ++#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ ++#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ ++#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ ++#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ ++#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ ++#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ ++#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ ++#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ ++#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ ++#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ ++#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ ++ ++/* GNU extension to support local ifunc. */ ++#define R_PPC64_JMP_IREL 247 ++#define R_PPC64_IRELATIVE 248 ++#define R_PPC64_REL16 249 /* half16 (sym+add-.) */ ++#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ ++#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ ++#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ ++ ++/* PowerPC64 specific values for the Dyn d_tag field. */ ++#define DT_PPC64_GLINK (DT_LOPROC + 0) ++#define DT_PPC64_OPD (DT_LOPROC + 1) ++#define DT_PPC64_OPDSZ (DT_LOPROC + 2) ++#define DT_PPC64_NUM 3 ++ ++ ++/* ARM specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_ARM_RELEXEC 0x01 ++#define EF_ARM_HASENTRY 0x02 ++#define EF_ARM_INTERWORK 0x04 ++#define EF_ARM_APCS_26 0x08 ++#define EF_ARM_APCS_FLOAT 0x10 ++#define EF_ARM_PIC 0x20 ++#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ ++#define EF_ARM_NEW_ABI 0x80 ++#define EF_ARM_OLD_ABI 0x100 ++#define EF_ARM_SOFT_FLOAT 0x200 ++#define EF_ARM_VFP_FLOAT 0x400 ++#define EF_ARM_MAVERICK_FLOAT 0x800 ++ ++ ++/* Other constants defined in the ARM ELF spec. version B-01. */ ++/* NB. These conflict with values defined above. */ ++#define EF_ARM_SYMSARESORTED 0x04 ++#define EF_ARM_DYNSYMSUSESEGIDX 0x08 ++#define EF_ARM_MAPSYMSFIRST 0x10 ++#define EF_ARM_EABIMASK 0XFF000000 ++ ++/* Constants defined in AAELF. */ ++#define EF_ARM_BE8 0x00800000 ++#define EF_ARM_LE8 0x00400000 ++ ++#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) ++#define EF_ARM_EABI_UNKNOWN 0x00000000 ++#define EF_ARM_EABI_VER1 0x01000000 ++#define EF_ARM_EABI_VER2 0x02000000 ++#define EF_ARM_EABI_VER3 0x03000000 ++#define EF_ARM_EABI_VER4 0x04000000 ++#define EF_ARM_EABI_VER5 0x05000000 ++ ++/* Additional symbol types for Thumb. */ ++#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ ++#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ ++ ++/* ARM-specific values for sh_flags */ ++#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ ++#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined ++ in the input to a link step. */ ++ ++/* ARM-specific program header flags */ ++#define PF_ARM_SB 0x10000000 /* Segment contains the location ++ addressed by the static base. */ ++#define PF_ARM_PI 0x20000000 /* Position-independent segment. */ ++#define PF_ARM_ABS 0x40000000 /* Absolute segment. */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ ++#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ ++#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ ++ ++ ++/* ARM relocs. */ ++ ++#define R_ARM_NONE 0 /* No reloc */ ++#define R_ARM_PC24 1 /* PC relative 26 bit branch */ ++#define R_ARM_ABS32 2 /* Direct 32 bit */ ++#define R_ARM_REL32 3 /* PC relative 32 bit */ ++#define R_ARM_PC13 4 ++#define R_ARM_ABS16 5 /* Direct 16 bit */ ++#define R_ARM_ABS12 6 /* Direct 12 bit */ ++#define R_ARM_THM_ABS5 7 ++#define R_ARM_ABS8 8 /* Direct 8 bit */ ++#define R_ARM_SBREL32 9 ++#define R_ARM_THM_PC22 10 ++#define R_ARM_THM_PC8 11 ++#define R_ARM_AMP_VCALL9 12 ++#define R_ARM_SWI24 13 /* Obsolete static relocation. */ ++#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ ++#define R_ARM_THM_SWI8 14 ++#define R_ARM_XPC25 15 ++#define R_ARM_THM_XPC22 16 ++#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ ++#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ ++#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ ++#define R_ARM_COPY 20 /* Copy symbol at runtime */ ++#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ ++#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ ++#define R_ARM_RELATIVE 23 /* Adjust by program base */ ++#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ ++#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ ++#define R_ARM_GOT32 26 /* 32 bit GOT entry */ ++#define R_ARM_PLT32 27 /* 32 bit PLT address */ ++#define R_ARM_ALU_PCREL_7_0 32 ++#define R_ARM_ALU_PCREL_15_8 33 ++#define R_ARM_ALU_PCREL_23_15 34 ++#define R_ARM_LDR_SBREL_11_0 35 ++#define R_ARM_ALU_SBREL_19_12 36 ++#define R_ARM_ALU_SBREL_27_20 37 ++#define R_ARM_TLS_GOTDESC 90 ++#define R_ARM_TLS_CALL 91 ++#define R_ARM_TLS_DESCSEQ 92 ++#define R_ARM_THM_TLS_CALL 93 ++#define R_ARM_GNU_VTENTRY 100 ++#define R_ARM_GNU_VTINHERIT 101 ++#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ ++#define R_ARM_THM_PC9 103 /* thumb conditional branch */ ++#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic ++ thread local data */ ++#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic ++ thread local data */ ++#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS ++ block */ ++#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of ++ static TLS block offset */ ++#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static ++ TLS block */ ++#define R_ARM_THM_TLS_DESCSEQ 129 ++#define R_ARM_IRELATIVE 160 ++#define R_ARM_RXPC25 249 ++#define R_ARM_RSBREL32 250 ++#define R_ARM_THM_RPC22 251 ++#define R_ARM_RREL32 252 ++#define R_ARM_RABS22 253 ++#define R_ARM_RPC24 254 ++#define R_ARM_RBASE 255 ++/* Keep this the last entry. */ ++#define R_ARM_NUM 256 ++ ++/* IA-64 specific declarations. */ ++ ++/* Processor specific flags for the Ehdr e_flags field. */ ++#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ ++#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ ++#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ ++ ++/* Processor specific values for the Phdr p_type field. */ ++#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ ++#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ ++#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) ++#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) ++#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) ++ ++/* Processor specific flags for the Phdr p_flags field. */ ++#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Shdr sh_type field. */ ++#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ ++#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ ++ ++/* Processor specific flags for the Shdr sh_flags field. */ ++#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ ++#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ ++ ++/* Processor specific values for the Dyn d_tag field. */ ++#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) ++#define DT_IA_64_NUM 1 ++ ++/* IA-64 relocations. */ ++#define R_IA64_NONE 0x00 /* none */ ++#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ ++#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ ++#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ ++#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ ++#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ ++#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ ++#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ ++#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ ++#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ ++#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ ++#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ ++#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ ++#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ ++#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ ++#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ ++#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ ++#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ ++#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ ++#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ ++#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ ++#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ ++#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ ++#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ ++#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ ++#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ ++#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ ++#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ ++#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ ++#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ ++#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ ++#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ ++#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ ++#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ ++#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ ++#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ ++#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ ++#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ ++#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ ++#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ ++#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ ++#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ ++#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ ++#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ ++#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ ++#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ ++#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ ++#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ ++#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ ++#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ ++#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ ++#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ ++#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ ++#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ ++#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ ++#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ ++#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ ++#define R_IA64_COPY 0x84 /* copy relocation */ ++#define R_IA64_SUB 0x85 /* Addend and symbol difference */ ++#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ ++#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ ++#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ ++#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ ++#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ ++#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ ++#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ ++#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ ++#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ ++#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ ++#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ ++#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ ++#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ ++#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ ++#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ ++#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ ++#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ ++ ++/* SH specific declarations */ ++ ++/* Processor specific flags for the ELF header e_flags field. */ ++#define EF_SH_MACH_MASK 0x1f ++#define EF_SH_UNKNOWN 0x0 ++#define EF_SH1 0x1 ++#define EF_SH2 0x2 ++#define EF_SH3 0x3 ++#define EF_SH_DSP 0x4 ++#define EF_SH3_DSP 0x5 ++#define EF_SH4AL_DSP 0x6 ++#define EF_SH3E 0x8 ++#define EF_SH4 0x9 ++#define EF_SH2E 0xb ++#define EF_SH4A 0xc ++#define EF_SH2A 0xd ++#define EF_SH4_NOFPU 0x10 ++#define EF_SH4A_NOFPU 0x11 ++#define EF_SH4_NOMMU_NOFPU 0x12 ++#define EF_SH2A_NOFPU 0x13 ++#define EF_SH3_NOMMU 0x14 ++#define EF_SH2A_SH4_NOFPU 0x15 ++#define EF_SH2A_SH3_NOFPU 0x16 ++#define EF_SH2A_SH4 0x17 ++#define EF_SH2A_SH3E 0x18 ++ ++/* SH relocs. */ ++#define R_SH_NONE 0 ++#define R_SH_DIR32 1 ++#define R_SH_REL32 2 ++#define R_SH_DIR8WPN 3 ++#define R_SH_IND12W 4 ++#define R_SH_DIR8WPL 5 ++#define R_SH_DIR8WPZ 6 ++#define R_SH_DIR8BP 7 ++#define R_SH_DIR8W 8 ++#define R_SH_DIR8L 9 ++#define R_SH_SWITCH16 25 ++#define R_SH_SWITCH32 26 ++#define R_SH_USES 27 ++#define R_SH_COUNT 28 ++#define R_SH_ALIGN 29 ++#define R_SH_CODE 30 ++#define R_SH_DATA 31 ++#define R_SH_LABEL 32 ++#define R_SH_SWITCH8 33 ++#define R_SH_GNU_VTINHERIT 34 ++#define R_SH_GNU_VTENTRY 35 ++#define R_SH_TLS_GD_32 144 ++#define R_SH_TLS_LD_32 145 ++#define R_SH_TLS_LDO_32 146 ++#define R_SH_TLS_IE_32 147 ++#define R_SH_TLS_LE_32 148 ++#define R_SH_TLS_DTPMOD32 149 ++#define R_SH_TLS_DTPOFF32 150 ++#define R_SH_TLS_TPOFF32 151 ++#define R_SH_GOT32 160 ++#define R_SH_PLT32 161 ++#define R_SH_COPY 162 ++#define R_SH_GLOB_DAT 163 ++#define R_SH_JMP_SLOT 164 ++#define R_SH_RELATIVE 165 ++#define R_SH_GOTOFF 166 ++#define R_SH_GOTPC 167 ++/* Keep this the last entry. */ ++#define R_SH_NUM 256 ++ ++/* S/390 specific definitions. */ ++ ++/* Valid values for the e_flags field. */ ++ ++#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ ++ ++/* Additional s390 relocs */ ++ ++#define R_390_NONE 0 /* No reloc. */ ++#define R_390_8 1 /* Direct 8 bit. */ ++#define R_390_12 2 /* Direct 12 bit. */ ++#define R_390_16 3 /* Direct 16 bit. */ ++#define R_390_32 4 /* Direct 32 bit. */ ++#define R_390_PC32 5 /* PC relative 32 bit. */ ++#define R_390_GOT12 6 /* 12 bit GOT offset. */ ++#define R_390_GOT32 7 /* 32 bit GOT offset. */ ++#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ ++#define R_390_COPY 9 /* Copy symbol at runtime. */ ++#define R_390_GLOB_DAT 10 /* Create GOT entry. */ ++#define R_390_JMP_SLOT 11 /* Create PLT entry. */ ++#define R_390_RELATIVE 12 /* Adjust by program base. */ ++#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ ++#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ ++#define R_390_GOT16 15 /* 16 bit GOT offset. */ ++#define R_390_PC16 16 /* PC relative 16 bit. */ ++#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ ++#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ ++#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ ++#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ ++#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ ++#define R_390_64 22 /* Direct 64 bit. */ ++#define R_390_PC64 23 /* PC relative 64 bit. */ ++#define R_390_GOT64 24 /* 64 bit GOT offset. */ ++#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ ++#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ ++#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ ++#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ ++#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ ++#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ ++#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ ++#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ ++#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ ++#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ ++#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ ++#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ ++#define R_390_TLS_GDCALL 38 /* Tag for function call in general ++ dynamic TLS code. */ ++#define R_390_TLS_LDCALL 39 /* Tag for function call in local ++ dynamic TLS code. */ ++#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic ++ thread local data. */ ++#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic ++ thread local data in LE code. */ ++#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for ++ negated static TLS block offset. */ ++#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to ++ static TLS block. */ ++#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS ++ block. */ ++#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ ++#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ ++#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS ++ block. */ ++#define R_390_20 57 /* Direct 20 bit. */ ++#define R_390_GOT20 58 /* 20 bit GOT offset. */ ++#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ ++#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS ++ block offset. */ ++#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */ ++/* Keep this the last entry. */ ++#define R_390_NUM 62 ++ ++ ++/* CRIS relocations. */ ++#define R_CRIS_NONE 0 ++#define R_CRIS_8 1 ++#define R_CRIS_16 2 ++#define R_CRIS_32 3 ++#define R_CRIS_8_PCREL 4 ++#define R_CRIS_16_PCREL 5 ++#define R_CRIS_32_PCREL 6 ++#define R_CRIS_GNU_VTINHERIT 7 ++#define R_CRIS_GNU_VTENTRY 8 ++#define R_CRIS_COPY 9 ++#define R_CRIS_GLOB_DAT 10 ++#define R_CRIS_JUMP_SLOT 11 ++#define R_CRIS_RELATIVE 12 ++#define R_CRIS_16_GOT 13 ++#define R_CRIS_32_GOT 14 ++#define R_CRIS_16_GOTPLT 15 ++#define R_CRIS_32_GOTPLT 16 ++#define R_CRIS_32_GOTREL 17 ++#define R_CRIS_32_PLT_GOTREL 18 ++#define R_CRIS_32_PLT_PCREL 19 ++ ++#define R_CRIS_NUM 20 ++ ++ ++/* AMD x86-64 relocations. */ ++#define R_X86_64_NONE 0 /* No reloc */ ++#define R_X86_64_64 1 /* Direct 64 bit */ ++#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ ++#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ ++#define R_X86_64_PLT32 4 /* 32 bit PLT address */ ++#define R_X86_64_COPY 5 /* Copy symbol at runtime */ ++#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ ++#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ ++#define R_X86_64_RELATIVE 8 /* Adjust by program base */ ++#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative ++ offset to GOT */ ++#define R_X86_64_32 10 /* Direct 32 bit zero extended */ ++#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ ++#define R_X86_64_16 12 /* Direct 16 bit zero extended */ ++#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ ++#define R_X86_64_8 14 /* Direct 8 bit sign extended */ ++#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ ++#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ ++#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ ++#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ ++#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset ++ to two GOT entries for GD symbol */ ++#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset ++ to two GOT entries for LD symbol */ ++#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ ++#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset ++ to GOT entry for IE symbol */ ++#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ ++#define R_X86_64_PC64 24 /* PC relative 64 bit */ ++#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ ++#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative ++ offset to GOT */ ++#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ ++#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset ++ to GOT entry */ ++#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ ++#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ ++#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset ++ to PLT entry */ ++#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ ++#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ ++#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ ++#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS ++ descriptor. */ ++#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ ++#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ ++#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */ ++ ++#define R_X86_64_NUM 39 ++ ++ ++/* AM33 relocations. */ ++#define R_MN10300_NONE 0 /* No reloc. */ ++#define R_MN10300_32 1 /* Direct 32 bit. */ ++#define R_MN10300_16 2 /* Direct 16 bit. */ ++#define R_MN10300_8 3 /* Direct 8 bit. */ ++#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ ++#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ ++#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ ++#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ ++#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ ++#define R_MN10300_24 9 /* Direct 24 bit. */ ++#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ ++#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ ++#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ ++#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ ++#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ ++#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ ++#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ ++#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ ++#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ ++#define R_MN10300_COPY 20 /* Copy symbol at runtime. */ ++#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ ++#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ ++#define R_MN10300_RELATIVE 23 /* Adjust by program base. */ ++ ++#define R_MN10300_NUM 24 ++ ++ ++/* M32R relocs. */ ++#define R_M32R_NONE 0 /* No reloc. */ ++#define R_M32R_16 1 /* Direct 16 bit. */ ++#define R_M32R_32 2 /* Direct 32 bit. */ ++#define R_M32R_24 3 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ ++#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ ++#define R_M32R_LO16 9 /* Low 16 bit. */ ++#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ ++#define R_M32R_GNU_VTINHERIT 11 ++#define R_M32R_GNU_VTENTRY 12 ++/* M32R relocs use SHT_RELA. */ ++#define R_M32R_16_RELA 33 /* Direct 16 bit. */ ++#define R_M32R_32_RELA 34 /* Direct 32 bit. */ ++#define R_M32R_24_RELA 35 /* Direct 24 bit. */ ++#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ ++#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ ++#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ ++#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ ++#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ ++#define R_M32R_LO16_RELA 41 /* Low 16 bit */ ++#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ ++#define R_M32R_RELA_GNU_VTINHERIT 43 ++#define R_M32R_RELA_GNU_VTENTRY 44 ++#define R_M32R_REL32 45 /* PC relative 32 bit. */ ++ ++#define R_M32R_GOT24 48 /* 24 bit GOT entry */ ++#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ ++#define R_M32R_COPY 50 /* Copy symbol at runtime */ ++#define R_M32R_GLOB_DAT 51 /* Create GOT entry */ ++#define R_M32R_JMP_SLOT 52 /* Create PLT entry */ ++#define R_M32R_RELATIVE 53 /* Adjust by program base */ ++#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ ++#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ ++#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned ++ low */ ++#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed ++ low */ ++#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ ++#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to ++ GOT with unsigned low */ ++#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to ++ GOT with signed low */ ++#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to ++ GOT */ ++#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT ++ with unsigned low */ ++#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT ++ with signed low */ ++#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ ++#define R_M32R_NUM 256 /* Keep this the last entry. */ ++ ++ ++/* TILEPro relocations. */ ++#define R_TILEPRO_NONE 0 /* No reloc */ ++#define R_TILEPRO_32 1 /* Direct 32 bit */ ++#define R_TILEPRO_16 2 /* Direct 16 bit */ ++#define R_TILEPRO_8 3 /* Direct 8 bit */ ++#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */ ++#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */ ++#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */ ++#define R_TILEPRO_LO16 7 /* Low 16 bit */ ++#define R_TILEPRO_HI16 8 /* High 16 bit */ ++#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */ ++#define R_TILEPRO_COPY 10 /* Copy relocation */ ++#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */ ++#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */ ++#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */ ++#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */ ++#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */ ++#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */ ++#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */ ++#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */ ++#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */ ++#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */ ++#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */ ++#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */ ++#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */ ++#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */ ++#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */ ++#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */ ++#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */ ++#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */ ++#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */ ++#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */ ++#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */ ++#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */ ++#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */ ++#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */ ++#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */ ++#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */ ++/* Relocs 56-59 are currently not defined. */ ++#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */ ++#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */ ++#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */ ++#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */ ++#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */ ++#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */ ++#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */ ++#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */ ++ ++#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEPRO_NUM 130 ++ ++ ++/* TILE-Gx relocations. */ ++#define R_TILEGX_NONE 0 /* No reloc */ ++#define R_TILEGX_64 1 /* Direct 64 bit */ ++#define R_TILEGX_32 2 /* Direct 32 bit */ ++#define R_TILEGX_16 3 /* Direct 16 bit */ ++#define R_TILEGX_8 4 /* Direct 8 bit */ ++#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */ ++#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */ ++#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */ ++#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */ ++#define R_TILEGX_HW0 9 /* hword 0 16-bit */ ++#define R_TILEGX_HW1 10 /* hword 1 16-bit */ ++#define R_TILEGX_HW2 11 /* hword 2 16-bit */ ++#define R_TILEGX_HW3 12 /* hword 3 16-bit */ ++#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */ ++#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */ ++#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */ ++#define R_TILEGX_COPY 16 /* Copy relocation */ ++#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */ ++#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */ ++#define R_TILEGX_RELATIVE 19 /* Adjust by program base */ ++#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */ ++#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */ ++#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */ ++#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */ ++#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */ ++#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */ ++#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */ ++#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */ ++#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */ ++#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */ ++#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */ ++#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */ ++#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */ ++#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */ ++#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */ ++#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */ ++#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */ ++#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */ ++/* Relocs 66-71 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */ ++/* Relocs 76-77 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */ ++/* Relocs 90-91 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */ ++#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */ ++/* Relocs 94-99 are currently not defined. */ ++#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */ ++#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */ ++#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */ ++/* Relocs 104-105 are currently not defined. */ ++#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */ ++#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */ ++#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */ ++#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */ ++#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */ ++#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */ ++#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */ ++#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */ ++#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */ ++#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */ ++ ++#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */ ++#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */ ++ ++#define R_TILEGX_NUM 130 ++ ++#endif /* elf.h */ +--- a/scripts/mod/mk_elfconfig.c ++++ b/scripts/mod/mk_elfconfig.c +@@ -2,7 +2,11 @@ + #include + #include + #include ++#ifndef __APPLE__ + #include ++#else ++#include "elf.h" ++#endif + + int + main(int argc, char **argv) +--- a/scripts/mod/modpost.h ++++ b/scripts/mod/modpost.h +@@ -8,7 +8,11 @@ + #include + #include + #include ++#if !(defined(__APPLE__) || defined(__CYGWIN__)) + #include ++#else ++#include "elf.h" ++#endif + + #include "elfconfig.h" + diff --git a/target/linux/generic/hack-6.1/211-darwin-uuid-typedef-clash.patch b/target/linux/generic/hack-6.1/211-darwin-uuid-typedef-clash.patch new file mode 100644 index 00000000000..50a6227148f --- /dev/null +++ b/target/linux/generic/hack-6.1/211-darwin-uuid-typedef-clash.patch @@ -0,0 +1,22 @@ +From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Wed, 5 Feb 2020 18:36:43 +0000 +Subject: [PATCH] file2alias: build on macos + +Signed-off-by: Kevin Darbyshire-Bryant +--- + scripts/mod/file2alias.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -38,6 +38,9 @@ typedef struct { + __u8 b[16]; + } guid_t; + ++#ifdef __APPLE__ ++#define uuid_t compat_uuid_t ++#endif + /* backwards compatibility, don't use in new code */ + typedef struct { + __u8 b[16]; diff --git a/target/linux/generic/hack-6.1/212-tools_portability.patch b/target/linux/generic/hack-6.1/212-tools_portability.patch new file mode 100644 index 00000000000..b488155f942 --- /dev/null +++ b/target/linux/generic/hack-6.1/212-tools_portability.patch @@ -0,0 +1,110 @@ +From 48232d3d931c95953ce2ddfe7da7bb164aef6a73 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:03:16 +0200 +Subject: fix portability of some includes files in tools/ used on the host + +Signed-off-by: Felix Fietkau +--- + tools/include/tools/be_byteshift.h | 4 ++++ + tools/include/tools/le_byteshift.h | 4 ++++ + tools/include/tools/linux_types.h | 22 ++++++++++++++++++++++ + 3 files changed, 30 insertions(+) + create mode 100644 tools/include/tools/linux_types.h + +--- a/tools/include/tools/be_byteshift.h ++++ b/tools/include/tools/be_byteshift.h +@@ -2,6 +2,10 @@ + #ifndef _TOOLS_BE_BYTESHIFT_H + #define _TOOLS_BE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_be16(const uint8_t *p) +--- a/tools/include/tools/le_byteshift.h ++++ b/tools/include/tools/le_byteshift.h +@@ -2,6 +2,10 @@ + #ifndef _TOOLS_LE_BYTESHIFT_H + #define _TOOLS_LE_BYTESHIFT_H + ++#ifndef __linux__ ++#include "linux_types.h" ++#endif ++ + #include + + static inline uint16_t __get_unaligned_le16(const uint8_t *p) +--- /dev/null ++++ b/tools/include/tools/linux_types.h +@@ -0,0 +1,26 @@ ++#ifndef __LINUX_TYPES_H ++#define __LINUX_TYPES_H ++ ++#include ++ ++typedef int8_t __s8; ++typedef uint8_t __u8; ++typedef uint8_t __be8; ++typedef uint8_t __le8; ++ ++typedef int16_t __s16; ++typedef uint16_t __u16; ++typedef uint16_t __be16; ++typedef uint16_t __le16; ++ ++typedef int32_t __s32; ++typedef uint32_t __u32; ++typedef uint32_t __be32; ++typedef uint32_t __le32; ++ ++typedef int64_t __s64; ++typedef uint64_t __u64; ++typedef uint64_t __be64; ++typedef uint64_t __le64; ++ ++#endif +--- a/tools/include/linux/types.h ++++ b/tools/include/linux/types.h +@@ -10,8 +10,12 @@ + #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ + #endif + ++#ifndef __linux__ ++#include ++#else + #include + #include ++#endif + + struct page; + struct kmem_cache; +--- a/tools/perf/pmu-events/jevents.c ++++ b/tools/perf/pmu-events/jevents.c +@@ -1,4 +1,6 @@ ++#ifdef __linux__ + #define _XOPEN_SOURCE 500 /* needed for nftw() */ ++#endif + #define _GNU_SOURCE /* needed for asprintf() */ + + /* Parse event JSON files */ +@@ -35,6 +37,7 @@ + #include + #include + #include ++#include + #include + #include + #include +--- a/tools/perf/pmu-events/json.c ++++ b/tools/perf/pmu-events/json.c +@@ -38,7 +38,6 @@ + #include + #include "jsmn.h" + #include "json.h" +-#include + + + static char *mapfile(const char *fn, size_t *size) diff --git a/target/linux/generic/hack-6.1/214-spidev_h_portability.patch b/target/linux/generic/hack-6.1/214-spidev_h_portability.patch new file mode 100644 index 00000000000..db754a29033 --- /dev/null +++ b/target/linux/generic/hack-6.1/214-spidev_h_portability.patch @@ -0,0 +1,24 @@ +From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:04:08 +0200 +Subject: kernel: fix linux/spi/spidev.h portability issues with musl + +Felix will try to get this define included into musl + +lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/spi/spidev.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/uapi/linux/spi/spidev.h ++++ b/include/uapi/linux/spi/spidev.h +@@ -93,7 +93,7 @@ struct spi_ioc_transfer { + + /* not all platforms use or _IOC_TYPECHECK() ... */ + #define SPI_MSGSIZE(N) \ +- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \ ++ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \ + ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0) + #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) + diff --git a/target/linux/generic/hack-6.1/220-arm-gc_sections.patch b/target/linux/generic/hack-6.1/220-arm-gc_sections.patch new file mode 100644 index 00000000000..0aa3eb840cd --- /dev/null +++ b/target/linux/generic/hack-6.1/220-arm-gc_sections.patch @@ -0,0 +1,123 @@ +From e3d8676f5722b7622685581e06e8f53e6138e3ab Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 23:42:36 +0200 +Subject: use -ffunction-sections, -fdata-sections and --gc-sections + +In combination with kernel symbol export stripping this significantly reduces +the kernel image size. Used on both ARM and MIPS architectures. + +Signed-off-by: Felix Fietkau +Signed-off-by: Jonas Gorski +Signed-off-by: Gabor Juhos +--- +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -117,6 +117,7 @@ config ARM + select HAVE_UID16 + select HAVE_VIRT_CPU_ACCOUNTING_GEN + select IRQ_FORCED_THREADING ++ select HAVE_LD_DEAD_CODE_DATA_ELIMINATION + select MODULES_USE_ELF_REL + select NEED_DMA_MAP_STATE + select OF_EARLY_FLATTREE if OF +--- a/arch/arm/boot/compressed/Makefile ++++ b/arch/arm/boot/compressed/Makefile +@@ -92,6 +92,7 @@ endif + ifeq ($(CONFIG_USE_OF),y) + OBJS += $(libfdt_objs) fdt_check_mem_start.o + endif ++KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) + + # -fstack-protector-strong triggers protection checks in this code, + # but it is being used too early to link to meaningful stack_chk logic. +--- a/arch/arm/kernel/vmlinux.lds.S ++++ b/arch/arm/kernel/vmlinux.lds.S +@@ -75,7 +75,7 @@ SECTIONS + . = ALIGN(4); + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; +- ARM_MMU_KEEP(*(__ex_table)) ++ KEEP(*(__ex_table)) + __stop___ex_table = .; + } + +@@ -100,24 +100,24 @@ SECTIONS + } + .init.arch.info : { + __arch_info_begin = .; +- *(.arch.info.init) ++ KEEP(*(.arch.info.init)) + __arch_info_end = .; + } + .init.tagtable : { + __tagtable_begin = .; +- *(.taglist.init) ++ KEEP(*(.taglist.init)) + __tagtable_end = .; + } + #ifdef CONFIG_SMP_ON_UP + .init.smpalt : { + __smpalt_begin = .; +- *(.alt.smp.init) ++ KEEP(*(.alt.smp.init)) + __smpalt_end = .; + } + #endif + .init.pv_table : { + __pv_table_begin = .; +- *(.pv_table) ++ KEEP(*(.pv_table)) + __pv_table_end = .; + } + +--- a/arch/arm/include/asm/vmlinux.lds.h ++++ b/arch/arm/include/asm/vmlinux.lds.h +@@ -42,13 +42,13 @@ + #define PROC_INFO \ + . = ALIGN(4); \ + __proc_info_begin = .; \ +- *(.proc.info.init) \ ++ KEEP(*(.proc.info.init)) \ + __proc_info_end = .; + + #define IDMAP_TEXT \ + ALIGN_FUNCTION(); \ + __idmap_text_start = .; \ +- *(.idmap.text) \ ++ KEEP(*(.idmap.text)) \ + __idmap_text_end = .; \ + + #define ARM_DISCARD \ +@@ -109,12 +109,12 @@ + . = ALIGN(8); \ + .ARM.unwind_idx : { \ + __start_unwind_idx = .; \ +- *(.ARM.exidx*) \ ++ KEEP(*(.ARM.exidx*)) \ + __stop_unwind_idx = .; \ + } \ + .ARM.unwind_tab : { \ + __start_unwind_tab = .; \ +- *(.ARM.extab*) \ ++ KEEP(*(.ARM.extab*)) \ + __stop_unwind_tab = .; \ + } + +@@ -126,7 +126,7 @@ + __vectors_lma = .; \ + OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \ + .vectors { \ +- *(.vectors) \ ++ KEEP(*(.vectors)) \ + } \ + .vectors.bhb.loop8 { \ + *(.vectors.bhb.loop8) \ +@@ -144,7 +144,7 @@ + \ + __stubs_lma = .; \ + .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) { \ +- *(.stubs) \ ++ KEEP(*(.stubs)) \ + } \ + ARM_LMA(__stubs, .stubs); \ + . = __stubs_lma + SIZEOF(.stubs); \ diff --git a/target/linux/generic/hack-6.1/221-module_exports.patch b/target/linux/generic/hack-6.1/221-module_exports.patch new file mode 100644 index 00000000000..87f541b46f2 --- /dev/null +++ b/target/linux/generic/hack-6.1/221-module_exports.patch @@ -0,0 +1,126 @@ +From b14784e7883390c20ed3ff904892255404a5914b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:05:53 +0200 +Subject: add an optional config option for stripping all unnecessary symbol exports from the kernel image + +lede-commit: bb5a40c64b7c4f4848509fa0a6625055fc9e66cc +Signed-off-by: Felix Fietkau +--- + include/asm-generic/vmlinux.lds.h | 18 +++++++++++++++--- + include/linux/export.h | 9 ++++++++- + scripts/Makefile.build | 2 +- + 3 files changed, 24 insertions(+), 5 deletions(-) + +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -81,6 +81,16 @@ + #define RO_EXCEPTION_TABLE + #endif + ++#ifndef SYMTAB_KEEP ++#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*))) ++#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*))) ++#endif ++ ++#ifndef SYMTAB_DISCARD ++#define SYMTAB_DISCARD ++#define SYMTAB_DISCARD_GPL ++#endif ++ + /* Align . to a 8 byte boundary equals to maximum function alignment. */ + #define ALIGN_FUNCTION() . = ALIGN(8) + +@@ -485,14 +495,14 @@ + /* Kernel symbol table: Normal symbols */ \ + __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ + __start___ksymtab = .; \ +- KEEP(*(SORT(___ksymtab+*))) \ ++ SYMTAB_KEEP \ + __stop___ksymtab = .; \ + } \ + \ + /* Kernel symbol table: GPL-only symbols */ \ + __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ + __start___ksymtab_gpl = .; \ +- KEEP(*(SORT(___ksymtab_gpl+*))) \ ++ SYMTAB_KEEP_GPL \ + __stop___ksymtab_gpl = .; \ + } \ + \ +@@ -512,7 +522,7 @@ + \ + /* Kernel symbol table: strings */ \ + __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ +- *(__ksymtab_strings) \ ++ *(__ksymtab_strings+*) \ + } \ + \ + /* __*init sections */ \ +@@ -1022,6 +1032,8 @@ + + #define COMMON_DISCARDS \ + SANITIZER_DISCARDS \ ++ SYMTAB_DISCARD \ ++ SYMTAB_DISCARD_GPL \ + *(.discard) \ + *(.discard.*) \ + *(.modinfo) \ +--- a/include/linux/export.h ++++ b/include/linux/export.h +@@ -84,6 +84,12 @@ struct kernel_symbol { + + #else + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(sym) ++#else ++#define __EXPORT_SUFFIX(sym) "+" #sym ++#endif ++ + /* + * For every exported symbol, do the following: + * +@@ -101,7 +107,7 @@ struct kernel_symbol { + extern const char __kstrtab_##sym[]; \ + extern const char __kstrtabns_##sym[]; \ + __CRC_SYMBOL(sym, sec); \ +- asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1 \n" \ ++ asm(" .section \"__ksymtab_strings" __EXPORT_SUFFIX(sym) "\",\"aMS\",%progbits,1 \n" \ + "__kstrtab_" #sym ": \n" \ + " .asciz \"" #sym "\" \n" \ + "__kstrtabns_" #sym ": \n" \ +--- a/include/asm-generic/export.h ++++ b/include/asm-generic/export.h +@@ -26,6 +26,12 @@ + #endif + .endm + ++#ifdef MODULE ++#define __EXPORT_SUFFIX(name) ++#else ++#define __EXPORT_SUFFIX(name) + #name ++#endif ++ + /* + * note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) + * section flag requires it. Use '%progbits' instead of '@progbits' since the +@@ -39,7 +45,7 @@ + __ksymtab_\name: + __put \val, __kstrtab_\name + .previous +- .section __ksymtab_strings,"aMS",%progbits,1 ++ .section __ksymtab_strings __EXPORT_SUFFIX(name),"aMS",%progbits,1 + __kstrtab_\name: + .asciz "\name" + .previous +--- a/scripts/Makefile.build ++++ b/scripts/Makefile.build +@@ -397,7 +397,7 @@ targets += $(real-dtb-y) $(lib-y) $(alwa + # Linker scripts preprocessor (.lds.S -> .lds) + # --------------------------------------------------------------------------- + quiet_cmd_cpp_lds_S = LDS $@ +- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \ ++ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -U$(ARCH) \ + -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< + + $(obj)/%.lds: $(src)/%.lds.S FORCE diff --git a/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch new file mode 100644 index 00000000000..f9361b060bd --- /dev/null +++ b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch @@ -0,0 +1,34 @@ +From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:06:55 +0200 +Subject: use the openwrt lzma options for now + +lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c +Signed-off-by: Imre Kaloz +--- + lib/decompress.c | 1 + + scripts/Makefile.lib | 2 +- + usr/gen_initramfs_list.sh | 10 +++++----- + 3 files changed, 7 insertions(+), 6 deletions(-) + +--- a/lib/decompress.c ++++ b/lib/decompress.c +@@ -53,6 +53,7 @@ static const struct compress_format comp + { {0x1f, 0x9e}, "gzip", gunzip }, + { {0x42, 0x5a}, "bzip2", bunzip2 }, + { {0x5d, 0x00}, "lzma", unlzma }, ++ { {0x6d, 0x00}, "lzma-openwrt", unlzma }, + { {0xfd, 0x37}, "xz", unxz }, + { {0x89, 0x4c}, "lzo", unlzo }, + { {0x02, 0x21}, "lz4", unlz4 }, +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -402,7 +402,7 @@ quiet_cmd_bzip2 = BZIP2 $@ + # --------------------------------------------------------------------------- + + quiet_cmd_lzma = LZMA $@ +- cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ ++ cmd_lzma = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ + + quiet_cmd_lzo = LZO $@ + cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ diff --git a/target/linux/generic/hack-6.1/250-netfilter_depends.patch b/target/linux/generic/hack-6.1/250-netfilter_depends.patch new file mode 100644 index 00000000000..d9a2b81d743 --- /dev/null +++ b/target/linux/generic/hack-6.1/250-netfilter_depends.patch @@ -0,0 +1,27 @@ +From: Felix Fietkau +Subject: hack: net: remove bogus netfilter dependencies + +lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6 +Signed-off-by: Felix Fietkau +--- + net/netfilter/Kconfig | 2 -- + 1 file changed, 2 deletions(-) + +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -242,7 +242,6 @@ config NF_CONNTRACK_FTP + + config NF_CONNTRACK_H323 + tristate "H.323 protocol support" +- depends on IPV6 || IPV6=n + depends on NETFILTER_ADVANCED + help + H.323 is a VoIP signalling protocol from ITU-T. As one of the most +@@ -1105,7 +1104,6 @@ config NETFILTER_XT_TARGET_SECMARK + + config NETFILTER_XT_TARGET_TCPMSS + tristate '"TCPMSS" target support' +- depends on IPV6 || IPV6=n + default m if NETFILTER_ADVANCED=n + help + This option adds a `TCPMSS' target, which allows you to alter the diff --git a/target/linux/generic/hack-6.1/251-kconfig.patch b/target/linux/generic/hack-6.1/251-kconfig.patch new file mode 100644 index 00000000000..0e24c3e8041 --- /dev/null +++ b/target/linux/generic/hack-6.1/251-kconfig.patch @@ -0,0 +1,210 @@ +From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:09:21 +0200 +Subject: kconfig: owrt specifc dependencies + +Signed-off-by: John Crispin +--- + crypto/Kconfig | 10 +++++----- + drivers/bcma/Kconfig | 1 + + drivers/ssb/Kconfig | 3 ++- + lib/Kconfig | 8 ++++---- + net/netfilter/Kconfig | 2 +- + net/wireless/Kconfig | 17 ++++++++++------- + sound/core/Kconfig | 4 ++-- + 7 files changed, 25 insertions(+), 20 deletions(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -34,7 +34,7 @@ config CRYPTO_FIPS + this is. + + config CRYPTO_ALGAPI +- tristate ++ tristate "ALGAPI" + select CRYPTO_ALGAPI2 + help + This option provides the API for cryptographic algorithms. +@@ -43,7 +43,7 @@ config CRYPTO_ALGAPI2 + tristate + + config CRYPTO_AEAD +- tristate ++ tristate "AEAD" + select CRYPTO_AEAD2 + select CRYPTO_ALGAPI + +@@ -54,7 +54,7 @@ config CRYPTO_AEAD2 + select CRYPTO_RNG2 + + config CRYPTO_SKCIPHER +- tristate ++ tristate "SKCIPHER" + select CRYPTO_SKCIPHER2 + select CRYPTO_ALGAPI + +@@ -64,7 +64,7 @@ config CRYPTO_SKCIPHER2 + select CRYPTO_RNG2 + + config CRYPTO_HASH +- tristate ++ tristate "HASH" + select CRYPTO_HASH2 + select CRYPTO_ALGAPI + +@@ -73,7 +73,7 @@ config CRYPTO_HASH2 + select CRYPTO_ALGAPI2 + + config CRYPTO_RNG +- tristate ++ tristate "RNG" + select CRYPTO_RNG2 + select CRYPTO_ALGAPI + +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -16,6 +16,7 @@ if BCMA + # Support for Block-I/O. SELECT this from the driver that needs it. + config BCMA_BLOCKIO + bool ++ default y + + config BCMA_HOST_PCI_POSSIBLE + bool +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -29,6 +29,7 @@ config SSB_SPROM + config SSB_BLOCKIO + bool + depends on SSB ++ default y + + config SSB_PCIHOST_POSSIBLE + bool +@@ -49,7 +50,7 @@ config SSB_PCIHOST + config SSB_B43_PCI_BRIDGE + bool + depends on SSB_PCIHOST +- default n ++ default y + + config SSB_PCMCIAHOST_POSSIBLE + bool +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -443,16 +443,16 @@ config BCH_CONST_T + # Textsearch support is select'ed if needed + # + config TEXTSEARCH +- bool ++ bool "Textsearch support" + + config TEXTSEARCH_KMP +- tristate ++ tristate "Textsearch KMP" + + config TEXTSEARCH_BM +- tristate ++ tristate "Textsearch BM" + + config TEXTSEARCH_FSM +- tristate ++ tristate "Textsearch FSM" + + config BTREE + bool +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -11,7 +11,7 @@ config NETFILTER_INGRESS + infrastructure. + + config NETFILTER_NETLINK +- tristate ++ tristate "Netfilter NFNETLINK interface" + + config NETFILTER_FAMILY_BRIDGE + bool +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -1,6 +1,6 @@ + # SPDX-License-Identifier: GPL-2.0-only + config WIRELESS_EXT +- bool ++ bool "Wireless extensions" + + config WEXT_CORE + def_bool y +@@ -12,10 +12,10 @@ config WEXT_PROC + depends on WEXT_CORE + + config WEXT_SPY +- bool ++ bool "WEXT_SPY" + + config WEXT_PRIV +- bool ++ bool "WEXT_PRIV" + + config CFG80211 + tristate "cfg80211 - wireless configuration API" +@@ -204,7 +204,7 @@ config CFG80211_WEXT_EXPORT + endif # CFG80211 + + config LIB80211 +- tristate ++ tristate "LIB80211" + default n + help + This options enables a library of common routines used +@@ -213,17 +213,17 @@ config LIB80211 + Drivers should select this themselves if needed. + + config LIB80211_CRYPT_WEP +- tristate ++ tristate "LIB80211_CRYPT_WEP" + select CRYPTO_LIB_ARC4 + + config LIB80211_CRYPT_CCMP +- tristate ++ tristate "LIB80211_CRYPT_CCMP" + select CRYPTO + select CRYPTO_AES + select CRYPTO_CCM + + config LIB80211_CRYPT_TKIP +- tristate ++ tristate "LIB80211_CRYPT_TKIP" + select CRYPTO_LIB_ARC4 + + config LIB80211_DEBUG +--- a/sound/core/Kconfig ++++ b/sound/core/Kconfig +@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM + tristate + + config SND_HWDEP +- tristate ++ tristate "Sound hardware support" + + config SND_SEQ_DEVICE + tristate +@@ -27,7 +27,7 @@ config SND_RAWMIDI + select SND_SEQ_DEVICE if SND_SEQUENCER != n + + config SND_COMPRESS_OFFLOAD +- tristate ++ tristate "Compression offloading support" + + config SND_JACK + bool +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -432,7 +432,7 @@ config NET_DEVLINK + default n + + config PAGE_POOL +- bool ++ bool "Page pool support" + + config PAGE_POOL_STATS + default n diff --git a/target/linux/generic/hack-6.1/253-ksmbd-config.patch b/target/linux/generic/hack-6.1/253-ksmbd-config.patch new file mode 100644 index 00000000000..b8cb94f62bc --- /dev/null +++ b/target/linux/generic/hack-6.1/253-ksmbd-config.patch @@ -0,0 +1,32 @@ +From dcd966fa7ca63f38cf7147e1184d13d66e2ca340 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:33:30 +0200 +Subject: [PATCH] Kconfig: add tristate for OID and ASNI string + +--- + init/Kconfig | 2 +- + lib/Kconfig | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -2388,7 +2388,7 @@ config PADATA + bool + + config ASN1 +- tristate ++ tristate "ASN1" + help + Build a simple ASN.1 grammar compiler that produces a bytecode output + that can be interpreted by the ASN.1 stream decoder and used to +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -614,7 +614,7 @@ config LIBFDT + bool + + config OID_REGISTRY +- tristate ++ tristate "OID" + help + Enable fast lookup object identifier registry. + diff --git a/target/linux/generic/hack-6.1/259-regmap_dynamic.patch b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch new file mode 100644 index 00000000000..76a5ace6f31 --- /dev/null +++ b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch @@ -0,0 +1,144 @@ +From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 15 Jul 2017 21:12:38 +0200 +Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules + +lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998 +Signed-off-by: Felix Fietkau +--- + drivers/base/regmap/Kconfig | 15 ++++++++++----- + drivers/base/regmap/Makefile | 12 ++++++++---- + drivers/base/regmap/regmap.c | 3 +++ + include/linux/regmap.h | 2 +- + 4 files changed, 22 insertions(+), 10 deletions(-) + +--- a/drivers/base/regmap/Kconfig ++++ b/drivers/base/regmap/Kconfig +@@ -4,10 +4,9 @@ + # subsystems should select the appropriate symbols. + + config REGMAP +- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO) + select IRQ_DOMAIN if REGMAP_IRQ + select MDIO_BUS if REGMAP_MDIO +- bool ++ tristate + + config REGCACHE_COMPRESSED + select LZO_COMPRESS +@@ -15,53 +14,67 @@ config REGCACHE_COMPRESSED + bool + + config REGMAP_AC97 ++ select REGMAP + tristate + + config REGMAP_I2C ++ select REGMAP + tristate + depends on I2C + + config REGMAP_SLIMBUS ++ select REGMAP + tristate + depends on SLIMBUS + + config REGMAP_SPI ++ select REGMAP + tristate + depends on SPI + + config REGMAP_SPMI ++ select REGMAP + tristate + depends on SPMI + + config REGMAP_W1 ++ select REGMAP + tristate + depends on W1 + + config REGMAP_MDIO ++ select REGMAP + tristate + + config REGMAP_MMIO ++ select REGMAP + tristate + + config REGMAP_IRQ ++ select REGMAP + bool + + config REGMAP_SOUNDWIRE ++ select REGMAP + tristate + depends on SOUNDWIRE + + config REGMAP_SOUNDWIRE_MBQ ++ select REGMAP + tristate + depends on SOUNDWIRE + + config REGMAP_SCCB ++ select REGMAP + tristate + depends on I2C + + config REGMAP_I3C ++ select REGMAP + tristate + depends on I3C + + config REGMAP_SPI_AVMM ++ select REGMAP + tristate + depends on SPI +--- a/drivers/base/regmap/Makefile ++++ b/drivers/base/regmap/Makefile +@@ -2,10 +2,14 @@ + # For include/trace/define_trace.h to include trace.h + CFLAGS_regmap.o := -I$(src) + +-obj-$(CONFIG_REGMAP) += regmap.o regcache.o +-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o +-obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o +-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o ++regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o ++ifdef CONFIG_DEBUG_FS ++regmap-core-objs += regmap-debugfs.o ++endif ++ifdef CONFIG_REGCACHE_COMPRESSED ++regmap-core-objs += regcache-lzo.o ++endif ++obj-$(CONFIG_REGMAP) += regmap-core.o + obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o + obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o + obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o +--- a/drivers/base/regmap/regmap.c ++++ b/drivers/base/regmap/regmap.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -3358,3 +3359,5 @@ static int __init regmap_initcall(void) + return 0; + } + postcore_initcall(regmap_initcall); ++ ++MODULE_LICENSE("GPL"); +--- a/include/linux/regmap.h ++++ b/include/linux/regmap.h +@@ -180,7 +180,7 @@ struct reg_sequence { + __ret ?: __tmp; \ + }) + +-#ifdef CONFIG_REGMAP ++#if IS_REACHABLE(CONFIG_REGMAP) + + enum regmap_endian { + /* Unspecified -> 0 -> Backwards compatible default */ diff --git a/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch b/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch new file mode 100644 index 00000000000..64daa827439 --- /dev/null +++ b/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch @@ -0,0 +1,52 @@ +From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:12:51 +0200 +Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run + +Reduces kernel size after LZMA by about 5k on MIPS + +lede-commit: 044c316167e076479a344c59905e5b435b84a77f +Signed-off-by: Felix Fietkau +--- + crypto/Kconfig | 13 ++++++------- + crypto/algboss.c | 4 ++++ + 2 files changed, 10 insertions(+), 7 deletions(-) + +--- a/crypto/Kconfig ++++ b/crypto/Kconfig +@@ -121,13 +121,13 @@ config CRYPTO_MANAGER + cbc(aes). + + config CRYPTO_MANAGER2 +- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) +- select CRYPTO_AEAD2 +- select CRYPTO_HASH2 +- select CRYPTO_SKCIPHER2 +- select CRYPTO_AKCIPHER2 +- select CRYPTO_KPP2 +- select CRYPTO_ACOMP2 ++ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS) ++ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_SKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS ++ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS + + config CRYPTO_USER + tristate "Userspace cryptographic algorithm configuration" +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -211,8 +211,12 @@ static int cryptomgr_schedule_test(struc + type = alg->cra_flags; + + /* Do not test internal algorithms. */ ++#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS ++ type |= CRYPTO_ALG_TESTED; ++#else + if (type & CRYPTO_ALG_INTERNAL) + type |= CRYPTO_ALG_TESTED; ++#endif + + param->type = type; + diff --git a/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch b/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch new file mode 100644 index 00000000000..ee923c73f75 --- /dev/null +++ b/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch @@ -0,0 +1,24 @@ +From 241e5d3f7b0dd3c01f8c7fa83cbc9a3882286d53 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:35:18 +0200 +Subject: [PATCH] lib/crypto: add tristate string for ARC4 + +This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We +need this to be able to compile this into the kernel and make use of it +from backports. + +--- + lib/crypto/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/lib/crypto/Kconfig ++++ b/lib/crypto/Kconfig +@@ -6,7 +6,7 @@ config CRYPTO_LIB_AES + tristate + + config CRYPTO_LIB_ARC4 +- tristate ++ tristate "ARC4 cipher library" + + config CRYPTO_ARCH_HAVE_LIB_BLAKE2S + bool diff --git a/target/linux/generic/hack-6.1/280-rfkill-stubs.patch b/target/linux/generic/hack-6.1/280-rfkill-stubs.patch new file mode 100644 index 00000000000..7a650d132eb --- /dev/null +++ b/target/linux/generic/hack-6.1/280-rfkill-stubs.patch @@ -0,0 +1,84 @@ +From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Fri, 7 Jul 2017 17:13:44 +0200 +Subject: rfkill: add fake rfkill support + +allow building of modules depending on RFKILL even if RFKILL is not enabled. + +Signed-off-by: John Crispin +--- + include/linux/rfkill.h | 2 +- + net/Makefile | 2 +- + net/rfkill/Kconfig | 14 +++++++++----- + net/rfkill/Makefile | 2 +- + 4 files changed, 12 insertions(+), 8 deletions(-) + +--- a/include/linux/rfkill.h ++++ b/include/linux/rfkill.h +@@ -64,7 +64,7 @@ struct rfkill_ops { + int (*set_block)(void *data, bool blocked); + }; + +-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ++#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE) + /** + * rfkill_alloc - Allocate rfkill structure + * @name: name of the struct -- the string is not copied internally +--- a/net/Makefile ++++ b/net/Makefile +@@ -52,7 +52,7 @@ obj-$(CONFIG_TIPC) += tipc/ + obj-$(CONFIG_NETLABEL) += netlabel/ + obj-$(CONFIG_IUCV) += iucv/ + obj-$(CONFIG_SMC) += smc/ +-obj-$(CONFIG_RFKILL) += rfkill/ ++obj-$(CONFIG_RFKILL_FULL) += rfkill/ + obj-$(CONFIG_NET_9P) += 9p/ + obj-$(CONFIG_CAIF) += caif/ + obj-$(CONFIG_DCB) += dcb/ +--- a/net/rfkill/Kconfig ++++ b/net/rfkill/Kconfig +@@ -2,7 +2,11 @@ + # + # RF switch subsystem configuration + # +-menuconfig RFKILL ++config RFKILL ++ bool ++ default y ++ ++menuconfig RFKILL_FULL + tristate "RF switch subsystem support" + help + Say Y here if you want to have control over RF switches +@@ -14,19 +18,19 @@ menuconfig RFKILL + # LED trigger support + config RFKILL_LEDS + bool +- depends on RFKILL ++ depends on RFKILL_FULL + depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS + default y + + config RFKILL_INPUT + bool "RF switch input support" if EXPERT +- depends on RFKILL ++ depends on RFKILL_FULL + depends on INPUT = y || RFKILL = INPUT + default y if !EXPERT + + config RFKILL_GPIO + tristate "GPIO RFKILL driver" +- depends on RFKILL ++ depends on RFKILL_FULL + depends on GPIOLIB || COMPILE_TEST + default n + help +--- a/net/rfkill/Makefile ++++ b/net/rfkill/Makefile +@@ -5,5 +5,5 @@ + + rfkill-y += core.o + rfkill-$(CONFIG_RFKILL_INPUT) += input.o +-obj-$(CONFIG_RFKILL) += rfkill.o ++obj-$(CONFIG_RFKILL_FULL) += rfkill.o + obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o diff --git a/target/linux/generic/hack-6.1/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch b/target/linux/generic/hack-6.1/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch new file mode 100644 index 00000000000..f21f200136f --- /dev/null +++ b/target/linux/generic/hack-6.1/300-MIPS-r4k_cache-use-more-efficient-cache-blast.patch @@ -0,0 +1,64 @@ +From: Ben Menchaca +Date: Fri, 7 Jun 2013 18:35:22 -0500 +Subject: MIPS: r4k_cache: use more efficient cache blast + +Optimize the compiler output for larger cache blast cases that are +common for DMA-based networking. + +Signed-off-by: Ben Menchaca +Signed-off-by: Felix Fietkau +--- +--- a/arch/mips/include/asm/r4kcache.h ++++ b/arch/mips/include/asm/r4kcache.h +@@ -286,14 +286,46 @@ static inline void prot##extra##blast_## + unsigned long end) \ + { \ + unsigned long lsize = cpu_##desc##_line_size(); \ ++ unsigned long lsize_2 = lsize * 2; \ ++ unsigned long lsize_3 = lsize * 3; \ ++ unsigned long lsize_4 = lsize * 4; \ ++ unsigned long lsize_5 = lsize * 5; \ ++ unsigned long lsize_6 = lsize * 6; \ ++ unsigned long lsize_7 = lsize * 7; \ ++ unsigned long lsize_8 = lsize * 8; \ + unsigned long addr = start & ~(lsize - 1); \ +- unsigned long aend = (end - 1) & ~(lsize - 1); \ ++ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \ ++ int lines = (aend - addr) / lsize; \ + \ +- while (1) { \ ++ while (lines >= 8) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ prot##cache_op(hitop, addr + lsize_4); \ ++ prot##cache_op(hitop, addr + lsize_5); \ ++ prot##cache_op(hitop, addr + lsize_6); \ ++ prot##cache_op(hitop, addr + lsize_7); \ ++ addr += lsize_8; \ ++ lines -= 8; \ ++ } \ ++ \ ++ if (lines & 0x4) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ prot##cache_op(hitop, addr + lsize_2); \ ++ prot##cache_op(hitop, addr + lsize_3); \ ++ addr += lsize_4; \ ++ } \ ++ \ ++ if (lines & 0x2) { \ ++ prot##cache_op(hitop, addr); \ ++ prot##cache_op(hitop, addr + lsize); \ ++ addr += lsize_2; \ ++ } \ ++ \ ++ if (lines & 0x1) { \ + prot##cache_op(hitop, addr); \ +- if (addr == aend) \ +- break; \ +- addr += lsize; \ + } \ + } + diff --git a/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch new file mode 100644 index 00000000000..f1942e20375 --- /dev/null +++ b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch @@ -0,0 +1,38 @@ +From 107c0964cb8db7ca28ac5199426414fdab3c274d Mon Sep 17 00:00:00 2001 +From: "Alexandros C. Couloumbis" +Date: Fri, 7 Jul 2017 17:14:51 +0200 +Subject: hack: arch: powerpc: drop register save/restore library from modules + +Upstream GCC uses a libgcc function for saving/restoring registers. This +makes the code bigger, and upstream kernels need to carry that function +for every single kernel module. Our GCC is patched to avoid those +references, so we can drop the extra bloat for modules. + +lede-commit: e8e1084654f50904e6bf77b70b2de3f137d7b3ec +Signed-off-by: Alexandros C. Couloumbis +--- + arch/powerpc/Makefile | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/powerpc/Makefile ++++ b/arch/powerpc/Makefile +@@ -44,19 +44,6 @@ machine-$(CONFIG_PPC64) += 64 + machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le + UTS_MACHINE := $(subst $(space),,$(machine-y)) + +-# XXX This needs to be before we override LD below +-ifdef CONFIG_PPC32 +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +-else +-ifeq ($(call ld-ifversion, -ge, 22500, y),y) +-# Have the linker provide sfpr if possible. +-# There is a corresponding test in arch/powerpc/lib/Makefile +-KBUILD_LDFLAGS_MODULE += --save-restore-funcs +-else +-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o +-endif +-endif +- + ifdef CONFIG_CPU_LITTLE_ENDIAN + KBUILD_CFLAGS += -mlittle-endian + KBUILD_LDFLAGS += -EL diff --git a/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch new file mode 100644 index 00000000000..32a7fb62664 --- /dev/null +++ b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch @@ -0,0 +1,98 @@ +From 0bccc3722bdd88e8ae995e77ef9f7b77ee4cbdee Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 7 Apr 2021 22:45:54 +0100 +Subject: [PATCH 2/2] mtd: blktrans: call add disks after mtd device +To: linux-mtd@lists.infradead.org +Cc: Vignesh Raghavendra , + Richard Weinberger , + Miquel Raynal , + David Woodhouse + +Calling device_add_disk while holding mtd_table_mutex leads +to deadlock in case part_bits!=0 as block partition parsers +will try to open the newly created disks, trying to acquire +mutex once again. +Move device_add_disk to additional function called after +add partitions of an MTD device have been added and locks +have been released. + +Signed-off-by: Daniel Golle +--- + drivers/mtd/mtd_blkdevs.c | 33 ++++++++++++++++++++++++++------- + drivers/mtd/mtdcore.c | 3 +++ + include/linux/mtd/blktrans.h | 1 + + 3 files changed, 30 insertions(+), 7 deletions(-) + +--- a/drivers/mtd/mtd_blkdevs.c ++++ b/drivers/mtd/mtd_blkdevs.c +@@ -384,13 +384,6 @@ int add_mtd_blktrans_dev(struct mtd_blkt + if (new->readonly) + set_disk_ro(gd, 1); + +- device_add_disk(&new->mtd->dev, gd, NULL); +- +- if (new->disk_attributes) { +- ret = sysfs_create_group(&disk_to_dev(gd)->kobj, +- new->disk_attributes); +- WARN_ON(ret); +- } + return 0; + + out_free_tag_set: +@@ -402,6 +395,27 @@ out_list_del: + return ret; + } + ++void register_mtd_blktrans_devs(void) ++{ ++ struct mtd_blktrans_ops *tr; ++ struct mtd_blktrans_dev *dev, *next; ++ int ret; ++ ++ list_for_each_entry(tr, &blktrans_majors, list) { ++ list_for_each_entry_safe(dev, next, &tr->devs, list) { ++ if (disk_live(dev->disk)) ++ continue; ++ ++ device_add_disk(&dev->mtd->dev, dev->disk, NULL); ++ if (dev->disk_attributes) { ++ ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj, ++ dev->disk_attributes); ++ WARN_ON(ret); ++ } ++ } ++ } ++} ++ + int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) + { + unsigned long flags; +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -32,6 +32,7 @@ + + #include + #include ++#include + + #include "mtdcore.h" + +@@ -1082,6 +1083,8 @@ int mtd_device_parse_register(struct mtd + register_reboot_notifier(&mtd->reboot_notifier); + } + ++ register_mtd_blktrans_devs(); ++ + out: + if (ret) { + nvmem_unregister(mtd->otp_user_nvmem); +--- a/include/linux/mtd/blktrans.h ++++ b/include/linux/mtd/blktrans.h +@@ -76,6 +76,7 @@ extern int deregister_mtd_blktrans(struc + extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev); ++extern void register_mtd_blktrans_devs(void); + + /** + * module_mtd_blktrans() - Helper macro for registering a mtd blktrans driver diff --git a/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch new file mode 100644 index 00000000000..96c89f41c48 --- /dev/null +++ b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch @@ -0,0 +1,214 @@ +From 69357074558daf6ff24c9f58714935e9e095a865 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:37:33 +0200 +Subject: [PATCH] kernel: add block fit partition parser + +--- + block/blk.h | 2 ++ + block/partitions/Kconfig | 7 +++++++ + block/partitions/Makefile | 1 + + block/partitions/check.h | 3 +++ + block/partitions/core.c | 17 +++++++++++++++++ + block/partitions/efi.c | 8 ++++++++ + block/partitions/efi.h | 3 +++ + block/partitions/msdos.c | 10 ++++++++++ + drivers/mtd/mtd_blkdevs.c | 2 ++ + drivers/mtd/ubi/block.c | 3 +++ + include/linux/msdos_partition.h | 1 + + 11 files changed, 57 insertions(+) + +--- a/block/blk.h ++++ b/block/blk.h +@@ -354,6 +354,8 @@ void blk_free_ext_minor(unsigned int min + #define ADDPART_FLAG_NONE 0 + #define ADDPART_FLAG_RAID 1 + #define ADDPART_FLAG_WHOLEDISK 2 ++#define ADDPART_FLAG_READONLY 4 ++#define ADDPART_FLAG_ROOTDEV 8 + int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, + sector_t length); + int bdev_del_partition(struct gendisk *disk, int partno); +--- a/block/partitions/Kconfig ++++ b/block/partitions/Kconfig +@@ -101,6 +101,13 @@ config ATARI_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned under the Atari OS. + ++config FIT_PARTITION ++ bool "Flattened-Image-Tree (FIT) partition support" if PARTITION_ADVANCED ++ default n ++ help ++ Say Y here if your system needs to mount the filesystem part of ++ a Flattened-Image-Tree (FIT) image commonly used with Das U-Boot. ++ + config IBM_PARTITION + bool "IBM disk label and partition support" + depends on PARTITION_ADVANCED && S390 +--- a/block/partitions/Makefile ++++ b/block/partitions/Makefile +@@ -8,6 +8,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o + obj-$(CONFIG_AMIGA_PARTITION) += amiga.o + obj-$(CONFIG_ATARI_PARTITION) += atari.o + obj-$(CONFIG_AIX_PARTITION) += aix.o ++obj-$(CONFIG_FIT_PARTITION) += fit.o + obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o + obj-$(CONFIG_MAC_PARTITION) += mac.o + obj-$(CONFIG_LDM_PARTITION) += ldm.o +--- a/block/partitions/check.h ++++ b/block/partitions/check.h +@@ -58,6 +58,7 @@ int amiga_partition(struct parsed_partit + int atari_partition(struct parsed_partitions *state); + int cmdline_partition(struct parsed_partitions *state); + int efi_partition(struct parsed_partitions *state); ++int fit_partition(struct parsed_partitions *state); + int ibm_partition(struct parsed_partitions *); + int karma_partition(struct parsed_partitions *state); + int ldm_partition(struct parsed_partitions *state); +@@ -68,3 +69,5 @@ int sgi_partition(struct parsed_partitio + int sun_partition(struct parsed_partitions *state); + int sysv68_partition(struct parsed_partitions *state); + int ultrix_partition(struct parsed_partitions *state); ++ ++int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain); +--- a/block/partitions/core.c ++++ b/block/partitions/core.c +@@ -12,6 +12,10 @@ + #include + #include + #include ++#ifdef CONFIG_FIT_PARTITION ++#include ++#endif ++ + #include "check.h" + + static int (*check_part[])(struct parsed_partitions *) = { +@@ -48,6 +52,9 @@ static int (*check_part[])(struct parsed + #ifdef CONFIG_EFI_PARTITION + efi_partition, /* this must come before msdos */ + #endif ++#ifdef CONFIG_FIT_PARTITION ++ fit_partition, ++#endif + #ifdef CONFIG_SGI_PARTITION + sgi_partition, + #endif +@@ -408,6 +415,11 @@ static struct block_device *add_partitio + goto out_del; + } + ++#ifdef CONFIG_FIT_PARTITION ++ if (flags & ADDPART_FLAG_READONLY) ++ bdev->bd_read_only = true; ++#endif ++ + /* everything is up and running, commence */ + err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL); + if (err) +@@ -598,6 +610,11 @@ static bool blk_add_partition(struct gen + (state->parts[p].flags & ADDPART_FLAG_RAID)) + md_autodetect_dev(part->bd_dev); + ++#ifdef CONFIG_FIT_PARTITION ++ if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0) ++ ROOT_DEV = part->bd_dev; ++#endif ++ + return true; + } + +--- a/block/partitions/efi.c ++++ b/block/partitions/efi.c +@@ -716,6 +716,9 @@ int efi_partition(struct parsed_partitio + gpt_entry *ptes = NULL; + u32 i; + unsigned ssz = queue_logical_block_size(state->disk->queue) / 512; ++#ifdef CONFIG_FIT_PARTITION ++ u32 extra_slot = 64; ++#endif + + if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { + kfree(gpt); +@@ -749,6 +752,11 @@ int efi_partition(struct parsed_partitio + ARRAY_SIZE(ptes[i].partition_name)); + utf16_le_to_7bit(ptes[i].partition_name, label_max, info->volname); + state->parts[i + 1].has_info = true; ++#ifdef CONFIG_FIT_PARTITION ++ /* If this is a U-Boot FIT volume it may have subpartitions */ ++ if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_FIT_GUID)) ++ (void) parse_fit_partitions(state, start * ssz, size * ssz, &extra_slot, 1); ++#endif + } + kfree(ptes); + kfree(gpt); +--- a/block/partitions/efi.h ++++ b/block/partitions/efi.h +@@ -52,6 +52,9 @@ + #define PARTITION_LINUX_LVM_GUID \ + EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ + 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) ++#define PARTITION_LINUX_FIT_GUID \ ++ EFI_GUID( 0xcae9be83, 0xb15f, 0x49cc, \ ++ 0x86, 0x3f, 0x08, 0x1b, 0x74, 0x4a, 0x2d, 0x93) + + typedef struct _gpt_header { + __le64 signature; +--- a/block/partitions/msdos.c ++++ b/block/partitions/msdos.c +@@ -564,6 +564,15 @@ static void parse_minix(struct parsed_pa + #endif /* CONFIG_MINIX_SUBPARTITION */ + } + ++static void parse_fit_mbr(struct parsed_partitions *state, ++ sector_t offset, sector_t size, int origin) ++{ ++#ifdef CONFIG_FIT_PARTITION ++ u32 extra_slot = 64; ++ (void) parse_fit_partitions(state, offset, size, &extra_slot, 1); ++#endif /* CONFIG_FIT_PARTITION */ ++} ++ + static struct { + unsigned char id; + void (*parse)(struct parsed_partitions *, sector_t, sector_t, int); +@@ -575,6 +584,7 @@ static struct { + {UNIXWARE_PARTITION, parse_unixware}, + {SOLARIS_X86_PARTITION, parse_solaris_x86}, + {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86}, ++ {FIT_PARTITION, parse_fit_mbr}, + {0, NULL}, + }; + +--- a/drivers/mtd/mtd_blkdevs.c ++++ b/drivers/mtd/mtd_blkdevs.c +@@ -345,6 +345,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt + gd->first_minor = (new->devnum) << tr->part_bits; + gd->minors = 1 << tr->part_bits; + gd->fops = &mtd_block_ops; ++ if (IS_ENABLED(CONFIG_FIT_PARTITION) && !mtd_type_is_nand(new->mtd)) ++ gd->flags |= GENHD_FL_EXT_DEVT; + + if (tr->part_bits) + if (new->devnum < 26) +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -428,6 +428,9 @@ int ubiblock_create(struct ubi_volume_in + goto out_cleanup_disk; + } + gd->private_data = dev; ++#ifdef CONFIG_FIT_PARTITION ++ gd->flags |= GENHD_FL_EXT_DEVT; ++#endif + sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); + set_capacity(gd, disk_capacity); + dev->gd = gd; +--- a/include/linux/msdos_partition.h ++++ b/include/linux/msdos_partition.h +@@ -31,6 +31,7 @@ enum msdos_sys_ind { + LINUX_LVM_PARTITION = 0x8e, + LINUX_RAID_PARTITION = 0xfd, /* autodetect RAID partition */ + ++ FIT_PARTITION = 0x2e, /* U-Boot uImage.FIT */ + SOLARIS_X86_PARTITION = 0x82, /* also Linux swap partitions */ + NEW_SOLARIS_X86_PARTITION = 0xbf, + diff --git a/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch b/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch new file mode 100644 index 00000000000..947b2c262f3 --- /dev/null +++ b/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch @@ -0,0 +1,24 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Mon, 7 Nov 2022 23:48:24 +0100 +Subject: [PATCH] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows setting ROOT_DEV to MTD partition named "rootfs". + +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -761,7 +761,8 @@ int add_mtd_device(struct mtd_info *mtd) + + mutex_unlock(&mtd_table_mutex); + +- if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL)) { ++ if (of_find_property(mtd_get_of_node(mtd), "linux,rootfs", NULL) || ++ (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) { + if (IS_BUILTIN(CONFIG_MTD)) { + pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name); + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index); diff --git a/target/linux/generic/hack-6.1/421-drivers-mtd-parsers-add-nvmem-support-to-cmdlinepart.patch b/target/linux/generic/hack-6.1/421-drivers-mtd-parsers-add-nvmem-support-to-cmdlinepart.patch new file mode 100644 index 00000000000..965a331a190 --- /dev/null +++ b/target/linux/generic/hack-6.1/421-drivers-mtd-parsers-add-nvmem-support-to-cmdlinepart.patch @@ -0,0 +1,120 @@ +From 6fa9e3678eb002246df1280322b6a024853950a5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 11 Oct 2021 00:53:14 +0200 +Subject: [PATCH] drivers: mtd: parsers: add nvmem support to cmdlinepart + +Assuming cmdlinepart is only one level deep partition scheme and that +static partition are also defined in DTS, we can assign an of_node for +partition declared from bootargs. cmdlinepart have priority than +fiexed-partition parser so in this specific case the parser doesn't +assign an of_node. Fix this by searching a defined of_node using a +similar fixed_partition parser and if a partition is found with the same +label, check that it has the same offset and size and return the DT +of_node to correctly use NVMEM cells. + +Signed-off-by: Ansuel Smith +--- + drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++ + 1 file changed, 71 insertions(+) + +--- a/drivers/mtd/parsers/cmdlinepart.c ++++ b/drivers/mtd/parsers/cmdlinepart.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + + /* debug macro */ + #if 0 +@@ -323,6 +324,68 @@ static int mtdpart_setup_real(char *s) + return 0; + } + ++static int search_fixed_partition(struct mtd_info *master, ++ struct mtd_partition *target_part, ++ struct mtd_partition *fixed_part) ++{ ++ struct device_node *mtd_node; ++ struct device_node *ofpart_node; ++ struct device_node *pp; ++ struct mtd_partition part; ++ const char *partname; ++ ++ mtd_node = mtd_get_of_node(master); ++ if (!mtd_node) ++ return -EINVAL; ++ ++ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); ++ ++ for_each_child_of_node(ofpart_node, pp) { ++ const __be32 *reg; ++ int len; ++ int a_cells, s_cells; ++ ++ reg = of_get_property(pp, "reg", &len); ++ if (!reg) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ continue; ++ } ++ ++ a_cells = of_n_addr_cells(pp); ++ s_cells = of_n_size_cells(pp); ++ if (len / 4 != a_cells + s_cells) { ++ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n", ++ master->name, pp, ++ mtd_node); ++ continue; ++ } ++ ++ part.offset = of_read_number(reg, a_cells); ++ part.size = of_read_number(reg + a_cells, s_cells); ++ part.of_node = pp; ++ ++ partname = of_get_property(pp, "label", &len); ++ if (!partname) ++ partname = of_get_property(pp, "name", &len); ++ part.name = partname; ++ ++ if (!strncmp(target_part->name, part.name, len)) { ++ if (part.offset != target_part->offset) ++ return -EINVAL; ++ ++ if (part.size != target_part->size) ++ return -EINVAL; ++ ++ memcpy(fixed_part, &part, sizeof(struct mtd_partition)); ++ return 0; ++ } ++ } ++ ++ return -EINVAL; ++} ++ + /* + * Main function to be called from the MTD mapping driver/device to + * obtain the partitioning information. At this point the command line +@@ -338,6 +401,7 @@ static int parse_cmdline_partitions(stru + int i, err; + struct cmdline_mtd_partition *part; + const char *mtd_id = master->name; ++ struct mtd_partition fixed_part; + + /* parse command line */ + if (!cmdline_parsed) { +@@ -382,6 +446,13 @@ static int parse_cmdline_partitions(stru + sizeof(*part->parts) * (part->num_parts - i)); + i--; + } ++ ++ err = search_fixed_partition(master, &part->parts[i], &fixed_part); ++ if (!err) { ++ part->parts[i].of_node = fixed_part.of_node; ++ pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.", ++ part->parts[i].name); ++ } + } + + *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, diff --git a/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch new file mode 100644 index 00000000000..2a83f46e0ee --- /dev/null +++ b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch @@ -0,0 +1,33 @@ +From ac84397efb3b3868c71c10ad7521161773228a17 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:41:44 +0200 +Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table + +--- + drivers/mtd/nand/Kconfig | 4 ++++ + drivers/mtd/nand/Makefile | 1 + + 2 files changed, 5 insertions(+) + +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH + ECC codes. They are used with NAND devices requiring more than 1 bit + of error correction. + ++config MTD_NAND_MTK_BMT ++ bool "Support MediaTek NAND Bad-block Management Table" ++ default n ++ + endmenu + + endmenu +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -2,6 +2,7 @@ + + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o ++obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o + + obj-y += onenand/ + obj-y += raw/ diff --git a/target/linux/generic/hack-6.1/600-bridge_offload.patch b/target/linux/generic/hack-6.1/600-bridge_offload.patch new file mode 100644 index 00000000000..9d71a741b25 --- /dev/null +++ b/target/linux/generic/hack-6.1/600-bridge_offload.patch @@ -0,0 +1,846 @@ +From 11c3fae5afa6cac444d12622e2cf5af60a99c1ef Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:43:15 +0200 +Subject: [PATCH] net/bridge: add bridge offload + +--- + include/linux/if_bridge.h | 1 + + net/bridge/Makefile | 2 +- + net/bridge/br.c | 8 + + net/bridge/br_device.c | 2 + + net/bridge/br_fdb.c | 5 + + net/bridge/br_forward.c | 3 + + net/bridge/br_if.c | 6 +- + net/bridge/br_input.c | 5 + + net/bridge/br_offload.c | 438 ++++++++++++++++++++++++++++++++ + net/bridge/br_private.h | 22 +- + net/bridge/br_private_offload.h | 23 ++ + net/bridge/br_stp.c | 3 + + net/bridge/br_sysfs_br.c | 35 +++ + net/bridge/br_sysfs_if.c | 2 + + net/bridge/br_vlan_tunnel.c | 3 + + 15 files changed, 555 insertions(+), 3 deletions(-) + create mode 100644 net/bridge/br_offload.c + create mode 100644 net/bridge/br_private_offload.h + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -59,6 +59,7 @@ struct br_ip_list { + #define BR_MRP_LOST_IN_CONT BIT(19) + #define BR_TX_FWD_OFFLOAD BIT(20) + #define BR_BPDU_FILTER BIT(21) ++#define BR_OFFLOAD BIT(22) + + #define BR_DEFAULT_AGEING_TIME (300 * HZ) + +--- a/net/bridge/Makefile ++++ b/net/bridge/Makefile +@@ -5,7 +5,7 @@ + + obj-$(CONFIG_BRIDGE) += bridge.o + +-bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ ++bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \ + br_ioctl.o br_stp.o br_stp_bpdu.o \ + br_stp_if.o br_stp_timer.o br_netlink.o \ + br_netlink_tunnel.o br_arp_nd_proxy.o +--- a/net/bridge/br.c ++++ b/net/bridge/br.c +@@ -18,6 +18,7 @@ + #include + + #include "br_private.h" ++#include "br_private_offload.h" + + /* + * Handle changes in state of network devices enslaved to a bridge. +@@ -381,6 +382,10 @@ static int __init br_init(void) + if (err) + goto err_out; + ++ err = br_offload_init(); ++ if (err) ++ goto err_out0; ++ + err = register_pernet_subsys(&br_net_ops); + if (err) + goto err_out1; +@@ -430,6 +435,8 @@ err_out3: + err_out2: + unregister_pernet_subsys(&br_net_ops); + err_out1: ++ br_offload_fini(); ++err_out0: + br_fdb_fini(); + err_out: + stp_proto_unregister(&br_stp_proto); +@@ -452,6 +459,7 @@ static void __exit br_deinit(void) + #if IS_ENABLED(CONFIG_ATM_LANE) + br_fdb_test_addr_hook = NULL; + #endif ++ br_offload_fini(); + br_fdb_fini(); + } + +--- a/net/bridge/br_device.c ++++ b/net/bridge/br_device.c +@@ -524,6 +524,8 @@ void br_dev_setup(struct net_device *dev + br->bridge_hello_time = br->hello_time = 2 * HZ; + br->bridge_forward_delay = br->forward_delay = 15 * HZ; + br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; ++ br->offload_cache_size = 128; ++ br->offload_cache_reserved = 8; + dev->max_mtu = ETH_MAX_MTU; + + br_netfilter_rtable_init(br); +--- a/net/bridge/br_fdb.c ++++ b/net/bridge/br_fdb.c +@@ -23,6 +23,7 @@ + #include + #include + #include "br_private.h" ++#include "br_private_offload.h" + + static const struct rhashtable_params br_fdb_rht_params = { + .head_offset = offsetof(struct net_bridge_fdb_entry, rhnode), +@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_ + fdb->key.vlan_id = vid; + fdb->flags = flags; + fdb->updated = fdb->used = jiffies; ++ INIT_HLIST_HEAD(&fdb->offload_in); ++ INIT_HLIST_HEAD(&fdb->offload_out); + if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, + &fdb->rhnode, + br_fdb_rht_params)) { +@@ -794,6 +797,8 @@ static void fdb_notify(struct net_bridge + struct sk_buff *skb; + int err = -ENOBUFS; + ++ br_offload_fdb_update(fdb); ++ + if (swdev_notify) + br_switchdev_fdb_notify(br, fdb, type); + +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -16,6 +16,7 @@ + #include + #include + #include "br_private.h" ++#include "br_private_offload.h" + + /* Don't forward packets to originating port or forwarding disabled */ + static inline int should_deliver(const struct net_bridge_port *p, +@@ -32,6 +33,8 @@ static inline int should_deliver(const s + + int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) + { ++ br_offload_output(skb); ++ + skb_push(skb, ETH_HLEN); + if (!is_skb_forwardable(skb->dev, skb)) + goto drop; +--- a/net/bridge/br_if.c ++++ b/net/bridge/br_if.c +@@ -25,6 +25,7 @@ + #include + + #include "br_private.h" ++#include "br_private_offload.h" + + /* + * Determine initial path cost based on speed. +@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s + p->path_cost = port_cost(dev); + p->priority = 0x8000 >> BR_PORT_BITS; + p->port_no = index; +- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; ++ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD; + br_init_port(p); + br_set_state(p, BR_STATE_DISABLED); + br_stp_port_timer_init(p); +@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri + + if (mask & BR_NEIGH_SUPPRESS) + br_recalculate_neigh_suppress_enabled(br); ++ ++ if (mask & BR_OFFLOAD) ++ br_offload_port_state(p); + } + + bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag) +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -22,6 +22,7 @@ + #include + #include "br_private.h" + #include "br_private_tunnel.h" ++#include "br_private_offload.h" + + static int + br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) +@@ -171,6 +172,7 @@ int br_handle_frame_finish(struct net *n + dst->used = now; + br_forward(dst->dst, skb, local_rcv, false); + } else { ++ br_offload_skb_disable(skb); + if (!mcast_hit) + br_flood(br, skb, pkt_type, local_rcv, false); + else +@@ -304,6 +306,9 @@ static rx_handler_result_t br_handle_fra + memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); + + p = br_port_get_rcu(skb->dev); ++ if (br_offload_input(p, skb)) ++ return RX_HANDLER_CONSUMED; ++ + if (p->flags & BR_VLAN_TUNNEL) + br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p)); + +--- /dev/null ++++ b/net/bridge/br_offload.c +@@ -0,0 +1,438 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++#include ++#include ++#include "br_private.h" ++#include "br_private_offload.h" ++ ++static DEFINE_SPINLOCK(offload_lock); ++ ++struct bridge_flow_key { ++ u8 dest[ETH_ALEN]; ++ u8 src[ETH_ALEN]; ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ u16 vlan_tag; ++ bool vlan_present; ++#endif ++}; ++ ++struct bridge_flow { ++ struct net_bridge_port *port; ++ struct rhash_head node; ++ struct bridge_flow_key key; ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ bool vlan_out_present; ++ u16 vlan_out; ++#endif ++ ++ unsigned long used; ++ struct net_bridge_fdb_entry *fdb_in, *fdb_out; ++ struct hlist_node fdb_list_in, fdb_list_out; ++ ++ struct rcu_head rcu; ++}; ++ ++static const struct rhashtable_params flow_params = { ++ .automatic_shrinking = true, ++ .head_offset = offsetof(struct bridge_flow, node), ++ .key_len = sizeof(struct bridge_flow_key), ++ .key_offset = offsetof(struct bridge_flow, key), ++}; ++ ++static struct kmem_cache *offload_cache __read_mostly; ++ ++static void ++flow_rcu_free(struct rcu_head *head) ++{ ++ struct bridge_flow *flow; ++ ++ flow = container_of(head, struct bridge_flow, rcu); ++ kmem_cache_free(offload_cache, flow); ++} ++ ++static void ++__br_offload_flow_free(struct bridge_flow *flow) ++{ ++ flow->used = 0; ++ hlist_del(&flow->fdb_list_in); ++ hlist_del(&flow->fdb_list_out); ++ ++ call_rcu(&flow->rcu, flow_rcu_free); ++} ++ ++static void ++br_offload_flow_free(struct bridge_flow *flow) ++{ ++ if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node, ++ flow_params) != 0) ++ return; ++ ++ __br_offload_flow_free(flow); ++} ++ ++static bool ++br_offload_flow_fdb_refresh_time(struct bridge_flow *flow, ++ struct net_bridge_fdb_entry *fdb) ++{ ++ if (!time_after(flow->used, fdb->updated)) ++ return false; ++ ++ fdb->updated = flow->used; ++ ++ return true; ++} ++ ++ ++static void ++br_offload_flow_refresh_time(struct bridge_flow *flow) ++{ ++ br_offload_flow_fdb_refresh_time(flow, flow->fdb_in); ++ br_offload_flow_fdb_refresh_time(flow, flow->fdb_out); ++} ++ ++static void ++br_offload_destroy_cb(void *ptr, void *arg) ++{ ++ struct bridge_flow *flow = ptr; ++ ++ __br_offload_flow_free(flow); ++} ++ ++static bool ++br_offload_need_gc(struct net_bridge_port *p) ++{ ++ return (atomic_read(&p->offload.rht.nelems) + ++ p->br->offload_cache_reserved) >= p->br->offload_cache_size; ++} ++ ++static void ++br_offload_gc_work(struct work_struct *work) ++{ ++ struct rhashtable_iter hti; ++ struct net_bridge_port *p; ++ struct bridge_flow *gc_flow = NULL; ++ struct bridge_flow *flow; ++ unsigned long gc_used; ++ ++ p = container_of(work, struct net_bridge_port, offload.gc_work); ++ ++ if (!br_offload_need_gc(p)) ++ return; ++ ++ rhashtable_walk_enter(&p->offload.rht, &hti); ++ rhashtable_walk_start(&hti); ++ while ((flow = rhashtable_walk_next(&hti)) != NULL) { ++ unsigned long used; ++ ++ if (IS_ERR(flow)) ++ continue; ++ ++ used = READ_ONCE(flow->used); ++ if (!used) ++ continue; ++ ++ if (gc_flow && !time_before(used, gc_used)) ++ continue; ++ ++ gc_flow = flow; ++ gc_used = used; ++ } ++ rhashtable_walk_stop(&hti); ++ rhashtable_walk_exit(&hti); ++ ++ if (!gc_flow) ++ return; ++ ++ spin_lock_bh(&offload_lock); ++ if (br_offload_need_gc(p) && gc_flow && ++ gc_flow->used == gc_used) ++ br_offload_flow_free(gc_flow); ++ if (p->offload.enabled && br_offload_need_gc(p)) ++ queue_work(system_long_wq, work); ++ spin_unlock_bh(&offload_lock); ++ ++} ++ ++void br_offload_port_state(struct net_bridge_port *p) ++{ ++ struct net_bridge_port_offload *o = &p->offload; ++ bool enabled = true; ++ bool flush = false; ++ ++ if (p->state != BR_STATE_FORWARDING || ++ !(p->flags & BR_OFFLOAD)) ++ enabled = false; ++ ++ spin_lock_bh(&offload_lock); ++ if (o->enabled == enabled) ++ goto out; ++ ++ if (enabled) { ++ if (!o->gc_work.func) ++ INIT_WORK(&o->gc_work, br_offload_gc_work); ++ rhashtable_init(&o->rht, &flow_params); ++ } else { ++ flush = true; ++ rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o); ++ } ++ ++ o->enabled = enabled; ++ ++out: ++ spin_unlock_bh(&offload_lock); ++ ++ if (flush) ++ flush_work(&o->gc_work); ++} ++ ++void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb) ++{ ++ struct bridge_flow *f; ++ struct hlist_node *tmp; ++ ++ spin_lock_bh(&offload_lock); ++ ++ hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in) ++ br_offload_flow_free(f); ++ ++ hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out) ++ br_offload_flow_free(f); ++ ++ spin_unlock_bh(&offload_lock); ++} ++ ++static void ++br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key, ++ struct sk_buff *skb) ++{ ++ memset(key, 0, sizeof(*key)); ++ memcpy(key, eth_hdr(skb), 2 * ETH_ALEN); ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ if (!br_opt_get(p->br, BROPT_VLAN_ENABLED)) ++ return; ++ ++ if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto) ++ return; ++ ++ key->vlan_present = true; ++ key->vlan_tag = skb_vlan_tag_get_id(skb); ++#endif ++} ++ ++void br_offload_output(struct sk_buff *skb) ++{ ++ struct net_bridge_port_offload *o; ++ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb; ++ struct net_bridge_port *p, *inp; ++ struct net_device *dev; ++ struct net_bridge_fdb_entry *fdb_in, *fdb_out; ++ struct net_bridge_vlan_group *vg; ++ struct bridge_flow_key key; ++ struct bridge_flow *flow; ++ u16 vlan; ++ ++ if (!cb->offload) ++ return; ++ ++ rcu_read_lock(); ++ ++ p = br_port_get_rcu(skb->dev); ++ if (!p) ++ goto out; ++ ++ o = &p->offload; ++ if (!o->enabled) ++ goto out; ++ ++ if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size) ++ goto out; ++ ++ dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex); ++ if (!dev) ++ goto out; ++ ++ inp = br_port_get_rcu(dev); ++ if (!inp) ++ goto out; ++ ++ vg = nbp_vlan_group_rcu(inp); ++ vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg); ++ fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan); ++ if (!fdb_in || !fdb_in->dst) ++ goto out; ++ ++ vg = nbp_vlan_group_rcu(p); ++ vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg); ++ fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan); ++ if (!fdb_out || !fdb_out->dst) ++ goto out; ++ ++ br_offload_prepare_key(p, &key, skb); ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ key.vlan_present = cb->input_vlan_present; ++ key.vlan_tag = cb->input_vlan_tag; ++#endif ++ ++ flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC); ++ flow->port = inp; ++ memcpy(&flow->key, &key, sizeof(key)); ++ ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ flow->vlan_out_present = skb_vlan_tag_present(skb); ++ flow->vlan_out = skb_vlan_tag_get(skb); ++#endif ++ ++ flow->fdb_in = fdb_in; ++ flow->fdb_out = fdb_out; ++ flow->used = jiffies; ++ ++ spin_lock_bh(&offload_lock); ++ if (!o->enabled || ++ atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size || ++ rhashtable_insert_fast(&inp->offload.rht, &flow->node, flow_params)) { ++ kmem_cache_free(offload_cache, flow); ++ goto out_unlock; ++ } ++ ++ hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in); ++ hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out); ++ ++ if (br_offload_need_gc(p)) ++ queue_work(system_long_wq, &p->offload.gc_work); ++ ++out_unlock: ++ spin_unlock_bh(&offload_lock); ++ ++out: ++ rcu_read_unlock(); ++} ++ ++bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb) ++{ ++ struct net_bridge_port_offload *o = &p->offload; ++ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb; ++ struct bridge_flow_key key; ++ struct net_bridge_port *dst; ++ struct bridge_flow *flow; ++ unsigned long now = jiffies; ++ bool ret = false; ++ ++ if (skb->len < sizeof(key)) ++ return false; ++ ++ if (!o->enabled) ++ return false; ++ ++ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) ++ return false; ++ ++ br_offload_prepare_key(p, &key, skb); ++ ++ rcu_read_lock(); ++ flow = rhashtable_lookup(&o->rht, &key, flow_params); ++ if (!flow) { ++ cb->offload = 1; ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ cb->input_vlan_present = key.vlan_present != 0; ++ cb->input_vlan_tag = key.vlan_tag; ++#endif ++ cb->input_ifindex = p->dev->ifindex; ++ goto out; ++ } ++ ++ if (flow->fdb_in->dst != p) ++ goto out; ++ ++ dst = flow->fdb_out->dst; ++ if (!dst) ++ goto out; ++ ++ ret = true; ++#ifdef CONFIG_BRIDGE_VLAN_FILTERING ++ if (!flow->vlan_out_present && key.vlan_present) { ++ __vlan_hwaccel_clear_tag(skb); ++ } else if (flow->vlan_out_present) { ++ if (skb_vlan_tag_present(skb) && ++ skb->vlan_proto != p->br->vlan_proto) { ++ /* Protocol-mismatch, empty out vlan_tci for new tag */ ++ skb_push(skb, ETH_HLEN); ++ skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, ++ skb_vlan_tag_get(skb)); ++ if (unlikely(!skb)) ++ goto out; ++ ++ skb_pull(skb, ETH_HLEN); ++ skb_reset_mac_len(skb); ++ } ++ ++ __vlan_hwaccel_put_tag(skb, p->br->vlan_proto, ++ flow->vlan_out); ++ } ++#endif ++ ++ skb->dev = dst->dev; ++ skb_push(skb, ETH_HLEN); ++ ++ if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) { ++ kfree_skb(skb); ++ goto out; ++ } ++ ++ if (now - flow->used >= HZ) { ++ flow->used = now; ++ br_offload_flow_refresh_time(flow); ++ } ++ ++ skb_forward_csum(skb); ++ dev_queue_xmit(skb); ++ ++out: ++ rcu_read_unlock(); ++ return ret; ++} ++ ++static void ++br_offload_check_gc(struct net_bridge *br) ++{ ++ struct net_bridge_port *p; ++ ++ spin_lock_bh(&br->lock); ++ list_for_each_entry(p, &br->port_list, list) ++ if (br_offload_need_gc(p)) ++ queue_work(system_long_wq, &p->offload.gc_work); ++ spin_unlock_bh(&br->lock); ++} ++ ++ ++int br_offload_set_cache_size(struct net_bridge *br, unsigned long val, ++ struct netlink_ext_ack *extack) ++{ ++ br->offload_cache_size = val; ++ br_offload_check_gc(br); ++ ++ return 0; ++} ++ ++int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val, ++ struct netlink_ext_ack *extack) ++{ ++ br->offload_cache_reserved = val; ++ br_offload_check_gc(br); ++ ++ return 0; ++} ++ ++int __init br_offload_init(void) ++{ ++ offload_cache = kmem_cache_create("bridge_offload_cache", ++ sizeof(struct bridge_flow), ++ 0, SLAB_HWCACHE_ALIGN, NULL); ++ if (!offload_cache) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++void br_offload_fini(void) ++{ ++ kmem_cache_destroy(offload_cache); ++} +--- a/net/bridge/br_private.h ++++ b/net/bridge/br_private.h +@@ -268,7 +268,13 @@ struct net_bridge_fdb_entry { + unsigned long updated ____cacheline_aligned_in_smp; + unsigned long used; + +- struct rcu_head rcu; ++ union { ++ struct { ++ struct hlist_head offload_in; ++ struct hlist_head offload_out; ++ }; ++ struct rcu_head rcu; ++ }; + }; + + #define MDB_PG_FLAGS_PERMANENT BIT(0) +@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry { + struct rcu_head rcu; + }; + ++struct net_bridge_port_offload { ++ struct rhashtable rht; ++ struct work_struct gc_work; ++ bool enabled; ++}; ++ + struct net_bridge_port { + struct net_bridge *br; + struct net_device *dev; +@@ -403,6 +415,7 @@ struct net_bridge_port { + u16 backup_redirected_cnt; + + struct bridge_stp_xstats stp_xstats; ++ struct net_bridge_port_offload offload; + }; + + #define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj) +@@ -519,6 +532,9 @@ struct net_bridge { + struct kobject *ifobj; + u32 auto_cnt; + ++ u32 offload_cache_size; ++ u32 offload_cache_reserved; ++ + #ifdef CONFIG_NET_SWITCHDEV + /* Counter used to make sure that hardware domains get unique + * identifiers in case a bridge spans multiple switchdev instances. +@@ -553,6 +569,10 @@ struct br_input_skb_cb { + #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE + u8 br_netfilter_broute:1; + #endif ++ u8 offload:1; ++ u8 input_vlan_present:1; ++ u16 input_vlan_tag; ++ int input_ifindex; + + #ifdef CONFIG_NET_SWITCHDEV + /* Set if TX data plane offloading is used towards at least one +--- /dev/null ++++ b/net/bridge/br_private_offload.h +@@ -0,0 +1,23 @@ ++#ifndef __BR_OFFLOAD_H ++#define __BR_OFFLOAD_H ++ ++bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb); ++void br_offload_output(struct sk_buff *skb); ++void br_offload_port_state(struct net_bridge_port *p); ++void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb); ++int br_offload_init(void); ++void br_offload_fini(void); ++int br_offload_set_cache_size(struct net_bridge *br, unsigned long val, ++ struct netlink_ext_ack *extack); ++int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val, ++ struct netlink_ext_ack *extack); ++ ++static inline void br_offload_skb_disable(struct sk_buff *skb) ++{ ++ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb; ++ ++ if (cb->offload) ++ cb->offload = 0; ++} ++ ++#endif +--- a/net/bridge/br_stp.c ++++ b/net/bridge/br_stp.c +@@ -12,6 +12,7 @@ + + #include "br_private.h" + #include "br_private_stp.h" ++#include "br_private_offload.h" + + /* since time values in bpdu are in jiffies and then scaled (1/256) + * before sending, make sure that is at least one STP tick. +@@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port + (unsigned int) p->port_no, p->dev->name, + br_port_state_names[p->state]); + ++ br_offload_port_state(p); ++ + if (p->br->stp_enabled == BR_KERNEL_STP) { + switch (p->state) { + case BR_STATE_BLOCKING: +--- a/net/bridge/br_sysfs_br.c ++++ b/net/bridge/br_sysfs_br.c +@@ -18,6 +18,7 @@ + #include + + #include "br_private.h" ++#include "br_private_offload.h" + + /* IMPORTANT: new bridge options must be added with netlink support only + * please do not add new sysfs entries +@@ -930,6 +931,38 @@ static ssize_t vlan_stats_per_port_store + static DEVICE_ATTR_RW(vlan_stats_per_port); + #endif + ++static ssize_t offload_cache_size_show(struct device *d, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct net_bridge *br = to_bridge(d); ++ return sprintf(buf, "%u\n", br->offload_cache_size); ++} ++ ++static ssize_t offload_cache_size_store(struct device *d, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return store_bridge_parm(d, buf, len, br_offload_set_cache_size); ++} ++static DEVICE_ATTR_RW(offload_cache_size); ++ ++static ssize_t offload_cache_reserved_show(struct device *d, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct net_bridge *br = to_bridge(d); ++ return sprintf(buf, "%u\n", br->offload_cache_reserved); ++} ++ ++static ssize_t offload_cache_reserved_store(struct device *d, ++ struct device_attribute *attr, ++ const char *buf, size_t len) ++{ ++ return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved); ++} ++static DEVICE_ATTR_RW(offload_cache_reserved); ++ + static struct attribute *bridge_attrs[] = { + &dev_attr_forward_delay.attr, + &dev_attr_hello_time.attr, +@@ -984,6 +1017,8 @@ static struct attribute *bridge_attrs[] + &dev_attr_vlan_stats_enabled.attr, + &dev_attr_vlan_stats_per_port.attr, + #endif ++ &dev_attr_offload_cache_size.attr, ++ &dev_attr_offload_cache_reserved.attr, + NULL + }; + +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -241,6 +241,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA + BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); + BRPORT_ATTR_FLAG(isolated, BR_ISOLATED); + BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER); ++BRPORT_ATTR_FLAG(offload, BR_OFFLOAD); + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) +@@ -295,6 +296,7 @@ static const struct brport_attribute *br + &brport_attr_isolated, + &brport_attr_bpdu_filter, + &brport_attr_backup_port, ++ &brport_attr_offload, + NULL + }; + +--- a/net/bridge/br_vlan_tunnel.c ++++ b/net/bridge/br_vlan_tunnel.c +@@ -15,6 +15,7 @@ + + #include "br_private.h" + #include "br_private_tunnel.h" ++#include "br_private_offload.h" + + static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg, + const void *ptr) +@@ -180,6 +181,7 @@ void br_handle_ingress_vlan_tunnel(struc + skb_dst_drop(skb); + + __vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid); ++ br_offload_skb_disable(skb); + } + + int br_handle_egress_vlan_tunnel(struct sk_buff *skb, +@@ -201,6 +203,7 @@ int br_handle_egress_vlan_tunnel(struct + if (err) + return err; + ++ br_offload_skb_disable(skb); + tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst); + if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst)) + skb_dst_set(skb, &tunnel_dst->dst); diff --git a/target/linux/generic/hack-6.1/601-of_net-add-mac-address-ascii-support.patch b/target/linux/generic/hack-6.1/601-of_net-add-mac-address-ascii-support.patch new file mode 100644 index 00000000000..55866c31350 --- /dev/null +++ b/target/linux/generic/hack-6.1/601-of_net-add-mac-address-ascii-support.patch @@ -0,0 +1,116 @@ +From: Yousong Zhou +Subject: [PATCH] of: net: add nvmem cell mac-address-ascii support + +This is needed for devices with mac address stored in ascii format, +e.g. HiWiFi HC6361 to be ported in the following patch. + +Submitted-by: Yousong Zhou +--- + net/core/of_net.c | 83 ++++++++++++------ + 1 files changed, 72 insertions(+), 11 deletions(-) + +--- a/net/core/of_net.c ++++ b/net/core/of_net.c +@@ -57,13 +57,70 @@ static int of_get_mac_addr(struct device + return -ENODEV; + } + ++static void *nvmem_cell_get_mac_address(struct nvmem_cell *cell) ++{ ++ size_t len; ++ void *mac; ++ ++ mac = nvmem_cell_read(cell, &len); ++ if (IS_ERR(mac)) ++ return mac; ++ if (len != ETH_ALEN) { ++ kfree(mac); ++ return ERR_PTR(-EINVAL); ++ } ++ return mac; ++} ++ ++static void *nvmem_cell_get_mac_address_ascii(struct nvmem_cell *cell) ++{ ++ size_t len; ++ int ret; ++ void *mac_ascii; ++ u8 *mac; ++ ++ mac_ascii = nvmem_cell_read(cell, &len); ++ if (IS_ERR(mac_ascii)) ++ return mac_ascii; ++ if (len != ETH_ALEN*2+5) { ++ kfree(mac_ascii); ++ return ERR_PTR(-EINVAL); ++ } ++ mac = kmalloc(ETH_ALEN, GFP_KERNEL); ++ if (!mac) { ++ kfree(mac_ascii); ++ return ERR_PTR(-ENOMEM); ++ } ++ ret = sscanf(mac_ascii, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", ++ &mac[0], &mac[1], &mac[2], ++ &mac[3], &mac[4], &mac[5]); ++ kfree(mac_ascii); ++ if (ret == ETH_ALEN) ++ return mac; ++ kfree(mac); ++ return ERR_PTR(-EINVAL); ++} ++ ++static struct nvmem_cell_mac_address_property { ++ char *name; ++ void *(*read)(struct nvmem_cell *); ++} nvmem_cell_mac_address_properties[] = { ++ { ++ .name = "mac-address", ++ .read = nvmem_cell_get_mac_address, ++ }, { ++ .name = "mac-address-ascii", ++ .read = nvmem_cell_get_mac_address_ascii, ++ }, ++}; ++ + static int of_get_mac_addr_nvmem(struct device_node *np, u8 *addr) + { + struct platform_device *pdev = of_find_device_by_node(np); ++ struct nvmem_cell_mac_address_property *property; + struct nvmem_cell *cell; + const void *mac; +- size_t len; +- int ret; ++ int ret, i; + + /* Try lookup by device first, there might be a nvmem_cell_lookup + * associated with a given device. +@@ -74,17 +131,26 @@ static int of_get_mac_addr_nvmem(struct + return ret; + } + +- cell = of_nvmem_cell_get(np, "mac-address"); ++ for (i = 0; i < ARRAY_SIZE(nvmem_cell_mac_address_properties); i++) { ++ property = &nvmem_cell_mac_address_properties[i]; ++ cell = of_nvmem_cell_get(np, property->name); ++ /* For -EPROBE_DEFER don't try other properties. ++ * We'll get back to this one. ++ */ ++ if (!IS_ERR(cell) || PTR_ERR(cell) == -EPROBE_DEFER) ++ break; ++ } ++ + if (IS_ERR(cell)) + return PTR_ERR(cell); + +- mac = nvmem_cell_read(cell, &len); ++ mac = property->read(cell); + nvmem_cell_put(cell); + + if (IS_ERR(mac)) + return PTR_ERR(mac); + +- if (len != ETH_ALEN || !is_valid_ether_addr(mac)) { ++ if (!is_valid_ether_addr(mac)) { + kfree(mac); + return -EINVAL; + } diff --git a/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch b/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch new file mode 100644 index 00000000000..c368c4ae3bf --- /dev/null +++ b/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch @@ -0,0 +1,214 @@ +From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001 +From: Kevin Darbyshire-Bryant +Date: Sat, 23 Mar 2019 09:29:49 +0000 +Subject: [PATCH] netfilter: connmark: introduce set-dscpmark + +set-dscpmark is a method of storing the DSCP of an ip packet into +conntrack mark. In combination with a suitable tc filter action +(act_ctinfo) DSCP values are able to be stored in the mark on egress and +restored on ingress across links that otherwise alter or bleach DSCP. + +This is useful for qdiscs such as CAKE which are able to shape according +to policies based on DSCP. + +Ingress classification is traditionally a challenging task since +iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT +lookups, hence are unable to see internal IPv4 addresses as used on the +typical home masquerading gateway. + +x_tables CONNMARK set-dscpmark target solves the problem of storing the +DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc +action to restore. + +The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a +32bit 'statemask'. The dscp mask must be 6 contiguous bits and +represents the area where the DSCP will be stored in the connmark. The +state mask is a minimum 1 bit length mask that must not overlap with the +dscpmask. It represents a flag which is set when the DSCP has been +stored in the conntrack mark. This is useful to implement a 'one shot' +iptables based classification where the 'complicated' iptables rules are +only run once to classify the connection on initial (egress) packet and +subsequent packets are all marked/restored with the same DSCP. A state +mask of zero disables the setting of a status bit/s. + +example syntax with a suitably modified iptables user space application: + +iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000 + +Would store the DSCP in the top 6 bits of the 32bit mark field, and use +the LSB of the top byte as the 'DSCP has been stored' marker. + +|----0xFC----conntrack mark----000000---| +| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| +| DSCP | unused | flag |unused | +|-----------------------0x01---000000---| + ^ ^ + | | + ---| Conditional flag + | set this when dscp +|-ip diffserv-| stored in mark +| 6 bits | +|-------------| + +an identically configured tc action to restore looks like: + +tc filter show dev eth0 ingress +filter parent ffff: protocol all pref 10 u32 chain 0 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1 +filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw + match 00000000/00000000 at 0 + action order 1: ctinfo zone 0 pipe + index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000 + + action order 2: mirred (Egress Redirect to device ifb4eth0) stolen + index 1 ref 1 bind 1 + +|----0xFC----conntrack mark----000000---| +| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0| +| DSCP | unused | flag |unused | +|-----------------------0x01---000000---| + | | + | | + ---| Conditional flag + v only restore if set +|-ip diffserv-| +| 6 bits | +|-------------| + +Signed-off-by: Kevin Darbyshire-Bryant +--- + include/uapi/linux/netfilter/xt_connmark.h | 10 ++++ + net/netfilter/xt_connmark.c | 55 ++++++++++++++++++---- + 2 files changed, 57 insertions(+), 8 deletions(-) + +--- a/include/uapi/linux/netfilter/xt_connmark.h ++++ b/include/uapi/linux/netfilter/xt_connmark.h +@@ -20,6 +20,11 @@ enum { + }; + + enum { ++ XT_CONNMARK_VALUE = (1 << 0), ++ XT_CONNMARK_DSCP = (1 << 1) ++}; ++ ++enum { + D_SHIFT_LEFT = 0, + D_SHIFT_RIGHT, + }; +@@ -34,6 +39,11 @@ struct xt_connmark_tginfo2 { + __u8 shift_dir, shift_bits, mode; + }; + ++struct xt_connmark_tginfo3 { ++ __u32 ctmark, ctmask, nfmask; ++ __u8 shift_dir, shift_bits, mode, func; ++}; ++ + struct xt_connmark_mtinfo1 { + __u32 mark, mask; + __u8 invert; +--- a/net/netfilter/xt_connmark.c ++++ b/net/netfilter/xt_connmark.c +@@ -24,13 +24,13 @@ MODULE_ALIAS("ipt_connmark"); + MODULE_ALIAS("ip6t_connmark"); + + static unsigned int +-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) ++connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info) + { + enum ip_conntrack_info ctinfo; + u_int32_t new_targetmark; + struct nf_conn *ct; + u_int32_t newmark; +- u_int32_t oldmark; ++ u_int8_t dscp; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) +@@ -38,13 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c + + switch (info->mode) { + case XT_CONNMARK_SET: +- oldmark = READ_ONCE(ct->mark); +- newmark = (oldmark & ~info->ctmask) ^ info->ctmark; +- if (info->shift_dir == D_SHIFT_RIGHT) +- newmark >>= info->shift_bits; +- else +- newmark <<= info->shift_bits; ++ newmark = READ_ONCE(ct->mark); ++ if (info->func & XT_CONNMARK_VALUE) { ++ newmark = (newmark & ~info->ctmask) ^ info->ctmark; ++ if (info->shift_dir == D_SHIFT_RIGHT) ++ newmark >>= info->shift_bits; ++ else ++ newmark <<= info->shift_bits; ++ } else if (info->func & XT_CONNMARK_DSCP) { ++ if (skb->protocol == htons(ETH_P_IP)) ++ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2; ++ else if (skb->protocol == htons(ETH_P_IPV6)) ++ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2; ++ else /* protocol doesn't have diffserv */ ++ break; + ++ newmark = (newmark & ~info->ctmark) | ++ (info->ctmask | (dscp << info->shift_bits)); ++ } + if (READ_ONCE(ct->mark) != newmark) { + WRITE_ONCE(ct->mark, newmark); + nf_conntrack_event_cache(IPCT_MARK, ct); +@@ -83,20 +94,36 @@ static unsigned int + connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo1 *info = par->targinfo; +- const struct xt_connmark_tginfo2 info2 = { ++ const struct xt_connmark_tginfo3 info3 = { + .ctmark = info->ctmark, + .ctmask = info->ctmask, + .nfmask = info->nfmask, + .mode = info->mode, ++ .func = XT_CONNMARK_VALUE + }; + +- return connmark_tg_shift(skb, &info2); ++ return connmark_tg_shift(skb, &info3); + } + + static unsigned int + connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) + { + const struct xt_connmark_tginfo2 *info = par->targinfo; ++ const struct xt_connmark_tginfo3 info3 = { ++ .ctmark = info->ctmark, ++ .ctmask = info->ctmask, ++ .nfmask = info->nfmask, ++ .mode = info->mode, ++ .func = XT_CONNMARK_VALUE ++ }; ++ ++ return connmark_tg_shift(skb, &info3); ++} ++ ++static unsigned int ++connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ const struct xt_connmark_tginfo3 *info = par->targinfo; + + return connmark_tg_shift(skb, info); + } +@@ -167,6 +194,16 @@ static struct xt_target connmark_tg_reg[ + .targetsize = sizeof(struct xt_connmark_tginfo2), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, ++ }, ++ { ++ .name = "CONNMARK", ++ .revision = 3, ++ .family = NFPROTO_UNSPEC, ++ .checkentry = connmark_tg_check, ++ .target = connmark_tg_v3, ++ .targetsize = sizeof(struct xt_connmark_tginfo3), ++ .destroy = connmark_tg_destroy, ++ .me = THIS_MODULE, + } + }; + diff --git a/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch new file mode 100644 index 00000000000..aa6c668558a --- /dev/null +++ b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch @@ -0,0 +1,861 @@ +From: Felix Fietkau +Date: Tue, 20 Feb 2018 15:56:02 +0100 +Subject: [PATCH] netfilter: add xt_FLOWOFFLOAD target + +Signed-off-by: Felix Fietkau +--- + create mode 100644 net/netfilter/xt_OFFLOAD.c + +--- a/net/ipv4/netfilter/Kconfig ++++ b/net/ipv4/netfilter/Kconfig +@@ -56,8 +56,6 @@ config NF_TABLES_ARP + help + This option enables the ARP support for nf_tables. + +-endif # NF_TABLES +- + config NF_FLOW_TABLE_IPV4 + tristate "Netfilter flow table IPv4 module" + depends on NF_FLOW_TABLE +@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4 + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_DUP_IPV4 + tristate "Netfilter IPv4 packet duplication to alternate destination" + depends on !NF_CONNTRACK || NF_CONNTRACK +--- a/net/ipv6/netfilter/Kconfig ++++ b/net/ipv6/netfilter/Kconfig +@@ -45,7 +45,6 @@ config NFT_FIB_IPV6 + multicast or blackhole. + + endif # NF_TABLES_IPV6 +-endif # NF_TABLES + + config NF_FLOW_TABLE_IPV6 + tristate "Netfilter flow table IPv6 module" +@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6 + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_DUP_IPV6 + tristate "Netfilter IPv6 packet duplication to alternate destination" + depends on !NF_CONNTRACK || NF_CONNTRACK +--- a/net/netfilter/Kconfig ++++ b/net/netfilter/Kconfig +@@ -707,8 +707,6 @@ config NFT_REJECT_NETDEV + + endif # NF_TABLES_NETDEV + +-endif # NF_TABLES +- + config NF_FLOW_TABLE_INET + tristate "Netfilter flow table mixed IPv4/IPv6 module" + depends on NF_FLOW_TABLE +@@ -717,11 +715,12 @@ config NF_FLOW_TABLE_INET + + To compile it as a module, choose M here. + ++endif # NF_TABLES ++ + config NF_FLOW_TABLE + tristate "Netfilter flow table module" + depends on NETFILTER_INGRESS + depends on NF_CONNTRACK +- depends on NF_TABLES + help + This option adds the flow table core infrastructure. + +@@ -1010,6 +1009,15 @@ config NETFILTER_XT_TARGET_NOTRACK + depends on NETFILTER_ADVANCED + select NETFILTER_XT_TARGET_CT + ++config NETFILTER_XT_TARGET_FLOWOFFLOAD ++ tristate '"FLOWOFFLOAD" target support' ++ depends on NF_FLOW_TABLE ++ depends on NETFILTER_INGRESS ++ help ++ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload ++ module to speed up processing of packets by bypassing the usual ++ netfilter chains ++ + config NETFILTER_XT_TARGET_RATEEST + tristate '"RATEEST" target support' + depends on NETFILTER_ADVANCED +--- a/net/netfilter/Makefile ++++ b/net/netfilter/Makefile +@@ -143,6 +143,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF + obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o + obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o ++obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o + obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o + obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o +--- /dev/null ++++ b/net/netfilter/xt_FLOWOFFLOAD.c +@@ -0,0 +1,698 @@ ++/* ++ * Copyright (C) 2018-2021 Felix Fietkau ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct xt_flowoffload_hook { ++ struct hlist_node list; ++ struct nf_hook_ops ops; ++ struct net *net; ++ bool registered; ++ bool used; ++}; ++ ++struct xt_flowoffload_table { ++ struct nf_flowtable ft; ++ struct hlist_head hooks; ++ struct delayed_work work; ++}; ++ ++struct nf_forward_info { ++ const struct net_device *indev; ++ const struct net_device *outdev; ++ const struct net_device *hw_outdev; ++ struct id { ++ __u16 id; ++ __be16 proto; ++ } encap[NF_FLOW_TABLE_ENCAP_MAX]; ++ u8 num_encaps; ++ u8 ingress_vlans; ++ u8 h_source[ETH_ALEN]; ++ u8 h_dest[ETH_ALEN]; ++ enum flow_offload_xmit_type xmit_type; ++}; ++ ++static DEFINE_SPINLOCK(hooks_lock); ++ ++struct xt_flowoffload_table flowtable[2]; ++ ++static unsigned int ++xt_flowoffload_net_hook(void *priv, struct sk_buff *skb, ++ const struct nf_hook_state *state) ++{ ++ struct vlan_ethhdr *veth; ++ __be16 proto; ++ ++ switch (skb->protocol) { ++ case htons(ETH_P_8021Q): ++ veth = (struct vlan_ethhdr *)skb_mac_header(skb); ++ proto = veth->h_vlan_encapsulated_proto; ++ break; ++ case htons(ETH_P_PPP_SES): ++ proto = nf_flow_pppoe_proto(skb); ++ break; ++ default: ++ proto = skb->protocol; ++ break; ++ } ++ ++ switch (proto) { ++ case htons(ETH_P_IP): ++ return nf_flow_offload_ip_hook(priv, skb, state); ++ case htons(ETH_P_IPV6): ++ return nf_flow_offload_ipv6_hook(priv, skb, state); ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static int ++xt_flowoffload_create_hook(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ struct nf_hook_ops *ops; ++ ++ hook = kzalloc(sizeof(*hook), GFP_ATOMIC); ++ if (!hook) ++ return -ENOMEM; ++ ++ ops = &hook->ops; ++ ops->pf = NFPROTO_NETDEV; ++ ops->hooknum = NF_NETDEV_INGRESS; ++ ops->priority = 10; ++ ops->priv = &table->ft; ++ ops->hook = xt_flowoffload_net_hook; ++ ops->dev = dev; ++ ++ hlist_add_head(&hook->list, &table->hooks); ++ mod_delayed_work(system_power_efficient_wq, &table->work, 0); ++ ++ return 0; ++} ++ ++static struct xt_flowoffload_hook * ++flow_offload_lookup_hook(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->ops.dev == dev) ++ return hook; ++ } ++ ++ return NULL; ++} ++ ++static void ++xt_flowoffload_check_device(struct xt_flowoffload_table *table, ++ struct net_device *dev) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++ if (!dev) ++ return; ++ ++ spin_lock_bh(&hooks_lock); ++ hook = flow_offload_lookup_hook(table, dev); ++ if (hook) ++ hook->used = true; ++ else ++ xt_flowoffload_create_hook(table, dev); ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_register_hooks(struct xt_flowoffload_table *table) ++{ ++ struct xt_flowoffload_hook *hook; ++ ++restart: ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->registered) ++ continue; ++ ++ hook->registered = true; ++ hook->net = dev_net(hook->ops.dev); ++ spin_unlock_bh(&hooks_lock); ++ nf_register_net_hook(hook->net, &hook->ops); ++ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) ++ table->ft.type->setup(&table->ft, hook->ops.dev, ++ FLOW_BLOCK_BIND); ++ spin_lock_bh(&hooks_lock); ++ goto restart; ++ } ++ ++} ++ ++static bool ++xt_flowoffload_cleanup_hooks(struct xt_flowoffload_table *table) ++{ ++ struct xt_flowoffload_hook *hook; ++ bool active = false; ++ ++restart: ++ spin_lock_bh(&hooks_lock); ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->used || !hook->registered) { ++ active = true; ++ continue; ++ } ++ ++ hlist_del(&hook->list); ++ spin_unlock_bh(&hooks_lock); ++ if (table->ft.flags & NF_FLOWTABLE_HW_OFFLOAD) ++ table->ft.type->setup(&table->ft, hook->ops.dev, ++ FLOW_BLOCK_UNBIND); ++ nf_unregister_net_hook(hook->net, &hook->ops); ++ kfree(hook); ++ goto restart; ++ } ++ spin_unlock_bh(&hooks_lock); ++ ++ return active; ++} ++ ++static void ++xt_flowoffload_check_hook(struct nf_flowtable *flowtable, ++ struct flow_offload *flow, void *data) ++{ ++ struct xt_flowoffload_table *table; ++ struct flow_offload_tuple *tuple0 = &flow->tuplehash[0].tuple; ++ struct flow_offload_tuple *tuple1 = &flow->tuplehash[1].tuple; ++ struct xt_flowoffload_hook *hook; ++ ++ table = container_of(flowtable, struct xt_flowoffload_table, ft); ++ ++ spin_lock_bh(&hooks_lock); ++ hlist_for_each_entry(hook, &table->hooks, list) { ++ if (hook->ops.dev->ifindex != tuple0->iifidx && ++ hook->ops.dev->ifindex != tuple1->iifidx) ++ continue; ++ ++ hook->used = true; ++ } ++ spin_unlock_bh(&hooks_lock); ++} ++ ++static void ++xt_flowoffload_hook_work(struct work_struct *work) ++{ ++ struct xt_flowoffload_table *table; ++ struct xt_flowoffload_hook *hook; ++ int err; ++ ++ table = container_of(work, struct xt_flowoffload_table, work.work); ++ ++ spin_lock_bh(&hooks_lock); ++ xt_flowoffload_register_hooks(table); ++ hlist_for_each_entry(hook, &table->hooks, list) ++ hook->used = false; ++ spin_unlock_bh(&hooks_lock); ++ ++ err = nf_flow_table_iterate(&table->ft, xt_flowoffload_check_hook, ++ NULL); ++ if (err && err != -EAGAIN) ++ goto out; ++ ++ if (!xt_flowoffload_cleanup_hooks(table)) ++ return; ++ ++out: ++ queue_delayed_work(system_power_efficient_wq, &table->work, HZ); ++} ++ ++static bool ++xt_flowoffload_skip(struct sk_buff *skb, int family) ++{ ++ if (skb_sec_path(skb)) ++ return true; ++ ++ if (family == NFPROTO_IPV4) { ++ const struct ip_options *opt = &(IPCB(skb)->opt); ++ ++ if (unlikely(opt->optlen)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static enum flow_offload_xmit_type nf_xmit_type(struct dst_entry *dst) ++{ ++ if (dst_xfrm(dst)) ++ return FLOW_OFFLOAD_XMIT_XFRM; ++ ++ return FLOW_OFFLOAD_XMIT_NEIGH; ++} ++ ++static void nf_default_forward_path(struct nf_flow_route *route, ++ struct dst_entry *dst_cache, ++ enum ip_conntrack_dir dir, ++ struct net_device **dev) ++{ ++ dev[!dir] = dst_cache->dev; ++ route->tuple[!dir].in.ifindex = dst_cache->dev->ifindex; ++ route->tuple[dir].dst = dst_cache; ++ route->tuple[dir].xmit_type = nf_xmit_type(dst_cache); ++} ++ ++static bool nf_is_valid_ether_device(const struct net_device *dev) ++{ ++ if (!dev || (dev->flags & IFF_LOOPBACK) || dev->type != ARPHRD_ETHER || ++ dev->addr_len != ETH_ALEN || !is_valid_ether_addr(dev->dev_addr)) ++ return false; ++ ++ return true; ++} ++ ++static void nf_dev_path_info(const struct net_device_path_stack *stack, ++ struct nf_forward_info *info, ++ unsigned char *ha) ++{ ++ const struct net_device_path *path; ++ int i; ++ ++ memcpy(info->h_dest, ha, ETH_ALEN); ++ ++ for (i = 0; i < stack->num_paths; i++) { ++ path = &stack->path[i]; ++ switch (path->type) { ++ case DEV_PATH_ETHERNET: ++ case DEV_PATH_DSA: ++ case DEV_PATH_VLAN: ++ case DEV_PATH_PPPOE: ++ info->indev = path->dev; ++ if (is_zero_ether_addr(info->h_source)) ++ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); ++ ++ if (path->type == DEV_PATH_ETHERNET) ++ break; ++ if (path->type == DEV_PATH_DSA) { ++ i = stack->num_paths; ++ break; ++ } ++ ++ /* DEV_PATH_VLAN and DEV_PATH_PPPOE */ ++ if (info->num_encaps >= NF_FLOW_TABLE_ENCAP_MAX) { ++ info->indev = NULL; ++ break; ++ } ++ if (!info->outdev) ++ info->outdev = path->dev; ++ info->encap[info->num_encaps].id = path->encap.id; ++ info->encap[info->num_encaps].proto = path->encap.proto; ++ info->num_encaps++; ++ if (path->type == DEV_PATH_PPPOE) ++ memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN); ++ break; ++ case DEV_PATH_BRIDGE: ++ if (is_zero_ether_addr(info->h_source)) ++ memcpy(info->h_source, path->dev->dev_addr, ETH_ALEN); ++ ++ switch (path->bridge.vlan_mode) { ++ case DEV_PATH_BR_VLAN_UNTAG_HW: ++ info->ingress_vlans |= BIT(info->num_encaps - 1); ++ break; ++ case DEV_PATH_BR_VLAN_TAG: ++ info->encap[info->num_encaps].id = path->bridge.vlan_id; ++ info->encap[info->num_encaps].proto = path->bridge.vlan_proto; ++ info->num_encaps++; ++ break; ++ case DEV_PATH_BR_VLAN_UNTAG: ++ info->num_encaps--; ++ break; ++ case DEV_PATH_BR_VLAN_KEEP: ++ break; ++ } ++ break; ++ default: ++ info->indev = NULL; ++ break; ++ } ++ } ++ if (!info->outdev) ++ info->outdev = info->indev; ++ ++ info->hw_outdev = info->indev; ++ ++ if (nf_is_valid_ether_device(info->indev)) ++ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT; ++} ++ ++static int nf_dev_fill_forward_path(const struct nf_flow_route *route, ++ const struct dst_entry *dst_cache, ++ const struct nf_conn *ct, ++ enum ip_conntrack_dir dir, u8 *ha, ++ struct net_device_path_stack *stack) ++{ ++ const void *daddr = &ct->tuplehash[!dir].tuple.src.u3; ++ struct net_device *dev = dst_cache->dev; ++ struct neighbour *n; ++ u8 nud_state; ++ ++ if (!nf_is_valid_ether_device(dev)) ++ goto out; ++ ++ n = dst_neigh_lookup(dst_cache, daddr); ++ if (!n) ++ return -1; ++ ++ read_lock_bh(&n->lock); ++ nud_state = n->nud_state; ++ ether_addr_copy(ha, n->ha); ++ read_unlock_bh(&n->lock); ++ neigh_release(n); ++ ++ if (!(nud_state & NUD_VALID)) ++ return -1; ++ ++out: ++ return dev_fill_forward_path(dev, ha, stack); ++} ++ ++static void nf_dev_forward_path(struct nf_flow_route *route, ++ const struct nf_conn *ct, ++ enum ip_conntrack_dir dir, ++ struct net_device **devs) ++{ ++ const struct dst_entry *dst = route->tuple[dir].dst; ++ struct net_device_path_stack stack; ++ struct nf_forward_info info = {}; ++ unsigned char ha[ETH_ALEN]; ++ int i; ++ ++ if (nf_dev_fill_forward_path(route, dst, ct, dir, ha, &stack) >= 0) ++ nf_dev_path_info(&stack, &info, ha); ++ ++ devs[!dir] = (struct net_device *)info.indev; ++ if (!info.indev) ++ return; ++ ++ route->tuple[!dir].in.ifindex = info.indev->ifindex; ++ for (i = 0; i < info.num_encaps; i++) { ++ route->tuple[!dir].in.encap[i].id = info.encap[i].id; ++ route->tuple[!dir].in.encap[i].proto = info.encap[i].proto; ++ } ++ route->tuple[!dir].in.num_encaps = info.num_encaps; ++ route->tuple[!dir].in.ingress_vlans = info.ingress_vlans; ++ ++ if (info.xmit_type == FLOW_OFFLOAD_XMIT_DIRECT) { ++ memcpy(route->tuple[dir].out.h_source, info.h_source, ETH_ALEN); ++ memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN); ++ route->tuple[dir].out.ifindex = info.outdev->ifindex; ++ route->tuple[dir].out.hw_ifindex = info.hw_outdev->ifindex; ++ route->tuple[dir].xmit_type = info.xmit_type; ++ } ++} ++ ++static int ++xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct, ++ const struct xt_action_param *par, ++ struct nf_flow_route *route, enum ip_conntrack_dir dir, ++ struct net_device **devs) ++{ ++ struct dst_entry *this_dst = skb_dst(skb); ++ struct dst_entry *other_dst = NULL; ++ struct flowi fl; ++ ++ memset(&fl, 0, sizeof(fl)); ++ switch (xt_family(par)) { ++ case NFPROTO_IPV4: ++ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip; ++ fl.u.ip4.flowi4_oif = xt_in(par)->ifindex; ++ break; ++ case NFPROTO_IPV6: ++ fl.u.ip6.saddr = ct->tuplehash[!dir].tuple.dst.u3.in6; ++ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6; ++ fl.u.ip6.flowi6_oif = xt_in(par)->ifindex; ++ break; ++ } ++ ++ nf_route(xt_net(par), &other_dst, &fl, false, xt_family(par)); ++ if (!other_dst) ++ return -ENOENT; ++ ++ nf_default_forward_path(route, this_dst, dir, devs); ++ nf_default_forward_path(route, other_dst, !dir, devs); ++ ++ if (route->tuple[dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH && ++ route->tuple[!dir].xmit_type == FLOW_OFFLOAD_XMIT_NEIGH) { ++ nf_dev_forward_path(route, ct, dir, devs); ++ nf_dev_forward_path(route, ct, !dir, devs); ++ } ++ ++ return 0; ++} ++ ++static unsigned int ++flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par) ++{ ++ struct xt_flowoffload_table *table; ++ const struct xt_flowoffload_target_info *info = par->targinfo; ++ struct tcphdr _tcph, *tcph = NULL; ++ enum ip_conntrack_info ctinfo; ++ enum ip_conntrack_dir dir; ++ struct nf_flow_route route = {}; ++ struct flow_offload *flow = NULL; ++ struct net_device *devs[2] = {}; ++ struct nf_conn *ct; ++ struct net *net; ++ ++ if (xt_flowoffload_skip(skb, xt_family(par))) ++ return XT_CONTINUE; ++ ++ ct = nf_ct_get(skb, &ctinfo); ++ if (ct == NULL) ++ return XT_CONTINUE; ++ ++ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) { ++ case IPPROTO_TCP: ++ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED) ++ return XT_CONTINUE; ++ ++ tcph = skb_header_pointer(skb, par->thoff, ++ sizeof(_tcph), &_tcph); ++ if (unlikely(!tcph || tcph->fin || tcph->rst)) ++ return XT_CONTINUE; ++ break; ++ case IPPROTO_UDP: ++ break; ++ default: ++ return XT_CONTINUE; ++ } ++ ++ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) || ++ ct->status & (IPS_SEQ_ADJUST | IPS_NAT_CLASH)) ++ return XT_CONTINUE; ++ ++ if (!nf_ct_is_confirmed(ct)) ++ return XT_CONTINUE; ++ ++ devs[dir] = xt_out(par); ++ devs[!dir] = xt_in(par); ++ ++ if (!devs[dir] || !devs[!dir]) ++ return XT_CONTINUE; ++ ++ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status)) ++ return XT_CONTINUE; ++ ++ dir = CTINFO2DIR(ctinfo); ++ ++ if (xt_flowoffload_route(skb, ct, par, &route, dir, devs) < 0) ++ goto err_flow_route; ++ ++ flow = flow_offload_alloc(ct); ++ if (!flow) ++ goto err_flow_alloc; ++ ++ if (flow_offload_route_init(flow, &route) < 0) ++ goto err_flow_add; ++ ++ if (tcph) { ++ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL; ++ } ++ ++ table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)]; ++ ++ net = read_pnet(&table->ft.net); ++ if (!net) ++ write_pnet(&table->ft.net, xt_net(par)); ++ ++ if (flow_offload_add(&table->ft, flow) < 0) ++ goto err_flow_add; ++ ++ xt_flowoffload_check_device(table, devs[0]); ++ xt_flowoffload_check_device(table, devs[1]); ++ ++ dst_release(route.tuple[!dir].dst); ++ ++ return XT_CONTINUE; ++ ++err_flow_add: ++ flow_offload_free(flow); ++err_flow_alloc: ++ dst_release(route.tuple[!dir].dst); ++err_flow_route: ++ clear_bit(IPS_OFFLOAD_BIT, &ct->status); ++ ++ return XT_CONTINUE; ++} ++ ++static int flowoffload_chk(const struct xt_tgchk_param *par) ++{ ++ struct xt_flowoffload_target_info *info = par->targinfo; ++ ++ if (info->flags & ~XT_FLOWOFFLOAD_MASK) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static struct xt_target offload_tg_reg __read_mostly = { ++ .family = NFPROTO_UNSPEC, ++ .name = "FLOWOFFLOAD", ++ .revision = 0, ++ .targetsize = sizeof(struct xt_flowoffload_target_info), ++ .usersize = sizeof(struct xt_flowoffload_target_info), ++ .checkentry = flowoffload_chk, ++ .target = flowoffload_tg, ++ .me = THIS_MODULE, ++}; ++ ++static int flow_offload_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct xt_flowoffload_hook *hook0, *hook1; ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (event != NETDEV_UNREGISTER) ++ return NOTIFY_DONE; ++ ++ spin_lock_bh(&hooks_lock); ++ hook0 = flow_offload_lookup_hook(&flowtable[0], dev); ++ if (hook0) ++ hlist_del(&hook0->list); ++ ++ hook1 = flow_offload_lookup_hook(&flowtable[1], dev); ++ if (hook1) ++ hlist_del(&hook1->list); ++ spin_unlock_bh(&hooks_lock); ++ ++ if (hook0) { ++ nf_unregister_net_hook(hook0->net, &hook0->ops); ++ kfree(hook0); ++ } ++ ++ if (hook1) { ++ nf_unregister_net_hook(hook1->net, &hook1->ops); ++ kfree(hook1); ++ } ++ ++ nf_flow_table_cleanup(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block flow_offload_netdev_notifier = { ++ .notifier_call = flow_offload_netdev_event, ++}; ++ ++static int nf_flow_rule_route_inet(struct net *net, ++ const struct flow_offload *flow, ++ enum flow_offload_tuple_dir dir, ++ struct nf_flow_rule *flow_rule) ++{ ++ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple; ++ int err; ++ ++ switch (flow_tuple->l3proto) { ++ case NFPROTO_IPV4: ++ err = nf_flow_rule_route_ipv4(net, flow, dir, flow_rule); ++ break; ++ case NFPROTO_IPV6: ++ err = nf_flow_rule_route_ipv6(net, flow, dir, flow_rule); ++ break; ++ default: ++ err = -1; ++ break; ++ } ++ ++ return err; ++} ++ ++static struct nf_flowtable_type flowtable_inet = { ++ .family = NFPROTO_INET, ++ .init = nf_flow_table_init, ++ .setup = nf_flow_table_offload_setup, ++ .action = nf_flow_rule_route_inet, ++ .free = nf_flow_table_free, ++ .hook = xt_flowoffload_net_hook, ++ .owner = THIS_MODULE, ++}; ++ ++static int init_flowtable(struct xt_flowoffload_table *tbl) ++{ ++ INIT_DELAYED_WORK(&tbl->work, xt_flowoffload_hook_work); ++ tbl->ft.type = &flowtable_inet; ++ tbl->ft.flags = NF_FLOWTABLE_COUNTER; ++ ++ return nf_flow_table_init(&tbl->ft); ++} ++ ++static int __init xt_flowoffload_tg_init(void) ++{ ++ int ret; ++ ++ register_netdevice_notifier(&flow_offload_netdev_notifier); ++ ++ ret = init_flowtable(&flowtable[0]); ++ if (ret) ++ return ret; ++ ++ ret = init_flowtable(&flowtable[1]); ++ if (ret) ++ goto cleanup; ++ ++ flowtable[1].ft.flags |= NF_FLOWTABLE_HW_OFFLOAD; ++ ++ ret = xt_register_target(&offload_tg_reg); ++ if (ret) ++ goto cleanup2; ++ ++ return 0; ++ ++cleanup2: ++ nf_flow_table_free(&flowtable[1].ft); ++cleanup: ++ nf_flow_table_free(&flowtable[0].ft); ++ return ret; ++} ++ ++static void __exit xt_flowoffload_tg_exit(void) ++{ ++ xt_unregister_target(&offload_tg_reg); ++ unregister_netdevice_notifier(&flow_offload_netdev_notifier); ++ nf_flow_table_free(&flowtable[0].ft); ++ nf_flow_table_free(&flowtable[1].ft); ++} ++ ++MODULE_LICENSE("GPL"); ++module_init(xt_flowoffload_tg_init); ++module_exit(xt_flowoffload_tg_exit); +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -380,8 +379,7 @@ flow_offload_lookup(struct nf_flowtable + } + EXPORT_SYMBOL_GPL(flow_offload_lookup); + +-static int +-nf_flow_table_iterate(struct nf_flowtable *flow_table, ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, + void (*iter)(struct nf_flowtable *flowtable, + struct flow_offload *flow, void *data), + void *data) +@@ -435,6 +433,7 @@ static void nf_flow_offload_gc_step(stru + nf_flow_offload_stats(flow_table, flow); + } + } ++EXPORT_SYMBOL_GPL(nf_flow_table_iterate); + + void nf_flow_table_gc_run(struct nf_flowtable *flow_table) + { +--- /dev/null ++++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++#ifndef _XT_FLOWOFFLOAD_H ++#define _XT_FLOWOFFLOAD_H ++ ++#include ++ ++enum { ++ XT_FLOWOFFLOAD_HW = 1 << 0, ++ ++ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW ++}; ++ ++struct xt_flowoffload_target_info { ++ __u32 flags; ++}; ++ ++#endif /* _XT_FLOWOFFLOAD_H */ +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -276,6 +276,11 @@ void nf_flow_table_free(struct nf_flowta + + void flow_offload_teardown(struct flow_offload *flow); + ++int nf_flow_table_iterate(struct nf_flowtable *flow_table, ++ void (*iter)(struct nf_flowtable *flowtable, ++ struct flow_offload *flow, void *data), ++ void *data); ++ + void nf_flow_snat_port(const struct flow_offload *flow, + struct sk_buff *skb, unsigned int thoff, + u8 protocol, enum flow_offload_tuple_dir dir); diff --git a/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch b/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch new file mode 100644 index 00000000000..12a031ec84d --- /dev/null +++ b/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch @@ -0,0 +1,24 @@ +From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Fri, 7 Jul 2017 17:21:05 +0200 +Subject: mac80211: increase wireless mesh header size + +lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1 +Signed-off-by: Imre Kaloz +--- + include/linux/netdevice.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -145,8 +145,8 @@ static inline bool dev_xmit_complete(int + + #if defined(CONFIG_HYPERV_NET) + # define LL_MAX_HEADER 128 +-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) +-# if defined(CONFIG_MAC80211_MESH) ++#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1 ++# if defined(CONFIG_MAC80211_MESH) || 1 + # define LL_MAX_HEADER 128 + # else + # define LL_MAX_HEADER 96 diff --git a/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch b/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch new file mode 100644 index 00000000000..a57a045f4a8 --- /dev/null +++ b/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch @@ -0,0 +1,27 @@ +From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:21:53 +0200 +Subject: hack: net: fq_codel: tune defaults for small devices + +Assume that x86_64 devices always have a big memory and do not need this +optimization compared to devices with only 32 MB or 64 MB RAM. + +Signed-off-by: Felix Fietkau +--- + net/sched/sch_fq_codel.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -467,7 +467,11 @@ static int fq_codel_init(struct Qdisc *s + + sch->limit = 10*1024; + q->flows_cnt = 1024; ++#ifdef CONFIG_X86_64 + q->memory_limit = 32 << 20; /* 32 MBytes */ ++#else ++ q->memory_limit = 4 << 20; /* 4 MBytes */ ++#endif + q->drop_batch_size = 64; + q->quantum = psched_mtu(qdisc_dev(sch)); + INIT_LIST_HEAD(&q->new_flows); diff --git a/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch b/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch new file mode 100644 index 00000000000..683aa8a8df3 --- /dev/null +++ b/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch @@ -0,0 +1,25 @@ +From 804fbb3f2ec9283f7b778e057a68bfff440a0be6 Mon Sep 17 00:00:00 2001 +From: Rui Salvaterra +Date: Wed, 30 Mar 2022 22:51:55 +0100 +Subject: [PATCH] kernel: ct: size the hashtable more adequately + +To set the default size of the connection tracking hash table, a divider of +16384 becomes inadequate for a router handling lots of connections. Divide by +2048 instead, making the default size scale better with the available RAM. + +Signed-off-by: Rui Salvaterra +--- + net/netfilter/nf_conntrack_core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -2735,7 +2735,7 @@ int nf_conntrack_init_start(void) + + if (!nf_conntrack_htable_size) { + nf_conntrack_htable_size +- = (((nr_pages << PAGE_SHIFT) / 16384) ++ = (((nr_pages << PAGE_SHIFT) / 2048) + / sizeof(struct hlist_head)); + if (BITS_PER_LONG >= 64 && + nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE))) diff --git a/target/linux/generic/hack-6.1/700-swconfig_switch_drivers.patch b/target/linux/generic/hack-6.1/700-swconfig_switch_drivers.patch new file mode 100644 index 00000000000..48be4400256 --- /dev/null +++ b/target/linux/generic/hack-6.1/700-swconfig_switch_drivers.patch @@ -0,0 +1,131 @@ +From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:24:23 +0200 +Subject: net: swconfig: adds openwrt switch layer + +Signed-off-by: Felix Fietkau +--- + drivers/net/phy/Kconfig | 83 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/net/phy/Makefile | 15 +++++++++ + include/uapi/linux/Kbuild | 1 + + 3 files changed, 99 insertions(+) + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -61,6 +61,80 @@ config SFP + depends on HWMON || HWMON=n + select MDIO_I2C + ++comment "Switch configuration API + drivers" ++ ++config SWCONFIG ++ tristate "Switch configuration API" ++ help ++ Switch configuration API using netlink. This allows ++ you to configure the VLAN features of certain switches. ++ ++config SWCONFIG_LEDS ++ bool "Switch LED trigger support" ++ depends on (SWCONFIG && LEDS_TRIGGERS) ++ ++config ADM6996_PHY ++ tristate "Driver for ADM6996 switches" ++ select SWCONFIG ++ help ++ Currently supports the ADM6996FC and ADM6996M switches. ++ Support for FC is very limited. ++ ++config AR8216_PHY ++ tristate "Driver for Atheros AR8216/8327 switches" ++ select SWCONFIG ++ select ETHERNET_PACKET_MANGLE ++ ++config AR8216_PHY_LEDS ++ bool "Atheros AR8216 switch LED support" ++ depends on (AR8216_PHY && LEDS_CLASS) ++ ++source "drivers/net/phy/b53/Kconfig" ++ ++config IP17XX_PHY ++ tristate "Driver for IC+ IP17xx switches" ++ select SWCONFIG ++ ++config PSB6970_PHY ++ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch" ++ select SWCONFIG ++ ++config RTL8306_PHY ++ tristate "Driver for Realtek RTL8306S switches" ++ select SWCONFIG ++ ++config RTL8366_SMI ++ tristate "Driver for the RTL8366 SMI interface" ++ depends on GPIOLIB ++ help ++ This module implements the SMI interface protocol which is used ++ by some RTL8366 ethernet switch devices via the generic GPIO API. ++ ++if RTL8366_SMI ++ ++config RTL8366_SMI_DEBUG_FS ++ bool "RTL8366 SMI interface debugfs support" ++ depends on DEBUG_FS ++ default n ++ ++config RTL8366S_PHY ++ tristate "Driver for the Realtek RTL8366S switch" ++ select SWCONFIG ++ ++config RTL8366RB_PHY ++ tristate "Driver for the Realtek RTL8366RB switch" ++ select SWCONFIG ++ ++config RTL8367_PHY ++ tristate "Driver for the Realtek RTL8367R/M switches" ++ select SWCONFIG ++ ++config RTL8367B_PHY ++ tristate "Driver fot the Realtek RTL8367R-VB switch" ++ select SWCONFIG ++ ++endif # RTL8366_SMI ++ + comment "MII PHY device drivers" + + config AMD_PHY +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -24,6 +24,21 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_ + obj-$(CONFIG_PHYLINK) += phylink.o + obj-$(CONFIG_PHYLIB) += libphy.o + ++obj-$(CONFIG_SWCONFIG) += swconfig.o ++obj-$(CONFIG_ADM6996_PHY) += adm6996.o ++obj-$(CONFIG_AR8216_PHY) += ar8xxx.o ++ar8xxx-y += ar8216.o ++ar8xxx-y += ar8327.o ++obj-$(CONFIG_SWCONFIG_B53) += b53/ ++obj-$(CONFIG_IP17XX_PHY) += ip17xx.o ++obj-$(CONFIG_PSB6970_PHY) += psb6970.o ++obj-$(CONFIG_RTL8306_PHY) += rtl8306.o ++obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o ++obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o ++obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o ++obj-$(CONFIG_RTL8367_PHY) += rtl8367.o ++obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o ++ + obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o + + obj-$(CONFIG_SFP) += sfp.o +--- a/include/linux/platform_data/b53.h ++++ b/include/linux/platform_data/b53.h +@@ -29,6 +29,9 @@ struct b53_platform_data { + u32 chip_id; + u16 enabled_ports; + ++ /* allow to specify an ethX alias */ ++ const char *alias; ++ + /* only used by MMAP'd driver */ + unsigned big_endian:1; + void __iomem *regs; diff --git a/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch new file mode 100644 index 00000000000..e62f45f3c33 --- /dev/null +++ b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch @@ -0,0 +1,21 @@ +From ebd924d773223593142d417c41d4ee6fa16f1805 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:45:56 +0200 +Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation + +--- + drivers/net/dsa/mv88e6xxx/chip.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -2985,6 +2985,9 @@ static int mv88e6xxx_setup_port(struct m + else + reg = 1 << port; + ++ /* Disable ATU member violation interrupt */ ++ reg |= MV88E6XXX_PORT_ASSOC_VECTOR_IGNORE_WRONG; ++ + err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_ASSOC_VECTOR, + reg); + if (err) diff --git a/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch new file mode 100644 index 00000000000..29050d38ea2 --- /dev/null +++ b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch @@ -0,0 +1,142 @@ +From: Birger Koblitz +Date: Sun, 5 Sep 2021 15:13:10 +0200 +Subject: [PATCH] kernel: Add AQR113C and AQR813 support + +This hack adds support for the Aquantia 4th generation, 10GBit +PHYs AQR113C and AQR813. + +Signed-off-by: Birger Koblitz + +--- a/drivers/net/phy/aquantia_main.c ++++ b/drivers/net/phy/aquantia_main.c +@@ -20,8 +20,10 @@ + #define PHY_ID_AQR105 0x03a1b4a2 + #define PHY_ID_AQR106 0x03a1b4d0 + #define PHY_ID_AQR107 0x03a1b4e0 ++#define PHY_ID_AQR113C 0x31c31c12 + #define PHY_ID_AQCS109 0x03a1b5c2 + #define PHY_ID_AQR405 0x03a1b4b0 ++#define PHY_ID_AQR813 0x31c31cb2 + + #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +@@ -381,6 +383,49 @@ static int aqr107_read_rate(struct phy_d + return 0; + } + ++static int aqr113c_read_status(struct phy_device *phydev) ++{ ++ int val, ret; ++ ++ ret = aqr_read_status(phydev); ++ if (ret) ++ return ret; ++ ++ if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) ++ return 0; ++ ++ // On AQR113C, the speed returned by aqr_read_status is wrong ++ aqr107_read_rate(phydev); ++ ++ val = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_VEND_IF_STATUS); ++ if (val < 0) ++ return val; ++ ++ switch (FIELD_GET(MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK, val)) { ++ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR: ++ phydev->interface = PHY_INTERFACE_MODE_10GKR; ++ break; ++ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_XFI: ++ phydev->interface = PHY_INTERFACE_MODE_10GBASER; ++ break; ++ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_USXGMII: ++ phydev->interface = PHY_INTERFACE_MODE_USXGMII; ++ break; ++ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_SGMII: ++ phydev->interface = PHY_INTERFACE_MODE_SGMII; ++ break; ++ case MDIO_PHYXS_VEND_IF_STATUS_TYPE_OCSGMII: ++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ break; ++ default: ++ phydev->interface = PHY_INTERFACE_MODE_NA; ++ break; ++ } ++ ++ /* Read downshifted rate from vendor register */ ++ return aqr107_read_rate(phydev); ++} ++ + static int aqr107_read_status(struct phy_device *phydev) + { + int val, ret; +@@ -511,7 +556,7 @@ static void aqr107_chip_info(struct phy_ + build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); + prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); + +- phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n", ++ phydev_info(phydev, "FW %u.%u, Build %u, Provisioning %u\n", + fw_major, fw_minor, build_id, prov_id); + } + +@@ -719,6 +764,24 @@ static struct phy_driver aqr_driver[] = + .link_change_notify = aqr107_link_change_notify, + }, + { ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), ++ .name = "Aquantia AQR113C", ++ .probe = aqr107_probe, ++ .config_init = aqr107_config_init, ++ .config_aneg = aqr_config_aneg, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr113c_read_status, ++ .get_tunable = aqr107_get_tunable, ++ .set_tunable = aqr107_set_tunable, ++ .suspend = aqr107_suspend, ++ .resume = aqr107_resume, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++ .link_change_notify = aqr107_link_change_notify, ++}, ++{ + PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), + .name = "Aquantia AQCS109", + .probe = aqr107_probe, +@@ -744,6 +807,24 @@ static struct phy_driver aqr_driver[] = + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr_read_status, + }, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR813), ++ .name = "Aquantia AQR813", ++ .probe = aqr107_probe, ++ .config_init = aqr107_config_init, ++ .config_aneg = aqr_config_aneg, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr113c_read_status, ++ .get_tunable = aqr107_get_tunable, ++ .set_tunable = aqr107_set_tunable, ++ .suspend = aqr107_suspend, ++ .resume = aqr107_resume, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++ .link_change_notify = aqr107_link_change_notify, ++}, + }; + + module_phy_driver(aqr_driver); +@@ -754,8 +835,10 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, + { } + }; + diff --git a/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch new file mode 100644 index 00000000000..dbdb141c6dc --- /dev/null +++ b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch @@ -0,0 +1,178 @@ +From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Fri, 7 Jul 2017 17:25:00 +0200 +Subject: net: add packet mangeling + +ar8216 switches have a hardware bug, which renders normal 802.1q support +unusable. Packet mangling is required to fix up the vlan for incoming +packets. + +Signed-off-by: Felix Fietkau +--- + include/linux/netdevice.h | 11 +++++++++++ + include/linux/skbuff.h | 14 ++++---------- + net/Kconfig | 6 ++++++ + net/core/dev.c | 20 +++++++++++++++----- + net/core/skbuff.c | 17 +++++++++++++++++ + net/ethernet/eth.c | 6 ++++++ + 6 files changed, 59 insertions(+), 15 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -1679,6 +1679,10 @@ enum netdev_priv_flags { + IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), + }; + ++enum netdev_extra_priv_flags { ++ IFF_NO_IP_ALIGN = 1<<0, ++}; ++ + #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN + #define IFF_EBRIDGE IFF_EBRIDGE + #define IFF_BONDING IFF_BONDING +@@ -1711,6 +1715,7 @@ enum netdev_priv_flags { + #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER + #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK + #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN + + /* Specifies the type of the struct net_device::ml_priv pointer */ + enum netdev_ml_priv_type { +@@ -2012,6 +2017,7 @@ struct net_device { + /* Read-mostly cache-line for fast-path access */ + unsigned int flags; + unsigned int priv_flags; ++ unsigned int extra_priv_flags; + const struct net_device_ops *netdev_ops; + int ifindex; + unsigned short gflags; +@@ -2072,6 +2078,11 @@ struct net_device { + const struct tlsdev_ops *tlsdev_ops; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb); ++ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb); ++#endif ++ + const struct header_ops *header_ops; + + unsigned char operstate; +@@ -2146,6 +2157,10 @@ struct net_device { + struct mctp_dev __rcu *mctp_ptr; + #endif + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ void *phy_ptr; /* PHY device specific data */ ++#endif ++ + /* + * Cache lines mostly used on receive path (including eth_type_trans()) + */ +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2855,6 +2855,10 @@ static inline int pskb_trim(struct sk_bu + return (len < skb->len) ? __pskb_trim(skb, len) : 0; + } + ++extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp); ++ ++ + /** + * pskb_trim_unique - remove end from a paged unique (not cloned) buffer + * @skb: buffer to alter +@@ -3005,16 +3009,6 @@ static inline struct sk_buff *dev_alloc_ + } + + +-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, +- unsigned int length, gfp_t gfp) +-{ +- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); +- +- if (NET_IP_ALIGN && skb) +- skb_reserve(skb, NET_IP_ALIGN); +- return skb; +-} +- + static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, + unsigned int length) + { +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -26,6 +26,12 @@ menuconfig NET + + if NET + ++config ETHERNET_PACKET_MANGLE ++ bool ++ help ++ This option can be selected by phy drivers that need to mangle ++ packets going in or out of an ethernet device. ++ + config WANT_COMPAT_NETLINK_MESSAGES + bool + help +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3590,6 +3590,11 @@ static int xmit_one(struct sk_buff *skb, + if (dev_nit_active(dev)) + dev_queue_xmit_nit(skb, dev); + ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb))) ++ return NETDEV_TX_OK; ++#endif ++ + len = skb->len; + PRANDOM_ADD_NOISE(skb, dev, txq, len + jiffies); + trace_net_dev_start_xmit(skb, dev); +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -61,6 +61,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -602,6 +603,22 @@ skb_fail: + } + EXPORT_SYMBOL(__napi_alloc_skb); + ++struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, ++ unsigned int length, gfp_t gfp) ++{ ++ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev && (dev->extra_priv_flags & IFF_NO_IP_ALIGN)) ++ return skb; ++#endif ++ ++ if (NET_IP_ALIGN && skb) ++ skb_reserve(skb, NET_IP_ALIGN); ++ return skb; ++} ++EXPORT_SYMBOL(__netdev_alloc_skb_ip_align); ++ + void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, + int size, unsigned int truesize) + { +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -170,6 +170,12 @@ __be16 eth_type_trans(struct sk_buff *sk + const struct ethhdr *eth; + + skb->dev = dev; ++ ++#ifdef CONFIG_ETHERNET_PACKET_MANGLE ++ if (dev->eth_mangle_rx) ++ dev->eth_mangle_rx(dev, skb); ++#endif ++ + skb_reset_mac_header(skb); + + eth = (struct ethhdr *)skb->data; diff --git a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch new file mode 100644 index 00000000000..211696c5688 --- /dev/null +++ b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch @@ -0,0 +1,154 @@ +From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001 +From: Alex Marginean +Date: Tue, 27 Aug 2019 15:16:56 +0300 +Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412 + +Adds support for AQR112 and AQR412 which is mostly based on existing code +with the addition of code configuring the protocol on system side. +This allows changing the system side protocol without having to deploy a +different firmware on the PHY. + +Signed-off-by: Alex Marginean +--- + drivers/net/phy/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 88 insertions(+) + +--- a/drivers/net/phy/aquantia_main.c ++++ b/drivers/net/phy/aquantia_main.c +@@ -20,9 +20,11 @@ + #define PHY_ID_AQR105 0x03a1b4a2 + #define PHY_ID_AQR106 0x03a1b4d0 + #define PHY_ID_AQR107 0x03a1b4e0 ++#define PHY_ID_AQR112 0x03a1b662 + #define PHY_ID_AQR113C 0x31c31c12 + #define PHY_ID_AQCS109 0x03a1b5c2 + #define PHY_ID_AQR405 0x03a1b4b0 ++#define PHY_ID_AQR412 0x03a1b712 + #define PHY_ID_AQR813 0x31c31cb2 + + #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 +@@ -135,6 +137,29 @@ + #define AQR107_OP_IN_PROG_SLEEP 1000 + #define AQR107_OP_IN_PROG_TIMEOUT 100000 + ++/* registers in MDIO_MMD_VEND1 region */ ++#define AQUANTIA_VND1_GLOBAL_SC 0x000 ++#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb) ++ ++/* global start rate, the protocol associated with this speed is used by default ++ * on SI. ++ */ ++#define AQUANTIA_VND1_GSTART_RATE 0x31a ++#define AQUANTIA_VND1_GSTART_RATE_OFF 0 ++#define AQUANTIA_VND1_GSTART_RATE_100M 1 ++#define AQUANTIA_VND1_GSTART_RATE_1G 2 ++#define AQUANTIA_VND1_GSTART_RATE_10G 3 ++#define AQUANTIA_VND1_GSTART_RATE_2_5G 4 ++#define AQUANTIA_VND1_GSTART_RATE_5G 5 ++ ++/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */ ++#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b ++#define AQUANTIA_VND1_GSYSCFG_100M 0 ++#define AQUANTIA_VND1_GSYSCFG_1G 1 ++#define AQUANTIA_VND1_GSYSCFG_2_5G 2 ++#define AQUANTIA_VND1_GSYSCFG_5G 3 ++#define AQUANTIA_VND1_GSYSCFG_10G 4 ++ + struct aqr107_hw_stat { + const char *name; + int reg; +@@ -266,6 +291,51 @@ static int aqr_config_aneg(struct phy_de + return genphy_c45_check_and_restart_aneg(phydev, changed); + } + ++static struct { ++ u16 syscfg; ++ int cnt; ++ u16 start_rate; ++} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = { ++ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G, ++ AQUANTIA_VND1_GSTART_RATE_1G}, ++ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G, ++ AQUANTIA_VND1_GSTART_RATE_2_5G}, ++ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G, ++ AQUANTIA_VND1_GSTART_RATE_10G}, ++ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G, ++ AQUANTIA_VND1_GSTART_RATE_10G}, ++}; ++ ++/* Sets up protocol on system side before calling aqr_config_aneg */ ++static int aqr_config_aneg_set_prot(struct phy_device *phydev) ++{ ++ int if_type = phydev->interface; ++ int i; ++ ++ if (!aquantia_syscfg[if_type].cnt) ++ return 0; ++ ++ /* set PHY in low power mode so we can configure protocols */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, ++ AQUANTIA_VND1_GLOBAL_SC_LP); ++ mdelay(10); ++ ++ /* set the default rate to enable the SI link */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, ++ aquantia_syscfg[if_type].start_rate); ++ ++ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, ++ AQUANTIA_VND1_GSYSCFG_BASE + i, ++ aquantia_syscfg[if_type].syscfg); ++ ++ /* wake PHY back up */ ++ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); ++ mdelay(10); ++ ++ return aqr_config_aneg(phydev); ++} ++ + static int aqr_config_intr(struct phy_device *phydev) + { + bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; +@@ -825,6 +895,30 @@ static struct phy_driver aqr_driver[] = + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, + }, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR112), ++ .name = "Aquantia AQR112", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR412), ++ .name = "Aquantia AQR412", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, + }; + + module_phy_driver(aqr_driver); +@@ -835,9 +929,11 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, + { } + }; diff --git a/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch new file mode 100644 index 00000000000..7d16c8aa289 --- /dev/null +++ b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch @@ -0,0 +1,34 @@ +From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001 +From: Alex Marginean +Date: Fri, 20 Sep 2019 18:22:52 +0300 +Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol + misconfiguration + +Do not set up protocols for speeds that are not supported by FW. Enabling +these protocols leads to link issues on system side. + +Signed-off-by: Alex Marginean +--- + drivers/net/phy/aquantia_main.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/aquantia_main.c ++++ b/drivers/net/phy/aquantia_main.c +@@ -324,10 +324,16 @@ static int aqr_config_aneg_set_prot(stru + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, + aquantia_syscfg[if_type].start_rate); + +- for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) ++ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) { ++ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ++ AQUANTIA_VND1_GSYSCFG_BASE + i); ++ if (!reg) ++ continue; ++ + phy_write_mmd(phydev, MDIO_MMD_VEND1, + AQUANTIA_VND1_GSYSCFG_BASE + i, + aquantia_syscfg[if_type].syscfg); ++ } + + /* wake PHY back up */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0); diff --git a/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch new file mode 100644 index 00000000000..d03c3430fae --- /dev/null +++ b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch @@ -0,0 +1,43 @@ +From 2e677e4ae8f8330f68013163b060d0fda3a43095 Mon Sep 17 00:00:00 2001 +From: "Langer, Thomas" +Date: Fri, 9 Jul 2021 17:36:46 +0200 +Subject: [PATCH] PONRTSYS-8842: aquantia: Add AQR113 driver support + +Add a new entry for AQR113 PHY_ID +--- + drivers/net/phy/aquantia_main.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/net/phy/aquantia_main.c ++++ b/drivers/net/phy/aquantia_main.c +@@ -21,6 +21,7 @@ + #define PHY_ID_AQR106 0x03a1b4d0 + #define PHY_ID_AQR107 0x03a1b4e0 + #define PHY_ID_AQR112 0x03a1b662 ++#define PHY_ID_AQR113 0x31c31c40 + #define PHY_ID_AQR113C 0x31c31c12 + #define PHY_ID_AQCS109 0x03a1b5c2 + #define PHY_ID_AQR405 0x03a1b4b0 +@@ -914,6 +915,14 @@ static struct phy_driver aqr_driver[] = + .get_stats = aqr107_get_stats, + }, + { ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR113), ++ .name = "Aquantia AQR113", ++ .config_aneg = aqr_config_aneg, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++}, ++{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR412), + .name = "Aquantia AQR412", + .probe = aqr107_probe, +@@ -936,6 +945,7 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, diff --git a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch new file mode 100644 index 00000000000..9821c0c86ee --- /dev/null +++ b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch @@ -0,0 +1,63 @@ +From 3b92ee7b7899b6beffb2b484c58326e36612a873 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Thu, 23 Dec 2021 14:52:56 +0000 +Subject: [PATCH] net: phy: aquantia: add PHY_ID for AQR112R + +As advised by Ian Chang this PHY is used in Puzzle devices. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/aquantia_main.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/net/phy/aquantia_main.c ++++ b/drivers/net/phy/aquantia_main.c +@@ -21,6 +21,8 @@ + #define PHY_ID_AQR106 0x03a1b4d0 + #define PHY_ID_AQR107 0x03a1b4e0 + #define PHY_ID_AQR112 0x03a1b662 ++#define PHY_ID_AQR112C 0x03a1b790 ++#define PHY_ID_AQR112R 0x31c31d12 + #define PHY_ID_AQR113 0x31c31c40 + #define PHY_ID_AQR113C 0x31c31c12 + #define PHY_ID_AQCS109 0x03a1b5c2 +@@ -915,6 +917,30 @@ static struct phy_driver aqr_driver[] = + .get_stats = aqr107_get_stats, + }, + { ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C), ++ .name = "Aquantia AQR112C", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, ++{ ++ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R), ++ .name = "Aquantia AQR112R", ++ .probe = aqr107_probe, ++ .config_aneg = aqr_config_aneg_set_prot, ++ .config_intr = aqr_config_intr, ++ .handle_interrupt = aqr_handle_interrupt, ++ .read_status = aqr107_read_status, ++ .get_sset_count = aqr107_get_sset_count, ++ .get_strings = aqr107_get_strings, ++ .get_stats = aqr107_get_stats, ++}, ++{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR113), + .name = "Aquantia AQR113", + .config_aneg = aqr_config_aneg, +@@ -945,6 +971,8 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, diff --git a/target/linux/generic/hack-6.1/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch b/target/linux/generic/hack-6.1/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch new file mode 100644 index 00000000000..8b7f2f09557 --- /dev/null +++ b/target/linux/generic/hack-6.1/750-net-pcs-mtk-lynxi-workaround-2500BaseX-no-an.patch @@ -0,0 +1,53 @@ +From 880d1311335120f64447ca9d11933872d734e19a Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 27 Mar 2023 18:41:54 +0100 +Subject: [PATCH] generic: pcs-mtk-lynxi: add hack to use 2500Base-X without AN + +Using 2500Base-T SFP modules e.g. on the BananaPi R3 requires manually +disabling auto-negotiation, e.g. using ethtool. While a proper fix +using SFP quirks is being discussed upstream, bring a work-around to +restore user experience to what it was before the switch to the +dedicated SGMII PCS driver. + +Signed-off-by: Daniel Golle + +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -92,14 +92,23 @@ static void mtk_pcs_lynxi_get_state(stru + struct phylink_link_state *state) + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); +- unsigned int bm, adv; ++ unsigned int bm, bmsr, adv; + + /* Read the BMSR and LPA */ + regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &bm); +- regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ bmsr = FIELD_GET(SGMII_BMSR, bm); ++ ++ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++ state->speed = SPEED_2500; ++ state->duplex = DUPLEX_FULL; + +- phylink_mii_c22_pcs_decode_state(state, FIELD_GET(SGMII_BMSR, bm), +- FIELD_GET(SGMII_LPA, adv)); ++ return; ++ } ++ ++ regmap_read(mpcs->regmap, SGMSYS_PCS_ADVERTISE, &adv); ++ phylink_mii_c22_pcs_decode_state(state, bmsr, FIELD_GET(SGMII_LPA, adv)); + } + + static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int mode, +@@ -134,7 +143,8 @@ static int mtk_pcs_lynxi_config(struct p + /* 1000base-X or 2500base-X autoneg */ + sgm_mode = SGMII_REMOTE_FAULT_DIS; + use_an = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, +- advertising); ++ advertising) && ++ !(interface == PHY_INTERFACE_MODE_2500BASEX); + } else { + /* 1000base-X or 2500base-X without autoneg */ + sgm_mode = 0; diff --git a/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch b/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch new file mode 100644 index 00000000000..f61c078521e --- /dev/null +++ b/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch @@ -0,0 +1,74 @@ +From 82985725e071f2a5735052f18e109a32aeac3a0b Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sun, 26 Jul 2020 02:38:31 +0200 +Subject: [PATCH] net: usb: r8152: add LED configuration from OF + +This adds the ability to configure the LED configuration register using +OF. This way, the correct value for board specific LED configuration can +be determined. + +Signed-off-by: David Bauer +--- + drivers/net/usb/r8152.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +--- a/drivers/net/usb/r8152.c ++++ b/drivers/net/usb/r8152.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -6886,6 +6887,22 @@ static void rtl_tally_reset(struct r8152 + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); + } + ++static int r8152_led_configuration(struct r8152 *tp) ++{ ++ u32 led_data; ++ int ret; ++ ++ ret = of_property_read_u32(tp->udev->dev.of_node, "realtek,led-data", ++ &led_data); ++ ++ if (ret) ++ return ret; ++ ++ ocp_write_word(tp, MCU_TYPE_PLA, PLA_LEDSEL, led_data); ++ ++ return 0; ++} ++ + static void r8152b_init(struct r8152 *tp) + { + u32 ocp_data; +@@ -6927,6 +6944,8 @@ static void r8152b_init(struct r8152 *tp + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); ++ ++ r8152_led_configuration(tp); + } + + static void r8153_init(struct r8152 *tp) +@@ -7067,6 +7086,8 @@ static void r8153_init(struct r8152 *tp) + tp->coalesce = COALESCE_SLOW; + break; + } ++ ++ r8152_led_configuration(tp); + } + + static void r8153b_init(struct r8152 *tp) +@@ -7149,6 +7170,8 @@ static void r8153b_init(struct r8152 *tp + rtl_tally_reset(tp); + + tp->coalesce = 15000; /* 15 us */ ++ ++ r8152_led_configuration(tp); + } + + static void r8153c_init(struct r8152 *tp) diff --git a/target/linux/generic/hack-6.1/761-dt-bindings-net-add-RTL8152-binding-documentation.patch b/target/linux/generic/hack-6.1/761-dt-bindings-net-add-RTL8152-binding-documentation.patch new file mode 100644 index 00000000000..be262b993cd --- /dev/null +++ b/target/linux/generic/hack-6.1/761-dt-bindings-net-add-RTL8152-binding-documentation.patch @@ -0,0 +1,54 @@ +From 3ee05f4aa64fc86af3be5bc176ba5808de9260a7 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sun, 26 Jul 2020 15:30:33 +0200 +Subject: [PATCH] dt-bindings: net: add RTL8152 binding documentation + +Add binding documentation for the Realtek RTL8152 / RTL8153 USB ethernet +adapters. + +Signed-off-by: David Bauer +--- + .../bindings/net/realtek,rtl8152.yaml | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/realtek,rtl8152.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/realtek,rtl8152.yaml +@@ -0,0 +1,36 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/net/realtek,rtl8152.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Realtek RTL8152/RTL8153 series USB ethernet ++ ++maintainers: ++ - David Bauer ++ ++properties: ++ compatible: ++ oneOf: ++ - items: ++ - enum: ++ - realtek,rtl8152 ++ - realtek,rtl8153 ++ ++ reg: ++ description: The device number on the USB bus ++ ++ realtek,led-data: ++ description: Value to be written to the LED configuration register. ++ ++required: ++ - compatible ++ - reg ++ ++examples: ++ - | ++ usb-eth@2 { ++ compatible = "realtek,rtl8153"; ++ reg = <2>; ++ realtek,led-data = <0x87>; ++ }; +\ No newline at end of file diff --git a/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch new file mode 100644 index 00000000000..8de3668def2 --- /dev/null +++ b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch @@ -0,0 +1,101 @@ +From 94b90966095f3fa625897e8f53d215882f6e19b3 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Sat, 11 Mar 2023 17:00:01 +0100 +Subject: [PATCH] mxl-gpy: control LED reg from DT + +Add dynamic configuration for the LED control registers on MXL PHYs. + +This patch has been tested with MaxLinear GPY211C. It is unlikely to be +accepted upstream, as upstream plans on integrating their own framework +for handling these LEDs. + +For the time being, use this hack to configure PHY driven device-LEDs to +show the correct state. + +A possible alternative might be to expose the LEDs using the kernel LED +framework and bind it to the netdevice. This might also be upstreamable, +although it is a considerable extra amount of work. + +Signed-off-by: David Bauer +--- + drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++- + 1 file changed, 36 insertions(+), 1 deletion(-) + +--- a/drivers/net/phy/mxl-gpy.c ++++ b/drivers/net/phy/mxl-gpy.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + +@@ -30,6 +31,7 @@ + #define PHY_MIISTAT 0x18 /* MII state */ + #define PHY_IMASK 0x19 /* interrupt mask */ + #define PHY_ISTAT 0x1A /* interrupt status */ ++#define PHY_LED 0x1B /* LED control */ + #define PHY_FWV 0x1E /* firmware version */ + + #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) +@@ -53,10 +55,15 @@ + PHY_IMASK_ADSC | \ + PHY_IMASK_ANC) + ++#define PHY_LED_NUM_LEDS 4 ++ + #define PHY_FWV_REL_MASK BIT(15) + #define PHY_FWV_TYPE_MASK GENMASK(11, 8) + #define PHY_FWV_MINOR_MASK GENMASK(7, 0) + ++/* LED */ ++#define VSPEC1_LED(x) (0x1 + x) ++ + /* SGMII */ + #define VSPEC1_SGMII_CTRL 0x08 + #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ +@@ -80,6 +87,31 @@ static const struct { + {9, 0x73}, + }; + ++static int gpy_led_write(struct phy_device *phydev) ++{ ++ struct device_node *node = phydev->mdio.dev.of_node; ++ u32 led_regs[PHY_LED_NUM_LEDS]; ++ int i, ret; ++ ++ if (!IS_ENABLED(CONFIG_OF_MDIO)) ++ return 0; ++ ++ if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS)) ++ return 0; ++ ++ /* Enable LED function handling on all ports*/ ++ phy_write(phydev, PHY_LED, 0xFF00); ++ ++ /* Write LED register values */ ++ for (i = 0; i < PHY_LED_NUM_LEDS; i++) { ++ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(i), (u16)led_regs[i]); ++ if (ret < 0) ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int gpy_config_init(struct phy_device *phydev) + { + int ret; +@@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_de + + /* Clear all pending interrupts */ + ret = phy_read(phydev, PHY_ISTAT); +- return ret < 0 ? ret : 0; ++ if (ret < 0) ++ return ret; ++ ++ return gpy_led_write(phydev); + } + + static int gpy_probe(struct phy_device *phydev) diff --git a/target/linux/generic/hack-6.1/766-net-phy-mediatek-ge-add-LED-configuration-interface.patch b/target/linux/generic/hack-6.1/766-net-phy-mediatek-ge-add-LED-configuration-interface.patch new file mode 100644 index 00000000000..3405d5c535b --- /dev/null +++ b/target/linux/generic/hack-6.1/766-net-phy-mediatek-ge-add-LED-configuration-interface.patch @@ -0,0 +1,72 @@ +From cc225d163b5a4f7a0d1968298bf7927306646a47 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Fri, 28 Apr 2023 01:53:01 +0200 +Subject: [PATCH] net: phy: mediatek-ge: add LED configuration interface + +This adds a small hack similar to the one used for ar8xxx switches to +read a reg:value map for configuring the LED configuration registers. + +This allows OpenWrt to write device-specific LED action as well as blink +configurations. It is unlikely to be accepted upstream, as upstream +plans on integrating their own framework for handling these LEDs. + +Signed-off-by: David Bauer +--- + drivers/net/phy/mediatek-ge.c | 33 +++++++++++++++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +--- a/drivers/net/phy/mediatek-ge.c ++++ b/drivers/net/phy/mediatek-ge.c +@@ -1,4 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0+ ++#include + #include + #include + #include +@@ -53,6 +54,36 @@ static int mt7530_phy_config_init(struct + return 0; + } + ++static int mt7530_led_config_of(struct phy_device *phydev) ++{ ++ struct device_node *np = phydev->mdio.dev.of_node; ++ const __be32 *paddr; ++ int len; ++ int i; ++ ++ paddr = of_get_property(np, "mediatek,led-config", &len); ++ if (!paddr) ++ return 0; ++ ++ if (len < (2 * sizeof(*paddr))) ++ return -EINVAL; ++ ++ len /= sizeof(*paddr); ++ ++ phydev_warn(phydev, "Configure LED registers (num=%d)\n", len); ++ for (i = 0; i < len - 1; i += 2) { ++ u32 reg; ++ u32 val; ++ ++ reg = be32_to_cpup(paddr + i); ++ val = be32_to_cpup(paddr + i + 1); ++ ++ phy_write_mmd(phydev, MDIO_MMD_VEND2, reg, val); ++ } ++ ++ return 0; ++} ++ + static int mt7531_phy_config_init(struct phy_device *phydev) + { + mtk_gephy_config_init(phydev); +@@ -65,6 +96,9 @@ static int mt7531_phy_config_init(struct + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); + phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); + ++ /* LED Config*/ ++ mt7530_led_config_of(phydev); ++ + return 0; + } + diff --git a/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch b/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch new file mode 100644 index 00000000000..7127aa136c6 --- /dev/null +++ b/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch @@ -0,0 +1,98 @@ +From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Fri, 7 Jul 2017 17:26:01 +0200 +Subject: bcm53xx: bgmac: use srab switch driver + +use the srab switch driver on these SoCs. + +Signed-off-by: Hauke Mehrtens +--- + drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 + + drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++++ + drivers/net/ethernet/broadcom/bgmac.h | 4 ++++ + 3 files changed, 29 insertions(+) + +--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c ++++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c +@@ -280,6 +280,7 @@ static int bgmac_probe(struct bcma_devic + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; + bgmac->feature_flags |= BGMAC_FEAT_NO_RESET; + bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500; ++ bgmac->feature_flags |= BGMAC_FEAT_SRAB; + break; + default: + bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST; +--- a/drivers/net/ethernet/broadcom/bgmac.c ++++ b/drivers/net/ethernet/broadcom/bgmac.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1408,6 +1409,17 @@ static const struct ethtool_ops bgmac_et + .set_link_ksettings = phy_ethtool_set_link_ksettings, + }; + ++static struct b53_platform_data bgmac_b53_pdata = { ++}; ++ ++static struct platform_device bgmac_b53_dev = { ++ .name = "b53-srab-switch", ++ .id = -1, ++ .dev = { ++ .platform_data = &bgmac_b53_pdata, ++ }, ++}; ++ + /************************************************** + * MII + **************************************************/ +@@ -1546,6 +1558,14 @@ int bgmac_enet_probe(struct bgmac *bgmac + + bgmac->in_init = false; + ++ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) { ++ bgmac_b53_pdata.regs = ioremap(0x18007000, 0x1000); ++ ++ err = platform_device_register(&bgmac_b53_dev); ++ if (!err) ++ bgmac->b53_device = &bgmac_b53_dev; ++ } ++ + err = register_netdev(bgmac->net_dev); + if (err) { + dev_err(bgmac->dev, "Cannot register net device\n"); +@@ -1568,6 +1588,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe); + + void bgmac_enet_remove(struct bgmac *bgmac) + { ++ if (bgmac->b53_device) ++ platform_device_unregister(&bgmac_b53_dev); ++ bgmac->b53_device = NULL; ++ + unregister_netdev(bgmac->net_dev); + phy_disconnect(bgmac->net_dev->phydev); + netif_napi_del(&bgmac->napi); +--- a/drivers/net/ethernet/broadcom/bgmac.h ++++ b/drivers/net/ethernet/broadcom/bgmac.h +@@ -390,6 +390,7 @@ + #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18) + #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19) + #define BGMAC_FEAT_IDM_MASK BIT(20) ++#define BGMAC_FEAT_SRAB BIT(21) + + struct bgmac_slot_info { + union { +@@ -497,6 +498,9 @@ struct bgmac { + void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, + u32 set); + int (*phy_connect)(struct bgmac *bgmac); ++ ++ /* platform device for associated switch */ ++ struct platform_device *b53_device; + }; + + struct bgmac *bgmac_alloc(struct device *dev); diff --git a/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch new file mode 100644 index 00000000000..367d66fc666 --- /dev/null +++ b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch @@ -0,0 +1,43 @@ +From f81700b6bb2eda3756247bce472d8eaf6f466f61 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:49:26 +0200 +Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support + +--- + drivers/net/usb/qmi_wwan.c | 1 + + drivers/usb/serial/option.c | 7 +++++++ + 2 files changed, 8 insertions(+) + +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1086,6 +1086,7 @@ static const struct usb_device_id produc + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ ++ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */ + + /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ +--- a/drivers/usb/serial/option.c ++++ b/drivers/usb/serial/option.c +@@ -244,6 +244,8 @@ static void option_instat_callback(struc + #define UBLOX_PRODUCT_R410M 0x90b2 + /* These Yuga products use Qualcomm's vendor ID */ + #define YUGA_PRODUCT_CLM920_NC5 0x9625 ++/* These MeigLink products use Qualcomm's vendor ID */ ++#define MEIGLINK_PRODUCT_SLM750 0xf601 + + #define QUECTEL_VENDOR_ID 0x2c7c + /* These Quectel products use Quectel's vendor ID */ +@@ -1169,6 +1171,11 @@ static const struct usb_device_id option + .driver_info = ZLP }, + { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), + .driver_info = RSVD(4) }, ++ /* Meiglink products using Qualcomm vendor ID */ ++ // Works OK. In case of some issues check macros that are used by Quectel Products ++ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff), ++ .driver_info = NUMEP2 }, ++ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff), + .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) }, diff --git a/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch new file mode 100644 index 00000000000..10af22e52e0 --- /dev/null +++ b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch @@ -0,0 +1,65 @@ +From 7cc39a6bedbd85f3ff7e16845f310e4ce8d9833f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 6 Sep 2022 00:31:19 +0100 +Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module +To: netdev@vger.kernel.org, + linux-kernel@vger.kernel.org, + Russell King , + Andrew Lunn , + Heiner Kallweit +Cc: David S. Miller , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + Josef Schlehofer + +This copper module comes with broken TX_FAULT indicator which must be +ignored for it to work. Implement ignoring TX_FAULT state bit also +during reset/insertion and mute the warning telling the user that the +module indicates TX_FAULT. + +Co-authored-by: Josef Schlehofer +Signed-off-by: Daniel Golle +--- + drivers/net/phy/sfp.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -383,6 +383,11 @@ static const struct sfp_quirk sfp_quirks + .modes = sfp_quirk_2500basex, + .fixup = sfp_fixup_ignore_tx_fault, + }, { ++ // OEM SFP-GE-T is 1000Base-T module ++ .vendor = "OEM", ++ .part = "SFP-GE-T", ++ .fixup = sfp_fixup_ignore_tx_fault, ++ }, { + // Lantech 8330-262D-E can operate at 2500base-X, but + // incorrectly report 2500MBd NRZ in their EEPROM + .vendor = "Lantech", +@@ -2312,7 +2317,8 @@ static void sfp_sm_main(struct sfp *sfp, + * or t_start_up, so assume there is a fault. + */ + sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, +- sfp->sm_fault_retries == N_FAULT_INIT); ++ !sfp->tx_fault_ignore && ++ (sfp->sm_fault_retries == N_FAULT_INIT)); + } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { + init_done: + sfp->sm_phy_retries = R_PHY_RETRY; +@@ -2535,10 +2541,12 @@ static void sfp_check_state(struct sfp * + mutex_lock(&sfp->st_mutex); + state = sfp_get_state(sfp); + changed = state ^ sfp->state; +- if (sfp->tx_fault_ignore) ++ if (sfp->tx_fault_ignore) { + changed &= SFP_F_PRESENT | SFP_F_LOS; +- else ++ state &= ~SFP_F_TX_FAULT; ++ } else { + changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT; ++ } + + for (i = 0; i < GPIO_MAX; i++) + if (changed & BIT(i)) diff --git a/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch b/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch new file mode 100644 index 00000000000..b1e7065a8b9 --- /dev/null +++ b/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch @@ -0,0 +1,167 @@ +From 027586ae8ecacff49757ed854c020f35d24a599c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 11 Mar 2023 03:44:41 +0000 +Subject: [PATCH] generic: backport some phylink helper functions + +It isn't feasible to literally backport all upstream phylink_pcs changes +down to Linux 5.15: It's just too many patches, and many downstream +drivers and hacks are likely to break. We are too close to branching off +to risk this, and it's also just too much work. +Instead just add helper functions used by modern PCS drivers while keeping +the original functions instact as well. While this may add a kilobyte or +two of extra kernel size, it has the advantage that we get the best of both +worlds: None of the existing codepaths are touched, but yet we have the +option to backport singular improvements to Ethernet drivers where needed. + +Signed-off-by: Daniel Golle + +--- a/include/linux/phylink.h ++++ b/include/linux/phylink.h +@@ -584,10 +584,37 @@ int phylink_speed_up(struct phylink *pl) + #define phylink_test(bm, mode) __phylink_do_bit(test_bit, bm, mode) + + void phylink_set_port_modes(unsigned long *bits); ++ ++/** ++ * phylink_get_link_timer_ns - return the PCS link timer value ++ * @interface: link &typedef phy_interface_t mode ++ * ++ * Return the PCS link timer setting in nanoseconds for the PHY @interface ++ * mode, or -EINVAL if not appropriate. ++ */ ++static inline int phylink_get_link_timer_ns(phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_SGMII: ++ return 1600000; ++ ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ return 10000000; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ + void phylink_helper_basex_speed(struct phylink_link_state *state); + ++void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, ++ u16 bmsr, u16 lpa); + void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, + struct phylink_link_state *state); ++int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, ++ const unsigned long *advertising); + int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, + phy_interface_t interface, + const unsigned long *advertising); +--- a/drivers/net/phy/phylink.c ++++ b/drivers/net/phy/phylink.c +@@ -885,7 +885,6 @@ static int phylink_change_inband_advert( + + return 0; + } +- + static void phylink_mac_pcs_get_state(struct phylink *pl, + struct phylink_link_state *state) + { +@@ -2966,6 +2965,52 @@ void phylink_mii_c22_pcs_get_state(struc + EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); + + /** ++ * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers ++ * @state: a pointer to a &struct phylink_link_state. ++ * @bmsr: The value of the %MII_BMSR register ++ * @lpa: The value of the %MII_LPA register ++ * ++ * Helper for MAC PCS supporting the 802.3 clause 22 register set for ++ * clause 37 negotiation and/or SGMII control. ++ * ++ * Parse the Clause 37 or Cisco SGMII link partner negotiation word into ++ * the phylink @state structure. This is suitable to be used for implementing ++ * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if ++ * accessing @bmsr and @lpa cannot be done with MDIO directly. ++ */ ++void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, ++ u16 bmsr, u16 lpa) ++{ ++ state->link = !!(bmsr & BMSR_LSTATUS); ++ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); ++ /* If there is no link or autonegotiation is disabled, the LP advertisement ++ * data is not meaningful, so don't go any further. ++ */ ++ if (!state->link || !state->an_enabled) ++ return; ++ ++ switch (state->interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ phylink_decode_c37_word(state, lpa, SPEED_1000); ++ break; ++ ++ case PHY_INTERFACE_MODE_2500BASEX: ++ phylink_decode_c37_word(state, lpa, SPEED_2500); ++ break; ++ ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ phylink_decode_sgmii_word(state, lpa); ++ break; ++ ++ default: ++ state->link = false; ++ break; ++ } ++} ++EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); ++ ++/** + * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS + * advertisement + * @pcs: a pointer to a &struct mdio_device. +@@ -3037,6 +3082,46 @@ int phylink_mii_c22_pcs_set_advertisemen + EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); + + /** ++ * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS ++ * advertisement ++ * @interface: the PHY interface mode being configured ++ * @advertising: the ethtool advertisement mask ++ * ++ * Helper for MAC PCS supporting the 802.3 clause 22 register set for ++ * clause 37 negotiation and/or SGMII control. ++ * ++ * Encode the clause 37 PCS advertisement as specified by @interface and ++ * @advertising. ++ * ++ * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed. ++ */ ++int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, ++ const unsigned long *advertising) ++{ ++ u16 adv; ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_1000BASEX: ++ case PHY_INTERFACE_MODE_2500BASEX: ++ adv = ADVERTISE_1000XFULL; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, ++ advertising)) ++ adv |= ADVERTISE_1000XPAUSE; ++ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, ++ advertising)) ++ adv |= ADVERTISE_1000XPSE_ASYM; ++ return adv; ++ case PHY_INTERFACE_MODE_SGMII: ++ case PHY_INTERFACE_MODE_QSGMII: ++ return 0x0001; ++ default: ++ /* Nothing to do for other modes */ ++ return -EINVAL; ++ } ++} ++EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); ++ ++/** + * phylink_mii_c22_pcs_config() - configure clause 22 PCS + * @pcs: a pointer to a &struct mdio_device. + * @mode: link autonegotiation mode diff --git a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch new file mode 100644 index 00000000000..0a2c82cacbc --- /dev/null +++ b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch @@ -0,0 +1,162 @@ +From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Tue, 12 Aug 2014 20:49:27 +0200 +Subject: [PATCH 30/36] GPIO: add named gpio exports + +Signed-off-by: John Crispin +--- a/drivers/gpio/gpiolib-of.c ++++ b/drivers/gpio/gpiolib-of.c +@@ -19,6 +19,8 @@ + #include + #include + #include ++#include ++#include + + #include "gpiolib.h" + #include "gpiolib-of.h" +@@ -1059,3 +1061,72 @@ void of_gpio_dev_init(struct gpio_chip * + else + gc->of_node = gdev->dev.of_node; + } ++ ++#ifdef CONFIG_GPIO_SYSFS ++ ++static struct of_device_id gpio_export_ids[] = { ++ { .compatible = "gpio-export" }, ++ { /* sentinel */ } ++}; ++ ++static int of_gpio_export_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct device_node *cnp; ++ u32 val; ++ int nb = 0; ++ ++ for_each_child_of_node(np, cnp) { ++ const char *name = NULL; ++ int gpio; ++ bool dmc; ++ int max_gpio = 1; ++ int i; ++ ++ of_property_read_string(cnp, "gpio-export,name", &name); ++ ++ if (!name) ++ max_gpio = of_gpio_count(cnp); ++ ++ for (i = 0; i < max_gpio; i++) { ++ unsigned flags = 0; ++ enum of_gpio_flags of_flags; ++ ++ gpio = of_get_gpio_flags(cnp, i, &of_flags); ++ if (!gpio_is_valid(gpio)) ++ return gpio; ++ ++ if (of_flags == OF_GPIO_ACTIVE_LOW) ++ flags |= GPIOF_ACTIVE_LOW; ++ ++ if (!of_property_read_u32(cnp, "gpio-export,output", &val)) ++ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; ++ else ++ flags |= GPIOF_IN; ++ ++ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np))) ++ continue; ++ ++ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change"); ++ gpio_export_with_name(gpio, dmc, name); ++ nb++; ++ } ++ } ++ ++ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb); ++ ++ return 0; ++} ++ ++static struct platform_driver gpio_export_driver = { ++ .driver = { ++ .name = "gpio-export", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(gpio_export_ids), ++ }, ++ .probe = of_gpio_export_probe, ++}; ++ ++module_platform_driver(gpio_export_driver); ++ ++#endif +--- a/include/asm-generic/gpio.h ++++ b/include/asm-generic/gpio.h +@@ -125,6 +125,12 @@ static inline int gpio_export(unsigned g + return gpiod_export(gpio_to_desc(gpio), direction_may_change); + } + ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); ++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name) ++{ ++ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name); ++} ++ + static inline int gpio_export_link(struct device *dev, const char *name, + unsigned gpio) + { +--- a/include/linux/gpio/consumer.h ++++ b/include/linux/gpio/consumer.h +@@ -712,6 +712,7 @@ static inline void devm_acpi_dev_remove_ + + #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) + ++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name); + int gpiod_export(struct gpio_desc *desc, bool direction_may_change); + int gpiod_export_link(struct device *dev, const char *name, + struct gpio_desc *desc); +@@ -719,6 +720,13 @@ void gpiod_unexport(struct gpio_desc *de + + #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ + ++static inline int _gpiod_export(struct gpio_desc *desc, ++ bool direction_may_change, ++ const char *name) ++{ ++ return -ENOSYS; ++} ++ + static inline int gpiod_export(struct gpio_desc *desc, + bool direction_may_change) + { +--- a/drivers/gpio/gpiolib-sysfs.c ++++ b/drivers/gpio/gpiolib-sysfs.c +@@ -561,7 +561,7 @@ static struct class gpio_class = { + * + * Returns zero on success, else an error. + */ +-int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name) + { + struct gpio_chip *chip; + struct gpio_device *gdev; +@@ -623,6 +623,8 @@ int gpiod_export(struct gpio_desc *desc, + offset = gpio_chip_hwgpio(desc); + if (chip->names && chip->names[offset]) + ioname = chip->names[offset]; ++ if (name) ++ ioname = name; + + dev = device_create_with_groups(&gpio_class, &gdev->dev, + MKDEV(0, 0), data, gpio_groups, +@@ -644,6 +646,12 @@ err_unlock: + gpiod_dbg(desc, "%s: status %d\n", __func__, status); + return status; + } ++EXPORT_SYMBOL_GPL(__gpiod_export); ++ ++int gpiod_export(struct gpio_desc *desc, bool direction_may_change) ++{ ++ return __gpiod_export(desc, direction_may_change, NULL); ++} + EXPORT_SYMBOL_GPL(gpiod_export); + + static int match_export(struct device *dev, const void *desc) diff --git a/target/linux/generic/hack-6.1/810-bcma-ssb-fallback-sprom.patch b/target/linux/generic/hack-6.1/810-bcma-ssb-fallback-sprom.patch new file mode 100644 index 00000000000..c581a512cbd --- /dev/null +++ b/target/linux/generic/hack-6.1/810-bcma-ssb-fallback-sprom.patch @@ -0,0 +1,187 @@ +From e4d708702e6c98f2111e33201a264d6788564cb2 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Fri, 12 May 2023 11:08:43 +0200 +Subject: [PATCH] ssb_sprom: add generic kernel support for Broadcom Fallback SPROMs + +--- + drivers/bcma/Kconfig | 4 ++++ + drivers/bcma/Makefile | 1 + + drivers/bcma/bcma_private.h | 4 ++++ + drivers/bcma/main.c | 8 ++++++++ + drivers/bcma/sprom.c | 23 ++++++++++++++--------- + drivers/ssb/Kconfig | 5 +++++ + drivers/ssb/Makefile | 1 + + drivers/ssb/main.c | 8 ++++++++ + drivers/ssb/sprom.c | 12 +++++++++++- + drivers/ssb/ssb_private.h | 4 ++++ + 10 files changed, 60 insertions(+), 10 deletions(-) + +--- a/drivers/bcma/Kconfig ++++ b/drivers/bcma/Kconfig +@@ -18,6 +18,10 @@ config BCMA_BLOCKIO + bool + default y + ++config BCMA_FALLBACK_SPROM ++ bool ++ default y ++ + config BCMA_HOST_PCI_POSSIBLE + bool + depends on PCI = y +--- a/drivers/bcma/Makefile ++++ b/drivers/bcma/Makefile +@@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) + bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o + bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o + bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o ++bcma-$(CONFIG_BCMA_FALLBACK_SPROM) += fallback-sprom.o + bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o + bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o + obj-$(CONFIG_BCMA) += bcma.o +--- a/drivers/bcma/bcma_private.h ++++ b/drivers/bcma/bcma_private.h +@@ -38,6 +38,10 @@ int bcma_bus_resume(struct bcma_bus *bus + void bcma_detect_chip(struct bcma_bus *bus); + int bcma_bus_scan(struct bcma_bus *bus); + ++/* fallback-sprom.c */ ++int __init bcma_fbs_register(void); ++int bcma_get_fallback_sprom(struct bcma_bus *dev, struct ssb_sprom *out); ++ + /* sprom.c */ + int bcma_sprom_get(struct bcma_bus *bus); + +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -668,6 +668,14 @@ static int __init bcma_modinit(void) + { + int err; + ++#ifdef CONFIG_BCMA_FALLBACK_SPROM ++ err = bcma_fbs_register(); ++ if (err) { ++ pr_err("Fallback SPROM initialization failed\n"); ++ err = 0; ++ } ++#endif /* CONFIG_BCMA_FALLBACK_SPROM */ ++ + err = bcma_init_bus_register(); + if (err) + return err; +--- a/drivers/bcma/sprom.c ++++ b/drivers/bcma/sprom.c +@@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback + { + int err; + +- if (!get_fallback_sprom) { ++ if (get_fallback_sprom) ++ err = get_fallback_sprom(bus, out); ++ ++#ifdef CONFIG_BCMA_FALLBACK_SPROM ++ if (!get_fallback_sprom || err) ++ err = bcma_get_fallback_sprom(bus, out); ++#else ++ if (!get_fallback_sprom) + err = -ENOENT; +- goto fail; +- } ++#endif /* CONFIG_BCMA_FALLBACK_SPROM */ + +- err = get_fallback_sprom(bus, out); +- if (err) +- goto fail; ++ if (err) { ++ bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); ++ return err; ++ } + + bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", + bus->sprom.revision); ++ + return 0; +-fail: +- bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); +- return err; + } + + /************************************************** +--- a/drivers/ssb/Kconfig ++++ b/drivers/ssb/Kconfig +@@ -25,6 +25,11 @@ if SSB + config SSB_SPROM + bool + ++config SSB_FALLBACK_SPROM ++ bool ++ depends on SSB_PCIHOST ++ default y ++ + # Support for Block-I/O. SELECT this from the driver that needs it. + config SSB_BLOCKIO + bool +--- a/drivers/ssb/Makefile ++++ b/drivers/ssb/Makefile +@@ -2,6 +2,7 @@ + # core + ssb-y += main.o scan.o + ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o ++ssb-$(CONFIG_SSB_FALLBACK_SPROM) += fallback-sprom.o + ssb-$(CONFIG_SSB_SPROM) += sprom.o + + # host support +--- a/drivers/ssb/main.c ++++ b/drivers/ssb/main.c +@@ -1287,6 +1287,14 @@ static int __init ssb_modinit(void) + { + int err; + ++#ifdef CONFIG_SSB_FALLBACK_SPROM ++ err = ssb_fbs_register(); ++ if (err) { ++ pr_err("Fallback SPROM initialization failed\n"); ++ err = 0; ++ } ++#endif /* CONFIG_SSB_FALLBACK_SPROM */ ++ + /* See the comment at the ssb_is_early_boot definition */ + ssb_is_early_boot = 0; + err = bus_register(&ssb_bustype); +--- a/drivers/ssb/sprom.c ++++ b/drivers/ssb/sprom.c +@@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int + + int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) + { ++ int err; ++ ++ if (get_fallback_sprom) ++ err = get_fallback_sprom(bus, out); ++ ++#ifdef CONFIG_SSB_FALLBACK_SPROM ++ if (!get_fallback_sprom || err) ++ err = ssb_get_fallback_sprom(bus, out); ++#else + if (!get_fallback_sprom) + return -ENOENT; ++#endif /* CONFIG_SSB_FALLBACK_SPROM */ + +- return get_fallback_sprom(bus, out); ++ return err; + } + + /* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ +--- a/drivers/ssb/ssb_private.h ++++ b/drivers/ssb/ssb_private.h +@@ -143,6 +143,10 @@ extern int ssb_bus_scan(struct ssb_bus * + extern void ssb_iounmap(struct ssb_bus *ssb); + + ++/* fallback-sprom.c */ ++int __init ssb_fbs_register(void); ++int ssb_get_fallback_sprom(struct ssb_bus *dev, struct ssb_sprom *out); ++ + /* sprom.c */ + extern + ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf, diff --git a/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch new file mode 100644 index 00000000000..ac502bdd16d --- /dev/null +++ b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch @@ -0,0 +1,162 @@ +From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:16:31 +0200 +Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS + +Signed-off-by: Felix Fietkau +--- + net/Kconfig | 3 +++ + net/core/Makefile | 3 ++- + net/core/sock.c | 2 ++ + net/ipv4/Kconfig | 1 + + net/netlink/Kconfig | 1 + + net/packet/Kconfig | 1 + + net/unix/Kconfig | 1 + + 7 files changed, 11 insertions(+), 1 deletion(-) + +--- a/net/Kconfig ++++ b/net/Kconfig +@@ -104,6 +104,9 @@ source "net/mptcp/Kconfig" + + endif # if INET + ++config SOCK_DIAG ++ bool ++ + config NETWORK_SECMARK + bool "Security Marking" + help +--- a/net/core/Makefile ++++ b/net/core/Makefile +@@ -10,9 +10,10 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. + + obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ + neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ +- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ ++ dev_ioctl.o tso.o sock_reuseport.o \ + fib_notifier.o xdp.o flow_offload.o + ++obj-$(CONFIG_SOCK_DIAG) += sock_diag.o + obj-y += net-sysfs.o + obj-$(CONFIG_PAGE_POOL) += page_pool.o + obj-$(CONFIG_PROC_FS) += net-procfs.o +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -114,6 +114,7 @@ + #include + #include + #include ++#include + + #include + +@@ -143,6 +144,7 @@ + + static DEFINE_MUTEX(proto_list_mutex); + static LIST_HEAD(proto_list); ++DEFINE_COOKIE(sock_cookie); + + static void sock_inuse_add(struct net *net, int val); + +@@ -545,6 +547,18 @@ discard_and_relse: + } + EXPORT_SYMBOL(__sk_receive_skb); + ++u64 __sock_gen_cookie(struct sock *sk) ++{ ++ while (1) { ++ u64 res = atomic64_read(&sk->sk_cookie); ++ ++ if (res) ++ return res; ++ res = gen_cookie_next(&sock_cookie); ++ atomic64_cmpxchg(&sk->sk_cookie, 0, res); ++ } ++} ++ + INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *, + u32)); + INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, +@@ -1983,9 +1997,11 @@ static void __sk_free(struct sock *sk) + if (likely(sk->sk_net_refcnt)) + sock_inuse_add(sock_net(sk), -1); + ++#ifdef CONFIG_SOCK_DIAG + if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk))) + sock_diag_broadcast_destroy(sk); + else ++#endif + sk_destruct(sk); + } + +--- a/net/core/sock_diag.c ++++ b/net/core/sock_diag.c +@@ -11,7 +11,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -20,20 +19,6 @@ static int (*inet_rcv_compat)(struct sk_ + static DEFINE_MUTEX(sock_diag_table_mutex); + static struct workqueue_struct *broadcast_wq; + +-DEFINE_COOKIE(sock_cookie); +- +-u64 __sock_gen_cookie(struct sock *sk) +-{ +- while (1) { +- u64 res = atomic64_read(&sk->sk_cookie); +- +- if (res) +- return res; +- res = gen_cookie_next(&sock_cookie); +- atomic64_cmpxchg(&sk->sk_cookie, 0, res); +- } +-} +- + int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) + { + u64 res; +--- a/net/ipv4/Kconfig ++++ b/net/ipv4/Kconfig +@@ -424,6 +424,7 @@ config INET_TUNNEL + + config INET_DIAG + tristate "INET: socket monitoring interface" ++ select SOCK_DIAG + default y + help + Support for INET (TCP, DCCP, etc) socket monitoring interface used by +--- a/net/netlink/Kconfig ++++ b/net/netlink/Kconfig +@@ -5,6 +5,7 @@ + + config NETLINK_DIAG + tristate "NETLINK: socket monitoring interface" ++ select SOCK_DIAG + default n + help + Support for NETLINK socket monitoring interface used by the ss tool. +--- a/net/packet/Kconfig ++++ b/net/packet/Kconfig +@@ -19,6 +19,7 @@ config PACKET + config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET ++ select SOCK_DIAG + default n + help + Support for PF_PACKET sockets monitoring interface used by the ss tool. +--- a/net/unix/Kconfig ++++ b/net/unix/Kconfig +@@ -33,6 +33,7 @@ config AF_UNIX_OOB + config UNIX_DIAG + tristate "UNIX: socket monitoring interface" + depends on UNIX ++ select SOCK_DIAG + default n + help + Support for UNIX socket monitoring interface used by the ss tool. diff --git a/target/linux/generic/hack-6.1/902-debloat_proc.patch b/target/linux/generic/hack-6.1/902-debloat_proc.patch new file mode 100644 index 00000000000..12e99280289 --- /dev/null +++ b/target/linux/generic/hack-6.1/902-debloat_proc.patch @@ -0,0 +1,408 @@ +From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:09 +0200 +Subject: debloat: procfs + +Signed-off-by: Felix Fietkau +--- + fs/locks.c | 2 ++ + fs/proc/Kconfig | 5 +++++ + fs/proc/consoles.c | 3 +++ + fs/proc/proc_tty.c | 11 ++++++++++- + include/net/snmp.h | 18 +++++++++++++++++- + ipc/msg.c | 3 +++ + ipc/sem.c | 2 ++ + ipc/shm.c | 2 ++ + ipc/util.c | 3 +++ + kernel/exec_domain.c | 2 ++ + kernel/irq/proc.c | 9 +++++++++ + kernel/time/timer_list.c | 2 ++ + mm/vmalloc.c | 2 ++ + mm/vmstat.c | 8 +++++--- + net/8021q/vlanproc.c | 6 ++++++ + net/core/net-procfs.c | 18 ++++++++++++------ + net/core/sock.c | 2 ++ + net/ipv4/fib_trie.c | 18 ++++++++++++------ + net/ipv4/proc.c | 3 +++ + net/ipv4/route.c | 3 +++ + 20 files changed, 105 insertions(+), 17 deletions(-) + +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2953,6 +2953,8 @@ static const struct seq_operations locks + + static int __init proc_locks_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_seq_private("locks", 0, NULL, &locks_seq_operations, + sizeof(struct locks_iterator), NULL); + return 0; +--- a/fs/proc/Kconfig ++++ b/fs/proc/Kconfig +@@ -100,6 +100,11 @@ config PROC_CHILDREN + Say Y if you are running any user-space software which takes benefit from + this interface. For example, rkt is such a piece of software. + ++config PROC_STRIPPED ++ default n ++ depends on EXPERT ++ bool "Strip non-essential /proc functionality to reduce code size" ++ + config PROC_PID_ARCH_STATUS + def_bool n + depends on PROC_FS +--- a/fs/proc/consoles.c ++++ b/fs/proc/consoles.c +@@ -92,6 +92,9 @@ static const struct seq_operations conso + + static int __init proc_consoles_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + proc_create_seq("consoles", 0, NULL, &consoles_op); + return 0; + } +--- a/fs/proc/proc_tty.c ++++ b/fs/proc/proc_tty.c +@@ -133,7 +133,10 @@ static const struct seq_operations tty_d + void proc_tty_register_driver(struct tty_driver *driver) + { + struct proc_dir_entry *ent; +- ++ ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!driver->driver_name || driver->proc_entry || + !driver->ops->proc_show) + return; +@@ -150,6 +153,9 @@ void proc_tty_unregister_driver(struct t + { + struct proc_dir_entry *ent; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ent = driver->proc_entry; + if (!ent) + return; +@@ -164,6 +170,9 @@ void proc_tty_unregister_driver(struct t + */ + void __init proc_tty_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (!proc_mkdir("tty", NULL)) + return; + proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ +--- a/include/net/snmp.h ++++ b/include/net/snmp.h +@@ -124,6 +124,21 @@ struct linux_tls_mib { + #define DECLARE_SNMP_STAT(type, name) \ + extern __typeof__(type) __percpu *name + ++#ifdef CONFIG_PROC_STRIPPED ++#define __SNMP_STATS_DUMMY(mib) \ ++ do { (void) mib->mibs[0]; } while(0) ++ ++#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib) ++#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib) ++ ++#else ++ + #define __SNMP_INC_STATS(mib, field) \ + __this_cpu_inc(mib->mibs[field]) + +@@ -154,8 +169,9 @@ struct linux_tls_mib { + __this_cpu_add(ptr[basefield##OCTETS], addend); \ + } while (0) + ++#endif + +-#if BITS_PER_LONG==32 ++#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED) + + #define __SNMP_ADD_STATS64(mib, field, addend) \ + do { \ +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -1350,6 +1350,9 @@ void __init msg_init(void) + { + msg_init_ns(&init_ipc_ns); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + ipc_init_proc_interface("sysvipc/msg", + " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", + IPC_MSG_IDS, sysvipc_msg_proc_show); +--- a/ipc/sem.c ++++ b/ipc/sem.c +@@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *n + void __init sem_init(void) + { + sem_init_ns(&init_ipc_ns); ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/sem", + " key semid perms nsems uid gid cuid cgid otime ctime\n", + IPC_SEM_IDS, sysvipc_sem_proc_show); +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -154,6 +154,8 @@ pure_initcall(ipc_ns_init); + + void __init shm_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; + ipc_init_proc_interface("sysvipc/shm", + #if BITS_PER_LONG <= 32 + " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n", +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(cons + struct proc_dir_entry *pde; + struct ipc_proc_iface *iface; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + iface = kmalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return; +--- a/kernel/exec_domain.c ++++ b/kernel/exec_domain.c +@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct + + static int __init proc_execdomains_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + proc_create_single("execdomains", 0, NULL, execdomains_proc_show); + return 0; + } +--- a/kernel/irq/proc.c ++++ b/kernel/irq/proc.c +@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq, + void __maybe_unused *irqp = (void *)(unsigned long) irq; + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) + return; + +@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir + { + char name [MAX_NAMELEN]; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + if (!root_irq_dir || !desc->dir) + return; + #ifdef CONFIG_SMP +@@ -432,6 +438,9 @@ void init_irq_proc(void) + unsigned int irq; + struct irq_desc *desc; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP)) ++ return; ++ + /* create /proc/irq */ + root_irq_dir = proc_mkdir("irq", NULL); + if (!root_irq_dir) +--- a/kernel/time/timer_list.c ++++ b/kernel/time/timer_list.c +@@ -350,6 +350,8 @@ static int __init init_timer_list_procfs + { + struct proc_dir_entry *pe; + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops, + sizeof(struct timer_list_iter), NULL); + if (!pe) +--- a/mm/vmalloc.c ++++ b/mm/vmalloc.c +@@ -3964,6 +3964,8 @@ static const struct seq_operations vmall + + static int __init proc_vmalloc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + if (IS_ENABLED(CONFIG_NUMA)) + proc_create_seq_private("vmallocinfo", 0400, NULL, + &vmalloc_op, +--- a/mm/vmstat.c ++++ b/mm/vmstat.c +@@ -2083,10 +2083,12 @@ void __init init_mm_internals(void) + start_shepherd_timer(); + #endif + #ifdef CONFIG_PROC_FS +- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); +- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op); ++ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op); ++ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); ++ } + proc_create_seq("vmstat", 0444, NULL, &vmstat_op); +- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op); + #endif + } + +--- a/net/8021q/vlanproc.c ++++ b/net/8021q/vlanproc.c +@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net) + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return; ++ + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); + +@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net + { + struct vlan_net *vn = net_generic(net, vlan_net_id); + ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) + goto err; +--- a/net/core/net-procfs.c ++++ b/net/core/net-procfs.c +@@ -317,10 +317,12 @@ static int __net_init dev_proc_net_init( + if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, + sizeof(struct seq_net_private))) + goto out; +- if (!proc_create_seq("softnet_stat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_seq("softnet_stat", 0444, net->proc_net, + &softnet_seq_ops)) + goto out_dev; +- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops, + sizeof(struct seq_net_private))) + goto out_softnet; + +@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init( + out: + return rc; + out_ptype: +- remove_proc_entry("ptype", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("ptype", net->proc_net); + out_softnet: +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("softnet_stat", net->proc_net); + out_dev: + remove_proc_entry("dev", net->proc_net); + goto out; +@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit + { + wext_proc_exit(net); + +- remove_proc_entry("ptype", net->proc_net); +- remove_proc_entry("softnet_stat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("ptype", net->proc_net); ++ remove_proc_entry("softnet_stat", net->proc_net); ++ } + remove_proc_entry("dev", net->proc_net); + } + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -3866,6 +3866,8 @@ static __net_initdata struct pernet_oper + + static int __init proto_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; + return register_pernet_subsys(&proto_net_ops); + } + +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -3024,11 +3024,13 @@ static const struct seq_operations fib_r + + int __net_init fib_proc_init(struct net *net) + { +- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops, + sizeof(struct fib_trie_iter))) + goto out1; + +- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net, ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) && ++ !proc_create_net_single("fib_triestat", 0444, net->proc_net, + fib_triestat_seq_show, NULL)) + goto out2; + +@@ -3039,17 +3041,21 @@ int __net_init fib_proc_init(struct net + return 0; + + out3: +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_triestat", net->proc_net); + out2: +- remove_proc_entry("fib_trie", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ remove_proc_entry("fib_trie", net->proc_net); + out1: + return -ENOMEM; + } + + void __net_exit fib_proc_exit(struct net *net) + { +- remove_proc_entry("fib_trie", net->proc_net); +- remove_proc_entry("fib_triestat", net->proc_net); ++ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) { ++ remove_proc_entry("fib_trie", net->proc_net); ++ remove_proc_entry("fib_triestat", net->proc_net); ++ } + remove_proc_entry("route", net->proc_net); + } + +--- a/net/ipv4/proc.c ++++ b/net/ipv4/proc.c +@@ -553,5 +553,8 @@ static __net_initdata struct pernet_oper + + int __init ip_misc_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_proc_ops); + } +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -387,6 +387,9 @@ static struct pernet_operations ip_rt_pr + + static int __init ip_rt_proc_init(void) + { ++ if (IS_ENABLED(CONFIG_PROC_STRIPPED)) ++ return 0; ++ + return register_pernet_subsys(&ip_rt_proc_ops); + } + diff --git a/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch new file mode 100644 index 00000000000..0291a5e9bd8 --- /dev/null +++ b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch @@ -0,0 +1,92 @@ +From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sat, 8 Jul 2017 08:20:43 +0200 +Subject: debloat: dmabuf + +Signed-off-by: Felix Fietkau +--- + drivers/base/Kconfig | 2 +- + drivers/dma-buf/Makefile | 10 +++++++--- + drivers/dma-buf/dma-buf.c | 4 +++- + kernel/sched/core.c | 1 + + 4 files changed, 12 insertions(+), 5 deletions(-) + +--- a/drivers/base/Kconfig ++++ b/drivers/base/Kconfig +@@ -187,7 +187,7 @@ config SOC_BUS + source "drivers/base/regmap/Kconfig" + + config DMA_SHARED_BUFFER +- bool ++ tristate + default n + select IRQ_WORK + help +--- a/drivers/dma-buf/heaps/Makefile ++++ b/drivers/dma-buf/heaps/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 +-obj-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o +-obj-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS_SYSTEM) += system_heap.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o +--- a/drivers/dma-buf/Makefile ++++ b/drivers/dma-buf/Makefile +@@ -1,16 +1,20 @@ + # SPDX-License-Identifier: GPL-2.0-only +-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ ++obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o ++ ++dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ + dma-resv.o seqno-fence.o +-obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o +-obj-$(CONFIG_DMABUF_HEAPS) += heaps/ +-obj-$(CONFIG_SYNC_FILE) += sync_file.o +-obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +-obj-$(CONFIG_UDMABUF) += udmabuf.o +-obj-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o ++dma-buf-objs-$(CONFIG_DMABUF_HEAPS) += dma-heap.o ++obj-$(CONFIG_DMABUF_HEAPS) += heaps/ ++dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o ++dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o ++dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o ++dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += udmabuf.o + + dmabuf_selftests-y := \ + selftest.o \ + st-dma-fence.o \ + st-dma-fence-chain.o + +-obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o ++dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o ++ ++dma-shared-buffer-objs := $(dma-buf-objs-y) +--- a/drivers/dma-buf/dma-buf.c ++++ b/drivers/dma-buf/dma-buf.c +@@ -1513,4 +1513,5 @@ static void __exit dma_buf_deinit(void) + kern_unmount(dma_buf_mnt); + dma_buf_uninit_sysfs_statistics(); + } +-__exitcall(dma_buf_deinit); ++module_exit(dma_buf_deinit); ++MODULE_LICENSE("GPL"); +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -4216,6 +4216,7 @@ int wake_up_state(struct task_struct *p, + { + return try_to_wake_up(p, state, 0); + } ++EXPORT_SYMBOL_GPL(wake_up_state); + + /* + * Perform scheduler related setup for a newly forked process p. +--- a/fs/d_path.c ++++ b/fs/d_path.c +@@ -316,6 +316,7 @@ char *dynamic_dname(struct dentry *dentr + buffer += buflen - sz; + return memcpy(buffer, temp, sz); + } ++EXPORT_SYMBOL_GPL(dynamic_dname); + + char *simple_dname(struct dentry *dentry, char *buffer, int buflen) + { diff --git a/target/linux/generic/hack-6.1/910-kobject_uevent.patch b/target/linux/generic/hack-6.1/910-kobject_uevent.patch new file mode 100644 index 00000000000..c4c41ca400a --- /dev/null +++ b/target/linux/generic/hack-6.1/910-kobject_uevent.patch @@ -0,0 +1,32 @@ +From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: lib: add uevent_next_seqnum() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 5 +++++ + lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -179,6 +179,18 @@ out: + return r; + } + ++u64 uevent_next_seqnum(void) ++{ ++ u64 seq; ++ ++ mutex_lock(&uevent_sock_mutex); ++ seq = ++uevent_seqnum; ++ mutex_unlock(&uevent_sock_mutex); ++ ++ return seq; ++} ++EXPORT_SYMBOL_GPL(uevent_next_seqnum); ++ + /** + * kobject_synth_uevent - send synthetic uevent with arguments + * diff --git a/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch new file mode 100644 index 00000000000..a487d551938 --- /dev/null +++ b/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch @@ -0,0 +1,76 @@ +From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 16 Jul 2017 16:56:10 +0200 +Subject: lib: add uevent_next_seqnum() + +Signed-off-by: Felix Fietkau +--- + include/linux/kobject.h | 5 +++++ + lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 42 insertions(+) + +--- a/include/linux/kobject.h ++++ b/include/linux/kobject.h +@@ -32,6 +32,8 @@ + #define UEVENT_NUM_ENVP 64 /* number of env pointers */ + #define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ + ++struct sk_buff; ++ + #ifdef CONFIG_UEVENT_HELPER + /* path to the userspace helper executed on an event */ + extern char uevent_helper[]; +@@ -244,4 +246,7 @@ int kobject_synth_uevent(struct kobject + __printf(2, 3) + int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); + ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation); ++ + #endif /* _KOBJECT_H_ */ +--- a/lib/kobject_uevent.c ++++ b/lib/kobject_uevent.c +@@ -691,6 +691,43 @@ int add_uevent_var(struct kobj_uevent_en + EXPORT_SYMBOL_GPL(add_uevent_var); + + #if defined(CONFIG_NET) ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ struct uevent_sock *ue_sk; ++ int err = 0; ++ ++ /* send netlink message */ ++ mutex_lock(&uevent_sock_mutex); ++ list_for_each_entry(ue_sk, &uevent_sock_list, list) { ++ struct sock *uevent_sock = ue_sk->sk; ++ struct sk_buff *skb2; ++ ++ skb2 = skb_clone(skb, allocation); ++ if (!skb2) ++ break; ++ ++ err = netlink_broadcast(uevent_sock, skb2, pid, group, ++ allocation); ++ if (err) ++ break; ++ } ++ mutex_unlock(&uevent_sock_mutex); ++ ++ kfree_skb(skb); ++ return err; ++} ++#else ++int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group, ++ gfp_t allocation) ++{ ++ kfree_skb(skb); ++ return 0; ++} ++#endif ++EXPORT_SYMBOL_GPL(broadcast_uevent); ++ ++#if defined(CONFIG_NET) + static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb, + struct netlink_ext_ack *extack) + { diff --git a/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch new file mode 100644 index 00000000000..d1f36e716ed --- /dev/null +++ b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch @@ -0,0 +1,21 @@ +From e08bcbbaa52fcc41f02743fd2e62a33255ce52da Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 13:52:28 +0200 +Subject: [PATCH] of/ftd: add device tree cmdline + +--- + drivers/of/fdt.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1158,6 +1158,9 @@ int __init early_init_dt_scan_chosen(uns + p = of_get_flat_dt_prop(node, "bootargs", &l); + if (p != NULL && l > 0) + strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); ++ p = of_get_flat_dt_prop(node, "bootargs-append", &l); ++ if (p != NULL && l > 0) ++ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else diff --git a/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch b/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch new file mode 100644 index 00000000000..4f4d6c75091 --- /dev/null +++ b/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch @@ -0,0 +1,30 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Date: Tue, 19 Jul 2022 06:17:48 +0200 +Subject: [PATCH] Revert "Revert "Revert "driver core: Set fw_devlink=on by + default""" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit ea718c699055c8566eb64432388a04974c43b2ea. + +With of_platform_populate() called for MTD partitions that commit breaks +probing devices which reference MTD in device tree. + +Link: https://lore.kernel.org/all/696cb2da-20b9-b3dd-46d9-de4bf91a1506@gmail.com/T/#u +Signed-off-by: Rafał Miłecki +--- + drivers/base/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -1562,7 +1562,7 @@ static void device_links_purge(struct de + #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \ + DL_FLAG_PM_RUNTIME) + +-static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON; ++static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE; + static int __init fw_devlink_setup(char *arg) + { + if (!arg) diff --git a/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch b/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch new file mode 100644 index 00000000000..22f52c1d462 --- /dev/null +++ b/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch @@ -0,0 +1,29 @@ +From: Felix Fietkau +Date: Thu, 22 Oct 2020 22:00:03 +0200 +Subject: [PATCH] compiler.h: only include asm/rwonce.h for kernel code + +This header file is not in uapi, which makes any user space code that includes +linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory' + +Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h") +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/compiler.h ++++ b/include/linux/compiler.h +@@ -220,6 +220,8 @@ void ftrace_likely_update(struct ftrace_ + #define function_nocfi(x) (x) + #endif + ++#include ++ + #endif /* __KERNEL__ */ + + /* +@@ -252,6 +254,4 @@ static inline void *offset_to_ptr(const + */ + #define prevent_tail_call_optimization() mb() + +-#include +- + #endif /* __LINUX_COMPILER_H */ diff --git a/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch b/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch new file mode 100644 index 00000000000..95a9656d268 --- /dev/null +++ b/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch @@ -0,0 +1,57 @@ +From: Felix Fietkau +Date: Wed, 18 Apr 2018 10:50:05 +0200 +Subject: [PATCH] MIPS: only process negative stack offsets on stack traces + +Fixes endless back traces in cases where the compiler emits a stack +pointer increase in a branch delay slot (probably for some form of +function return). + +[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low! +[ 3.480070] turning off the locking correctness validator. +[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0 +[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000 +[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f +[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000 +[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000 +[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000 +[ 3.532942] ... +[ 3.535362] Call Trace: +[ 3.537818] [<80010a48>] show_stack+0x58/0x100 +[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170 +[ 3.546613] [<80079f90>] save_trace+0xf0/0x110 +[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c +[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08 +[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c +[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78 +[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac +[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0 +[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac + +Signed-off-by: Felix Fietkau +--- + +--- a/arch/mips/kernel/process.c ++++ b/arch/mips/kernel/process.c +@@ -393,6 +393,8 @@ static inline int is_sp_move_ins(union m + + if (ip->i_format.opcode == addiu_op || + ip->i_format.opcode == daddiu_op) { ++ if (ip->i_format.simmediate > 0) ++ return 0; + *frame_size = -ip->i_format.simmediate; + return 1; + } diff --git a/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch new file mode 100644 index 00000000000..120b6e4cf89 --- /dev/null +++ b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch @@ -0,0 +1,21 @@ +From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001 +From: Felix Fietkau +Date: Sun, 9 Jul 2017 00:26:53 +0200 +Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86 + +Signed-off-by: Felix Fietkau +--- + Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/Makefile ++++ b/Makefile +@@ -534,7 +534,7 @@ KBUILD_LDFLAGS_MODULE := + KBUILD_LDFLAGS := + CLANG_FLAGS := + +-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG ++export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG + export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL + export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX + export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD diff --git a/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch new file mode 100644 index 00000000000..5216d6a7068 --- /dev/null +++ b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch @@ -0,0 +1,32 @@ +From f7982c726e02001afc19052fe48f642dfcbc00b2 Mon Sep 17 00:00:00 2001 +From: Vincent Tremblay +Date: Mon, 26 Dec 2022 21:10:37 -0500 +Subject: [PATCH 1/2] spidev: Add Silicon Labs EM3581 device compatible + +Add compatible string for Silicon Labs EM3581 device. + +Note: This patch is adapted from a patch submitted to the for-next branch (v6.3). + +Signed-off-by: Vincent Tremblay +--- + drivers/spi/spidev.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -691,6 +691,7 @@ static const struct spi_device_id spidev + { .name = "m53cpld" }, + { .name = "spi-petra" }, + { .name = "spi-authenta" }, ++ { .name = "em3581" }, + {}, + }; + MODULE_DEVICE_TABLE(spi, spidev_spi_ids); +@@ -705,6 +706,7 @@ static const struct of_device_id spidev_ + { .compatible = "menlo,m53cpld" }, + { .compatible = "cisco,spi-petra" }, + { .compatible = "micron,spi-authenta" }, ++ { .compatible = "silabs,em3581" }, + {}, + }; + MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch new file mode 100644 index 00000000000..ffbed0c622b --- /dev/null +++ b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch @@ -0,0 +1,32 @@ +From 536581825219e97fa2ae0c4de35605d2f6311416 Mon Sep 17 00:00:00 2001 +From: Vincent Tremblay +Date: Tue, 27 Dec 2022 09:00:58 -0500 +Subject: [PATCH 2/2] spidev: Add Silicon Labs SI3210 device compatible + +Add compatible string for Silicon Labs SI3210 device. + +Note: This patch is adapted from a patch submitted to the for-next branch (v6.3). + +Signed-off-by: Vincent Tremblay +--- + drivers/spi/spidev.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -692,6 +692,7 @@ static const struct spi_device_id spidev + { .name = "spi-petra" }, + { .name = "spi-authenta" }, + { .name = "em3581" }, ++ { .name = "si3210" }, + {}, + }; + MODULE_DEVICE_TABLE(spi, spidev_spi_ids); +@@ -707,6 +708,7 @@ static const struct of_device_id spidev_ + { .compatible = "cisco,spi-petra" }, + { .compatible = "micron,spi-authenta" }, + { .compatible = "silabs,em3581" }, ++ { .compatible = "silabs,si3210" }, + {}, + }; + MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/target/linux/generic/pending-6.1/111-watchdog-max63xx_wdt-Add-support-for-specifying-WDI-.patch b/target/linux/generic/pending-6.1/111-watchdog-max63xx_wdt-Add-support-for-specifying-WDI-.patch new file mode 100644 index 00000000000..d6b10491f83 --- /dev/null +++ b/target/linux/generic/pending-6.1/111-watchdog-max63xx_wdt-Add-support-for-specifying-WDI-.patch @@ -0,0 +1,75 @@ +From bd1b9f66d5134e518419f4c4dacf1884c1616983 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pali=20Roh=C3=A1r?= +Date: Thu, 28 Apr 2022 11:13:23 +0200 +Subject: [PATCH] watchdog: max63xx_wdt: Add support for specifying WDI logic + via GPIO +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On some boards is WDI logic of max6370 chip connected via GPIO. +So extend max63xx_wdt driver to allow specifying WDI logic via GPIO. + +Signed-off-by: Pali Rohár +--- + drivers/watchdog/max63xx_wdt.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +--- a/drivers/watchdog/max63xx_wdt.c ++++ b/drivers/watchdog/max63xx_wdt.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + #define DEFAULT_HEARTBEAT 60 + #define MAX_HEARTBEAT 60 +@@ -53,6 +54,9 @@ struct max63xx_wdt { + void __iomem *base; + spinlock_t lock; + ++ /* GPIOs */ ++ struct gpio_desc *gpio_wdi; ++ + /* WDI and WSET bits write access routines */ + void (*ping)(struct max63xx_wdt *wdt); + void (*set)(struct max63xx_wdt *wdt, u8 set); +@@ -158,6 +162,17 @@ static const struct watchdog_info max63x + .identity = "max63xx Watchdog", + }; + ++static void max63xx_gpio_ping(struct max63xx_wdt *wdt) ++{ ++ spin_lock(&wdt->lock); ++ ++ gpiod_set_value(wdt->gpio_wdi, 1); ++ udelay(1); ++ gpiod_set_value(wdt->gpio_wdi, 0); ++ ++ spin_unlock(&wdt->lock); ++} ++ + static void max63xx_mmap_ping(struct max63xx_wdt *wdt) + { + u8 val; +@@ -225,10 +240,19 @@ static int max63xx_wdt_probe(struct plat + return -EINVAL; + } + ++ wdt->gpio_wdi = devm_gpiod_get(dev, NULL, GPIOD_FLAGS_BIT_DIR_OUT); ++ if (IS_ERR(wdt->gpio_wdi) && PTR_ERR(wdt->gpio_wdi) != -ENOENT) ++ return dev_err_probe(dev, PTR_ERR(wdt->gpio_wdi), ++ "unable to request gpio: %ld\n", ++ PTR_ERR(wdt->gpio_wdi)); ++ + err = max63xx_mmap_init(pdev, wdt); + if (err) + return err; + ++ if (!IS_ERR(wdt->gpio_wdi)) ++ wdt->ping = max63xx_gpio_ping; ++ + platform_set_drvdata(pdev, &wdt->wdd); + watchdog_set_drvdata(&wdt->wdd, wdt); + diff --git a/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch new file mode 100644 index 00000000000..ac5e3a69b80 --- /dev/null +++ b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch @@ -0,0 +1,82 @@ +From: Tobias Wolf +Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation + +An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any +kernel beyond version 4.3 resulting in: + +BUG: Bad page state in process swapper pfn:086ac + +bisect resulted in: + +a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit +commit a1c34a3bf00af2cede839879502e12dc68491ad5 +Author: Laura Abbott +Date: Thu Nov 5 18:48:46 2015 -0800 + + mm: Don't offset memmap for flatmem + + Srinivas Kandagatla reported bad page messages when trying to remove the + bottom 2MB on an ARM based IFC6410 board + + BUG: Bad page state in process swapper pfn:fffa8 + page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0 + flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked) + page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set + bad because of flags: + flags: 0x200041(locked|active|mlocked) + Modules linked in: + CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty +#816 + Hardware name: Qualcomm (Flattened Device Tree) + unwind_backtrace + show_stack + dump_stack + bad_page + free_pages_prepare + free_hot_cold_page + __free_pages + free_highmem_page + mem_init + start_kernel + Disabling lock debugging due to kernel taint + [...] +:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4 +0a8156f848733dfa21e16c196dfb6c0a76290709 M mm + +This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by +page_to_pfn anymore. + +The following output was generated with two hacked in printk statements: + +printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map - +(pgdat->node_start_pfn - ARCH_PFN_OFFSET)); + if (page_to_pfn(mem_map) != pgdat->node_start_pfn) + mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); +printk("after %p\n", mem_map); + +Output: + +[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280 +[ 0.000000] after 8851b280 + +As seen in the first line mem_map with subtraction of offset does not equal the +mem_map after subtraction of ARCH_PFN_OFFSET. + +After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the +previously calculated offset is zero for the named platform it is able to boot +4.4 and 4.9-rc7 again. + +Signed-off-by: Tobias Wolf +--- + +--- a/mm/page_alloc.c ++++ b/mm/page_alloc.c +@@ -7620,7 +7620,7 @@ static void __init alloc_node_mem_map(st + if (pgdat == NODE_DATA(0)) { + mem_map = NODE_DATA(0)->node_mem_map; + if (page_to_pfn(mem_map) != pgdat->node_start_pfn) +- mem_map -= offset; ++ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET); + } + #endif + } diff --git a/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch b/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch new file mode 100644 index 00000000000..f04007e982d --- /dev/null +++ b/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch @@ -0,0 +1,94 @@ +From ca71e00839fcdd26f122fb6d9e97903c9fe198f7 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Sat, 6 May 2023 08:08:35 +0200 +Subject: [PATCH] binfmt_elf: dynamically allocate note.data in + parse_elf_properties + +Dynamically allocate note.data in parse_elf_properties to fix +compilation warning on some arch. + +On some arch note.data exceet the stack limit for a single function and +this cause the following compilation warning: +fs/binfmt_elf.c: In function 'parse_elf_properties.isra': +fs/binfmt_elf.c:821:1: error: the frame size of 1040 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] + 821 | } + | ^ +cc1: all warnings being treated as errors + +Fix this by dynamically allocating the array. + +Fixes: 00e19ceec80b ("ELF: Add ELF program property parsing support") +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org # v5.8+ +--- + fs/binfmt_elf.c | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -768,7 +768,7 @@ static int parse_elf_properties(struct f + { + union { + struct elf_note nhdr; +- char data[NOTE_DATA_SZ]; ++ char *data; + } note; + loff_t pos; + ssize_t n; +@@ -788,26 +788,38 @@ static int parse_elf_properties(struct f + if (phdr->p_filesz > sizeof(note)) + return -ENOEXEC; + ++ note.data = kcalloc(NOTE_DATA_SZ, sizeof(*note.data), GFP_KERNEL); ++ if (!note.data) ++ return -ENOMEM; ++ + pos = phdr->p_offset; + n = kernel_read(f, ¬e, phdr->p_filesz, &pos); + + BUILD_BUG_ON(sizeof(note) < sizeof(note.nhdr) + NOTE_NAME_SZ); +- if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) +- return -EIO; ++ if (n < 0 || n < sizeof(note.nhdr) + NOTE_NAME_SZ) { ++ ret = -EIO; ++ goto exit; ++ } + + if (note.nhdr.n_type != NT_GNU_PROPERTY_TYPE_0 || + note.nhdr.n_namesz != NOTE_NAME_SZ || + strncmp(note.data + sizeof(note.nhdr), +- GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) +- return -ENOEXEC; ++ GNU_PROPERTY_TYPE_0_NAME, n - sizeof(note.nhdr))) { ++ ret = -ENOEXEC; ++ goto exit; ++ } + + off = round_up(sizeof(note.nhdr) + NOTE_NAME_SZ, + ELF_GNU_PROPERTY_ALIGN); +- if (off > n) +- return -ENOEXEC; +- +- if (note.nhdr.n_descsz > n - off) +- return -ENOEXEC; ++ if (off > n) { ++ ret = -ENOEXEC; ++ goto exit; ++ } ++ ++ if (note.nhdr.n_descsz > n - off) { ++ ret = -ENOEXEC; ++ goto exit; ++ } + datasz = off + note.nhdr.n_descsz; + + have_prev_type = false; +@@ -817,6 +829,8 @@ static int parse_elf_properties(struct f + have_prev_type = true; + } while (!ret); + ++exit: ++ kfree(note.data); + return ret == -ENOENT ? 0 : ret; + } + diff --git a/target/linux/generic/pending-6.1/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch b/target/linux/generic/pending-6.1/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch new file mode 100644 index 00000000000..8f40ae3ba24 --- /dev/null +++ b/target/linux/generic/pending-6.1/140-jffs2-use-.rename2-and-add-RENAME_WHITEOUT-support.patch @@ -0,0 +1,81 @@ +From: Felix Fietkau +Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support + +It is required for renames on overlayfs + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -614,8 +614,8 @@ static int jffs2_rmdir (struct inode *di + return ret; + } + +-static int jffs2_mknod (struct user_namespace *mnt_userns, struct inode *dir_i, +- struct dentry *dentry, umode_t mode, dev_t rdev) ++static int __jffs2_mknod (struct user_namespace *mnt_userns, struct inode *dir_i, ++ struct dentry *dentry, umode_t mode, dev_t rdev, bool whiteout) + { + struct jffs2_inode_info *f, *dir_f; + struct jffs2_sb_info *c; +@@ -754,7 +754,11 @@ static int jffs2_mknod (struct user_name + mutex_unlock(&dir_f->sem); + jffs2_complete_reservation(c); + +- d_instantiate_new(dentry, inode); ++ if (!whiteout) ++ d_instantiate_new(dentry, inode); ++ else ++ unlock_new_inode(inode); ++ + return 0; + + fail: +@@ -762,6 +766,19 @@ static int jffs2_mknod (struct user_name + return ret; + } + ++static int jffs2_mknod (struct user_namespace *mnt_userns, struct inode *dir_i, ++ struct dentry *dentry, umode_t mode, dev_t rdev) ++{ ++ return __jffs2_mknod(mnt_userns, dir_i, dentry, mode, rdev, false); ++} ++ ++static int jffs2_whiteout (struct user_namespace *mnt_userns, struct inode *old_dir, ++ struct dentry *old_dentry) ++{ ++ return __jffs2_mknod(mnt_userns, old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, ++ WHITEOUT_DEV, true); ++} ++ + static int jffs2_rename (struct user_namespace *mnt_userns, + struct inode *old_dir_i, struct dentry *old_dentry, + struct inode *new_dir_i, struct dentry *new_dentry, +@@ -773,7 +790,7 @@ static int jffs2_rename (struct user_nam + uint8_t type; + uint32_t now; + +- if (flags & ~RENAME_NOREPLACE) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) + return -EINVAL; + + /* The VFS will check for us and prevent trying to rename a +@@ -839,9 +856,14 @@ static int jffs2_rename (struct user_nam + if (d_is_dir(old_dentry) && !victim_f) + inc_nlink(new_dir_i); + +- /* Unlink the original */ +- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now); ++ if (flags & RENAME_WHITEOUT) ++ /* Replace with whiteout */ ++ ret = jffs2_whiteout(mnt_userns, old_dir_i, old_dentry); ++ else ++ /* Unlink the original */ ++ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), ++ old_dentry->d_name.name, ++ old_dentry->d_name.len, NULL, now); + + /* We don't touch inode->i_nlink */ + diff --git a/target/linux/generic/pending-6.1/141-jffs2-add-RENAME_EXCHANGE-support.patch b/target/linux/generic/pending-6.1/141-jffs2-add-RENAME_EXCHANGE-support.patch new file mode 100644 index 00000000000..f58fc791d28 --- /dev/null +++ b/target/linux/generic/pending-6.1/141-jffs2-add-RENAME_EXCHANGE-support.patch @@ -0,0 +1,73 @@ +From: Felix Fietkau +Subject: jffs2: add RENAME_EXCHANGE support + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -787,18 +787,31 @@ static int jffs2_rename (struct user_nam + int ret; + struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); + struct jffs2_inode_info *victim_f = NULL; ++ struct inode *fst_inode = d_inode(old_dentry); ++ struct inode *snd_inode = d_inode(new_dentry); + uint8_t type; + uint32_t now; + +- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT)) ++ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE)) + return -EINVAL; + ++ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) { ++ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { ++ inc_nlink(new_dir_i); ++ drop_nlink(old_dir_i); ++ } ++ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { ++ drop_nlink(new_dir_i); ++ inc_nlink(old_dir_i); ++ } ++ } ++ + /* The VFS will check for us and prevent trying to rename a + * file over a directory and vice versa, but if it's a directory, + * the VFS can't check whether the victim is empty. The filesystem + * needs to do that for itself. + */ +- if (d_really_is_positive(new_dentry)) { ++ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) { + victim_f = JFFS2_INODE_INFO(d_inode(new_dentry)); + if (d_is_dir(new_dentry)) { + struct jffs2_full_dirent *fd; +@@ -833,7 +846,7 @@ static int jffs2_rename (struct user_nam + if (ret) + return ret; + +- if (victim_f) { ++ if (victim_f && !(flags & RENAME_EXCHANGE)) { + /* There was a victim. Kill it off nicely */ + if (d_is_dir(new_dentry)) + clear_nlink(d_inode(new_dentry)); +@@ -859,6 +872,12 @@ static int jffs2_rename (struct user_nam + if (flags & RENAME_WHITEOUT) + /* Replace with whiteout */ + ret = jffs2_whiteout(mnt_userns, old_dir_i, old_dentry); ++ else if (flags & RENAME_EXCHANGE) ++ /* Replace the original */ ++ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i), ++ d_inode(new_dentry)->i_ino, type, ++ old_dentry->d_name.name, old_dentry->d_name.len, ++ now); + else + /* Unlink the original */ + ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), +@@ -890,7 +909,7 @@ static int jffs2_rename (struct user_nam + return ret; + } + +- if (d_is_dir(old_dentry)) ++ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE)) + drop_nlink(old_dir_i); + + new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now); diff --git a/target/linux/generic/pending-6.1/142-jffs2-add-splice-ops.patch b/target/linux/generic/pending-6.1/142-jffs2-add-splice-ops.patch new file mode 100644 index 00000000000..de847a1f5cd --- /dev/null +++ b/target/linux/generic/pending-6.1/142-jffs2-add-splice-ops.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau +Subject: jffs2: add splice ops + +Add splice_read using generic_file_splice_read. +Add splice_write using iter_file_splice_write + +Signed-off-by: Felix Fietkau +--- + +--- a/fs/jffs2/file.c ++++ b/fs/jffs2/file.c +@@ -53,6 +53,8 @@ const struct file_operations jffs2_file_ + .open = generic_file_open, + .read_iter = generic_file_read_iter, + .write_iter = generic_file_write_iter, ++ .splice_read = generic_file_splice_read, ++ .splice_write = iter_file_splice_write, + .unlocked_ioctl=jffs2_ioctl, + .mmap = generic_file_readonly_mmap, + .fsync = jffs2_fsync, diff --git a/target/linux/generic/pending-6.1/143-jffs2-reduce-stack-usage-in-jffs2_build_xattr_subsys.patch b/target/linux/generic/pending-6.1/143-jffs2-reduce-stack-usage-in-jffs2_build_xattr_subsys.patch new file mode 100644 index 00000000000..e5a86dd29fe --- /dev/null +++ b/target/linux/generic/pending-6.1/143-jffs2-reduce-stack-usage-in-jffs2_build_xattr_subsys.patch @@ -0,0 +1,121 @@ +From eee53f6eb7561f516b9c4bac829ce31c48096130 Mon Sep 17 00:00:00 2001 +From: Fabian Frederick +Date: Tue, 9 May 2017 22:30:03 +0200 +Subject: [PATCH] jffs2: reduce stack usage in jffs2_build_xattr_subsystem() + +Use kcalloc() for allocation/flush of 128 pointers table to +reduce stack usage. + +Function now returns -ENOMEM or 0 on success. + +stackusage +Before: +./fs/jffs2/xattr.c:775 jffs2_build_xattr_subsystem 1208 +dynamic,bounded + +After: +./fs/jffs2/xattr.c:775 jffs2_build_xattr_subsystem 192 +dynamic,bounded + +Also update definition when CONFIG_JFFS2_FS_XATTR is not enabled + +Tested with an MTD mount point and some user set/getfattr. + +Many current target on OpenWRT also suffer from a compilation warning +(that become an error with CONFIG_WERROR) with the following output: + +fs/jffs2/xattr.c: In function 'jffs2_build_xattr_subsystem': +fs/jffs2/xattr.c:887:1: error: the frame size of 1088 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] + 887 | } + | ^ + +Using dynamic allocation fix this compilation warning. + +Fixes: c9f700f840bd ("[JFFS2][XATTR] using 'delete marker' for xdatum/xref deletion") +Reported-by: Tim Gardner +Reported-by: kernel test robot +Reported-by: Ron Economos +Reported-by: Nathan Chancellor +Reviewed-by: Nick Desaulniers +Signed-off-by: Fabian Frederick +Signed-off-by: Christian Marangi +Cc: stable@vger.kernel.org +--- + fs/jffs2/build.c | 5 ++++- + fs/jffs2/xattr.c | 13 +++++++++---- + fs/jffs2/xattr.h | 4 ++-- + 3 files changed, 15 insertions(+), 7 deletions(-) + +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -211,7 +211,10 @@ static int jffs2_build_filesystem(struct + ic->scan_dents = NULL; + cond_resched(); + } +- jffs2_build_xattr_subsystem(c); ++ ret = jffs2_build_xattr_subsystem(c); ++ if (ret) ++ goto exit; ++ + c->flags &= ~JFFS2_SB_FLAG_BUILDING; + + dbg_fsbuild("FS build complete\n"); +--- a/fs/jffs2/xattr.c ++++ b/fs/jffs2/xattr.c +@@ -772,10 +772,10 @@ void jffs2_clear_xattr_subsystem(struct + } + + #define XREF_TMPHASH_SIZE (128) +-void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) ++int jffs2_build_xattr_subsystem(struct jffs2_sb_info *c) + { + struct jffs2_xattr_ref *ref, *_ref; +- struct jffs2_xattr_ref *xref_tmphash[XREF_TMPHASH_SIZE]; ++ struct jffs2_xattr_ref **xref_tmphash; + struct jffs2_xattr_datum *xd, *_xd; + struct jffs2_inode_cache *ic; + struct jffs2_raw_node_ref *raw; +@@ -784,9 +784,12 @@ void jffs2_build_xattr_subsystem(struct + + BUG_ON(!(c->flags & JFFS2_SB_FLAG_BUILDING)); + ++ xref_tmphash = kcalloc(XREF_TMPHASH_SIZE, ++ sizeof(struct jffs2_xattr_ref *), GFP_KERNEL); ++ if (!xref_tmphash) ++ return -ENOMEM; ++ + /* Phase.1 : Merge same xref */ +- for (i=0; i < XREF_TMPHASH_SIZE; i++) +- xref_tmphash[i] = NULL; + for (ref=c->xref_temp; ref; ref=_ref) { + struct jffs2_xattr_ref *tmp; + +@@ -884,6 +887,8 @@ void jffs2_build_xattr_subsystem(struct + "%u of xref (%u dead, %u orphan) found.\n", + xdatum_count, xdatum_unchecked_count, xdatum_orphan_count, + xref_count, xref_dead_count, xref_orphan_count); ++ kfree(xref_tmphash); ++ return 0; + } + + struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, +--- a/fs/jffs2/xattr.h ++++ b/fs/jffs2/xattr.h +@@ -71,7 +71,7 @@ static inline int is_xattr_ref_dead(stru + #ifdef CONFIG_JFFS2_FS_XATTR + + extern void jffs2_init_xattr_subsystem(struct jffs2_sb_info *c); +-extern void jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); ++extern int jffs2_build_xattr_subsystem(struct jffs2_sb_info *c); + extern void jffs2_clear_xattr_subsystem(struct jffs2_sb_info *c); + + extern struct jffs2_xattr_datum *jffs2_setup_xattr_datum(struct jffs2_sb_info *c, +@@ -103,7 +103,7 @@ extern ssize_t jffs2_listxattr(struct de + #else + + #define jffs2_init_xattr_subsystem(c) +-#define jffs2_build_xattr_subsystem(c) ++#define jffs2_build_xattr_subsystem(c) (0) + #define jffs2_clear_xattr_subsystem(c) + + #define jffs2_xattr_do_crccheck_inode(c, ic) diff --git a/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch new file mode 100644 index 00000000000..9968a79699f --- /dev/null +++ b/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch @@ -0,0 +1,45 @@ +From: Stephen Hemminger +Subject: bridge: allow receiption on disabled port + +When an ethernet device is enslaved to a bridge, and the bridge STP +detects loss of carrier (or operational state down), then normally +packet receiption is blocked. + +This breaks control applications like WPA which maybe expecting to +receive packets to negotiate to bring link up. The bridge needs to +block forwarding packets from these disabled ports, but there is no +hard requirement to not allow local packet delivery. + +Signed-off-by: Stephen Hemminger +Signed-off-by: Felix Fietkau + +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -204,6 +204,9 @@ static void __br_handle_local_finish(str + /* note: already called with rcu_read_lock */ + static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) + { ++ struct net_bridge_port *p = br_port_get_rcu(skb->dev); ++ ++ if (p->state != BR_STATE_DISABLED) + __br_handle_local_finish(skb); + + /* return 1 to signal the okfn() was called so it's ok to use the skb */ +@@ -369,6 +372,17 @@ static rx_handler_result_t br_handle_fra + + forward: + switch (p->state) { ++ case BR_STATE_DISABLED: ++ if (ether_addr_equal(p->br->dev->dev_addr, dest)) ++ skb->pkt_type = PACKET_HOST; ++ ++ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, ++ dev_net(skb->dev), NULL, skb, skb->dev, NULL, ++ br_handle_local_finish) == 1) { ++ return RX_HANDLER_PASS; ++ } ++ break; ++ + case BR_STATE_FORWARDING: + case BR_STATE_LEARNING: + if (ether_addr_equal(p->br->dev->dev_addr, dest)) diff --git a/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch b/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch new file mode 100644 index 00000000000..13b79b5c098 --- /dev/null +++ b/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch @@ -0,0 +1,94 @@ +From: Daniel González Cabanelas +Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week + +The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week +alarms. + +Read the "wday" alarm register and convert it to a date to support up 1 +week in our driver. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 42 insertions(+), 6 deletions(-) + +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device + { + struct i2c_client *client = to_i2c_client(dev); + struct rs5c372 *rs5c = i2c_get_clientdata(client); +- int status; ++ int status, wday_offs; ++ struct rtc_time rtc; ++ unsigned long alarm_secs; + + status = rs5c_get_regs(rs5c); + if (status < 0) +@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device + t->time.tm_sec = 0; + t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); + t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); ++ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1; ++ ++ /* determine the day, month and year based on alarm wday, taking as a ++ * reference the current time from the rtc ++ */ ++ status = rs5c372_rtc_read_time(dev, &rtc); ++ if (status < 0) ++ return status; ++ ++ wday_offs = t->time.tm_wday - rtc.tm_wday; ++ alarm_secs = mktime64(rtc.tm_year + 1900, ++ rtc.tm_mon + 1, ++ rtc.tm_mday + wday_offs, ++ t->time.tm_hour, ++ t->time.tm_min, ++ t->time.tm_sec); ++ ++ if (wday_offs < 0 || (wday_offs == 0 && ++ (t->time.tm_hour < rtc.tm_hour || ++ (t->time.tm_hour == rtc.tm_hour && ++ t->time.tm_min <= rtc.tm_min)))) ++ alarm_secs += 7 * 86400; ++ ++ rtc_time64_to_tm(alarm_secs, &t->time); + + /* ... and status */ + t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); +@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device + struct rs5c372 *rs5c = i2c_get_clientdata(client); + int status, addr, i; + unsigned char buf[3]; ++ struct rtc_time rtc_tm; ++ unsigned long rtc_secs, alarm_secs; + +- /* only handle up to 24 hours in the future, like RTC_ALM_SET */ +- if (t->time.tm_mday != -1 +- || t->time.tm_mon != -1 +- || t->time.tm_year != -1) ++ /* chip only can handle alarms up to one week in the future*/ ++ status = rs5c372_rtc_read_time(dev, &rtc_tm); ++ if (status) ++ return status; ++ rtc_secs = rtc_tm_to_time64(&rtc_tm); ++ alarm_secs = rtc_tm_to_time64(&t->time); ++ if (alarm_secs >= rtc_secs + 7 * 86400) { ++ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n", ++ __func__, status); + return -EINVAL; ++ } + + /* REVISIT: round up tm_sec */ + +@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device + /* set alarm */ + buf[0] = bin2bcd(t->time.tm_min); + buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); +- buf[2] = 0x7f; /* any/all days */ ++ /* each bit is the day of the week, 0x7f means all days */ ++ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ? ++ BIT(t->time.tm_wday) : 0x7f; + + for (i = 0; i < sizeof(buf); i++) { + addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i); diff --git a/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch new file mode 100644 index 00000000000..7e9d0e66c05 --- /dev/null +++ b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch @@ -0,0 +1,70 @@ +From: Daniel González Cabanelas +Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source + +Currently there is no use for the interrupts on the rs5c372 RTC and the +wakealarm isn't enabled. There are some devices like NASes which use this +RTC to wake up from the power off state when the INTR pin is activated by +the alarm clock. + +Enable the alarm and let to be used as a wakeup source. + +Tested on a Buffalo LS421DE NAS. + +Signed-off-by: Daniel González Cabanelas +--- + drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +--- a/drivers/rtc/rtc-rs5c372.c ++++ b/drivers/rtc/rtc-rs5c372.c +@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_clie + int err = 0; + int smbus_mode = 0; + struct rs5c372 *rs5c372; ++ bool rs5c372_can_wakeup_device = false; + + dev_dbg(&client->dev, "%s\n", __func__); + +@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_clie + else + rs5c372->type = id->driver_data; + ++#ifdef CONFIG_OF ++ if(of_property_read_bool(client->dev.of_node, ++ "wakeup-source")) ++ rs5c372_can_wakeup_device = true; ++#endif ++ + /* we read registers 0x0f then 0x00-0x0f; skip the first one */ + rs5c372->regs = &rs5c372->buf[1]; + rs5c372->smbus = smbus_mode; +@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_clie + goto exit; + } + ++ rs5c372->has_irq = 1; ++ + /* if the oscillator lost power and no other software (like + * the bootloader) set it up, do it here. + * +@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_clie + ); + + /* REVISIT use client->irq to register alarm irq ... */ ++ if (rs5c372_can_wakeup_device) { ++ device_init_wakeup(&client->dev, true); ++ } ++ + rs5c372->rtc = devm_rtc_device_register(&client->dev, + rs5c372_driver.driver.name, + &rs5c372_rtc_ops, THIS_MODULE); +@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_clie + if (err) + goto exit; + ++ /* the rs5c372 alarm only supports a minute accuracy */ ++ rs5c372->rtc->uie_unsupported = 1; ++ + return 0; + + exit: diff --git a/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch new file mode 100644 index 00000000000..930d0ff0fe4 --- /dev/null +++ b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch @@ -0,0 +1,119 @@ +From: Felix Fietkau +Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx + +[john@phrozen.org: added to my upstream queue 30.12.2016] +lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed +Signed-off-by: Felix Fietkau +--- + init/Kconfig | 11 +++++++++++ + kernel/kallsyms.c | 8 ++++++++ + scripts/kallsyms.c | 12 ++++++++++++ + scripts/link-vmlinux.sh | 4 ++++ + 4 files changed, 35 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1447,6 +1447,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW + the unaligned access emulation. + see arch/parisc/kernel/unaligned.c for reference + ++config KALLSYMS_UNCOMPRESSED ++ bool "Keep kallsyms uncompressed" ++ depends on KALLSYMS ++ help ++ Normally kallsyms contains compressed symbols (using a token table), ++ reducing the uncompressed kernel image size. Keeping the symbol table ++ uncompressed significantly improves the size of this part in compressed ++ kernel images. ++ ++ Say N unless you need compressed kernel images to be small. ++ + config HAVE_PCSPKR_PLATFORM + bool + +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -80,6 +80,11 @@ static unsigned int kallsyms_expand_symb + * For every byte on the compressed symbol data, copy the table + * entry for that byte. + */ ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ memcpy(result, data + 1, len - 1); ++ result += len - 1; ++ len = 0; ++#endif + while (len) { + tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; + data++; +@@ -112,6 +117,9 @@ tail: + */ + static char kallsyms_get_symbol_type(unsigned int off) + { ++#ifdef CONFIG_KALLSYMS_UNCOMPRESSED ++ return kallsyms_names[off + 1]; ++#endif + /* + * Get just the first code, look it up in the token table, + * and return the first char from this token. +--- a/scripts/kallsyms.c ++++ b/scripts/kallsyms.c +@@ -58,6 +58,7 @@ static struct addr_range percpu_range = + static struct sym_entry **table; + static unsigned int table_size, table_cnt; + static int all_symbols; ++static int uncompressed; + static int absolute_percpu; + static int base_relative; + +@@ -486,6 +487,9 @@ static void write_src(void) + + free(markers); + ++ if (uncompressed) ++ return; ++ + output_label("kallsyms_token_table"); + off = 0; + for (i = 0; i < 256; i++) { +@@ -537,6 +541,9 @@ static unsigned char *find_token(unsigne + { + int i; + ++ if (uncompressed) ++ return NULL; ++ + for (i = 0; i < len - 1; i++) { + if (str[i] == token[0] && str[i+1] == token[1]) + return &str[i]; +@@ -609,6 +616,9 @@ static void optimize_result(void) + { + int i, best; + ++ if (uncompressed) ++ return; ++ + /* using the '\0' symbol last allows compress_symbols to use standard + * fast string functions */ + for (i = 255; i >= 0; i--) { +@@ -773,6 +783,8 @@ int main(int argc, char **argv) + absolute_percpu = 1; + else if (strcmp(argv[i], "--base-relative") == 0) + base_relative = 1; ++ else if (strcmp(argv[i], "--uncompressed") == 0) ++ uncompressed = 1; + else + usage(); + } +--- a/scripts/link-vmlinux.sh ++++ b/scripts/link-vmlinux.sh +@@ -257,6 +257,10 @@ kallsyms() + kallsymopt="${kallsymopt} --base-relative" + fi + ++ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ kallsymopt="${kallsymopt} --uncompressed" ++ fi ++ + info KSYMS ${2} + ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2} + } diff --git a/target/linux/generic/pending-6.1/205-backtrace_module_info.patch b/target/linux/generic/pending-6.1/205-backtrace_module_info.patch new file mode 100644 index 00000000000..6379ce071d7 --- /dev/null +++ b/target/linux/generic/pending-6.1/205-backtrace_module_info.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries + +[john@phrozen.org: felix will add this to his upstream queue] + +lede-commit 53827cdc824556cda910b23ce5030c363b8f1461 +Signed-off-by: Felix Fietkau +--- + lib/vsprintf.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/lib/vsprintf.c ++++ b/lib/vsprintf.c +@@ -1003,8 +1003,10 @@ char *symbol_string(char *buf, char *end + struct printf_spec spec, const char *fmt) + { + unsigned long value; +-#ifdef CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; ++#ifndef CONFIG_KALLSYMS ++ struct module *mod; ++ int len; + #endif + + if (fmt[1] == 'R') +@@ -1025,8 +1027,14 @@ char *symbol_string(char *buf, char *end + + return string_nocheck(buf, end, sym, spec); + #else +- return special_hex_number(buf, end, value, sizeof(void *)); ++ len = snprintf(sym, sizeof(sym), "0x%lx", value); ++ mod = __module_address(value); ++ if (mod) ++ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]", ++ mod->name, mod->core_layout.base, ++ mod->core_layout.size); + #endif ++ return string(buf, end, sym, spec); + } + + static const struct printf_spec default_str_spec = { diff --git a/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch new file mode 100644 index 00000000000..29cfade7163 --- /dev/null +++ b/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -0,0 +1,30 @@ +From: Gabor Juhos +Subject: usr: sanitize deps_initramfs list + +If any filename in the intramfs dependency +list contains a colon, that causes a kernel +build error like this: + +/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop. +make[5]: *** [usr] Error 2 + +Fix it by removing such filenames from the +deps_initramfs list. + +Signed-off-by: Gabor Juhos +Signed-off-by: Felix Fietkau +--- + usr/Makefile | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/usr/Makefile ++++ b/usr/Makefile +@@ -61,6 +61,8 @@ hostprogs := gen_init_cpio + # The dependency list is generated by gen_initramfs.sh -l + -include $(obj)/.initramfs_data.cpio.d + ++deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v))) ++ + # do not try to update files included in initramfs + $(deps_initramfs): ; + diff --git a/target/linux/generic/pending-6.1/261-enable_wilink_platform_without_drivers.patch b/target/linux/generic/pending-6.1/261-enable_wilink_platform_without_drivers.patch new file mode 100644 index 00000000000..cd31f9d9342 --- /dev/null +++ b/target/linux/generic/pending-6.1/261-enable_wilink_platform_without_drivers.patch @@ -0,0 +1,20 @@ +From: Imre Kaloz +Subject: [PATCH] hack: net: wireless: make the wl12xx glue code available with + compat-wireless, too + +Signed-off-by: Imre Kaloz +--- + drivers/net/wireless/ti/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/wireless/ti/Kconfig ++++ b/drivers/net/wireless/ti/Kconfig +@@ -20,7 +20,7 @@ source "drivers/net/wireless/ti/wlcore/K + + config WILINK_PLATFORM_DATA + bool "TI WiLink platform data" +- depends on WLCORE_SDIO || WL1251_SDIO ++ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS + default y + help + Small platform data bit needed to pass data to the sdio modules. diff --git a/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch new file mode 100644 index 00000000000..99f83bb2c4e --- /dev/null +++ b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch @@ -0,0 +1,31 @@ +From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Sat, 28 Mar 2020 12:11:50 +0100 +Subject: [PATCH] generic: platform/mikrotik build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds platform/mikrotik kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/platform/Kconfig | 2 ++ + drivers/platform/Makefile | 1 + + 2 files changed, 3 insertions(+) + +--- a/drivers/platform/Kconfig ++++ b/drivers/platform/Kconfig +@@ -15,3 +15,5 @@ source "drivers/platform/mellanox/Kconfi + source "drivers/platform/olpc/Kconfig" + + source "drivers/platform/surface/Kconfig" ++ ++source "drivers/platform/mikrotik/Kconfig" +--- a/drivers/platform/Makefile ++++ b/drivers/platform/Makefile +@@ -10,3 +10,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/ + obj-$(CONFIG_GOLDFISH) += goldfish/ + obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ + obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ ++obj-$(CONFIG_MIKROTIK) += mikrotik/ diff --git a/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch b/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch new file mode 100644 index 00000000000..05d024925df --- /dev/null +++ b/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch @@ -0,0 +1,40 @@ +From: Mark Miller +Subject: mips: expose CONFIG_BOOT_RAW + +This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on +certain Broadcom chipsets running CFE in order to load the kernel. + +Signed-off-by: Mark Miller +Acked-by: Rob Landley +--- +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -1100,9 +1100,6 @@ config FW_ARC + config ARCH_MAY_HAVE_PC_FDC + bool + +-config BOOT_RAW +- bool +- + config CEVT_BCM1480 + bool + +@@ -3182,6 +3179,18 @@ choice + bool "Extend builtin kernel arguments with bootloader arguments" + endchoice + ++config BOOT_RAW ++ bool "Enable the kernel to be executed from the load address" ++ default n ++ help ++ Allow the kernel to be executed from the load address for ++ bootloaders which cannot read the ELF format. This places ++ a jump to start_kernel at the load address. ++ ++ If unsure, say N. ++ ++ ++ + endmenu + + config LOCKDEP_SUPPORT diff --git a/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch b/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch new file mode 100644 index 00000000000..726c884027f --- /dev/null +++ b/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch @@ -0,0 +1,71 @@ +From e6e6ef4275978823ec3a84133fc91f4ffbef5c84 Mon Sep 17 00:00:00 2001 +From: Paul Burton +Date: Mon, 22 Feb 2016 18:09:44 +0000 +Subject: [PATCH] MIPS: Add barriers between dcache & icache flushes + +Index-based cache operations may be arbitrarily reordered by out of +order CPUs. Thus code which writes back the dcache & then invalidates +the icache using indexed cache ops must include a barrier between +operating on the 2 caches in order to prevent the scenario in which: + + - icache invalidation occurs. + + - icache fetch occurs, due to speculation. + + - dcache writeback occurs. + +If the above were allowed to happen then the icache would contain stale +data. Forcing the dcache writeback to complete before the icache +invalidation avoids this. + +Signed-off-by: Paul Burton +Cc: James Hogan +--- + arch/mips/mm/c-r4k.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/arch/mips/mm/c-r4k.c ++++ b/arch/mips/mm/c-r4k.c +@@ -515,6 +515,7 @@ static inline void local_r4k___flush_cac + + default: + r4k_blast_dcache(); ++ mb(); /* cache instructions may be reordered */ + r4k_blast_icache(); + break; + } +@@ -595,8 +596,10 @@ static inline void local_r4k_flush_cache + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) + r4k_blast_dcache(); + /* If executable, blast stale lines from icache */ +- if (exec) ++ if (exec) { ++ mb(); /* cache instructions may be reordered */ + r4k_blast_icache(); ++ } + } + + static void r4k_flush_cache_range(struct vm_area_struct *vma, +@@ -697,8 +700,13 @@ static inline void local_r4k_flush_cache + if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { + vaddr ? r4k_blast_dcache_page(addr) : + r4k_blast_dcache_user_page(addr); +- if (exec && !cpu_icache_snoops_remote_store) ++ if (exec) ++ mb(); /* cache instructions may be reordered */ ++ ++ if (exec && !cpu_icache_snoops_remote_store) { + r4k_blast_scache_page(addr); ++ mb(); /* cache instructions may be reordered */ ++ } + } + if (exec) { + if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { +@@ -765,6 +773,7 @@ static inline void __local_r4k_flush_ica + else + blast_dcache_range(start, end); + } ++ mb(); /* cache instructions may be reordered */ + } + + if (type == R4K_INDEX || diff --git a/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch b/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch new file mode 100644 index 00000000000..271923fca8c --- /dev/null +++ b/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: mips: use -mno-branch-likely for kernel and userspace + +saves ~11k kernel size after lzma and ~12k squashfs size in the + +lede-commit: 41a039f46450ffae9483d6216422098669da2900 +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -95,7 +95,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + # machines may also. Since BFD is incredibly buggy with respect to + # crossformat linking we rely on the elf2ecoff tool for format conversion. + # +-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe ++cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib + KBUILD_AFLAGS_MODULE += -mlong-calls diff --git a/target/linux/generic/pending-6.1/305-mips_module_reloc.patch b/target/linux/generic/pending-6.1/305-mips_module_reloc.patch new file mode 100644 index 00000000000..bbea1f61c14 --- /dev/null +++ b/target/linux/generic/pending-6.1/305-mips_module_reloc.patch @@ -0,0 +1,370 @@ +From: Felix Fietkau +Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to + +lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 5 + + arch/mips/include/asm/module.h | 5 + + arch/mips/kernel/module.c | 279 ++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 284 insertions(+), 5 deletions(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -98,8 +98,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin + cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely + cflags-y += -msoft-float + LDFLAGS_vmlinux += -G 0 -static -n -nostdlib ++ifdef CONFIG_64BIT + KBUILD_AFLAGS_MODULE += -mlong-calls + KBUILD_CFLAGS_MODULE += -mlong-calls ++else ++ ifdef CONFIG_DYNAMIC_FTRACE ++ KBUILD_AFLAGS_MODULE += -mlong-calls ++ KBUILD_CFLAGS_MODULE += -mlong-calls ++ else ++ KBUILD_AFLAGS_MODULE += -mno-long-calls ++ KBUILD_CFLAGS_MODULE += -mno-long-calls ++ endif ++endif + + ifeq ($(CONFIG_RELOCATABLE),y) + LDFLAGS_vmlinux += --emit-relocs +--- a/arch/mips/include/asm/module.h ++++ b/arch/mips/include/asm/module.h +@@ -12,6 +12,11 @@ struct mod_arch_specific { + const struct exception_table_entry *dbe_start; + const struct exception_table_entry *dbe_end; + struct mips_hi16 *r_mips_hi16_list; ++ ++ void *phys_plt_tbl; ++ void *virt_plt_tbl; ++ unsigned int phys_plt_offset; ++ unsigned int virt_plt_offset; + }; + + typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ +--- a/arch/mips/kernel/module.c ++++ b/arch/mips/kernel/module.c +@@ -31,23 +31,261 @@ struct mips_hi16 { + static LIST_HEAD(dbe_list); + static DEFINE_SPINLOCK(dbe_lock); + +-#ifdef MODULE_START ++/* ++ * Get the potential max trampolines size required of the init and ++ * non-init sections. Only used if we cannot find enough contiguous ++ * physically mapped memory to put the module into. ++ */ ++static unsigned int ++get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, ++ const char *secstrings, unsigned int symindex, bool is_init) ++{ ++ unsigned long ret = 0; ++ unsigned int i, j; ++ Elf_Sym *syms; ++ ++ /* Everything marked ALLOC (this includes the exported symbols) */ ++ for (i = 1; i < hdr->e_shnum; ++i) { ++ unsigned int info = sechdrs[i].sh_info; ++ ++ if (sechdrs[i].sh_type != SHT_REL ++ && sechdrs[i].sh_type != SHT_RELA) ++ continue; ++ ++ /* Not a valid relocation section? */ ++ if (info >= hdr->e_shnum) ++ continue; ++ ++ /* Don't bother with non-allocated sections */ ++ if (!(sechdrs[info].sh_flags & SHF_ALLOC)) ++ continue; ++ ++ /* If it's called *.init*, and we're not init, we're ++ not interested */ ++ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0) ++ != is_init) ++ continue; ++ ++ syms = (Elf_Sym *) sechdrs[symindex].sh_addr; ++ if (sechdrs[i].sh_type == SHT_REL) { ++ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rel); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rel[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } else { ++ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr; ++ unsigned int size = sechdrs[i].sh_size / sizeof(*rela); ++ ++ for (j = 0; j < size; ++j) { ++ Elf_Sym *sym; ++ ++ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26) ++ continue; ++ ++ sym = syms + ELF_MIPS_R_SYM(rela[j]); ++ if (!is_init && sym->st_shndx != SHN_UNDEF) ++ continue; ++ ++ ret += 4 * sizeof(int); ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++#ifndef MODULE_START ++static void *alloc_phys(unsigned long size) ++{ ++ unsigned order; ++ struct page *page; ++ struct page *p; ++ ++ size = PAGE_ALIGN(size); ++ order = get_order(size); ++ ++ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN | ++ __GFP_THISNODE, order); ++ if (!page) ++ return NULL; ++ ++ split_page(page, order); ++ ++ /* mark all pages except for the last one */ ++ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p) ++ set_bit(PG_owner_priv_1, &p->flags); ++ ++ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p) ++ __free_page(p); ++ ++ return page_address(page); ++} ++#endif ++ ++static void free_phys(void *ptr) ++{ ++ struct page *page; ++ bool free; ++ ++ page = virt_to_page(ptr); ++ do { ++ free = test_and_clear_bit(PG_owner_priv_1, &page->flags); ++ __free_page(page); ++ page++; ++ } while (free); ++} ++ ++ + void *module_alloc(unsigned long size) + { ++#ifdef MODULE_START + return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, + GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, + __builtin_return_address(0)); ++#else ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = alloc_phys(size); ++ ++ /* If we failed to allocate physically contiguous memory, ++ * fall back to regular vmalloc. The module loader code will ++ * create jump tables to handle long jumps */ ++ if (!ptr) ++ return vmalloc(size); ++ ++ return ptr; ++#endif + } ++ ++static inline bool is_phys_addr(void *ptr) ++{ ++#ifdef CONFIG_64BIT ++ return (KSEGX((unsigned long)ptr) == CKSEG0); ++#else ++ return (KSEGX(ptr) == KSEG0); + #endif ++} ++ ++/* Free memory returned from module_alloc */ ++void module_memfree(void *module_region) ++{ ++ if (is_phys_addr(module_region)) ++ free_phys(module_region); ++ else ++ vfree(module_region); ++} ++ ++static void *__module_alloc(int size, bool phys) ++{ ++ void *ptr; ++ ++ if (phys) ++ ptr = kmalloc(size, GFP_KERNEL); ++ else ++ ptr = vmalloc(size); ++ return ptr; ++} ++ ++static void __module_free(void *ptr) ++{ ++ if (is_phys_addr(ptr)) ++ kfree(ptr); ++ else ++ vfree(ptr); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ unsigned int symindex = 0; ++ unsigned int core_size, init_size; ++ int i; ++ ++ mod->arch.phys_plt_offset = 0; ++ mod->arch.virt_plt_offset = 0; ++ mod->arch.phys_plt_tbl = NULL; ++ mod->arch.virt_plt_tbl = NULL; ++ ++ if (IS_ENABLED(CONFIG_64BIT)) ++ return 0; ++ ++ for (i = 1; i < hdr->e_shnum; i++) ++ if (sechdrs[i].sh_type == SHT_SYMTAB) ++ symindex = i; ++ ++ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false); ++ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true); ++ ++ if ((core_size + init_size) == 0) ++ return 0; ++ ++ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1); ++ if (!mod->arch.phys_plt_tbl) ++ return -ENOMEM; ++ ++ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0); ++ if (!mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ return -ENOMEM; ++ } ++ ++ return 0; ++} + + static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v) + { + *location = base + v; + } + ++static Elf_Addr add_plt_entry_to(unsigned *plt_offset, ++ void *start, Elf_Addr v) ++{ ++ unsigned *tramp = start + *plt_offset; ++ *plt_offset += 4 * sizeof(int); ++ ++ /* adjust carry for addiu */ ++ if (v & 0x00008000) ++ v += 0x10000; ++ ++ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */ ++ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */ ++ tramp[2] = 0x03200008; /* jr t9 */ ++ tramp[3] = 0x00000000; /* nop */ ++ ++ return (Elf_Addr) tramp; ++} ++ ++static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v) ++{ ++ if (is_phys_addr(location)) ++ return add_plt_entry_to(&me->arch.phys_plt_offset, ++ me->arch.phys_plt_tbl, v); ++ else ++ return add_plt_entry_to(&me->arch.virt_plt_offset, ++ me->arch.virt_plt_tbl, v); ++ ++} ++ + static int apply_r_mips_26(struct module *me, u32 *location, u32 base, + Elf_Addr v) + { ++ u32 ofs = base & 0x03ffffff; ++ + if (v % 4) { + pr_err("module %s: dangerous R_MIPS_26 relocation\n", + me->name); +@@ -55,13 +293,17 @@ static int apply_r_mips_26(struct module + } + + if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { +- pr_err("module %s: relocation overflow\n", +- me->name); +- return -ENOEXEC; ++ v = add_plt_entry(me, location, v + (ofs << 2)); ++ if (!v) { ++ pr_err("module %s: relocation overflow\n", ++ me->name); ++ return -ENOEXEC; ++ } ++ ofs = 0; + } + + *location = (*location & ~0x03ffffff) | +- ((base + (v >> 2)) & 0x03ffffff); ++ ((ofs + (v >> 2)) & 0x03ffffff); + + return 0; + } +@@ -441,9 +683,36 @@ int module_finalize(const Elf_Ehdr *hdr, + list_add(&me->arch.dbe_list, &dbe_list); + spin_unlock_irq(&dbe_lock); + } ++ ++ /* Get rid of the fixup trampoline if we're running the module ++ * from physically mapped address space */ ++ if (me->arch.phys_plt_offset == 0) { ++ __module_free(me->arch.phys_plt_tbl); ++ me->arch.phys_plt_tbl = NULL; ++ } ++ if (me->arch.virt_plt_offset == 0) { ++ __module_free(me->arch.virt_plt_tbl); ++ me->arch.virt_plt_tbl = NULL; ++ } ++ + return 0; + } + ++void module_arch_freeing_init(struct module *mod) ++{ ++ if (mod->state == MODULE_STATE_LIVE) ++ return; ++ ++ if (mod->arch.phys_plt_tbl) { ++ __module_free(mod->arch.phys_plt_tbl); ++ mod->arch.phys_plt_tbl = NULL; ++ } ++ if (mod->arch.virt_plt_tbl) { ++ __module_free(mod->arch.virt_plt_tbl); ++ mod->arch.virt_plt_tbl = NULL; ++ } ++} ++ + void module_arch_cleanup(struct module *mod) + { + spin_lock_irq(&dbe_lock); diff --git a/target/linux/generic/pending-6.1/307-mips_highmem_offset.patch b/target/linux/generic/pending-6.1/307-mips_highmem_offset.patch new file mode 100644 index 00000000000..0529b0c5c8a --- /dev/null +++ b/target/linux/generic/pending-6.1/307-mips_highmem_offset.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau +Subject: kernel: adjust mips highmem offset to avoid the need for -mlong-calls on systems with >256M RAM + +Signed-off-by: Felix Fietkau +--- + arch/mips/include/asm/mach-generic/spaces.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/include/asm/mach-generic/spaces.h ++++ b/arch/mips/include/asm/mach-generic/spaces.h +@@ -46,7 +46,7 @@ + * Memory above this physical address will be considered highmem. + */ + #ifndef HIGHMEM_START +-#define HIGHMEM_START _AC(0x20000000, UL) ++#define HIGHMEM_START _AC(0x10000000, UL) + #endif + + #endif /* CONFIG_32BIT */ diff --git a/target/linux/generic/pending-6.1/308-mips32r2_tune.patch b/target/linux/generic/pending-6.1/308-mips32r2_tune.patch new file mode 100644 index 00000000000..ef92a5dfb69 --- /dev/null +++ b/target/linux/generic/pending-6.1/308-mips32r2_tune.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2 + +This provides a good tradeoff across at least 24Kc-74Kc, while also +producing smaller code. + +Signed-off-by: Felix Fietkau +--- + arch/mips/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/mips/Makefile ++++ b/arch/mips/Makefile +@@ -175,7 +175,7 @@ cflags-$(CONFIG_CPU_VR41XX) += -march=r4 + cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap + cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap +-cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap ++cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap + cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg + cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg + cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap diff --git a/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch new file mode 100644 index 00000000000..191dc6ac3cd --- /dev/null +++ b/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: fix errors in unresolved weak symbols on arm + +lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f +Signed-off-by: Felix Fietkau +--- + arch/arm/kernel/module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/kernel/module.c ++++ b/arch/arm/kernel/module.c +@@ -105,6 +105,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons + return -ENOEXEC; + } + ++ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) && ++ ELF_ST_BIND(sym->st_info) == STB_WEAK) ++ continue; ++ + loc = dstsec->sh_addr + rel->r_offset; + + switch (ELF32_R_TYPE(rel->r_info)) { diff --git a/target/linux/generic/pending-6.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch b/target/linux/generic/pending-6.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch new file mode 100644 index 00000000000..3f553b28b34 --- /dev/null +++ b/target/linux/generic/pending-6.1/330-MIPS-kexec-Accept-command-line-parameters-from-users.patch @@ -0,0 +1,282 @@ +From: Yousong Zhou +Subject: MIPS: kexec: Accept command line parameters from userspace. + +Signed-off-by: Yousong Zhou +--- + arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++----- + arch/mips/kernel/machine_kexec.h | 20 +++++ + arch/mips/kernel/relocate_kernel.S | 21 +++-- + 3 files changed, 167 insertions(+), 27 deletions(-) + create mode 100644 arch/mips/kernel/machine_kexec.h + +--- a/arch/mips/kernel/machine_kexec.c ++++ b/arch/mips/kernel/machine_kexec.c +@@ -9,14 +9,11 @@ + #include + #include + ++#include + #include + #include +- +-extern const unsigned char relocate_new_kernel[]; +-extern const size_t relocate_new_kernel_size; +- +-extern unsigned long kexec_start_address; +-extern unsigned long kexec_indirection_page; ++#include ++#include "machine_kexec.h" + + static unsigned long reboot_code_buffer; + +@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL + void (*_machine_kexec_shutdown)(void) = NULL; + void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; + ++static void machine_kexec_print_args(void) ++{ ++ unsigned long argc = (int)kexec_args[0]; ++ int i; ++ ++ pr_info("kexec_args[0] (argc): %lu\n", argc); ++ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]); ++ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]); ++ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]); ++ ++ for (i = 0; i < argc; i++) { ++ pr_info("kexec_argv[%d] = %p, %s\n", ++ i, kexec_argv[i], kexec_argv[i]); ++ } ++} ++ ++static void machine_kexec_init_argv(struct kimage *image) ++{ ++ void __user *buf = NULL; ++ size_t bufsz; ++ size_t size; ++ int i; ++ ++ bufsz = 0; ++ for (i = 0; i < image->nr_segments; i++) { ++ struct kexec_segment *seg; ++ ++ seg = &image->segment[i]; ++ if (seg->bufsz < 6) ++ continue; ++ ++ if (strncmp((char *) seg->buf, "kexec ", 6)) ++ continue; ++ ++ buf = seg->buf; ++ bufsz = seg->bufsz; ++ break; ++ } ++ ++ if (!buf) ++ return; ++ ++ size = KEXEC_COMMAND_LINE_SIZE; ++ size = min(size, bufsz); ++ if (size < bufsz) ++ pr_warn("kexec command line truncated to %zd bytes\n", size); ++ ++ /* Copy to kernel space */ ++ if (copy_from_user(kexec_argv_buf, buf, size)) ++ pr_warn("kexec command line copy to kernel space failed\n"); ++ ++ kexec_argv_buf[size - 1] = 0; ++} ++ ++static void machine_kexec_parse_argv(struct kimage *image) ++{ ++ char *reboot_code_buffer; ++ int reloc_delta; ++ char *ptr; ++ int argc; ++ int i; ++ ++ ptr = kexec_argv_buf; ++ argc = 0; ++ ++ /* ++ * convert command line string to array of parameters ++ * (as bootloader does). ++ */ ++ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) { ++ if (*ptr == ' ') { ++ *ptr++ = '\0'; ++ continue; ++ } ++ ++ kexec_argv[argc++] = ptr; ++ ptr = strchr(ptr, ' '); ++ } ++ ++ if (!argc) ++ return; ++ ++ kexec_args[0] = argc; ++ kexec_args[1] = (unsigned long)kexec_argv; ++ kexec_args[2] = 0; ++ kexec_args[3] = 0; ++ ++ reboot_code_buffer = page_address(image->control_code_page); ++ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel; ++ ++ kexec_args[1] += reloc_delta; ++ for (i = 0; i < argc; i++) ++ kexec_argv[i] += reloc_delta; ++} ++ + static void kexec_image_info(const struct kimage *kimage) + { + unsigned long i; +@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim + #endif + + kexec_image_info(kimage); ++ /* ++ * Whenever arguments passed from kexec-tools, Init the arguments as ++ * the original ones to try avoiding booting failure. ++ */ ++ ++ kexec_args[0] = fw_arg0; ++ kexec_args[1] = fw_arg1; ++ kexec_args[2] = fw_arg2; ++ kexec_args[3] = fw_arg3; ++ ++ machine_kexec_init_argv(kimage); ++ machine_kexec_parse_argv(kimage); + + if (_machine_kexec_prepare) + return _machine_kexec_prepare(kimage); +@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r + void kexec_nonboot_cpu_jump(void) + { + local_flush_icache_range((unsigned long)relocated_kexec_smp_wait, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + relocated_kexec_smp_wait(NULL); + } +@@ -199,7 +303,7 @@ void kexec_reboot(void) + * machine_kexec() CPU. + */ + local_flush_icache_range(reboot_code_buffer, +- reboot_code_buffer + relocate_new_kernel_size); ++ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE); + + do_kexec = (void *)reboot_code_buffer; + do_kexec(); +@@ -212,10 +316,12 @@ machine_kexec(struct kimage *image) + unsigned long *ptr; + + reboot_code_buffer = +- (unsigned long)page_address(image->control_code_page); ++ (unsigned long)page_address(image->control_code_page); ++ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer); + + kexec_start_address = + (unsigned long) phys_to_virt(image->start); ++ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address); + + if (image->type == KEXEC_TYPE_DEFAULT) { + kexec_indirection_page = +@@ -223,9 +329,19 @@ machine_kexec(struct kimage *image) + } else { + kexec_indirection_page = (unsigned long)&image->head; + } ++ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page); + +- memcpy((void*)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ pr_info("Where is memcpy: %p\n", memcpy); ++ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n", ++ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end); ++ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE, ++ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer); ++ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel, ++ KEXEC_RELOCATE_NEW_KERNEL_SIZE); ++ ++ pr_info("Before _print_args().\n"); ++ machine_kexec_print_args(); ++ pr_info("Before eval loop.\n"); + + /* + * The generic kexec code builds a page list with physical +@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image) + #ifdef CONFIG_SMP + /* All secondary cpus now may jump to kexec_wait cycle */ + relocated_kexec_smp_wait = reboot_code_buffer + +- (void *)(kexec_smp_wait - relocate_new_kernel); ++ (void *)(kexec_smp_wait - kexec_relocate_new_kernel); + smp_wmb(); + atomic_set(&kexec_ready_to_reboot, 1); + #endif +--- /dev/null ++++ b/arch/mips/kernel/machine_kexec.h +@@ -0,0 +1,20 @@ ++#ifndef _MACHINE_KEXEC_H ++#define _MACHINE_KEXEC_H ++ ++#ifndef __ASSEMBLY__ ++extern const unsigned char kexec_relocate_new_kernel[]; ++extern unsigned long kexec_relocate_new_kernel_end; ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++ ++extern char kexec_argv_buf[]; ++extern char *kexec_argv[]; ++ ++#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel) ++#endif /* !__ASSEMBLY__ */ ++ ++#define KEXEC_COMMAND_LINE_SIZE 256 ++#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16) ++#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long)) ++ ++#endif +--- a/arch/mips/kernel/relocate_kernel.S ++++ b/arch/mips/kernel/relocate_kernel.S +@@ -10,10 +10,11 @@ + #include + #include + #include ++#include "machine_kexec.h" + + #include + +-LEAF(relocate_new_kernel) ++LEAF(kexec_relocate_new_kernel) + PTR_L a0, arg0 + PTR_L a1, arg1 + PTR_L a2, arg2 +@@ -98,7 +99,7 @@ done: + #endif + /* jump to kexec_start_address */ + j s1 +- END(relocate_new_kernel) ++ END(kexec_relocate_new_kernel) + + #ifdef CONFIG_SMP + /* +@@ -177,8 +178,15 @@ EXPORT(kexec_indirection_page) + PTR_WD 0 + .size kexec_indirection_page, PTRSIZE + +-relocate_new_kernel_end: ++kexec_argv_buf: ++ EXPORT(kexec_argv_buf) ++ .skip KEXEC_COMMAND_LINE_SIZE ++ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE ++ ++kexec_argv: ++ EXPORT(kexec_argv) ++ .skip KEXEC_ARGV_SIZE ++ .size kexec_argv, KEXEC_ARGV_SIZE + +-EXPORT(relocate_new_kernel_size) +- PTR_WD relocate_new_kernel_end - relocate_new_kernel +- .size relocate_new_kernel_size, PTRSIZE ++kexec_relocate_new_kernel_end: ++ EXPORT(kexec_relocate_new_kernel_end) diff --git a/target/linux/generic/pending-6.1/332-arc-add-OWRTDTB-section.patch b/target/linux/generic/pending-6.1/332-arc-add-OWRTDTB-section.patch new file mode 100644 index 00000000000..30158cf399b --- /dev/null +++ b/target/linux/generic/pending-6.1/332-arc-add-OWRTDTB-section.patch @@ -0,0 +1,84 @@ +From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001 +From: Evgeniy Didin +Date: Fri, 15 Mar 2019 18:53:38 +0300 +Subject: [PATCH] arc add OWRTDTB section + +This change allows OpenWRT to patch resulting kernel binary with +external .dtb. + +That allows us to re-use exactky the same vmlinux on different boards +given its ARC core configurations match (at least cache line sizes etc). + +""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external +.dtb right after it, keeping the string in place. + +Signed-off-by: Eugeniy Paltsev +Signed-off-by: Alexey Brodkin +Signed-off-by: Evgeniy Didin +--- + arch/arc/kernel/head.S | 10 ++++++++++ + arch/arc/kernel/setup.c | 4 +++- + arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++ + 3 files changed, 26 insertions(+), 1 deletion(-) + +--- a/arch/arc/kernel/head.S ++++ b/arch/arc/kernel/head.S +@@ -88,6 +88,16 @@ + DSP_EARLY_INIT + .endm + ++ ; Here "patch-dtb" will embed external .dtb ++ ; Note "patch-dtb" searches for ASCII "OWRTDTB:" string ++ ; and pastes .dtb right after it, hense the string precedes ++ ; __image_dtb symbol. ++ .section .owrt, "aw",@progbits ++ .ascii "OWRTDTB:" ++ENTRY(__image_dtb) ++ .fill 0x4000 ++END(__image_dtb) ++ + .section .init.text, "ax",@progbits + + ;---------------------------------------------------------------- +--- a/arch/arc/kernel/setup.c ++++ b/arch/arc/kernel/setup.c +@@ -495,6 +495,8 @@ static inline bool uboot_arg_invalid(uns + /* We always pass 0 as magic from U-boot */ + #define UBOOT_MAGIC_VALUE 0 + ++extern struct boot_param_header __image_dtb; ++ + void __init handle_uboot_args(void) + { + bool use_embedded_dtb = true; +@@ -533,7 +535,7 @@ void __init handle_uboot_args(void) + ignore_uboot_args: + + if (use_embedded_dtb) { +- machine_desc = setup_machine_fdt(__dtb_start); ++ machine_desc = setup_machine_fdt(&__image_dtb); + if (!machine_desc) + panic("Embedded DT invalid\n"); + } +--- a/arch/arc/kernel/vmlinux.lds.S ++++ b/arch/arc/kernel/vmlinux.lds.S +@@ -27,6 +27,19 @@ SECTIONS + + . = CONFIG_LINUX_LINK_BASE; + ++ /* ++ * In OpenWRT we want to patch built binary embedding .dtb of choice. ++ * This is implemented with "patch-dtb" utility which searches for ++ * "OWRTDTB:" string in first 16k of image and if it is found ++ * copies .dtb right after mentioned string. ++ * ++ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it. ++ */ ++ .owrt : { ++ *(.owrt) ++ . = ALIGN(PAGE_SIZE); ++ } ++ + _int_vec_base_lds = .; + .vector : { + *(.vector) diff --git a/target/linux/generic/pending-6.1/333-arc-enable-unaligned-access-in-kernel-mode.patch b/target/linux/generic/pending-6.1/333-arc-enable-unaligned-access-in-kernel-mode.patch new file mode 100644 index 00000000000..1848a84cc49 --- /dev/null +++ b/target/linux/generic/pending-6.1/333-arc-enable-unaligned-access-in-kernel-mode.patch @@ -0,0 +1,24 @@ +From: Alexey Brodkin +Subject: arc: enable unaligned access in kernel mode + +This enables misaligned access handling even in kernel mode. +Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses +here and there and to cope with that without fixing stuff in the drivers +we're just gracefully handling it on ARC. + +Signed-off-by: Alexey Brodkin +--- + arch/arc/kernel/unaligned.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arc/kernel/unaligned.c ++++ b/arch/arc/kernel/unaligned.c +@@ -202,7 +202,7 @@ int misaligned_fixup(unsigned long addre + char buf[TASK_COMM_LEN]; + + /* handle user mode only and only if enabled by sysadmin */ +- if (!user_mode(regs) || !unaligned_enabled) ++ if (!unaligned_enabled) + return 1; + + if (no_unaligned_warning) { diff --git a/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch b/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch new file mode 100644 index 00000000000..082b122cb4d --- /dev/null +++ b/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch @@ -0,0 +1,25 @@ +From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Fri, 24 May 2019 17:56:19 +0200 +Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx + +Enable kernel XZ compression option on PPC_85xx. Tested with +simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor). + +Suggested-by: Christian Lamparter +Signed-off-by: Pawel Dembicki +--- + arch/powerpc/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/powerpc/Kconfig ++++ b/arch/powerpc/Kconfig +@@ -221,7 +221,7 @@ config PPC + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE + select HAVE_KERNEL_LZO if DEFAULT_UIMAGE +- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x ++ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx + select HAVE_KPROBES + select HAVE_KPROBES_ON_FTRACE + select HAVE_KRETPROBES diff --git a/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch b/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch new file mode 100644 index 00000000000..9fad4f62c61 --- /dev/null +++ b/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch @@ -0,0 +1,113 @@ +From patchwork Thu Mar 16 19:28:33 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13178238 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 5EF2AC6FD19 + for ; Thu, 16 Mar 2023 19:28:43 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S230076AbjCPT2l (ORCPT ); + Thu, 16 Mar 2023 15:28:41 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56412 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S230039AbjCPT2k (ORCPT + ); Thu, 16 Mar 2023 15:28:40 -0400 +Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com + [IPv6:2a00:1450:4864:20::42f]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7259B7D9F; + Thu, 16 Mar 2023 12:28:38 -0700 (PDT) +Received: by mail-wr1-x42f.google.com with SMTP id y14so2539231wrq.4; + Thu, 16 Mar 2023 12:28:38 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1678994917; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=j8afldfRZftLeVmekmQfoh01jVdumsVP7nkKoPaU3Q0=; + b=FzMRr5ekh/fDiJqTlezNj6nLjzvn5z92FtYeB8MquVSMB8PuvarccnyqAzsXiccf+v + uwRFIomnTWNLGVjzc1xrB2hGiCKD3jBo5n1u8p/yEV6rpolbxVjfM7eTHXyAHXGXz7ZJ + TPeVbWfAlxiSD6+BPtXr/efehcdI64fIoL6G/U1WHNMo01Tzr/Obf3y5tug17N0fGcXg + CH6E5a2HguZUtwrm26LcK9IOV/7xEx5eIE1cOvTLMxPbGWaZwEjjP16HylJr06xRLhaf + RpiYBT3mXwwuOx0jLOhqavY/2kZ9GVbZRWMMwZrZv9xNO13SBwc1VUVgD4k3FntnSk7Z + AaOQ== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1678994917; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=j8afldfRZftLeVmekmQfoh01jVdumsVP7nkKoPaU3Q0=; + b=OaA5DMgqalrfqO5iOtmmxFPsH90MkN7l4EJpyVnzuiO1Wd6rSCpqPOR7xpxZno8OPP + tdfm4vzn9Ie4AUDbFKDTUlPG+tgkmIruo3K9C0VnY9DD2PRZMEYBbWaJKU1otqKt0NKu + IAAHNvxvQvCESKzbXFLYwWbRKFScOSMGmGBTDfgThz51A18Ff1hJy/BmnuZk7M2TLgHO + wQpy9t7oeB/Hkxl41y46emLc/nESsvwvAG/fx/zPzCe9UiaQLrdZq+BKeOwSBedktzK5 + U/ZTfgzU2UGSI67aGRqqGnI0uXq+MAJMK18qzM0VByxj6W+AXJ6BJr5P0quljeQ8upSg + bEUg== +X-Gm-Message-State: AO0yUKWnqTlccBDnqwCSRdqOBGc2FyfiLy1Tg7EjPENlISpzXuDYwW/R + lJSI06rrfq+Vel/SigfpGJI= +X-Google-Smtp-Source: + AK7set/jYfYl9ttVzIXJO+ZQVfa6cE/yOsP8fx4teiTmGNNWyVlIJRzMAlF3IUGqRAXAmY3hAabIuQ== +X-Received: by 2002:a5d:40ce:0:b0:2cd:ceab:df1a with SMTP id + b14-20020a5d40ce000000b002cdceabdf1amr381006wrq.32.1678994916642; + Thu, 16 Mar 2023 12:28:36 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + l10-20020a5d4bca000000b002cfea3c49d5sm180041wrt.52.2023.03.16.12.28.35 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Thu, 16 Mar 2023 12:28:35 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: f.fainelli@gmail.com, jonas.gorski@gmail.com, + bcm-kernel-feedback-list@broadcom.com, tglx@linutronix.de, + maz@kernel.org, linux-mips@vger.kernel.org, + linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v2] irqchip/bcm-6345-l1: request memory region +Date: Thu, 16 Mar 2023 20:28:33 +0100 +Message-Id: <20230316192833.1603149-1-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230316180701.783785-1-noltari@gmail.com> +References: <20230316180701.783785-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: linux-mips@vger.kernel.org + +Request memory region in order to display it in /proc/iomem. +Also stop printing the MMIO address since it just displays (ptrval). + +Signed-off-by: Álvaro Fernández Rojas +Acked-by: Florian Fainelli +--- + v2: request memory region and stop displaying MMIO address. + + drivers/irqchip/irq-bcm6345-l1.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/irqchip/irq-bcm6345-l1.c ++++ b/drivers/irqchip/irq-bcm6345-l1.c +@@ -261,6 +261,9 @@ static int __init bcm6345_l1_init_one(st + if (!cpu->map_base) + return -ENOMEM; + ++ if (!request_mem_region(res.start, sz, res.name)) ++ pr_err("failed to request intc memory"); ++ + for (i = 0; i < n_words; i++) { + cpu->enable_cache[i] = 0; + __raw_writel(0, cpu->map_base + reg_enable(intc, i)); +@@ -339,8 +342,7 @@ static int __init bcm6345_l1_of_init(str + for_each_cpu(idx, &intc->cpumask) { + struct bcm6345_l1_cpu *cpu = intc->cpus[idx]; + +- pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx, +- cpu->map_base, cpu->parent_irq); ++ pr_info(" CPU%u (irq = %d)\n", idx, cpu->parent_irq); + } + + return 0; diff --git a/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch new file mode 100644 index 00000000000..46ef15d127d --- /dev/null +++ b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch @@ -0,0 +1,328 @@ +From 39717277d5c87bdb183cf2f258957b44ba99b4df Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 11:47:35 +0200 +Subject: [PATCH] mtd: mtdsplit support + +--- + drivers/mtd/Kconfig | 19 ++++ + drivers/mtd/Makefile | 2 + + drivers/mtd/mtdpart.c | 169 ++++++++++++++++++++++++++++----- + include/linux/mtd/mtd.h | 25 +++++ + include/linux/mtd/partitions.h | 7 ++ + 5 files changed, 197 insertions(+), 25 deletions(-) + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -12,6 +12,25 @@ menuconfig MTD + + if MTD + ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default y ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default y ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ ++source "drivers/mtd/mtdsplit/Kconfig" ++ ++endmenu ++ + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc + + obj-y += parsers/ + ++obj-$(CONFIG_MTD_SPLIT) += mtdsplit/ ++ + # 'Users' - code which presents functionality to userspace. + obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o + obj-$(CONFIG_MTD_BLOCK) += mtdblock.o +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -15,11 +15,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + #include "mtdcore.h" ++#include "mtdsplit/mtdsplit.h" + + /* + * MTD methods which simply translate the effective address and pass through +@@ -236,6 +238,147 @@ static int mtd_add_partition_attrs(struc + return ret; + } + ++static DEFINE_SPINLOCK(part_parser_lock); ++static LIST_HEAD(part_parsers); ++ ++static struct mtd_part_parser *mtd_part_parser_get(const char *name) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ list_for_each_entry(p, &part_parsers, list) ++ if (!strcmp(p->name, name) && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ ++static inline void mtd_part_parser_put(const struct mtd_part_parser *p) ++{ ++ module_put(p->owner); ++} ++ ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ mtd_part_parser_put(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++ ++static int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ mtd_part_parser_put(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++ ++static int ++run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += child->part.offset; ++ ++ mtd_add_partition(child->parent, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_info *part) ++{ ++ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (of_find_property(mtd_get_of_node(part), "linux,rootfs", NULL) || ++ !strcmp(part->name, "rootfs")) { ++ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ ++ rootfs_found = 1; ++ } ++ ++ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) && ++ !strcmp(part->name, SPLIT_FIRMWARE_NAME) && ++ !of_find_property(mtd_get_of_node(part), "compatible", NULL)) ++ split_firmware(master, part); ++} ++ + int mtd_add_partition(struct mtd_info *parent, const char *name, + long long offset, long long length) + { +@@ -274,6 +417,7 @@ int mtd_add_partition(struct mtd_info *p + if (ret) + goto err_remove_part; + ++ mtd_partition_split(parent, child); + mtd_add_partition_attrs(child); + + return 0; +@@ -422,6 +566,7 @@ int add_mtd_partitions(struct mtd_info * + goto err_del_partitions; + } + ++ mtd_partition_split(master, child); + mtd_add_partition_attrs(child); + + /* Look for subpartitions */ +@@ -438,31 +583,6 @@ err_del_partitions: + return ret; + } + +-static DEFINE_SPINLOCK(part_parser_lock); +-static LIST_HEAD(part_parsers); +- +-static struct mtd_part_parser *mtd_part_parser_get(const char *name) +-{ +- struct mtd_part_parser *p, *ret = NULL; +- +- spin_lock(&part_parser_lock); +- +- list_for_each_entry(p, &part_parsers, list) +- if (!strcmp(p->name, name) && try_module_get(p->owner)) { +- ret = p; +- break; +- } +- +- spin_unlock(&part_parser_lock); +- +- return ret; +-} +- +-static inline void mtd_part_parser_put(const struct mtd_part_parser *p) +-{ +- module_put(p->owner); +-} +- + /* + * Many partition parsers just expected the core to kfree() all their data in + * one chunk. Do that by default. +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -620,6 +620,24 @@ static inline void mtd_align_erase_req(s + req->len += mtd->erasesize - mod; + } + ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) +@@ -693,6 +711,13 @@ extern struct mtd_info *of_get_mtd_devic + extern struct mtd_info *get_mtd_device_nm(const char *name); + extern void put_mtd_device(struct mtd_info *mtd); + ++static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return mtd->part.offset; ++} + + struct mtd_notifier { + void (*add)(struct mtd_info *mtd); +--- a/include/linux/mtd/partitions.h ++++ b/include/linux/mtd/partitions.h +@@ -75,6 +75,12 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, ++}; ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; +@@ -83,6 +89,7 @@ struct mtd_part_parser { + int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, + struct mtd_part_parser_data *); + void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); ++ enum mtd_parser_type type; + }; + + /* Container for passing around a set of parsed partitions */ diff --git a/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch b/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch new file mode 100644 index 00000000000..d12bc9c3d59 --- /dev/null +++ b/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch @@ -0,0 +1,245 @@ +From acacdac272927ae1d96e0bca51eb82899671eaea Mon Sep 17 00:00:00 2001 +From: John Thomson +Date: Fri, 25 Dec 2020 18:50:08 +1000 +Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Do not prevent writing to mtd partitions where a partition boundary sits +on a minor erasesize boundary. +This addresses a FIXME that has been present since the start of the +linux git history: +/* Doesn't start on a boundary of major erase size */ +/* FIXME: Let it be writable if it is on a boundary of + * _minor_ erase size though */ + +Allow a uniform erase region spi-nor device to be configured +to use the non-uniform erase regions code path for an erase with: +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y + +On supporting hardware (SECT_4K: majority of current SPI-NOR device) +provide the facility for an erase to use the least number +of SPI-NOR operations, as well as access to 4K erase without +requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + +Introduce erasesize_minor to the mtd struct, +the smallest erasesize supported by the device + +On existing devices, this is useful where write support is wanted +for data on a 4K partition, such as some u-boot-env partitions, +or RouterBoot soft_config, while still netting the performance +benefits of using 64K sectors + +Performance: +time mtd erase firmware +OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length + +Without this patch +MTD_SPI_NOR_USE_4K_SECTORS=y |n +real 2m 11.66s |0m 50.86s +user 0m 0.00s |0m 0.00s +sys 1m 56.20s |0m 50.80s + +With this patch +MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y +real 0m 51.68s |0m 50.85s |2m 12.89s +user 0m 0.00s |0m 0.00s |0m 0.01s +sys 0m 46.94s |0m 50.38s |2m 12.46s + +Signed-off-by: John Thomson +Signed-off-by: Thibaut VARÈNE + +--- + +checkpatch does not like the printk(KERN_WARNING +these should be changed separately beforehand? + +Changes v1 -> v2: +Added mtdcore sysfs for erasesize_minor +Removed finding minor erasesize for variable erase regions device, +as untested and no responses regarding it. +Moved IF_ENABLED for SPINOR variable erase to guard setting +erasesize_minor in spi-nor/core.c +Removed setting erasesize to minor where partition boundaries require +minor erase to be writable +Simplified minor boundary check by relying on minor being a factor of +major + +Changes RFC -> v1: +Fix uninitialized variable smatch warning +Reported-by: kernel test robot +Reported-by: Dan Carpenter +--- + drivers/mtd/mtdcore.c | 10 ++++++++++ + drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++---------- + drivers/mtd/spi-nor/Kconfig | 10 ++++++++++ + drivers/mtd/spi-nor/core.c | 11 +++++++++-- + include/linux/mtd/mtd.h | 2 ++ + 5 files changed, 56 insertions(+), 12 deletions(-) + +--- a/drivers/mtd/mtdcore.c ++++ b/drivers/mtd/mtdcore.c +@@ -169,6 +169,15 @@ static ssize_t mtd_erasesize_show(struct + } + MTD_DEVICE_ATTR_RO(erasesize); + ++static ssize_t mtd_erasesize_minor_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct mtd_info *mtd = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor); ++} ++MTD_DEVICE_ATTR_RO(erasesize_minor); ++ + static ssize_t mtd_writesize_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -314,6 +323,7 @@ static struct attribute *mtd_attrs[] = { + &dev_attr_flags.attr, + &dev_attr_size.attr, + &dev_attr_erasesize.attr, ++ &dev_attr_erasesize_minor.attr, + &dev_attr_writesize.attr, + &dev_attr_subpagesize.attr, + &dev_attr_oobsize.attr, +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -41,6 +41,7 @@ static struct mtd_info *allocate_partiti + struct mtd_info *master = mtd_get_master(parent); + int wr_alignment = (parent->flags & MTD_NO_ERASE) ? + master->writesize : master->erasesize; ++ int wr_alignment_minor = 0; + u64 parent_size = mtd_is_partition(parent) ? + parent->part.size : parent->size; + struct mtd_info *child; +@@ -165,6 +166,7 @@ static struct mtd_info *allocate_partiti + } else { + /* Single erase size */ + child->erasesize = master->erasesize; ++ child->erasesize_minor = master->erasesize_minor; + } + + /* +@@ -172,26 +174,39 @@ static struct mtd_info *allocate_partiti + * exposes several regions with different erasesize. Adjust + * wr_alignment accordingly. + */ +- if (!(child->flags & MTD_NO_ERASE)) ++ if (!(child->flags & MTD_NO_ERASE)) { + wr_alignment = child->erasesize; ++ wr_alignment_minor = child->erasesize_minor; ++ } + + tmp = mtd_get_master_ofs(child, 0); + remainder = do_div(tmp, wr_alignment); + if ((child->flags & MTD_WRITEABLE) && remainder) { +- /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- child->flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", +- part->name); ++ if (wr_alignment_minor) { ++ /* rely on minor being a factor of major erasesize */ ++ tmp = remainder; ++ remainder = do_div(tmp, wr_alignment_minor); ++ } ++ if (remainder) { ++ child->flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", ++ part->name); ++ } + } + + tmp = mtd_get_master_ofs(child, 0) + child->part.size; + remainder = do_div(tmp, wr_alignment); + if ((child->flags & MTD_WRITEABLE) && remainder) { +- child->flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", +- part->name); ++ if (wr_alignment_minor) { ++ tmp = remainder; ++ remainder = do_div(tmp, wr_alignment_minor); ++ } ++ ++ if (remainder) { ++ child->flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", ++ part->name); ++ } + } + + child->size = child->part.size; +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR + + if MTD_SPI_NOR + ++config MTD_SPI_NOR_USE_VARIABLE_ERASE ++ bool "Disable uniform_erase to allow use of all hardware supported erasesizes" ++ depends on !MTD_SPI_NOR_USE_4K_SECTORS ++ default n ++ help ++ Allow mixed use of all hardware supported erasesizes, ++ by forcing spi_nor to use the multiple eraseregions code path. ++ For example: A 68K erase will use one 64K erase, and one 4K erase ++ on supporting hardware. ++ + config MTD_SPI_NOR_USE_4K_SECTORS + bool "Use small 4096 B erase sectors" + default y +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -1271,6 +1271,8 @@ static u8 spi_nor_convert_3to4_erase(u8 + + static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) + { ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE)) ++ return false; + return !!nor->params->erase_map.uniform_erase_type; + } + +@@ -2400,6 +2402,7 @@ static int spi_nor_select_erase(struct s + { + struct spi_nor_erase_map *map = &nor->params->erase_map; + const struct spi_nor_erase_type *erase = NULL; ++ const struct spi_nor_erase_type *erase_minor = NULL; + struct mtd_info *mtd = &nor->mtd; + u32 wanted_size = nor->info->sector_size; + int i; +@@ -2432,8 +2435,9 @@ static int spi_nor_select_erase(struct s + */ + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (map->erase_type[i].size) { +- erase = &map->erase_type[i]; +- break; ++ if (!erase) ++ erase = &map->erase_type[i]; ++ erase_minor = &map->erase_type[i]; + } + } + +@@ -2441,6 +2445,9 @@ static int spi_nor_select_erase(struct s + return -EINVAL; + + mtd->erasesize = erase->size; ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) && ++ erase_minor && erase_minor->size < erase->size) ++ mtd->erasesize_minor = erase_minor->size; + return 0; + } + +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -250,6 +250,8 @@ struct mtd_info { + * information below if they desire + */ + uint32_t erasesize; ++ /* "Minor" (smallest) erase size supported by the whole device */ ++ uint32_t erasesize_minor; + /* Minimal writable flash unit size. In case of NOR flash it is 1 (even + * though individual bits can be cleared), in case of NAND flash it is + * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR diff --git a/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch new file mode 100644 index 00000000000..5518ea71dd5 --- /dev/null +++ b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable) + +[john@phrozen.org: used by ixp and others] + +lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00 +Signed-off-by: Felix Fietkau +--- + drivers/mtd/redboot.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/mtd/parsers/redboot.c ++++ b/drivers/mtd/parsers/redboot.c +@@ -278,14 +278,21 @@ nogood: + #endif + names += strlen(names) + 1; + +-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED + if (fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { +- i++; +- parts[i].offset = parts[i - 1].size + parts[i - 1].offset; +- parts[i].size = fl->next->img->flash_base - parts[i].offset; +- parts[i].name = nullname; +- } ++ if (!strcmp(parts[i].name, "rootfs")) { ++ parts[i].size = fl->next->img->flash_base; ++ parts[i].size &= ~(master->erasesize - 1); ++ parts[i].size -= parts[i].offset; ++#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED ++ nrparts--; ++ } else { ++ i++; ++ parts[i].offset = parts[i-1].size + parts[i-1].offset; ++ parts[i].size = fl->next->img->flash_base - parts[i].offset; ++ parts[i].name = nullname; + #endif ++ } ++ } + tmp_fl = fl; + fl = fl->next; + kfree(tmp_fl); diff --git a/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch new file mode 100644 index 00000000000..8a6e6305301 --- /dev/null +++ b/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch @@ -0,0 +1,229 @@ +From: Florian Fainelli +Subject: Add myloader partition table parser + +[john@phozen.org: shoud be upstreamable] + +lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8 +Signed-off-by: Florian Fainelli +[adjust for kernel 5.4, add myloader.c to patch] +Signed-off-by: Adrian Schmutzler + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -57,6 +57,22 @@ config MTD_CMDLINE_PARTS + + If unsure, say 'N'. + ++config MTD_MYLOADER_PARTS ++ tristate "MyLoader partition parsing" ++ depends on ADM5120 || ATH25 || ATH79 ++ help ++ MyLoader is a bootloader which allows the user to define partitions ++ in flash devices, by putting a table in the second erase block ++ on the device, similar to a partition table. This table gives the ++ offsets and lengths of the user defined partitions. ++ ++ If you need code which can detect and parse these tables, and ++ register MTD 'partitions' corresponding to each image detected, ++ enable this option. ++ ++ You will still need the parsing functions to be called by the driver ++ for your particular device. It won't happen automatically. ++ + config MTD_OF_PARTS + tristate "OpenFirmware (device tree) partitioning parser" + default y +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part. + obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o + obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o ++obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + ofpart-y += ofpart_core.o + ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o +--- /dev/null ++++ b/drivers/mtd/parsers/myloader.c +@@ -0,0 +1,181 @@ ++/* ++ * Parse MyLoader-style flash partition tables and produce a Linux partition ++ * array to match. ++ * ++ * Copyright (C) 2007-2009 Gabor Juhos ++ * ++ * This file was based on drivers/mtd/redboot.c ++ * Author: Red Hat, Inc. - David Woodhouse ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 as published ++ * by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define BLOCK_LEN_MIN 0x10000 ++#define PART_NAME_LEN 32 ++ ++struct part_data { ++ struct mylo_partition_table tab; ++ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN]; ++}; ++ ++static int myloader_parse_partitions(struct mtd_info *master, ++ const struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct part_data *buf; ++ struct mylo_partition_table *tab; ++ struct mylo_partition *part; ++ struct mtd_partition *mtd_parts; ++ struct mtd_partition *mtd_part; ++ int num_parts; ++ int ret, i; ++ size_t retlen; ++ char *names; ++ unsigned long offset; ++ unsigned long blocklen; ++ ++ buf = vmalloc(sizeof(*buf)); ++ if (!buf) { ++ return -ENOMEM; ++ goto out; ++ } ++ tab = &buf->tab; ++ ++ blocklen = master->erasesize; ++ if (blocklen < BLOCK_LEN_MIN) ++ blocklen = BLOCK_LEN_MIN; ++ ++ offset = blocklen; ++ ++ /* Find the partition table */ ++ for (i = 0; i < 4; i++, offset += blocklen) { ++ printk(KERN_DEBUG "%s: searching for MyLoader partition table" ++ " at offset 0x%lx\n", master->name, offset); ++ ++ ret = mtd_read(master, offset, sizeof(*buf), &retlen, ++ (void *)buf); ++ if (ret) ++ goto out_free_buf; ++ ++ if (retlen != sizeof(*buf)) { ++ ret = -EIO; ++ goto out_free_buf; ++ } ++ ++ /* Check for Partition Table magic number */ ++ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS)) ++ break; ++ ++ } ++ ++ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) { ++ printk(KERN_DEBUG "%s: no MyLoader partition table found\n", ++ master->name); ++ ret = 0; ++ goto out_free_buf; ++ } ++ ++ /* The MyLoader and the Partition Table is always present */ ++ num_parts = 2; ++ ++ /* Detect number of used partitions */ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ num_parts++; ++ } ++ ++ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) + ++ num_parts * PART_NAME_LEN), GFP_KERNEL); ++ ++ if (!mtd_parts) { ++ ret = -ENOMEM; ++ goto out_free_buf; ++ } ++ ++ mtd_part = mtd_parts; ++ names = (char *)&mtd_parts[num_parts]; ++ ++ strncpy(names, "myloader", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = 0; ++ mtd_part->size = offset; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ strncpy(names, "partition_table", PART_NAME_LEN); ++ mtd_part->name = names; ++ mtd_part->offset = offset; ++ mtd_part->size = blocklen; ++ mtd_part->mask_flags = MTD_WRITEABLE; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ ++ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) { ++ part = &tab->partitions[i]; ++ ++ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE) ++ continue; ++ ++ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff')) ++ strncpy(names, buf->names[i], PART_NAME_LEN); ++ else ++ snprintf(names, PART_NAME_LEN, "partition%d", i); ++ ++ mtd_part->offset = le32_to_cpu(part->addr); ++ mtd_part->size = le32_to_cpu(part->size); ++ mtd_part->name = names; ++ mtd_part++; ++ names += PART_NAME_LEN; ++ } ++ ++ *pparts = mtd_parts; ++ ret = num_parts; ++ ++ out_free_buf: ++ vfree(buf); ++ out: ++ return ret; ++} ++ ++static struct mtd_part_parser myloader_mtd_parser = { ++ .owner = THIS_MODULE, ++ .parse_fn = myloader_parse_partitions, ++ .name = "MyLoader", ++}; ++ ++static int __init myloader_mtd_parser_init(void) ++{ ++ register_mtd_parser(&myloader_mtd_parser); ++ ++ return 0; ++} ++ ++static void __exit myloader_mtd_parser_exit(void) ++{ ++ deregister_mtd_parser(&myloader_mtd_parser); ++} ++ ++module_init(myloader_mtd_parser_init); ++module_exit(myloader_mtd_parser_exit); ++ ++MODULE_AUTHOR("Gabor Juhos "); ++MODULE_DESCRIPTION("Parsing code for MyLoader partition tables"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/pending-6.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch b/target/linux/generic/pending-6.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch new file mode 100644 index 00000000000..bcea45d009b --- /dev/null +++ b/target/linux/generic/pending-6.1/431-mtd-bcm47xxpart-check-for-bad-blocks-when-calculatin.patch @@ -0,0 +1,68 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets + +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/mtd/parsers/parser_trx.c ++++ b/drivers/mtd/parsers/parser_trx.c +@@ -25,6 +25,33 @@ struct trx_header { + uint32_t offset[3]; + } __packed; + ++/* ++ * Calculate real end offset (address) for a given amount of data. It checks ++ * all blocks skipping bad ones. ++ */ ++static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes) ++{ ++ size_t real_offset = 0; ++ ++ if (mtd_block_isbad(mtd, real_offset)) ++ pr_warn("Base offset shouldn't be at bad block"); ++ ++ while (bytes >= mtd->erasesize) { ++ bytes -= mtd->erasesize; ++ real_offset += mtd->erasesize; ++ while (mtd_block_isbad(mtd, real_offset)) { ++ real_offset += mtd->erasesize; ++ ++ if (real_offset >= mtd->size) ++ return real_offset - mtd->erasesize; ++ } ++ } ++ ++ real_offset += bytes; ++ ++ return real_offset; ++} ++ + static const char *parser_trx_data_part_name(struct mtd_info *master, + size_t offset) + { +@@ -86,21 +113,21 @@ static int parser_trx_parse(struct mtd_i + if (trx.offset[2]) { + part = &parts[curr_part++]; + part->name = "loader"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; + part->name = "linux"; +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); + i++; + } + + if (trx.offset[i]) { + part = &parts[curr_part++]; +- part->name = parser_trx_data_part_name(mtd, trx.offset[i]); +- part->offset = trx.offset[i]; ++ part->offset = parser_trx_real_offset(mtd, trx.offset[i]); ++ part->name = parser_trx_data_part_name(mtd, part->offset); + i++; + } + diff --git a/target/linux/generic/pending-6.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch b/target/linux/generic/pending-6.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch new file mode 100644 index 00000000000..852654d924a --- /dev/null +++ b/target/linux/generic/pending-6.1/432-mtd-bcm47xxpart-detect-T_Meter-partition.patch @@ -0,0 +1,37 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: mtd: bcm47xxpart: detect T_Meter partition + +It can be found on many Netgear devices. It consists of many 0x30 blocks +starting with 4D 54. + +Signed-off-by: Rafał Miłecki +--- + drivers/mtd/bcm47xxpart.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/parsers/bcm47xxpart.c ++++ b/drivers/mtd/parsers/bcm47xxpart.c +@@ -35,6 +35,7 @@ + #define NVRAM_HEADER 0x48534C46 /* FLSH */ + #define POT_MAGIC1 0x54544f50 /* POTT */ + #define POT_MAGIC2 0x504f /* OP */ ++#define T_METER_MAGIC 0x4D540000 /* MT */ + #define ML_MAGIC1 0x39685a42 + #define ML_MAGIC2 0x26594131 + #define TRX_MAGIC 0x30524448 +@@ -178,6 +179,15 @@ static int bcm47xxpart_parse(struct mtd_ + MTD_WRITEABLE); + continue; + } ++ ++ /* T_Meter */ ++ if ((le32_to_cpu(buf[0x000 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x030 / 4]) & 0xFFFF0000) == T_METER_MAGIC && ++ (le32_to_cpu(buf[0x060 / 4]) & 0xFFFF0000) == T_METER_MAGIC) { ++ bcm47xxpart_add_part(&parts[curr_part++], "T_Meter", offset, ++ MTD_WRITEABLE); ++ continue; ++ } + + /* TRX */ + if (buf[0x000 / 4] == TRX_MAGIC) { diff --git a/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch b/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch new file mode 100644 index 00000000000..ee949f73c09 --- /dev/null +++ b/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch @@ -0,0 +1,38 @@ +From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= +Date: Tue, 24 Mar 2020 11:45:07 +0100 +Subject: [PATCH] generic: routerboot partition build bits (5.4) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch adds routerbootpart kernel build bits + +Signed-off-by: Thibaut VARÈNE +--- + drivers/mtd/parsers/Kconfig | 9 +++++++++ + drivers/mtd/parsers/Makefile | 1 + + 2 files changed, 10 insertions(+) + +--- a/drivers/mtd/parsers/Kconfig ++++ b/drivers/mtd/parsers/Kconfig +@@ -226,3 +226,12 @@ config MTD_SERCOMM_PARTS + partition map. This partition table contains real partition + offsets, which may differ from device to device depending on the + number and location of bad blocks on NAND. ++ ++config MTD_ROUTERBOOT_PARTS ++ tristate "RouterBoot flash partition parser" ++ depends on MTD && OF ++ help ++ MikroTik RouterBoot is implemented as a multi segment system on the ++ flash, some of which are fixed and some of which are located at ++ variable offsets. This parser handles both cases via properly ++ formatted DTS. +--- a/drivers/mtd/parsers/Makefile ++++ b/drivers/mtd/parsers/Makefile +@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa + obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o + obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o ++obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o diff --git a/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch new file mode 100644 index 00000000000..0be74a59777 --- /dev/null +++ b/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Subject: kernel: disable cfi cmdset 0002 erase suspend + +on some platforms, erase suspend leads to data corruption and lockups when write +ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh. +rather than play whack-a-mole with a hard to reproduce issue on a variety of devices, +simply disable erase suspend, as it will usually not produce any useful gain on +the small filesystems used on embedded hardware. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -907,7 +907,7 @@ static int get_chip(struct map_info *map + return 0; + + case FL_ERASING: +- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) || ++ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)))) + goto sleep; diff --git a/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch new file mode 100644 index 00000000000..ca56de82711 --- /dev/null +++ b/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -0,0 +1,17 @@ +From: George Kashperko +Subject: Issue map read after Write Buffer Load command to ensure chip is ready to receive data. + +Signed-off-by: George Kashperko +--- + drivers/mtd/chips/cfi_cmdset_0002.c | 1 + + 1 file changed, 1 insertion(+) +--- a/drivers/mtd/chips/cfi_cmdset_0002.c ++++ b/drivers/mtd/chips/cfi_cmdset_0002.c +@@ -2051,6 +2051,7 @@ static int __xipram do_write_buffer(stru + + /* Write Buffer Load */ + map_write(map, CMD(0x25), cmd_adr); ++ (void) map_read(map, cmd_adr); + + chip->state = FL_WRITING_TO_BUFFER; + diff --git a/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch b/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch new file mode 100644 index 00000000000..f58d5452abe --- /dev/null +++ b/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch @@ -0,0 +1,18 @@ +From: Felix Fietkau +Subject: Disable software protection bits for Macronix flashes. + +Signed-off-by: Felix Fietkau +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -93,6 +93,7 @@ static void macronix_default_init(struct + { + nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; ++ nor->flags |= SNOR_F_HAS_LOCK; + } + + static const struct spi_nor_fixups macronix_fixups = { diff --git a/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch new file mode 100644 index 00000000000..9383e48856d --- /dev/null +++ b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch @@ -0,0 +1,18 @@ +From: Piotr Dymacz +Subject: kernel/mtd: add support for EON EN25Q128 + +Signed-off-by: Piotr Dymacz +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/eon.c ++++ b/drivers/mtd/spi-nor/eon.c +@@ -25,6 +25,7 @@ static const struct flash_info eon_parts + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) }, + { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, diff --git a/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch new file mode 100644 index 00000000000..3c579e55e34 --- /dev/null +++ b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch @@ -0,0 +1,21 @@ +From: Christian Marangi +Subject: kernel/mtd: add support for EON EN25QX128A + +Add support for EON EN25QX128A with no flags as it does +support SFDP parsing. + +Signed-off-by: Christian Marangi +--- + drivers/mtd/spi-nor/spi-nor.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/eon.c ++++ b/drivers/mtd/spi-nor/eon.c +@@ -26,6 +26,7 @@ static const struct flash_info eon_parts + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, + { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) }, ++ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256, 0) }, + { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, + SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, diff --git a/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch new file mode 100644 index 00000000000..5a064b714bf --- /dev/null +++ b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch @@ -0,0 +1,79 @@ +From patchwork Thu Feb 6 17:19:41 2020 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 1234465 +Date: Thu, 6 Feb 2020 19:19:41 +0200 +From: Daniel Golle +To: linux-mtd@lists.infradead.org +Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip +Message-ID: <20200206171941.GA2398@makrotopia.org> +MIME-Version: 1.0 +Content-Disposition: inline +List-Subscribe: , + +Cc: Eitan Cohen , Piotr Dymacz , + Tudor Ambarus +Sender: "linux-mtd" +Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org + +Add XT25F128B made by XTX Technology (Shenzhen) Limited. +This chip supports dual and quad read and uniform 4K-byte erase. +Verified on Teltonika RUT955 which comes with XT25F128B in recent +versions of the device. + +Signed-off-by: Daniel Golle +Signed-off-by: Felix Fietkau +--- + drivers/mtd/spi-nor/spi-nor.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/spi-nor/Makefile ++++ b/drivers/mtd/spi-nor/Makefile +@@ -17,6 +17,7 @@ spi-nor-objs += sst.o + spi-nor-objs += winbond.o + spi-nor-objs += xilinx.o + spi-nor-objs += xmc.o ++spi-nor-objs += xtx.o + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o + + obj-$(CONFIG_MTD_SPI_NOR) += controllers/ +--- /dev/null ++++ b/drivers/mtd/spi-nor/xtx.c +@@ -0,0 +1,15 @@ ++// SPDX-License-Identifier: GPL-2.0 ++#include ++ ++#include "core.h" ++ ++static const struct flash_info xtx_parts[] = { ++ /* XTX Technology (Shenzhen) Limited */ ++ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++}; ++ ++const struct spi_nor_manufacturer spi_nor_xtx = { ++ .name = "xtx", ++ .parts = xtx_parts, ++ .nparts = ARRAY_SIZE(xtx_parts), ++}; +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -1859,6 +1859,7 @@ static const struct spi_nor_manufacturer + &spi_nor_winbond, + &spi_nor_xilinx, + &spi_nor_xmc, ++ &spi_nor_xtx, + }; + + static const struct flash_info * +--- a/drivers/mtd/spi-nor/core.h ++++ b/drivers/mtd/spi-nor/core.h +@@ -489,6 +489,7 @@ extern const struct spi_nor_manufacturer + extern const struct spi_nor_manufacturer spi_nor_winbond; + extern const struct spi_nor_manufacturer spi_nor_xilinx; + extern const struct spi_nor_manufacturer spi_nor_xmc; ++extern const struct spi_nor_manufacturer spi_nor_xtx; + + extern const struct attribute_group *spi_nor_sysfs_groups[]; + diff --git a/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch new file mode 100644 index 00000000000..c32cde559db --- /dev/null +++ b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch @@ -0,0 +1,22 @@ +From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001 +From: Koen Vandeputte +Date: Mon, 6 Jan 2020 13:07:56 +0100 +Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05 + +Signed-off-by: Koen Vandeputte +--- + drivers/mtd/spi-nor/spi-nor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -24,6 +24,9 @@ static struct spi_nor_fixups gd25q256_fi + }; + + static const struct flash_info gigadevice_parts[] = { ++ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | ++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, diff --git a/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch new file mode 100644 index 00000000000..7c8b6862777 --- /dev/null +++ b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch @@ -0,0 +1,21 @@ +From f8943df3beb0d3f9754bb35320c3a378727175a8 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Thu, 14 Jul 2022 08:38:07 +0200 +Subject: [PATCH] spi-nor/gigadevic: add gd25q512 + +--- + drivers/mtd/spi-nor/gigadevice.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -53,6 +53,9 @@ static const struct flash_info gigadevic + SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | + SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) + .fixups = &gd25q256_fixups }, ++ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | ++ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES) }, + }; + + const struct spi_nor_manufacturer spi_nor_gigadevice = { diff --git a/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch new file mode 100644 index 00000000000..ab402e622a2 --- /dev/null +++ b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch @@ -0,0 +1,23 @@ +From 87363cc0e522de3294ea6ae10fb468d2a8d6fb2f Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:17:21 +0200 +Subject: [PATCH] spi-nor/esmt.c: add esmt f25l16pa + +This fixes support for Dongwon T&I DW02-412H which uses F25L16PA(2S) +flash. + +--- + drivers/mtd/spi-nor/esmt.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/mtd/spi-nor/esmt.c ++++ b/drivers/mtd/spi-nor/esmt.c +@@ -10,6 +10,8 @@ + + static const struct flash_info esmt_parts[] = { + /* ESMT */ ++ { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32, ++ SECT_4K | SPI_NOR_HAS_LOCK) }, + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, + { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, diff --git a/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch new file mode 100644 index 00000000000..68e373ea236 --- /dev/null +++ b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch @@ -0,0 +1,24 @@ +From f6b33d850f7f12555df2fa0e3349b33427bf5890 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:19:01 +0200 +Subject: [PATCH] spi-nor/xmc.c: add xm25qh128c + +The XMC XM25QH128C is a 16MB SPI NOR chip. The patch is verified on +Ruijie RG-EW3200GX PRO. +Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf + +--- + drivers/mtd/spi-nor/xmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/mtd/spi-nor/xmc.c ++++ b/drivers/mtd/spi-nor/xmc.c +@@ -14,6 +14,8 @@ static const struct flash_info xmc_parts + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + }; + + const struct spi_nor_manufacturer spi_nor_xmc = { diff --git a/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch new file mode 100644 index 00000000000..d117cfe0a3a --- /dev/null +++ b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch @@ -0,0 +1,143 @@ +From a43b844cb40bf1b783055fdc81b7f991e21e7e76 Mon Sep 17 00:00:00 2001 +From: Chuanhong Guo +Date: Wed, 13 Apr 2022 11:58:17 +0800 +Subject: [PATCH] mtd: spinand: add support for ESMT F50x1G41LB + +This patch adds support for ESMT F50L1G41LB and F50D1G41LB. +It seems that ESMT likes to use random JEDEC ID from other vendors. +Their 1G chips uses 0xc8 from GigaDevice and 2G/4G chips uses 0x2c from +Micron. For this reason, the ESMT entry is named esmt_c8 with explicit +JEDEC ID in variable name. + +Datasheets: +https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50L1G41LB(2M).pdf +https://www.esmt.com.tw/upload/pdf/ESMT/datasheets/F50D1G41LB(2M).pdf + +Signed-off-by: Chuanhong Guo +--- + drivers/mtd/nand/spi/Makefile | 2 +- + drivers/mtd/nand/spi/core.c | 1 + + drivers/mtd/nand/spi/esmt.c | 89 +++++++++++++++++++++++++++++++++++ + include/linux/mtd/spinand.h | 1 + + 4 files changed, 92 insertions(+), 1 deletion(-) + create mode 100644 drivers/mtd/nand/spi/esmt.c + +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o ++spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -906,6 +906,7 @@ static const struct nand_ops spinand_ops + }; + + static const struct spinand_manufacturer *spinand_manufacturers[] = { ++ &esmt_c8_spinand_manufacturer, + &gigadevice_spinand_manufacturer, + ¯onix_spinand_manufacturer, + µn_spinand_manufacturer, +--- /dev/null ++++ b/drivers/mtd/nand/spi/esmt.c +@@ -0,0 +1,89 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Author: ++ * Chuanhong Guo ++ */ ++ ++#include ++#include ++#include ++ ++/* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */ ++#define SPINAND_MFR_ESMT_C8 0xc8 ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), ++ SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ ++static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = 16 * section + 8; ++ region->length = 8; ++ ++ return 0; ++} ++ ++static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *region) ++{ ++ if (section > 3) ++ return -ERANGE; ++ ++ region->offset = 16 * section + 2; ++ region->length = 6; ++ ++ return 0; ++} ++ ++static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = { ++ .ecc = f50l1g41lb_ooblayout_ecc, ++ .free = f50l1g41lb_ooblayout_free, ++}; ++ ++static const struct spinand_info esmt_c8_spinand_table[] = { ++ SPINAND_INFO("F50L1G41LB", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(1, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), ++ SPINAND_INFO("F50D1G41LB", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11), ++ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), ++ NAND_ECCREQ(1, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ 0, ++ SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), ++}; ++ ++static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer esmt_c8_spinand_manufacturer = { ++ .id = SPINAND_MFR_ESMT_C8, ++ .name = "ESMT", ++ .chips = esmt_c8_spinand_table, ++ .nchips = ARRAY_SIZE(esmt_c8_spinand_table), ++ .ops = &esmt_spinand_manuf_ops, ++}; +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -260,6 +260,7 @@ struct spinand_manufacturer { + }; + + /* SPI NAND manufacturers */ ++extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; + extern const struct spinand_manufacturer macronix_spinand_manufacturer; + extern const struct spinand_manufacturer micron_spinand_manufacturer; diff --git a/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch new file mode 100644 index 00000000000..7e20e14bb62 --- /dev/null +++ b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch @@ -0,0 +1,168 @@ +From f32085fc0b87049491b07e198d924d738a1a2834 Mon Sep 17 00:00:00 2001 +From: Daniel Danzberger +Date: Wed, 3 Aug 2022 17:31:03 +0200 +Subject: [PATCH] mtd: spinand: Add support for Etron EM73D044VCx + +Airoha is a new ARM platform based on Cortex-A53 which has recently been +merged into linux-next. + +Due to BootROM limitations on this platform, the Cortex-A53 can't run in +Aarch64 mode and code must be compiled for 32-Bit ARM. + +This support is based mostly on those linux-next commits backported +for kernel 5.15. + +Patches: +1 - platform support = linux-next +2 - clock driver = linux-next +3 - gpio driver = linux-next +4 - linux,usable-memory-range dts support = linux-next +5 - mtd spinand driver +6 - spi driver +7 - pci driver (kconfig only, uses mediatek PCI) = linux-next + +Still missing: +- Ethernet driver +- Sysupgrade support + +A.t.m there exists one subtarget EN7523 with only one evaluation +board. + +The initramfs can be run with the following commands from u-boot: +- +u-boot> setenv bootfile \ + openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin +u-boot> tftpboot +u-boot> bootm 0x81800000 +- + +Submitted-by: Daniel Danzberger + +--- a/drivers/mtd/nand/spi/Makefile ++++ b/drivers/mtd/nand/spi/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 +-spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o ++spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o + obj-$(CONFIG_MTD_SPI_NAND) += spinand.o +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -908,6 +908,7 @@ static const struct nand_ops spinand_ops + static const struct spinand_manufacturer *spinand_manufacturers[] = { + &esmt_c8_spinand_manufacturer, + &gigadevice_spinand_manufacturer, ++ &etron_spinand_manufacturer, + ¯onix_spinand_manufacturer, + µn_spinand_manufacturer, + ¶gon_spinand_manufacturer, +--- /dev/null ++++ b/drivers/mtd/nand/spi/etron.c +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++ ++#define SPINAND_MFR_ETRON 0xd5 ++ ++ ++static SPINAND_OP_VARIANTS(read_cache_variants, ++ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), ++ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(write_cache_variants, ++ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), ++ SPINAND_PROG_LOAD(true, 0, NULL, 0)); ++ ++static SPINAND_OP_VARIANTS(update_cache_variants, ++ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), ++ SPINAND_PROG_LOAD(false, 0, NULL, 0)); ++ ++static int etron_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 72; ++ oobregion->length = 56; ++ ++ return 0; ++} ++ ++static int etron_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) ++{ ++ if (section) ++ return -ERANGE; ++ ++ oobregion->offset = 1; ++ oobregion->length = 71; ++ ++ return 0; ++} ++ ++static int etron_ecc_get_status(struct spinand_device *spinand, u8 status) ++{ ++ switch (status & STATUS_ECC_MASK) { ++ case STATUS_ECC_NO_BITFLIPS: ++ return 0; ++ ++ case STATUS_ECC_HAS_BITFLIPS: ++ /* Between 1-7 bitflips were corrected */ ++ return 7; ++ ++ case STATUS_ECC_MASK: ++ /* Maximum bitflips were corrected */ ++ return 8; ++ ++ case STATUS_ECC_UNCOR_ERROR: ++ return -EBADMSG; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct mtd_ooblayout_ops etron_ooblayout = { ++ .ecc = etron_ooblayout_ecc, ++ .free = etron_ooblayout_free, ++}; ++ ++static const struct spinand_info etron_spinand_table[] = { ++ SPINAND_INFO("EM73D044VCx", ++ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f), ++ // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t ++ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), ++ NAND_ECCREQ(8, 512), ++ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, ++ &write_cache_variants, ++ &update_cache_variants), ++ SPINAND_HAS_QE_BIT, ++ SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)), ++}; ++ ++static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = { ++}; ++ ++const struct spinand_manufacturer etron_spinand_manufacturer = { ++ .id = SPINAND_MFR_ETRON, ++ .name = "Etron", ++ .chips = etron_spinand_table, ++ .nchips = ARRAY_SIZE(etron_spinand_table), ++ .ops = &etron_spinand_manuf_ops, ++}; +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -261,6 +261,7 @@ struct spinand_manufacturer { + + /* SPI NAND manufacturers */ + extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; ++extern const struct spinand_manufacturer etron_spinand_manufacturer; + extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; + extern const struct spinand_manufacturer macronix_spinand_manufacturer; + extern const struct spinand_manufacturer micron_spinand_manufacturer; diff --git a/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch new file mode 100644 index 00000000000..236d1c2755f --- /dev/null +++ b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch @@ -0,0 +1,22 @@ +From: Joe Mullally +Subject: mtd/spi-nor/xmc: add support for XMC XM25QH64C + +The XMC XM25QH64C is a 8MB SPI NOR chip. The patch is verified on TL-WPA8631P v3. +Datasheet available at https://www.xmcwh.com/uploads/442/XM25QH64C.pdf + +Signed-off-by: Joe Mullally +--- + drivers/mtd/spi-nor/xmc.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/mtd/spi-nor/xmc.c ++++ b/drivers/mtd/spi-nor/xmc.c +@@ -12,6 +12,8 @@ static const struct flash_info xmc_parts + /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ + { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "XM25QH64C", INFO(0x204017, 0, 64 * 1024, 128, ++ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256, diff --git a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch new file mode 100644 index 00000000000..2751da541a0 --- /dev/null +++ b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -0,0 +1,97 @@ +From: Daniel Golle +Subject: ubi: auto-attach mtd device named "ubi" or "data" on boot + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/drivers/mtd/ubi/build.c ++++ b/drivers/mtd/ubi/build.c +@@ -1200,6 +1200,73 @@ static struct mtd_info * __init open_mtd + return mtd; + } + ++/* ++ * This function tries attaching mtd partitions named either "ubi" or "data" ++ * during boot. ++ */ ++static void __init ubi_auto_attach(void) ++{ ++ int err; ++ struct mtd_info *mtd; ++ loff_t offset = 0; ++ size_t len; ++ char magic[4]; ++ ++ /* try attaching mtd device named "ubi" or "data" */ ++ mtd = open_mtd_device("ubi"); ++ if (IS_ERR(mtd)) ++ mtd = open_mtd_device("data"); ++ ++ if (IS_ERR(mtd)) ++ return; ++ ++ /* get the first not bad block */ ++ if (mtd_can_have_bb(mtd)) ++ while (mtd_block_isbad(mtd, offset)) { ++ offset += mtd->erasesize; ++ ++ if (offset > mtd->size) { ++ pr_err("UBI error: Failed to find a non-bad " ++ "block on mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ } ++ ++ /* check if the read from flash was successful */ ++ err = mtd_read(mtd, offset, 4, &len, (void *) magic); ++ if ((err && !mtd_is_bitflip(err)) || len != 4) { ++ pr_err("UBI error: unable to read from mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* check for a valid ubi magic */ ++ if (strncmp(magic, "UBI#", 4)) { ++ pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ /* don't auto-add media types where UBI doesn't makes sense */ ++ if (mtd->type != MTD_NANDFLASH && ++ mtd->type != MTD_NORFLASH && ++ mtd->type != MTD_DATAFLASH && ++ mtd->type != MTD_MLCNANDFLASH) ++ goto cleanup; ++ ++ mutex_lock(&ubi_devices_mutex); ++ pr_notice("UBI: auto-attach mtd%d\n", mtd->index); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ mutex_unlock(&ubi_devices_mutex); ++ if (err < 0) { ++ pr_err("UBI error: cannot attach mtd%d\n", mtd->index); ++ goto cleanup; ++ } ++ ++ return; ++ ++cleanup: ++ put_mtd_device(mtd); ++} ++ + static int __init ubi_init(void) + { + int err, i, k; +@@ -1283,6 +1350,12 @@ static int __init ubi_init(void) + } + } + ++ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd ++ * parameter was given */ ++ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ !ubi_is_module() && !mtd_devs) ++ ubi_auto_attach(); ++ + err = ubiblock_init(); + if (err) { + pr_err("UBI error: block: cannot initialize, error %d\n", err); diff --git a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch new file mode 100644 index 00000000000..ae53770c11c --- /dev/null +++ b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -0,0 +1,69 @@ +From: Daniel Golle +Subject: ubi: auto-create ubiblock device for rootfs + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -642,6 +642,47 @@ static void __init ubiblock_create_from_ + } + } + ++#define UBIFS_NODE_MAGIC 0x06101831 ++static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) ++{ ++ int ret; ++ uint32_t magic_of, magic; ++ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); ++ if (ret) ++ return 0; ++ magic = le32_to_cpu(magic_of); ++ return magic == UBIFS_NODE_MAGIC; ++} ++ ++static void __init ubiblock_create_auto_rootfs(void) ++{ ++ int ubi_num, ret, is_ubifs; ++ struct ubi_volume_desc *desc; ++ struct ubi_volume_info vi; ++ ++ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { ++ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); ++ if (IS_ERR(desc)) ++ desc = ubi_open_volume_nm(ubi_num, "fit", UBI_READONLY);; ++ ++ if (IS_ERR(desc)) ++ continue; ++ ++ ubi_get_volume_info(desc, &vi); ++ is_ubifs = ubi_vol_is_ubifs(desc); ++ ubi_close_volume(desc); ++ if (is_ubifs) ++ break; ++ ++ ret = ubiblock_create(&vi); ++ if (ret) ++ pr_err("UBI error: block: can't add '%s' volume, err=%d\n", ++ vi.name, ret); ++ /* always break if we get here */ ++ break; ++ } ++} ++ + static void ubiblock_remove_all(void) + { + struct ubiblock *next; +@@ -674,6 +715,10 @@ int __init ubiblock_init(void) + */ + ubiblock_create_from_param(); + ++ /* auto-attach "rootfs" volume if existing and non-ubifs */ ++ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV)) ++ ubiblock_create_auto_rootfs(); ++ + /* + * Block devices are only created upon user requests, so we ignore + * existing volumes. diff --git a/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch new file mode 100644 index 00000000000..cf41c8cad3f --- /dev/null +++ b/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -0,0 +1,53 @@ +From: Daniel Golle +Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c + +Signed-off-by: Daniel Golle +--- + init/do_mounts.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +--- a/init/do_mounts.c ++++ b/init/do_mounts.c +@@ -447,7 +447,30 @@ retry: + out: + put_page(page); + } +- ++ ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++static int __init mount_ubi_rootfs(void) ++{ ++ int flags = MS_SILENT; ++ int err, tried = 0; ++ ++ while (tried < 2) { ++ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \ ++ root_mount_data); ++ switch (err) { ++ case -EACCES: ++ flags |= MS_RDONLY; ++ tried++; ++ break; ++ default: ++ return err; ++ } ++ } ++ ++ return -EINVAL; ++} ++#endif ++ + #ifdef CONFIG_ROOT_NFS + + #define NFSROOT_TIMEOUT_MIN 5 +@@ -580,6 +603,10 @@ void __init mount_root(void) + return; + } + #endif ++#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV ++ if (!mount_ubi_rootfs()) ++ return; ++#endif + if (ROOT_DEV == 0 && root_device_name && root_fs_names) { + if (mount_nodev_root() == 0) + return; diff --git a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch new file mode 100644 index 00000000000..266a6331c2a --- /dev/null +++ b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -0,0 +1,34 @@ +From: Daniel Golle +Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset + +Signed-off-by: Daniel Golle +--- + drivers/mtd/ubi/block.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/mtd/ubi/block.c ++++ b/drivers/mtd/ubi/block.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #include "ubi-media.h" + #include "ubi.h" +@@ -451,6 +452,15 @@ int ubiblock_create(struct ubi_volume_in + dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", + dev->ubi_num, dev->vol_id, vi->name); + mutex_unlock(&devices_mutex); ++ ++ if (!strcmp(vi->name, "rootfs") && ++ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && ++ ROOT_DEV == 0) { ++ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n", ++ dev->ubi_num, dev->vol_id, vi->name); ++ ROOT_DEV = MKDEV(gd->major, gd->first_minor); ++ } ++ + return 0; + + out_remove_minor: diff --git a/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch new file mode 100644 index 00000000000..413431755f1 --- /dev/null +++ b/target/linux/generic/pending-6.1/494-mtd-ubi-add-EOF-marker-support.patch @@ -0,0 +1,60 @@ +From: Gabor Juhos +Subject: mtd: add EOF marker support to the UBI layer + +Signed-off-by: Gabor Juhos +--- + drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++--- + drivers/mtd/ubi/ubi.h | 1 + + 2 files changed, 23 insertions(+), 3 deletions(-) + +--- a/drivers/mtd/ubi/attach.c ++++ b/drivers/mtd/ubi/attach.c +@@ -926,6 +926,13 @@ static bool vol_ignored(int vol_id) + #endif + } + ++static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech) ++{ ++ return ech->padding1[0] == 'E' && ++ ech->padding1[1] == 'O' && ++ ech->padding1[2] == 'F'; ++} ++ + /** + * scan_peb - scan and process UBI headers of a PEB. + * @ubi: UBI device description object +@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u + return 0; + } + +- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); +- if (err < 0) +- return err; ++ if (!ai->eof_found) { ++ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); ++ if (err < 0) ++ return err; ++ ++ if (ec_hdr_has_eof(ech)) { ++ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n", ++ pnum); ++ ai->eof_found = true; ++ } ++ } ++ ++ if (ai->eof_found) ++ err = UBI_IO_FF_BITFLIPS; ++ + switch (err) { + case 0: + break; +--- a/drivers/mtd/ubi/ubi.h ++++ b/drivers/mtd/ubi/ubi.h +@@ -778,6 +778,7 @@ struct ubi_attach_info { + int mean_ec; + uint64_t ec_sum; + int ec_count; ++ bool eof_found; + struct kmem_cache *aeb_slab_cache; + struct ubi_ec_hdr *ech; + struct ubi_vid_io_buf *vidb; diff --git a/target/linux/generic/pending-6.1/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch b/target/linux/generic/pending-6.1/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch new file mode 100644 index 00000000000..01f3b9ec2da --- /dev/null +++ b/target/linux/generic/pending-6.1/496-dt-bindings-add-bindings-for-mtd-concat-devices.patch @@ -0,0 +1,52 @@ +From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Wed, 5 Sep 2018 01:32:51 +0200 +Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices + +Document virtual mtd-concat device bindings. + +Signed-off-by: Bernhard Frauendienst +--- + .../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt + +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt +@@ -0,0 +1,36 @@ ++Virtual MTD concat device ++ ++Requires properties: ++- devices: list of phandles to mtd nodes that should be concatenated ++ ++Example: ++ ++&spi { ++ flash0: flash@0 { ++ ... ++ }; ++ flash1: flash@1 { ++ ... ++ }; ++}; ++ ++flash { ++ compatible = "mtd-concat"; ++ ++ devices = <&flash0 &flash1>; ++ ++ partitions { ++ compatible = "fixed-partitions"; ++ ++ partition@0 { ++ label = "boot"; ++ reg = <0x0000000 0x0040000>; ++ read-only; ++ }; ++ ++ partition@40000 { ++ label = "firmware"; ++ reg = <0x0040000 0x1fc0000>; ++ }; ++ } ++} diff --git a/target/linux/generic/pending-6.1/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch b/target/linux/generic/pending-6.1/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch new file mode 100644 index 00000000000..e0cbc4508b0 --- /dev/null +++ b/target/linux/generic/pending-6.1/497-mtd-mtdconcat-add-dt-driver-for-concat-devices.patch @@ -0,0 +1,216 @@ +From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001 +From: Bernhard Frauendienst +Date: Sat, 25 Aug 2018 12:35:22 +0200 +Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices + +Some mtd drivers like physmap variants have support for concatenating +multiple mtd devices, but there is no generic way to define such a +concat device from within the device tree. + +This is useful for some SoC boards that use multiple flash chips as +memory banks of a single mtd device, with partitions spanning chip +borders. + +This commit adds a driver for creating virtual mtd-concat devices. They +must have a compatible = "mtd-concat" line, and define a list of devices +to concat in the 'devices' property, for example: + +flash { + compatible = "mtd-concat"; + + devices = <&flash0 &flash1>; + + partitions { + ... + }; +}; + +The driver is added to the very end of the mtd Makefile to increase the +likelyhood of all child devices already being loaded at the time of +probing, preventing unnecessary deferred probes. + +Signed-off-by: Bernhard Frauendienst +--- + drivers/mtd/Kconfig | 2 + + drivers/mtd/Makefile | 3 + + drivers/mtd/composite/Kconfig | 12 +++ + drivers/mtd/composite/Makefile | 6 ++ + drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++ + 5 files changed, 151 insertions(+) + create mode 100644 drivers/mtd/composite/Kconfig + create mode 100644 drivers/mtd/composite/Makefile + create mode 100644 drivers/mtd/composite/virt_concat.c + +--- a/drivers/mtd/Kconfig ++++ b/drivers/mtd/Kconfig +@@ -241,4 +241,6 @@ source "drivers/mtd/ubi/Kconfig" + + source "drivers/mtd/hyperbus/Kconfig" + ++source "drivers/mtd/composite/Kconfig" ++ + endif # MTD +--- a/drivers/mtd/Makefile ++++ b/drivers/mtd/Makefile +@@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n + obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ + obj-$(CONFIG_MTD_UBI) += ubi/ + obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ ++ ++# Composite drivers must be loaded last ++obj-y += composite/ +--- /dev/null ++++ b/drivers/mtd/composite/Kconfig +@@ -0,0 +1,12 @@ ++menu "Composite MTD device drivers" ++ depends on MTD!=n ++ ++config MTD_VIRT_CONCAT ++ tristate "Virtual concat MTD device" ++ help ++ This driver allows creation of a virtual MTD concat device, which ++ concatenates multiple underlying MTD devices to a single device. ++ This is required by some SoC boards where multiple memory banks are ++ used as one device with partitions spanning across device boundaries. ++ ++endmenu +--- /dev/null ++++ b/drivers/mtd/composite/Makefile +@@ -0,0 +1,6 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# ++# linux/drivers/mtd/composite/Makefile ++# ++ ++obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o +--- /dev/null ++++ b/drivers/mtd/composite/virt_concat.c +@@ -0,0 +1,128 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Virtual concat MTD device driver ++ * ++ * Copyright (C) 2018 Bernhard Frauendienst ++ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * struct of_virt_concat - platform device driver data. ++ * @cmtd the final mtd_concat device ++ * @num_devices the number of devices in @devices ++ * @devices points to an array of devices already loaded ++ */ ++struct of_virt_concat { ++ struct mtd_info *cmtd; ++ int num_devices; ++ struct mtd_info **devices; ++}; ++ ++static int virt_concat_remove(struct platform_device *pdev) ++{ ++ struct of_virt_concat *info; ++ int i; ++ ++ info = platform_get_drvdata(pdev); ++ if (!info) ++ return 0; ++ ++ // unset data for when this is called after a probe error ++ platform_set_drvdata(pdev, NULL); ++ ++ if (info->cmtd) { ++ mtd_device_unregister(info->cmtd); ++ mtd_concat_destroy(info->cmtd); ++ } ++ ++ if (info->devices) { ++ for (i = 0; i < info->num_devices; i++) ++ put_mtd_device(info->devices[i]); ++ } ++ ++ return 0; ++} ++ ++static int virt_concat_probe(struct platform_device *pdev) ++{ ++ struct device_node *node = pdev->dev.of_node; ++ struct of_phandle_iterator it; ++ struct of_virt_concat *info; ++ struct mtd_info *mtd; ++ int err = 0, count; ++ ++ count = of_count_phandle_with_args(node, "devices", NULL); ++ if (count <= 0) ++ return -EINVAL; ++ ++ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return -ENOMEM; ++ info->devices = devm_kcalloc(&pdev->dev, count, ++ sizeof(*(info->devices)), GFP_KERNEL); ++ if (!info->devices) { ++ err = -ENOMEM; ++ goto err_remove; ++ } ++ ++ platform_set_drvdata(pdev, info); ++ ++ of_for_each_phandle(&it, err, node, "devices", NULL, 0) { ++ mtd = of_get_mtd_device_by_node(it.node); ++ if (IS_ERR(mtd)) { ++ of_node_put(it.node); ++ err = -EPROBE_DEFER; ++ goto err_remove; ++ } ++ ++ info->devices[info->num_devices++] = mtd; ++ } ++ ++ info->cmtd = mtd_concat_create(info->devices, info->num_devices, ++ dev_name(&pdev->dev)); ++ if (!info->cmtd) { ++ err = -ENXIO; ++ goto err_remove; ++ } ++ ++ info->cmtd->dev.parent = &pdev->dev; ++ mtd_set_of_node(info->cmtd, node); ++ mtd_device_register(info->cmtd, NULL, 0); ++ ++ return 0; ++ ++err_remove: ++ virt_concat_remove(pdev); ++ ++ return err; ++} ++ ++static const struct of_device_id virt_concat_of_match[] = { ++ { .compatible = "mtd-concat", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, virt_concat_of_match); ++ ++static struct platform_driver virt_concat_driver = { ++ .probe = virt_concat_probe, ++ .remove = virt_concat_remove, ++ .driver = { ++ .name = "virt-mtdconcat", ++ .of_match_table = virt_concat_of_match, ++ }, ++}; ++ ++module_platform_driver(virt_concat_driver); ++ ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Bernhard Frauendienst "); ++MODULE_DESCRIPTION("Virtual concat MTD device driver"); diff --git a/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch new file mode 100644 index 00000000000..81de7648760 --- /dev/null +++ b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch @@ -0,0 +1,34 @@ +From 8bf2ce6ea4ee840b70f55a27f80e1cd308051b13 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Mon, 27 Dec 2021 00:38:13 +0100 +Subject: [PATCH 1/2] mtd: spi-nor: locking support for MX25L6405D + +Macronix MX25L6405D supports locking with four block-protection bits. +Currently, the driver only sets three bits. If the bootloader does not +sustain the flash chip in an unlocked state, the flash might be +non-writeable. Add the corresponding flag to enable locking support with +four bits in the status register. + +Tested on Nanostation M2 XM. + +Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for +MX25L12805D") + +Signed-off-by: David Bauer +Signed-off-by: Nick Hainke +--- + drivers/mtd/spi-nor/macronix.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -41,7 +41,8 @@ static const struct flash_info macronix_ + { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, + { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, +- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, ++ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K | ++ SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) }, + { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, + { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, + SECT_4K | SPI_NOR_DUAL_READ | diff --git a/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch b/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch new file mode 100644 index 00000000000..ec14f6341cc --- /dev/null +++ b/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch @@ -0,0 +1,30 @@ +From 245224608b5368c10407da07557e546743d3c489 Mon Sep 17 00:00:00 2001 +From: Nick Hainke +Date: Mon, 27 Dec 2021 09:33:13 +0100 +Subject: [PATCH 2/2] mtd: spi-nor: disable 16-bit-sr for macronix + +Macronix flash chips seem to consist of only one status register. +These chips will not work with the "16-bit Write Status (01h) Command". +Disable SNOR_F_HAS_16BIT_SR for all Macronix chips. + +Tested with MX25L6405D. + +Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on +lock()/unlock()") + +Signed-off-by: David Bauer +Signed-off-by: Nick Hainke +--- + drivers/mtd/spi-nor/macronix.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/mtd/spi-nor/macronix.c ++++ b/drivers/mtd/spi-nor/macronix.c +@@ -94,6 +94,7 @@ static void macronix_default_init(struct + { + nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; + nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; ++ nor->flags &= ~SNOR_F_HAS_16BIT_SR; + nor->flags |= SNOR_F_HAS_LOCK; + } + diff --git a/target/linux/generic/pending-6.1/500-fs_cdrom_dependencies.patch b/target/linux/generic/pending-6.1/500-fs_cdrom_dependencies.patch new file mode 100644 index 00000000000..2053c0fbe2e --- /dev/null +++ b/target/linux/generic/pending-6.1/500-fs_cdrom_dependencies.patch @@ -0,0 +1,52 @@ +From af7b91bcecce0eae24e90acd35d96ecee73e1407 Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:21:15 +0200 +Subject: [PATCH] fs: add cdrom dependency + +--- + fs/hfs/Kconfig | 1 + + fs/hfsplus/Kconfig | 1 + + fs/isofs/Kconfig | 1 + + fs/udf/Kconfig | 1 + + 4 files changed, 4 insertions(+) + +--- a/fs/hfs/Kconfig ++++ b/fs/hfs/Kconfig +@@ -2,6 +2,7 @@ + config HFS_FS + tristate "Apple Macintosh file system support" + depends on BLOCK ++ select CDROM + select NLS + help + If you say Y here, you will be able to mount Macintosh-formatted +--- a/fs/hfsplus/Kconfig ++++ b/fs/hfsplus/Kconfig +@@ -2,6 +2,7 @@ + config HFSPLUS_FS + tristate "Apple Extended HFS file system support" + depends on BLOCK ++ select CDROM + select NLS + select NLS_UTF8 + help +--- a/fs/isofs/Kconfig ++++ b/fs/isofs/Kconfig +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config ISO9660_FS + tristate "ISO 9660 CDROM file system support" ++ select CDROM + help + This is the standard file system used on CD-ROMs. It was previously + known as "High Sierra File System" and is called "hsfs" on other +--- a/fs/udf/Kconfig ++++ b/fs/udf/Kconfig +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0-only + config UDF_FS + tristate "UDF file system support" ++ select CDROM + select CRC_ITU_T + select NLS + help diff --git a/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch new file mode 100644 index 00000000000..ac784d0b0bb --- /dev/null +++ b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch @@ -0,0 +1,4581 @@ +From: Alexandros C. Couloumbis +Subject: fs: add jffs2/lzma support (not activated by default yet) + +lede-commit: c2c88d315fa0e881f8b19da07b62859b915b11b2 +Signed-off-by: Alexandros C. Couloumbis +--- + fs/jffs2/Kconfig | 9 + + fs/jffs2/Makefile | 3 + + fs/jffs2/compr.c | 6 + + fs/jffs2/compr.h | 10 +- + fs/jffs2/compr_lzma.c | 128 +++ + fs/jffs2/super.c | 33 +- + include/linux/lzma.h | 62 ++ + include/linux/lzma/LzFind.h | 115 +++ + include/linux/lzma/LzHash.h | 54 + + include/linux/lzma/LzmaDec.h | 231 +++++ + include/linux/lzma/LzmaEnc.h | 80 ++ + include/linux/lzma/Types.h | 226 +++++ + include/uapi/linux/jffs2.h | 1 + + lib/Kconfig | 6 + + lib/Makefile | 12 + + lib/lzma/LzFind.c | 761 ++++++++++++++ + lib/lzma/LzmaDec.c | 999 +++++++++++++++++++ + lib/lzma/LzmaEnc.c | 2271 ++++++++++++++++++++++++++++++++++++++++++ + lib/lzma/Makefile | 7 + + 19 files changed, 5008 insertions(+), 6 deletions(-) + create mode 100644 fs/jffs2/compr_lzma.c + create mode 100644 include/linux/lzma.h + create mode 100644 include/linux/lzma/LzFind.h + create mode 100644 include/linux/lzma/LzHash.h + create mode 100644 include/linux/lzma/LzmaDec.h + create mode 100644 include/linux/lzma/LzmaEnc.h + create mode 100644 include/linux/lzma/Types.h + create mode 100644 lib/lzma/LzFind.c + create mode 100644 lib/lzma/LzmaDec.c + create mode 100644 lib/lzma/LzmaEnc.c + create mode 100644 lib/lzma/Makefile + +--- a/fs/jffs2/Kconfig ++++ b/fs/jffs2/Kconfig +@@ -136,6 +136,15 @@ config JFFS2_LZO + This feature was added in July, 2007. Say 'N' if you need + compatibility with older bootloaders or kernels. + ++config JFFS2_LZMA ++ bool "JFFS2 LZMA compression support" if JFFS2_COMPRESSION_OPTIONS ++ select LZMA_COMPRESS ++ select LZMA_DECOMPRESS ++ depends on JFFS2_FS ++ default n ++ help ++ JFFS2 wrapper to the LZMA C SDK ++ + config JFFS2_RTIME + bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS + depends on JFFS2_FS +--- a/fs/jffs2/Makefile ++++ b/fs/jffs2/Makefile +@@ -19,4 +19,7 @@ jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rub + jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o + jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o + jffs2-$(CONFIG_JFFS2_LZO) += compr_lzo.o ++jffs2-$(CONFIG_JFFS2_LZMA) += compr_lzma.o + jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o ++ ++CFLAGS_compr_lzma.o += -Iinclude/linux -Ilib/lzma +--- a/fs/jffs2/compr.c ++++ b/fs/jffs2/compr.c +@@ -378,6 +378,9 @@ int __init jffs2_compressors_init(void) + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_init(); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_init(); ++#endif + /* Setting default compression mode */ + #ifdef CONFIG_JFFS2_CMODE_NONE + jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; +@@ -401,6 +404,9 @@ int __init jffs2_compressors_init(void) + int jffs2_compressors_exit(void) + { + /* Unregistering compressors */ ++#ifdef CONFIG_JFFS2_LZMA ++ jffs2_lzma_exit(); ++#endif + #ifdef CONFIG_JFFS2_LZO + jffs2_lzo_exit(); + #endif +--- a/fs/jffs2/compr.h ++++ b/fs/jffs2/compr.h +@@ -29,9 +29,9 @@ + #define JFFS2_DYNRUBIN_PRIORITY 20 + #define JFFS2_LZARI_PRIORITY 30 + #define JFFS2_RTIME_PRIORITY 50 +-#define JFFS2_ZLIB_PRIORITY 60 +-#define JFFS2_LZO_PRIORITY 80 +- ++#define JFFS2_LZMA_PRIORITY 70 ++#define JFFS2_ZLIB_PRIORITY 80 ++#define JFFS2_LZO_PRIORITY 90 + + #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */ + #define JFFS2_DYNRUBIN_DISABLED /* for decompression */ +@@ -101,5 +101,9 @@ void jffs2_zlib_exit(void); + int jffs2_lzo_init(void); + void jffs2_lzo_exit(void); + #endif ++#ifdef CONFIG_JFFS2_LZMA ++int jffs2_lzma_init(void); ++void jffs2_lzma_exit(void); ++#endif + + #endif /* __JFFS2_COMPR_H__ */ +--- /dev/null ++++ b/fs/jffs2/compr_lzma.c +@@ -0,0 +1,128 @@ ++/* ++ * JFFS2 -- Journalling Flash File System, Version 2. ++ * ++ * For licensing information, see the file 'LICENCE' in this directory. ++ * ++ * JFFS2 wrapper to the LZMA C SDK ++ * ++ */ ++ ++#include ++#include "compr.h" ++ ++#ifdef __KERNEL__ ++ static DEFINE_MUTEX(deflate_mutex); ++#endif ++ ++CLzmaEncHandle *p; ++Byte propsEncoded[LZMA_PROPS_SIZE]; ++SizeT propsSize = sizeof(propsEncoded); ++ ++STATIC void lzma_free_workspace(void) ++{ ++ LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); ++} ++ ++STATIC int INIT lzma_alloc_workspace(CLzmaEncProps *props) ++{ ++ if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) ++ { ++ PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); ++ return -ENOMEM; ++ } ++ ++ if (LzmaEnc_SetProps(p, props) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) ++ { ++ lzma_free_workspace(); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_compress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t *sourcelen, uint32_t *dstlen) ++{ ++ SizeT compress_size = (SizeT)(*dstlen); ++ int ret; ++ ++ #ifdef __KERNEL__ ++ mutex_lock(&deflate_mutex); ++ #endif ++ ++ ret = LzmaEnc_MemEncode(p, cpage_out, &compress_size, data_in, *sourcelen, ++ 0, NULL, &lzma_alloc, &lzma_alloc); ++ ++ #ifdef __KERNEL__ ++ mutex_unlock(&deflate_mutex); ++ #endif ++ ++ if (ret != SZ_OK) ++ return -1; ++ ++ *dstlen = (uint32_t)compress_size; ++ ++ return 0; ++} ++ ++STATIC int jffs2_lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, ++ uint32_t srclen, uint32_t destlen) ++{ ++ int ret; ++ SizeT dl = (SizeT)destlen; ++ SizeT sl = (SizeT)srclen; ++ ELzmaStatus status; ++ ++ ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, ++ propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); ++ ++ if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (SizeT)destlen) ++ return -1; ++ ++ return 0; ++} ++ ++static struct jffs2_compressor jffs2_lzma_comp = { ++ .priority = JFFS2_LZMA_PRIORITY, ++ .name = "lzma", ++ .compr = JFFS2_COMPR_LZMA, ++ .compress = &jffs2_lzma_compress, ++ .decompress = &jffs2_lzma_decompress, ++ .disabled = 0, ++}; ++ ++int INIT jffs2_lzma_init(void) ++{ ++ int ret; ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ ++ props.dictSize = LZMA_BEST_DICT(0x2000); ++ props.level = LZMA_BEST_LEVEL; ++ props.lc = LZMA_BEST_LC; ++ props.lp = LZMA_BEST_LP; ++ props.pb = LZMA_BEST_PB; ++ props.fb = LZMA_BEST_FB; ++ ++ ret = lzma_alloc_workspace(&props); ++ if (ret < 0) ++ return ret; ++ ++ ret = jffs2_register_compressor(&jffs2_lzma_comp); ++ if (ret) ++ lzma_free_workspace(); ++ ++ return ret; ++} ++ ++void jffs2_lzma_exit(void) ++{ ++ jffs2_unregister_compressor(&jffs2_lzma_comp); ++ lzma_free_workspace(); ++} +--- a/fs/jffs2/super.c ++++ b/fs/jffs2/super.c +@@ -374,14 +374,41 @@ static int __init init_jffs2_fs(void) + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + +- pr_info("version 2.2." ++ pr_info("version 2.2" + #ifdef CONFIG_JFFS2_FS_WRITEBUFFER + " (NAND)" + #endif + #ifdef CONFIG_JFFS2_SUMMARY +- " (SUMMARY) " ++ " (SUMMARY)" + #endif +- " © 2001-2006 Red Hat, Inc.\n"); ++#ifdef CONFIG_JFFS2_ZLIB ++ " (ZLIB)" ++#endif ++#ifdef CONFIG_JFFS2_LZO ++ " (LZO)" ++#endif ++#ifdef CONFIG_JFFS2_LZMA ++ " (LZMA)" ++#endif ++#ifdef CONFIG_JFFS2_RTIME ++ " (RTIME)" ++#endif ++#ifdef CONFIG_JFFS2_RUBIN ++ " (RUBIN)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_NONE ++ " (CMODE_NONE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_PRIORITY ++ " (CMODE_PRIORITY)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_SIZE ++ " (CMODE_SIZE)" ++#endif ++#ifdef CONFIG_JFFS2_CMODE_FAVOURLZO ++ " (CMODE_FAVOURLZO)" ++#endif ++ " (c) 2001-2006 Red Hat, Inc.\n"); + + jffs2_inode_cachep = kmem_cache_create("jffs2_i", + sizeof(struct jffs2_inode_info), +--- /dev/null ++++ b/include/linux/lzma.h +@@ -0,0 +1,62 @@ ++#ifndef __LZMA_H__ ++#define __LZMA_H__ ++ ++#ifdef __KERNEL__ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #define LZMA_MALLOC vmalloc ++ #define LZMA_FREE vfree ++ #define PRINT_ERROR(msg) printk(KERN_WARNING #msg) ++ #define INIT __init ++ #define STATIC static ++#else ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #ifndef PAGE_SIZE ++ extern int page_size; ++ #define PAGE_SIZE page_size ++ #endif ++ #define LZMA_MALLOC malloc ++ #define LZMA_FREE free ++ #define PRINT_ERROR(msg) fprintf(stderr, msg) ++ #define INIT ++ #define STATIC ++#endif ++ ++#include "lzma/LzmaDec.h" ++#include "lzma/LzmaEnc.h" ++ ++#define LZMA_BEST_LEVEL (9) ++#define LZMA_BEST_LC (0) ++#define LZMA_BEST_LP (0) ++#define LZMA_BEST_PB (0) ++#define LZMA_BEST_FB (273) ++ ++#define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) ++ ++static void *p_lzma_malloc(void *p, size_t size) ++{ ++ if (size == 0) ++ return NULL; ++ ++ return LZMA_MALLOC(size); ++} ++ ++static void p_lzma_free(void *p, void *address) ++{ ++ if (address != NULL) ++ LZMA_FREE(address); ++} ++ ++static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzFind.h +@@ -0,0 +1,98 @@ ++/* LzFind.h -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_FIND_H ++#define __LZ_FIND_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef UInt32 CLzRef; ++ ++typedef struct _CMatchFinder ++{ ++ Byte *buffer; ++ UInt32 pos; ++ UInt32 posLimit; ++ UInt32 streamPos; ++ UInt32 lenLimit; ++ ++ UInt32 cyclicBufferPos; ++ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ ++ ++ UInt32 matchMaxLen; ++ CLzRef *hash; ++ CLzRef *son; ++ UInt32 hashMask; ++ UInt32 cutValue; ++ ++ Byte *bufferBase; ++ ISeqInStream *stream; ++ int streamEndWasReached; ++ ++ UInt32 blockSize; ++ UInt32 keepSizeBefore; ++ UInt32 keepSizeAfter; ++ ++ UInt32 numHashBytes; ++ int directInput; ++ size_t directInputRem; ++ int btMode; ++ int bigHash; ++ UInt32 historySize; ++ UInt32 fixedHashSize; ++ UInt32 hashSizeSum; ++ UInt32 numSons; ++ SRes result; ++ UInt32 crc[256]; ++} CMatchFinder; ++ ++#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) ++#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) ++ ++#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) ++ ++void MatchFinder_Construct(CMatchFinder *p); ++ ++/* Conditions: ++ historySize <= 3 GB ++ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB ++*/ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc); ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++ ++/* ++Conditions: ++ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. ++ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function ++*/ ++ ++typedef void (*Mf_Init_Func)(void *object); ++typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); ++typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); ++typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); ++typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); ++typedef void (*Mf_Skip_Func)(void *object, UInt32); ++ ++typedef struct _IMatchFinder ++{ ++ Mf_Init_Func Init; ++ Mf_GetIndexByte_Func GetIndexByte; ++ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; ++ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; ++ Mf_GetMatches_Func GetMatches; ++ Mf_Skip_Func Skip; ++} IMatchFinder; ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzHash.h +@@ -0,0 +1,54 @@ ++/* LzHash.h -- HASH functions for LZ algorithms ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZ_HASH_H ++#define __LZ_HASH_H ++ ++#define kHash2Size (1 << 10) ++#define kHash3Size (1 << 16) ++#define kHash4Size (1 << 20) ++ ++#define kFix3HashSize (kHash2Size) ++#define kFix4HashSize (kHash2Size + kHash3Size) ++#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) ++ ++#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); ++ ++#define HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } ++ ++#define HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } ++ ++#define HASH5_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ ++ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ ++ hash4Value &= (kHash4Size - 1); } ++ ++/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ ++#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; ++ ++ ++#define MT_HASH2_CALC \ ++ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); ++ ++#define MT_HASH3_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } ++ ++#define MT_HASH4_CALC { \ ++ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ ++ hash2Value = temp & (kHash2Size - 1); \ ++ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ ++ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaDec.h +@@ -0,0 +1,130 @@ ++/* LzmaDec.h -- LZMA Decoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_DEC_H ++#define __LZMA_DEC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* #define _LZMA_PROB32 */ ++/* _LZMA_PROB32 can increase the speed on some CPUs, ++ but memory usage for CLzmaDec::probs will be doubled in that case */ ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++ ++/* ---------- LZMA Properties ---------- */ ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaProps ++{ ++ unsigned lc, lp, pb; ++ UInt32 dicSize; ++} CLzmaProps; ++ ++ ++/* ---------- LZMA Decoder state ---------- */ ++ ++/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. ++ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ ++ ++#define LZMA_REQUIRED_INPUT_MAX 20 ++ ++typedef struct ++{ ++ CLzmaProps prop; ++ CLzmaProb *probs; ++ Byte *dic; ++ const Byte *buf; ++ UInt32 range, code; ++ SizeT dicPos; ++ SizeT dicBufSize; ++ UInt32 processedPos; ++ UInt32 checkDicSize; ++ unsigned state; ++ UInt32 reps[4]; ++ unsigned remainLen; ++ int needFlush; ++ int needInitState; ++ UInt32 numProbs; ++ unsigned tempBufSize; ++ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; ++} CLzmaDec; ++ ++#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } ++ ++/* There are two types of LZMA streams: ++ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. ++ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ ++ ++typedef enum ++{ ++ LZMA_FINISH_ANY, /* finish at any point */ ++ LZMA_FINISH_END /* block must be finished at the end */ ++} ELzmaFinishMode; ++ ++/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! ++ ++ You must use LZMA_FINISH_END, when you know that current output buffer ++ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. ++ ++ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, ++ and output value of destLen will be less than output buffer size limit. ++ You can check status result also. ++ ++ You can use multiple checks to test data integrity after full decompression: ++ 1) Check Result and "status" variable. ++ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. ++ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. ++ You must use correct finish mode in that case. */ ++ ++typedef enum ++{ ++ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ ++ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ ++ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ ++ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ ++} ELzmaStatus; ++ ++/* ELzmaStatus is used only as output value for function call */ ++ ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaDecode ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). ++*/ ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/LzmaEnc.h +@@ -0,0 +1,60 @@ ++/* LzmaEnc.h -- LZMA Encoder ++2009-02-07 : Igor Pavlov : Public domain */ ++ ++#ifndef __LZMA_ENC_H ++#define __LZMA_ENC_H ++ ++#include "Types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define LZMA_PROPS_SIZE 5 ++ ++typedef struct _CLzmaEncProps ++{ ++ int level; /* 0 <= level <= 9 */ ++ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version ++ (1 << 12) <= dictSize <= (1 << 30) for 64-bit version ++ default = (1 << 24) */ ++ int lc; /* 0 <= lc <= 8, default = 3 */ ++ int lp; /* 0 <= lp <= 4, default = 0 */ ++ int pb; /* 0 <= pb <= 4, default = 2 */ ++ int algo; /* 0 - fast, 1 - normal, default = 1 */ ++ int fb; /* 5 <= fb <= 273, default = 32 */ ++ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ ++ int numHashBytes; /* 2, 3 or 4, default = 4 */ ++ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ ++ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ ++ int numThreads; /* 1 or 2, default = 2 */ ++} CLzmaEncProps; ++ ++void LzmaEncProps_Init(CLzmaEncProps *p); ++ ++/* ---------- CLzmaEncHandle Interface ---------- */ ++ ++/* LzmaEnc_* functions can return the following exit codes: ++Returns: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater in props ++ SZ_ERROR_WRITE - Write callback error. ++ SZ_ERROR_PROGRESS - some break from progress callback ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++typedef void * CLzmaEncHandle; ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); ++SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/include/linux/lzma/Types.h +@@ -0,0 +1,226 @@ ++/* Types.h -- Basic types ++2009-11-23 : Igor Pavlov : Public domain */ ++ ++#ifndef __7Z_TYPES_H ++#define __7Z_TYPES_H ++ ++#include ++ ++#ifdef _WIN32 ++#include ++#endif ++ ++#ifndef EXTERN_C_BEGIN ++#ifdef __cplusplus ++#define EXTERN_C_BEGIN extern "C" { ++#define EXTERN_C_END } ++#else ++#define EXTERN_C_BEGIN ++#define EXTERN_C_END ++#endif ++#endif ++ ++EXTERN_C_BEGIN ++ ++#define SZ_OK 0 ++ ++#define SZ_ERROR_DATA 1 ++#define SZ_ERROR_MEM 2 ++#define SZ_ERROR_CRC 3 ++#define SZ_ERROR_UNSUPPORTED 4 ++#define SZ_ERROR_PARAM 5 ++#define SZ_ERROR_INPUT_EOF 6 ++#define SZ_ERROR_OUTPUT_EOF 7 ++#define SZ_ERROR_READ 8 ++#define SZ_ERROR_WRITE 9 ++#define SZ_ERROR_PROGRESS 10 ++#define SZ_ERROR_FAIL 11 ++#define SZ_ERROR_THREAD 12 ++ ++#define SZ_ERROR_ARCHIVE 16 ++#define SZ_ERROR_NO_ARCHIVE 17 ++ ++typedef int SRes; ++ ++#ifdef _WIN32 ++typedef DWORD WRes; ++#else ++typedef int WRes; ++#endif ++ ++#ifndef RINOK ++#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } ++#endif ++ ++typedef unsigned char Byte; ++typedef short Int16; ++typedef unsigned short UInt16; ++ ++#ifdef _LZMA_UINT32_IS_ULONG ++typedef long Int32; ++typedef unsigned long UInt32; ++#else ++typedef int Int32; ++typedef unsigned int UInt32; ++#endif ++ ++#ifdef _SZ_NO_INT_64 ++ ++/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. ++ NOTES: Some code will work incorrectly in that case! */ ++ ++typedef long Int64; ++typedef unsigned long UInt64; ++ ++#else ++ ++#if defined(_MSC_VER) || defined(__BORLANDC__) ++typedef __int64 Int64; ++typedef unsigned __int64 UInt64; ++#else ++typedef long long int Int64; ++typedef unsigned long long int UInt64; ++#endif ++ ++#endif ++ ++#ifdef _LZMA_NO_SYSTEM_SIZE_T ++typedef UInt32 SizeT; ++#else ++typedef size_t SizeT; ++#endif ++ ++typedef int Bool; ++#define True 1 ++#define False 0 ++ ++ ++#ifdef _WIN32 ++#define MY_STD_CALL __stdcall ++#else ++#define MY_STD_CALL ++#endif ++ ++#ifdef _MSC_VER ++ ++#if _MSC_VER >= 1300 ++#define MY_NO_INLINE __declspec(noinline) ++#else ++#define MY_NO_INLINE ++#endif ++ ++#define MY_CDECL __cdecl ++#define MY_FAST_CALL __fastcall ++ ++#else ++ ++#define MY_CDECL ++#define MY_FAST_CALL ++ ++#endif ++ ++ ++/* The following interfaces use first parameter as pointer to structure */ ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) < input(*size)) is allowed */ ++} ISeqInStream; ++ ++/* it can return SZ_ERROR_INPUT_EOF */ ++SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); ++SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); ++SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); ++ ++typedef struct ++{ ++ size_t (*Write)(void *p, const void *buf, size_t size); ++ /* Returns: result - the number of actually written bytes. ++ (result < size) means error */ ++} ISeqOutStream; ++ ++typedef enum ++{ ++ SZ_SEEK_SET = 0, ++ SZ_SEEK_CUR = 1, ++ SZ_SEEK_END = 2 ++} ESzSeek; ++ ++typedef struct ++{ ++ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ISeekInStream; ++ ++typedef struct ++{ ++ SRes (*Look)(void *p, void **buf, size_t *size); ++ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. ++ (output(*size) > input(*size)) is not allowed ++ (output(*size) < input(*size)) is allowed */ ++ SRes (*Skip)(void *p, size_t offset); ++ /* offset must be <= output(*size) of Look */ ++ ++ SRes (*Read)(void *p, void *buf, size_t *size); ++ /* reads directly (without buffer). It's same as ISeqInStream::Read */ ++ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); ++} ILookInStream; ++ ++SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); ++SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); ++ ++/* reads via ILookInStream::Read */ ++SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); ++SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); ++ ++#define LookToRead_BUF_SIZE (1 << 14) ++ ++typedef struct ++{ ++ ILookInStream s; ++ ISeekInStream *realStream; ++ size_t pos; ++ size_t size; ++ Byte buf[LookToRead_BUF_SIZE]; ++} CLookToRead; ++ ++void LookToRead_CreateVTable(CLookToRead *p, int lookahead); ++void LookToRead_Init(CLookToRead *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToLook; ++ ++void SecToLook_CreateVTable(CSecToLook *p); ++ ++typedef struct ++{ ++ ISeqInStream s; ++ ILookInStream *realStream; ++} CSecToRead; ++ ++void SecToRead_CreateVTable(CSecToRead *p); ++ ++typedef struct ++{ ++ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); ++ /* Returns: result. (result != SZ_OK) means break. ++ Value (UInt64)(Int64)-1 for size means unknown value. */ ++} ICompressProgress; ++ ++typedef struct ++{ ++ void *(*Alloc)(void *p, size_t size); ++ void (*Free)(void *p, void *address); /* address can be 0 */ ++} ISzAlloc; ++ ++#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) ++#define IAlloc_Free(p, a) (p)->Free((p), a) ++ ++EXTERN_C_END ++ ++#endif +--- a/include/uapi/linux/jffs2.h ++++ b/include/uapi/linux/jffs2.h +@@ -46,6 +46,7 @@ + #define JFFS2_COMPR_DYNRUBIN 0x05 + #define JFFS2_COMPR_ZLIB 0x06 + #define JFFS2_COMPR_LZO 0x07 ++#define JFFS2_COMPR_LZMA 0x08 + /* Compatibility flags. */ + #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ + #define JFFS2_NODE_ACCURATE 0x2000 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -340,6 +340,12 @@ config ZSTD_DECOMPRESS + + source "lib/xz/Kconfig" + ++config LZMA_COMPRESS ++ tristate ++ ++config LZMA_DECOMPRESS ++ tristate ++ + # + # These all provide a common interface (hence the apparent duplication with + # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) +--- a/lib/Makefile ++++ b/lib/Makefile +@@ -135,6 +135,16 @@ CFLAGS_kobject.o += -DDEBUG + CFLAGS_kobject_uevent.o += -DDEBUG + endif + ++ifdef CONFIG_JFFS2_ZLIB ++ CONFIG_ZLIB_INFLATE:=y ++ CONFIG_ZLIB_DEFLATE:=y ++endif ++ ++ifdef CONFIG_JFFS2_LZMA ++ CONFIG_LZMA_DECOMPRESS:=y ++ CONFIG_LZMA_COMPRESS:=y ++endif ++ + obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o + CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) + +@@ -192,6 +202,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ + obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ + obj-$(CONFIG_XZ_DEC) += xz/ + obj-$(CONFIG_RAID6_PQ) += raid6/ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma/ ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma/ + + lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o + lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o +--- /dev/null ++++ b/lib/lzma/LzFind.c +@@ -0,0 +1,522 @@ ++/* LzFind.c -- Match finder for LZ algorithms ++2009-04-22 : Igor Pavlov : Public domain */ ++ ++#include ++ ++#include "LzFind.h" ++#include "LzHash.h" ++ ++#define kEmptyHashValue 0 ++#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) ++#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ ++#define kNormalizeMask (~(kNormalizeStepMin - 1)) ++#define kMaxHistorySize ((UInt32)3 << 30) ++ ++#define kStartMaxLen 3 ++ ++#if 0 ++#define DIRECT_INPUT p->directInput ++#else ++#define DIRECT_INPUT 1 ++#endif ++ ++static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ if (!DIRECT_INPUT) ++ { ++ alloc->Free(alloc, p->bufferBase); ++ p->bufferBase = 0; ++ } ++} ++ ++/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ ++ ++static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) ++{ ++ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; ++ if (DIRECT_INPUT) ++ { ++ p->blockSize = blockSize; ++ return 1; ++ } ++ if (p->bufferBase == 0 || p->blockSize != blockSize) ++ { ++ LzInWindow_Free(p, alloc); ++ p->blockSize = blockSize; ++ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); ++ } ++ return (p->bufferBase != 0); ++} ++ ++static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++ ++static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++ ++static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++{ ++ p->posLimit -= subValue; ++ p->pos -= subValue; ++ p->streamPos -= subValue; ++} ++ ++static void MatchFinder_ReadBlock(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached || p->result != SZ_OK) ++ return; ++ if (DIRECT_INPUT) ++ { ++ UInt32 curSize = 0xFFFFFFFF - p->streamPos; ++ if (curSize > p->directInputRem) ++ curSize = (UInt32)p->directInputRem; ++ p->directInputRem -= curSize; ++ p->streamPos += curSize; ++ if (p->directInputRem == 0) ++ p->streamEndWasReached = 1; ++ return; ++ } ++ for (;;) ++ { ++ Byte *dest = p->buffer + (p->streamPos - p->pos); ++ size_t size = (p->bufferBase + p->blockSize - dest); ++ if (size == 0) ++ return; ++ p->result = p->stream->Read(p->stream, dest, &size); ++ if (p->result != SZ_OK) ++ return; ++ if (size == 0) ++ { ++ p->streamEndWasReached = 1; ++ return; ++ } ++ p->streamPos += (UInt32)size; ++ if (p->streamPos - p->pos > p->keepSizeAfter) ++ return; ++ } ++} ++ ++static void MatchFinder_MoveBlock(CMatchFinder *p) ++{ ++ memmove(p->bufferBase, ++ p->buffer - p->keepSizeBefore, ++ (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); ++ p->buffer = p->bufferBase + p->keepSizeBefore; ++} ++ ++static int MatchFinder_NeedMove(CMatchFinder *p) ++{ ++ if (DIRECT_INPUT) ++ return 0; ++ /* if (p->streamEndWasReached) return 0; */ ++ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); ++} ++ ++static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) ++{ ++ if (MatchFinder_NeedMove(p)) ++ MatchFinder_MoveBlock(p); ++ MatchFinder_ReadBlock(p); ++} ++ ++static void MatchFinder_SetDefaultSettings(CMatchFinder *p) ++{ ++ p->cutValue = 32; ++ p->btMode = 1; ++ p->numHashBytes = 4; ++ p->bigHash = 0; ++} ++ ++#define kCrcPoly 0xEDB88320 ++ ++void MatchFinder_Construct(CMatchFinder *p) ++{ ++ UInt32 i; ++ p->bufferBase = 0; ++ p->directInput = 0; ++ p->hash = 0; ++ MatchFinder_SetDefaultSettings(p); ++ ++ for (i = 0; i < 256; i++) ++ { ++ UInt32 r = i; ++ int j; ++ for (j = 0; j < 8; j++) ++ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); ++ p->crc[i] = r; ++ } ++} ++ ++static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->hash); ++ p->hash = 0; ++} ++ ++void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) ++{ ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ LzInWindow_Free(p, alloc); ++} ++ ++static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) ++{ ++ size_t sizeInBytes = (size_t)num * sizeof(CLzRef); ++ if (sizeInBytes / sizeof(CLzRef) != num) ++ return 0; ++ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); ++} ++ ++int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, ++ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ++ ISzAlloc *alloc) ++{ ++ UInt32 sizeReserv; ++ if (historySize > kMaxHistorySize) ++ { ++ MatchFinder_Free(p, alloc); ++ return 0; ++ } ++ sizeReserv = historySize >> 1; ++ if (historySize > ((UInt32)2 << 30)) ++ sizeReserv = historySize >> 2; ++ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); ++ ++ p->keepSizeBefore = historySize + keepAddBufferBefore + 1; ++ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; ++ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ ++ if (LzInWindow_Create(p, sizeReserv, alloc)) ++ { ++ UInt32 newCyclicBufferSize = historySize + 1; ++ UInt32 hs; ++ p->matchMaxLen = matchMaxLen; ++ { ++ p->fixedHashSize = 0; ++ if (p->numHashBytes == 2) ++ hs = (1 << 16) - 1; ++ else ++ { ++ hs = historySize - 1; ++ hs |= (hs >> 1); ++ hs |= (hs >> 2); ++ hs |= (hs >> 4); ++ hs |= (hs >> 8); ++ hs >>= 1; ++ hs |= 0xFFFF; /* don't change it! It's required for Deflate */ ++ if (hs > (1 << 24)) ++ { ++ if (p->numHashBytes == 3) ++ hs = (1 << 24) - 1; ++ else ++ hs >>= 1; ++ } ++ } ++ p->hashMask = hs; ++ hs++; ++ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; ++ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; ++ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; ++ hs += p->fixedHashSize; ++ } ++ ++ { ++ UInt32 prevSize = p->hashSizeSum + p->numSons; ++ UInt32 newSize; ++ p->historySize = historySize; ++ p->hashSizeSum = hs; ++ p->cyclicBufferSize = newCyclicBufferSize; ++ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); ++ newSize = p->hashSizeSum + p->numSons; ++ if (p->hash != 0 && prevSize == newSize) ++ return 1; ++ MatchFinder_FreeThisClassMemory(p, alloc); ++ p->hash = AllocRefs(newSize, alloc); ++ if (p->hash != 0) ++ { ++ p->son = p->hash + p->hashSizeSum; ++ return 1; ++ } ++ } ++ } ++ MatchFinder_Free(p, alloc); ++ return 0; ++} ++ ++static void MatchFinder_SetLimits(CMatchFinder *p) ++{ ++ UInt32 limit = kMaxValForNormalize - p->pos; ++ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; ++ if (limit2 < limit) ++ limit = limit2; ++ limit2 = p->streamPos - p->pos; ++ if (limit2 <= p->keepSizeAfter) ++ { ++ if (limit2 > 0) ++ limit2 = 1; ++ } ++ else ++ limit2 -= p->keepSizeAfter; ++ if (limit2 < limit) ++ limit = limit2; ++ { ++ UInt32 lenLimit = p->streamPos - p->pos; ++ if (lenLimit > p->matchMaxLen) ++ lenLimit = p->matchMaxLen; ++ p->lenLimit = lenLimit; ++ } ++ p->posLimit = p->pos + limit; ++} ++ ++static void MatchFinder_Init(CMatchFinder *p) ++{ ++ UInt32 i; ++ for (i = 0; i < p->hashSizeSum; i++) ++ p->hash[i] = kEmptyHashValue; ++ p->cyclicBufferPos = 0; ++ p->buffer = p->bufferBase; ++ p->pos = p->streamPos = p->cyclicBufferSize; ++ p->result = SZ_OK; ++ p->streamEndWasReached = 0; ++ MatchFinder_ReadBlock(p); ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) ++{ ++ return (p->pos - p->historySize - 1) & kNormalizeMask; ++} ++ ++static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++{ ++ UInt32 i; ++ for (i = 0; i < numItems; i++) ++ { ++ UInt32 value = items[i]; ++ if (value <= subValue) ++ value = kEmptyHashValue; ++ else ++ value -= subValue; ++ items[i] = value; ++ } ++} ++ ++static void MatchFinder_Normalize(CMatchFinder *p) ++{ ++ UInt32 subValue = MatchFinder_GetSubValue(p); ++ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); ++ MatchFinder_ReduceOffsets(p, subValue); ++} ++ ++static void MatchFinder_CheckLimits(CMatchFinder *p) ++{ ++ if (p->pos == kMaxValForNormalize) ++ MatchFinder_Normalize(p); ++ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) ++ MatchFinder_CheckAndMoveAndRead(p); ++ if (p->cyclicBufferPos == p->cyclicBufferSize) ++ p->cyclicBufferPos = 0; ++ MatchFinder_SetLimits(p); ++} ++ ++static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return distances; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ if (++len != lenLimit && pb[len] == cur[len]) ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return distances; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) ++{ ++ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; ++ CLzRef *ptr1 = son + (_cyclicBufferPos << 1); ++ UInt32 len0 = 0, len1 = 0; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ { ++ *ptr0 = *ptr1 = kEmptyHashValue; ++ return; ++ } ++ { ++ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); ++ const Byte *pb = cur - delta; ++ UInt32 len = (len0 < len1 ? len0 : len1); ++ if (pb[len] == cur[len]) ++ { ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ { ++ if (len == lenLimit) ++ { ++ *ptr1 = pair[0]; ++ *ptr0 = pair[1]; ++ return; ++ } ++ } ++ } ++ if (pb[len] < cur[len]) ++ { ++ *ptr1 = curMatch; ++ ptr1 = pair + 1; ++ curMatch = *ptr1; ++ len1 = len; ++ } ++ else ++ { ++ *ptr0 = curMatch; ++ ptr0 = pair; ++ curMatch = *ptr0; ++ len0 = len; ++ } ++ } ++ } ++} ++ ++#define MOVE_POS \ ++ ++p->cyclicBufferPos; \ ++ p->buffer++; \ ++ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); ++ ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++ ++#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++ ++#define GET_MATCHES_HEADER2(minLen, ret_op) \ ++ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ ++ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ ++ cur = p->buffer; ++ ++#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) ++#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) ++ ++#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue ++ ++#define GET_MATCHES_FOOTER(offset, maxLen) \ ++ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ ++ distances + offset, maxLen) - distances); MOVE_POS_RET; ++ ++#define SKIP_FOOTER \ ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); ++ ++static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ GET_MATCHES_FOOTER(offset, maxLen) ++} ++ ++static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = p->pos; ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) ++{ ++ vTable->Init = (Mf_Init_Func)MatchFinder_Init; ++ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; ++ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; ++ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++} +--- /dev/null ++++ b/lib/lzma/LzmaDec.c +@@ -0,0 +1,925 @@ ++/* LzmaDec.c -- LZMA Decoder ++2009-09-20 : Igor Pavlov : Public domain */ ++ ++#include "LzmaDec.h" ++ ++#include ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++ ++#define RC_INIT_SIZE 5 ++ ++#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); ++#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); ++#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ ++ { UPDATE_0(p); i = (i + i); A0; } else \ ++ { UPDATE_1(p); i = (i + i) + 1; A1; } ++#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) ++ ++#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } ++#define TREE_DECODE(probs, limit, i) \ ++ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } ++ ++/* #define _LZMA_SIZE_OPT */ ++ ++#ifdef _LZMA_SIZE_OPT ++#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) ++#else ++#define TREE_6_DECODE(probs, i) \ ++ { i = 1; \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ TREE_GET_BIT(probs, i); \ ++ i -= 0x40; } ++#endif ++ ++#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } ++ ++#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) ++#define UPDATE_0_CHECK range = bound; ++#define UPDATE_1_CHECK range -= bound; code -= bound; ++#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ ++ { UPDATE_0_CHECK; i = (i + i); A0; } else \ ++ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } ++#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) ++#define TREE_DECODE_CHECK(probs, limit, i) \ ++ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } ++ ++ ++#define kNumPosBitsMax 4 ++#define kNumPosStatesMax (1 << kNumPosBitsMax) ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define LenChoice 0 ++#define LenChoice2 (LenChoice + 1) ++#define LenLow (LenChoice2 + 1) ++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) ++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) ++#define kNumLenProbs (LenHigh + kLenNumHighSymbols) ++ ++ ++#define kNumStates 12 ++#define kNumLitStates 7 ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#define kNumPosSlotBits 6 ++#define kNumLenToPosStates 4 ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++ ++#define kMatchMinLen 2 ++#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define IsMatch 0 ++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) ++#define IsRepG0 (IsRep + kNumStates) ++#define IsRepG1 (IsRepG0 + kNumStates) ++#define IsRepG2 (IsRepG1 + kNumStates) ++#define IsRep0Long (IsRepG2 + kNumStates) ++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) ++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) ++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) ++#define LenCoder (Align + kAlignTableSize) ++#define RepLenCoder (LenCoder + kNumLenProbs) ++#define Literal (RepLenCoder + kNumLenProbs) ++ ++#define LZMA_BASE_SIZE 1846 ++#define LZMA_LIT_SIZE 768 ++ ++#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) ++ ++#if Literal != LZMA_BASE_SIZE ++StopCompilingDueBUG ++#endif ++ ++#define LZMA_DIC_MIN (1 << 12) ++ ++/* First LZMA-symbol is always decoded. ++And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization ++Out: ++ Result: ++ SZ_OK - OK ++ SZ_ERROR_DATA - Error ++ p->remainLen: ++ < kMatchSpecLenStart : normal remain ++ = kMatchSpecLenStart : finished ++ = kMatchSpecLenStart + 1 : Flush marker ++ = kMatchSpecLenStart + 2 : State Init Marker ++*/ ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ CLzmaProb *probs = p->probs; ++ ++ unsigned state = p->state; ++ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; ++ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; ++ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; ++ unsigned lc = p->prop.lc; ++ ++ Byte *dic = p->dic; ++ SizeT dicBufSize = p->dicBufSize; ++ SizeT dicPos = p->dicPos; ++ ++ UInt32 processedPos = p->processedPos; ++ UInt32 checkDicSize = p->checkDicSize; ++ unsigned len = 0; ++ ++ const Byte *buf = p->buf; ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ ++ do ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = processedPos & pbMask; ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ unsigned symbol; ++ UPDATE_0(prob); ++ prob = probs + Literal; ++ if (checkDicSize != 0 || processedPos != 0) ++ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + ++ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ state -= (state < 4) ? state : 3; ++ symbol = 1; ++ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ state -= (state < 10) ? 3 : 6; ++ symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ dic[dicPos++] = (Byte)symbol; ++ processedPos++; ++ continue; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRep + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ state += kNumStates; ++ prob = probs + LenCoder; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ if (checkDicSize == 0 && processedPos == 0) ++ return SZ_ERROR_DATA; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ processedPos++; ++ state = state < kNumLitStates ? 9 : 11; ++ continue; ++ } ++ UPDATE_1(prob); ++ } ++ else ++ { ++ UInt32 distance; ++ UPDATE_1(prob); ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep1; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0(prob) ++ { ++ UPDATE_0(prob); ++ distance = rep2; ++ } ++ else ++ { ++ UPDATE_1(prob); ++ distance = rep3; ++ rep3 = rep2; ++ } ++ rep2 = rep1; ++ } ++ rep1 = rep0; ++ rep0 = distance; ++ } ++ state = state < kNumLitStates ? 8 : 11; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = (1 << kLenNumLowBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenChoice2; ++ IF_BIT_0(probLen) ++ { ++ UPDATE_0(probLen); ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = (1 << kLenNumMidBits); ++ } ++ else ++ { ++ UPDATE_1(probLen); ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = (1 << kLenNumHighBits); ++ } ++ } ++ TREE_DECODE(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state >= kNumStates) ++ { ++ UInt32 distance; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); ++ TREE_6_DECODE(prob, distance); ++ if (distance >= kStartPosModelIndex) ++ { ++ unsigned posSlot = (unsigned)distance; ++ int numDirectBits = (int)(((distance >> 1) - 1)); ++ distance = (2 | (distance & 1)); ++ if (posSlot < kEndPosModelIndex) ++ { ++ distance <<= numDirectBits; ++ prob = probs + SpecPos + distance - posSlot - 1; ++ { ++ UInt32 mask = 1; ++ unsigned i = 1; ++ do ++ { ++ GET_BIT2(prob + i, i, ; , distance |= mask); ++ mask <<= 1; ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE ++ range >>= 1; ++ ++ { ++ UInt32 t; ++ code -= range; ++ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ ++ distance = (distance << 1) + (t + 1); ++ code += range & t; ++ } ++ /* ++ distance <<= 1; ++ if (code >= range) ++ { ++ code -= range; ++ distance |= 1; ++ } ++ */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ distance <<= kNumAlignBits; ++ { ++ unsigned i = 1; ++ GET_BIT2(prob + i, i, ; , distance |= 1); ++ GET_BIT2(prob + i, i, ; , distance |= 2); ++ GET_BIT2(prob + i, i, ; , distance |= 4); ++ GET_BIT2(prob + i, i, ; , distance |= 8); ++ } ++ if (distance == (UInt32)0xFFFFFFFF) ++ { ++ len += kMatchSpecLenStart; ++ state -= kNumStates; ++ break; ++ } ++ } ++ } ++ rep3 = rep2; ++ rep2 = rep1; ++ rep1 = rep0; ++ rep0 = distance + 1; ++ if (checkDicSize == 0) ++ { ++ if (distance >= processedPos) ++ return SZ_ERROR_DATA; ++ } ++ else if (distance >= checkDicSize) ++ return SZ_ERROR_DATA; ++ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; ++ } ++ ++ len += kMatchMinLen; ++ ++ if (limit == dicPos) ++ return SZ_ERROR_DATA; ++ { ++ SizeT rem = limit - dicPos; ++ unsigned curLen = ((rem < len) ? (unsigned)rem : len); ++ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); ++ ++ processedPos += curLen; ++ ++ len -= curLen; ++ if (pos + curLen <= dicBufSize) ++ { ++ Byte *dest = dic + dicPos; ++ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; ++ const Byte *lim = dest + curLen; ++ dicPos += curLen; ++ do ++ *(dest) = (Byte)*(dest + src); ++ while (++dest != lim); ++ } ++ else ++ { ++ do ++ { ++ dic[dicPos++] = dic[pos]; ++ if (++pos == dicBufSize) ++ pos = 0; ++ } ++ while (--curLen != 0); ++ } ++ } ++ } ++ } ++ while (dicPos < limit && buf < bufLimit); ++ NORMALIZE; ++ p->buf = buf; ++ p->range = range; ++ p->code = code; ++ p->remainLen = len; ++ p->dicPos = dicPos; ++ p->processedPos = processedPos; ++ p->reps[0] = rep0; ++ p->reps[1] = rep1; ++ p->reps[2] = rep2; ++ p->reps[3] = rep3; ++ p->state = state; ++ ++ return SZ_OK; ++} ++ ++static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) ++{ ++ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) ++ { ++ Byte *dic = p->dic; ++ SizeT dicPos = p->dicPos; ++ SizeT dicBufSize = p->dicBufSize; ++ unsigned len = p->remainLen; ++ UInt32 rep0 = p->reps[0]; ++ if (limit - dicPos < len) ++ len = (unsigned)(limit - dicPos); ++ ++ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) ++ p->checkDicSize = p->prop.dicSize; ++ ++ p->processedPos += len; ++ p->remainLen -= len; ++ while (len-- != 0) ++ { ++ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; ++ dicPos++; ++ } ++ p->dicPos = dicPos; ++ } ++} ++ ++static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) ++{ ++ do ++ { ++ SizeT limit2 = limit; ++ if (p->checkDicSize == 0) ++ { ++ UInt32 rem = p->prop.dicSize - p->processedPos; ++ if (limit - p->dicPos > rem) ++ limit2 = p->dicPos + rem; ++ } ++ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); ++ if (p->processedPos >= p->prop.dicSize) ++ p->checkDicSize = p->prop.dicSize; ++ LzmaDec_WriteRem(p, limit); ++ } ++ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); ++ ++ if (p->remainLen > kMatchSpecLenStart) ++ { ++ p->remainLen = kMatchSpecLenStart; ++ } ++ return 0; ++} ++ ++typedef enum ++{ ++ DUMMY_ERROR, /* unexpected end of input stream */ ++ DUMMY_LIT, ++ DUMMY_MATCH, ++ DUMMY_REP ++} ELzmaDummy; ++ ++static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) ++{ ++ UInt32 range = p->range; ++ UInt32 code = p->code; ++ const Byte *bufLimit = buf + inSize; ++ CLzmaProb *probs = p->probs; ++ unsigned state = p->state; ++ ELzmaDummy res; ++ ++ { ++ CLzmaProb *prob; ++ UInt32 bound; ++ unsigned ttt; ++ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); ++ ++ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK ++ ++ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ ++ ++ prob = probs + Literal; ++ if (p->checkDicSize != 0 || p->processedPos != 0) ++ prob += (LZMA_LIT_SIZE * ++ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + ++ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); ++ ++ if (state < kNumLitStates) ++ { ++ unsigned symbol = 1; ++ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); ++ } ++ else ++ { ++ unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ++ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; ++ unsigned offs = 0x100; ++ unsigned symbol = 1; ++ do ++ { ++ unsigned bit; ++ CLzmaProb *probLit; ++ matchByte <<= 1; ++ bit = (matchByte & offs); ++ probLit = prob + offs + bit + symbol; ++ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) ++ } ++ while (symbol < 0x100); ++ } ++ res = DUMMY_LIT; ++ } ++ else ++ { ++ unsigned len; ++ UPDATE_1_CHECK; ++ ++ prob = probs + IsRep + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ state = 0; ++ prob = probs + LenCoder; ++ res = DUMMY_MATCH; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ res = DUMMY_REP; ++ prob = probs + IsRepG0 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ NORMALIZE_CHECK; ++ return DUMMY_REP; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG1 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ prob = probs + IsRepG2 + state; ++ IF_BIT_0_CHECK(prob) ++ { ++ UPDATE_0_CHECK; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ } ++ } ++ } ++ state = kNumStates; ++ prob = probs + RepLenCoder; ++ } ++ { ++ unsigned limit, offset; ++ CLzmaProb *probLen = prob + LenChoice; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenLow + (posState << kLenNumLowBits); ++ offset = 0; ++ limit = 1 << kLenNumLowBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenChoice2; ++ IF_BIT_0_CHECK(probLen) ++ { ++ UPDATE_0_CHECK; ++ probLen = prob + LenMid + (posState << kLenNumMidBits); ++ offset = kLenNumLowSymbols; ++ limit = 1 << kLenNumMidBits; ++ } ++ else ++ { ++ UPDATE_1_CHECK; ++ probLen = prob + LenHigh; ++ offset = kLenNumLowSymbols + kLenNumMidSymbols; ++ limit = 1 << kLenNumHighBits; ++ } ++ } ++ TREE_DECODE_CHECK(probLen, limit, len); ++ len += offset; ++ } ++ ++ if (state < 4) ++ { ++ unsigned posSlot; ++ prob = probs + PosSlot + ++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << ++ kNumPosSlotBits); ++ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); ++ if (posSlot >= kStartPosModelIndex) ++ { ++ int numDirectBits = ((posSlot >> 1) - 1); ++ ++ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ ++ ++ if (posSlot < kEndPosModelIndex) ++ { ++ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; ++ } ++ else ++ { ++ numDirectBits -= kNumAlignBits; ++ do ++ { ++ NORMALIZE_CHECK ++ range >>= 1; ++ code -= range & (((code - range) >> 31) - 1); ++ /* if (code >= range) code -= range; */ ++ } ++ while (--numDirectBits != 0); ++ prob = probs + Align; ++ numDirectBits = kNumAlignBits; ++ } ++ { ++ unsigned i = 1; ++ do ++ { ++ GET_BIT_CHECK(prob + i, i); ++ } ++ while (--numDirectBits != 0); ++ } ++ } ++ } ++ } ++ } ++ NORMALIZE_CHECK; ++ return res; ++} ++ ++ ++static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) ++{ ++ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); ++ p->range = 0xFFFFFFFF; ++ p->needFlush = 0; ++} ++ ++static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++{ ++ p->needFlush = 1; ++ p->remainLen = 0; ++ p->tempBufSize = 0; ++ ++ if (initDic) ++ { ++ p->processedPos = 0; ++ p->checkDicSize = 0; ++ p->needInitState = 1; ++ } ++ if (initState) ++ p->needInitState = 1; ++} ++ ++static void LzmaDec_Init(CLzmaDec *p) ++{ ++ p->dicPos = 0; ++ LzmaDec_InitDicAndState(p, True, True); ++} ++ ++static void LzmaDec_InitStateReal(CLzmaDec *p) ++{ ++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); ++ UInt32 i; ++ CLzmaProb *probs = p->probs; ++ for (i = 0; i < numProbs; i++) ++ probs[i] = kBitModelTotal >> 1; ++ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; ++ p->state = 0; ++ p->needInitState = 0; ++} ++ ++static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++ ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT inSize = *srcLen; ++ (*srcLen) = 0; ++ LzmaDec_WriteRem(p, dicLimit); ++ ++ *status = LZMA_STATUS_NOT_SPECIFIED; ++ ++ while (p->remainLen != kMatchSpecLenStart) ++ { ++ int checkEndMarkNow; ++ ++ if (p->needFlush != 0) ++ { ++ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) ++ p->tempBuf[p->tempBufSize++] = *src++; ++ if (p->tempBufSize < RC_INIT_SIZE) ++ { ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (p->tempBuf[0] != 0) ++ return SZ_ERROR_DATA; ++ ++ LzmaDec_InitRc(p, p->tempBuf); ++ p->tempBufSize = 0; ++ } ++ ++ checkEndMarkNow = 0; ++ if (p->dicPos >= dicLimit) ++ { ++ if (p->remainLen == 0 && p->code == 0) ++ { ++ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; ++ return SZ_OK; ++ } ++ if (finishMode == LZMA_FINISH_ANY) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_OK; ++ } ++ if (p->remainLen != 0) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ checkEndMarkNow = 1; ++ } ++ ++ if (p->needInitState) ++ LzmaDec_InitStateReal(p); ++ ++ if (p->tempBufSize == 0) ++ { ++ SizeT processed; ++ const Byte *bufLimit; ++ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, src, inSize); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ memcpy(p->tempBuf, src, inSize); ++ p->tempBufSize = (unsigned)inSize; ++ (*srcLen) += inSize; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ bufLimit = src; ++ } ++ else ++ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; ++ p->buf = src; ++ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) ++ return SZ_ERROR_DATA; ++ processed = (SizeT)(p->buf - src); ++ (*srcLen) += processed; ++ src += processed; ++ inSize -= processed; ++ } ++ else ++ { ++ unsigned rem = p->tempBufSize, lookAhead = 0; ++ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) ++ p->tempBuf[rem++] = src[lookAhead++]; ++ p->tempBufSize = rem; ++ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) ++ { ++ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); ++ if (dummyRes == DUMMY_ERROR) ++ { ++ (*srcLen) += lookAhead; ++ *status = LZMA_STATUS_NEEDS_MORE_INPUT; ++ return SZ_OK; ++ } ++ if (checkEndMarkNow && dummyRes != DUMMY_MATCH) ++ { ++ *status = LZMA_STATUS_NOT_FINISHED; ++ return SZ_ERROR_DATA; ++ } ++ } ++ p->buf = p->tempBuf; ++ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) ++ return SZ_ERROR_DATA; ++ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); ++ (*srcLen) += lookAhead; ++ src += lookAhead; ++ inSize -= lookAhead; ++ p->tempBufSize = 0; ++ } ++ } ++ if (p->code == 0) ++ *status = LZMA_STATUS_FINISHED_WITH_MARK; ++ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; ++} ++ ++static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->probs); ++ p->probs = 0; ++} ++ ++static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++{ ++ UInt32 dicSize; ++ Byte d; ++ ++ if (size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_UNSUPPORTED; ++ else ++ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); ++ ++ if (dicSize < LZMA_DIC_MIN) ++ dicSize = LZMA_DIC_MIN; ++ p->dicSize = dicSize; ++ ++ d = data[0]; ++ if (d >= (9 * 5 * 5)) ++ return SZ_ERROR_UNSUPPORTED; ++ ++ p->lc = d % 9; ++ d /= 9; ++ p->pb = d / 5; ++ p->lp = d % 5; ++ ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) ++{ ++ UInt32 numProbs = LzmaProps_GetNumProbs(propNew); ++ if (p->probs == 0 || numProbs != p->numProbs) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); ++ p->numProbs = numProbs; ++ if (p->probs == 0) ++ return SZ_ERROR_MEM; ++ } ++ return SZ_OK; ++} ++ ++static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ p->prop = propNew; ++ return SZ_OK; ++} ++ ++SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ++ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ++ ELzmaStatus *status, ISzAlloc *alloc) ++{ ++ CLzmaDec p; ++ SRes res; ++ SizeT inSize = *srcLen; ++ SizeT outSize = *destLen; ++ *srcLen = *destLen = 0; ++ if (inSize < RC_INIT_SIZE) ++ return SZ_ERROR_INPUT_EOF; ++ ++ LzmaDec_Construct(&p); ++ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); ++ if (res != 0) ++ return res; ++ p.dic = dest; ++ p.dicBufSize = outSize; ++ ++ LzmaDec_Init(&p); ++ ++ *srcLen = inSize; ++ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); ++ ++ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) ++ res = SZ_ERROR_INPUT_EOF; ++ ++ (*destLen) = p.dicPos; ++ LzmaDec_FreeProbs(&p, alloc); ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/LzmaEnc.c +@@ -0,0 +1,2123 @@ ++/* LzmaEnc.c -- LZMA Encoder ++2009-11-24 : Igor Pavlov : Public domain */ ++ ++#include ++ ++/* #define SHOW_STAT */ ++/* #define SHOW_STAT2 */ ++ ++#if defined(SHOW_STAT) || defined(SHOW_STAT2) ++#include ++#endif ++ ++#include "LzmaEnc.h" ++ ++/* disable MT */ ++#define _7ZIP_ST ++ ++#include "LzFind.h" ++#ifndef _7ZIP_ST ++#include "LzFindMt.h" ++#endif ++ ++#ifdef SHOW_STAT ++static int ttt = 0; ++#endif ++ ++#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) ++ ++#define kBlockSize (9 << 10) ++#define kUnpackBlockSize (1 << 18) ++#define kMatchArraySize (1 << 21) ++#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) ++ ++#define kNumMaxDirectBits (31) ++ ++#define kNumTopBits 24 ++#define kTopValue ((UInt32)1 << kNumTopBits) ++ ++#define kNumBitModelTotalBits 11 ++#define kBitModelTotal (1 << kNumBitModelTotalBits) ++#define kNumMoveBits 5 ++#define kProbInitValue (kBitModelTotal >> 1) ++ ++#define kNumMoveReducingBits 4 ++#define kNumBitPriceShiftBits 4 ++#define kBitPrice (1 << kNumBitPriceShiftBits) ++ ++void LzmaEncProps_Init(CLzmaEncProps *p) ++{ ++ p->level = 5; ++ p->dictSize = p->mc = 0; ++ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; ++ p->writeEndMark = 0; ++} ++ ++static void LzmaEncProps_Normalize(CLzmaEncProps *p) ++{ ++ int level = p->level; ++ if (level < 0) level = 5; ++ p->level = level; ++ if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); ++ if (p->lc < 0) p->lc = 3; ++ if (p->lp < 0) p->lp = 0; ++ if (p->pb < 0) p->pb = 2; ++ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); ++ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); ++ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); ++ if (p->numHashBytes < 0) p->numHashBytes = 4; ++ if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); ++ if (p->numThreads < 0) ++ p->numThreads = ++ #ifndef _7ZIP_ST ++ ((p->btMode && p->algo) ? 2 : 1); ++ #else ++ 1; ++ #endif ++} ++ ++static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++{ ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ return props.dictSize; ++} ++ ++/* #define LZMA_LOG_BSR */ ++/* Define it for Intel's CPU */ ++ ++ ++#ifdef LZMA_LOG_BSR ++ ++#define kDicLogSizeMaxCompress 30 ++ ++#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } ++ ++static UInt32 GetPosSlot1(UInt32 pos) ++{ ++ UInt32 res; ++ BSR2_RET(pos, res); ++ return res; ++} ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } ++ ++#else ++ ++#define kNumLogBits (9 + (int)sizeof(size_t) / 2) ++#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) ++ ++static void LzmaEnc_FastPosInit(Byte *g_FastPos) ++{ ++ int c = 2, slotFast; ++ g_FastPos[0] = 0; ++ g_FastPos[1] = 1; ++ ++ for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) ++ { ++ UInt32 k = (1 << ((slotFast >> 1) - 1)); ++ UInt32 j; ++ for (j = 0; j < k; j++, c++) ++ g_FastPos[c] = (Byte)slotFast; ++ } ++} ++ ++#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ ++ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ ++ res = p->g_FastPos[pos >> i] + (i * 2); } ++/* ++#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ ++ p->g_FastPos[pos >> 6] + 12 : \ ++ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } ++*/ ++ ++#define GetPosSlot1(pos) p->g_FastPos[pos] ++#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } ++#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } ++ ++#endif ++ ++ ++#define LZMA_NUM_REPS 4 ++ ++typedef unsigned CState; ++ ++typedef struct ++{ ++ UInt32 price; ++ ++ CState state; ++ int prev1IsChar; ++ int prev2; ++ ++ UInt32 posPrev2; ++ UInt32 backPrev2; ++ ++ UInt32 posPrev; ++ UInt32 backPrev; ++ UInt32 backs[LZMA_NUM_REPS]; ++} COptimal; ++ ++#define kNumOpts (1 << 12) ++ ++#define kNumLenToPosStates 4 ++#define kNumPosSlotBits 6 ++#define kDicLogSizeMin 0 ++#define kDicLogSizeMax 32 ++#define kDistTableSizeMax (kDicLogSizeMax * 2) ++ ++ ++#define kNumAlignBits 4 ++#define kAlignTableSize (1 << kNumAlignBits) ++#define kAlignMask (kAlignTableSize - 1) ++ ++#define kStartPosModelIndex 4 ++#define kEndPosModelIndex 14 ++#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) ++ ++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) ++ ++#ifdef _LZMA_PROB32 ++#define CLzmaProb UInt32 ++#else ++#define CLzmaProb UInt16 ++#endif ++ ++#define LZMA_PB_MAX 4 ++#define LZMA_LC_MAX 8 ++#define LZMA_LP_MAX 4 ++ ++#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) ++ ++ ++#define kLenNumLowBits 3 ++#define kLenNumLowSymbols (1 << kLenNumLowBits) ++#define kLenNumMidBits 3 ++#define kLenNumMidSymbols (1 << kLenNumMidBits) ++#define kLenNumHighBits 8 ++#define kLenNumHighSymbols (1 << kLenNumHighBits) ++ ++#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) ++ ++#define LZMA_MATCH_LEN_MIN 2 ++#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) ++ ++#define kNumStates 12 ++ ++typedef struct ++{ ++ CLzmaProb choice; ++ CLzmaProb choice2; ++ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; ++ CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; ++ CLzmaProb high[kLenNumHighSymbols]; ++} CLenEnc; ++ ++typedef struct ++{ ++ CLenEnc p; ++ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; ++ UInt32 tableSize; ++ UInt32 counters[LZMA_NUM_PB_STATES_MAX]; ++} CLenPriceEnc; ++ ++typedef struct ++{ ++ UInt32 range; ++ Byte cache; ++ UInt64 low; ++ UInt64 cacheSize; ++ Byte *buf; ++ Byte *bufLim; ++ Byte *bufBase; ++ ISeqOutStream *outStream; ++ UInt64 processed; ++ SRes res; ++} CRangeEnc; ++ ++typedef struct ++{ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++} CSaveState; ++ ++typedef struct ++{ ++ IMatchFinder matchFinder; ++ void *matchFinderObj; ++ ++ #ifndef _7ZIP_ST ++ Bool mtMode; ++ CMatchFinderMt matchFinderMt; ++ #endif ++ ++ CMatchFinder matchFinderBase; ++ ++ #ifndef _7ZIP_ST ++ Byte pad[128]; ++ #endif ++ ++ UInt32 optimumEndIndex; ++ UInt32 optimumCurrentIndex; ++ ++ UInt32 longestMatchLength; ++ UInt32 numPairs; ++ UInt32 numAvail; ++ COptimal opt[kNumOpts]; ++ ++ #ifndef LZMA_LOG_BSR ++ Byte g_FastPos[1 << kNumLogBits]; ++ #endif ++ ++ UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; ++ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; ++ UInt32 numFastBytes; ++ UInt32 additionalOffset; ++ UInt32 reps[LZMA_NUM_REPS]; ++ UInt32 state; ++ ++ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; ++ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; ++ UInt32 alignPrices[kAlignTableSize]; ++ UInt32 alignPriceCount; ++ ++ UInt32 distTableSize; ++ ++ unsigned lc, lp, pb; ++ unsigned lpMask, pbMask; ++ ++ CLzmaProb *litProbs; ++ ++ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ CLzmaProb isRep[kNumStates]; ++ CLzmaProb isRepG0[kNumStates]; ++ CLzmaProb isRepG1[kNumStates]; ++ CLzmaProb isRepG2[kNumStates]; ++ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; ++ ++ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; ++ CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; ++ CLzmaProb posAlignEncoder[1 << kNumAlignBits]; ++ ++ CLenPriceEnc lenEnc; ++ CLenPriceEnc repLenEnc; ++ ++ unsigned lclp; ++ ++ Bool fastMode; ++ ++ CRangeEnc rc; ++ ++ Bool writeEndMark; ++ UInt64 nowPos64; ++ UInt32 matchPriceCount; ++ Bool finished; ++ Bool multiThread; ++ ++ SRes result; ++ UInt32 dictSize; ++ UInt32 matchFinderCycles; ++ ++ int needInit; ++ ++ CSaveState saveState; ++} CLzmaEnc; ++ ++SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CLzmaEncProps props = *props2; ++ LzmaEncProps_Normalize(&props); ++ ++ if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || ++ props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) ++ return SZ_ERROR_PARAM; ++ p->dictSize = props.dictSize; ++ p->matchFinderCycles = props.mc; ++ { ++ unsigned fb = props.fb; ++ if (fb < 5) ++ fb = 5; ++ if (fb > LZMA_MATCH_LEN_MAX) ++ fb = LZMA_MATCH_LEN_MAX; ++ p->numFastBytes = fb; ++ } ++ p->lc = props.lc; ++ p->lp = props.lp; ++ p->pb = props.pb; ++ p->fastMode = (props.algo == 0); ++ p->matchFinderBase.btMode = props.btMode; ++ { ++ UInt32 numHashBytes = 4; ++ if (props.btMode) ++ { ++ if (props.numHashBytes < 2) ++ numHashBytes = 2; ++ else if (props.numHashBytes < 4) ++ numHashBytes = props.numHashBytes; ++ } ++ p->matchFinderBase.numHashBytes = numHashBytes; ++ } ++ ++ p->matchFinderBase.cutValue = props.mc; ++ ++ p->writeEndMark = props.writeEndMark; ++ ++ #ifndef _7ZIP_ST ++ /* ++ if (newMultiThread != _multiThread) ++ { ++ ReleaseMatchFinder(); ++ _multiThread = newMultiThread; ++ } ++ */ ++ p->multiThread = (props.numThreads > 1); ++ #endif ++ ++ return SZ_OK; ++} ++ ++static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; ++static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; ++static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; ++static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; ++ ++#define IsCharState(s) ((s) < 7) ++ ++#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) ++ ++#define kInfinityPrice (1 << 30) ++ ++static void RangeEnc_Construct(CRangeEnc *p) ++{ ++ p->outStream = 0; ++ p->bufBase = 0; ++} ++ ++#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) ++ ++#define RC_BUF_SIZE (1 << 16) ++static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ if (p->bufBase == 0) ++ { ++ p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); ++ if (p->bufBase == 0) ++ return 0; ++ p->bufLim = p->bufBase + RC_BUF_SIZE; ++ } ++ return 1; ++} ++ ++static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->bufBase); ++ p->bufBase = 0; ++} ++ ++static void RangeEnc_Init(CRangeEnc *p) ++{ ++ /* Stream.Init(); */ ++ p->low = 0; ++ p->range = 0xFFFFFFFF; ++ p->cacheSize = 1; ++ p->cache = 0; ++ ++ p->buf = p->bufBase; ++ ++ p->processed = 0; ++ p->res = SZ_OK; ++} ++ ++static void RangeEnc_FlushStream(CRangeEnc *p) ++{ ++ size_t num; ++ if (p->res != SZ_OK) ++ return; ++ num = p->buf - p->bufBase; ++ if (num != p->outStream->Write(p->outStream, p->bufBase, num)) ++ p->res = SZ_ERROR_WRITE; ++ p->processed += num; ++ p->buf = p->bufBase; ++} ++ ++static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) ++{ ++ if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) ++ { ++ Byte temp = p->cache; ++ do ++ { ++ Byte *buf = p->buf; ++ *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); ++ p->buf = buf; ++ if (buf == p->bufLim) ++ RangeEnc_FlushStream(p); ++ temp = 0xFF; ++ } ++ while (--p->cacheSize != 0); ++ p->cache = (Byte)((UInt32)p->low >> 24); ++ } ++ p->cacheSize++; ++ p->low = (UInt32)p->low << 8; ++} ++ ++static void RangeEnc_FlushData(CRangeEnc *p) ++{ ++ int i; ++ for (i = 0; i < 5; i++) ++ RangeEnc_ShiftLow(p); ++} ++ ++static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) ++{ ++ do ++ { ++ p->range >>= 1; ++ p->low += p->range & (0 - ((value >> --numBits) & 1)); ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++ } ++ while (numBits != 0); ++} ++ ++static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) ++{ ++ UInt32 ttt = *prob; ++ UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; ++ if (symbol == 0) ++ { ++ p->range = newBound; ++ ttt += (kBitModelTotal - ttt) >> kNumMoveBits; ++ } ++ else ++ { ++ p->low += newBound; ++ p->range -= newBound; ++ ttt -= ttt >> kNumMoveBits; ++ } ++ *prob = (CLzmaProb)ttt; ++ if (p->range < kTopValue) ++ { ++ p->range <<= 8; ++ RangeEnc_ShiftLow(p); ++ } ++} ++ ++static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) ++{ ++ symbol |= 0x100; ++ do ++ { ++ RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) ++{ ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++} ++ ++static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++{ ++ UInt32 i; ++ for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) ++ { ++ const int kCyclesBits = kNumBitPriceShiftBits; ++ UInt32 w = i; ++ UInt32 bitCount = 0; ++ int j; ++ for (j = 0; j < kCyclesBits; j++) ++ { ++ w = w * w; ++ bitCount <<= 1; ++ while (w >= ((UInt32)1 << 16)) ++ { ++ w >>= 1; ++ bitCount++; ++ } ++ } ++ ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); ++ } ++} ++ ++ ++#define GET_PRICE(prob, symbol) \ ++ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICEa(prob, symbol) \ ++ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; ++ ++#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] ++#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] ++ ++static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= 0x100; ++ do ++ { ++ price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); ++ symbol <<= 1; ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 offs = 0x100; ++ symbol |= 0x100; ++ do ++ { ++ matchByte <<= 1; ++ price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); ++ symbol <<= 1; ++ offs &= ~(matchByte ^ symbol); ++ } ++ while (symbol < 0x10000); ++ return price; ++} ++ ++ ++static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0;) ++ { ++ UInt32 bit; ++ i--; ++ bit = (symbol >> i) & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ } ++} ++ ++static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) ++{ ++ UInt32 m = 1; ++ int i; ++ for (i = 0; i < numBitLevels; i++) ++ { ++ UInt32 bit = symbol & 1; ++ RangeEnc_EncodeBit(rc, probs + m, bit); ++ m = (m << 1) | bit; ++ symbol >>= 1; ++ } ++} ++ ++static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ symbol |= (1 << numBitLevels); ++ while (symbol != 1) ++ { ++ price += GET_PRICEa(probs[symbol >> 1], symbol & 1); ++ symbol >>= 1; ++ } ++ return price; ++} ++ ++static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) ++{ ++ UInt32 price = 0; ++ UInt32 m = 1; ++ int i; ++ for (i = numBitLevels; i != 0; i--) ++ { ++ UInt32 bit = symbol & 1; ++ symbol >>= 1; ++ price += GET_PRICEa(probs[m], bit); ++ m = (m << 1) | bit; ++ } ++ return price; ++} ++ ++ ++static void LenEnc_Init(CLenEnc *p) ++{ ++ unsigned i; ++ p->choice = p->choice2 = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) ++ p->low[i] = kProbInitValue; ++ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) ++ p->mid[i] = kProbInitValue; ++ for (i = 0; i < kLenNumHighSymbols; i++) ++ p->high[i] = kProbInitValue; ++} ++ ++static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) ++{ ++ if (symbol < kLenNumLowSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 0); ++ RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice, 1); ++ if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 0); ++ RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); ++ } ++ else ++ { ++ RangeEnc_EncodeBit(rc, &p->choice2, 1); ++ RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); ++ } ++ } ++} ++ ++static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) ++{ ++ UInt32 a0 = GET_PRICE_0a(p->choice); ++ UInt32 a1 = GET_PRICE_1a(p->choice); ++ UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); ++ UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); ++ UInt32 i = 0; ++ for (i = 0; i < kLenNumLowSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); ++ } ++ for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) ++ { ++ if (i >= numSymbols) ++ return; ++ prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); ++ } ++ for (; i < numSymbols; i++) ++ prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); ++} ++ ++static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) ++{ ++ LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); ++ p->counters[posState] = p->tableSize; ++} ++ ++static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) ++{ ++ UInt32 posState; ++ for (posState = 0; posState < numPosStates; posState++) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) ++{ ++ LenEnc_Encode(&p->p, rc, symbol, posState); ++ if (updatePrice) ++ if (--p->counters[posState] == 0) ++ LenPriceEnc_UpdateTable(p, posState, ProbPrices); ++} ++ ++ ++ ++ ++static void MovePos(CLzmaEnc *p, UInt32 num) ++{ ++ #ifdef SHOW_STAT ++ ttt += num; ++ printf("\n MovePos %d", num); ++ #endif ++ if (num != 0) ++ { ++ p->additionalOffset += num; ++ p->matchFinder.Skip(p->matchFinderObj, num); ++ } ++} ++ ++static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) ++{ ++ UInt32 lenRes = 0, numPairs; ++ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++ numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); ++ #ifdef SHOW_STAT ++ printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ++ ttt++; ++ { ++ UInt32 i; ++ for (i = 0; i < numPairs; i += 2) ++ printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); ++ } ++ #endif ++ if (numPairs > 0) ++ { ++ lenRes = p->matches[numPairs - 2]; ++ if (lenRes == p->numFastBytes) ++ { ++ const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ UInt32 distance = p->matches[numPairs - 1] + 1; ++ UInt32 numAvail = p->numAvail; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ { ++ const Byte *pby2 = pby - distance; ++ for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); ++ } ++ } ++ } ++ p->additionalOffset++; ++ *numDistancePairsRes = numPairs; ++ return lenRes; ++} ++ ++ ++#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; ++#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; ++#define IsShortRep(p) ((p)->backPrev == 0) ++ ++static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) ++{ ++ return ++ GET_PRICE_0(p->isRepG0[state]) + ++ GET_PRICE_0(p->isRep0Long[state][posState]); ++} ++ ++static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) ++{ ++ UInt32 price; ++ if (repIndex == 0) ++ { ++ price = GET_PRICE_0(p->isRepG0[state]); ++ price += GET_PRICE_1(p->isRep0Long[state][posState]); ++ } ++ else ++ { ++ price = GET_PRICE_1(p->isRepG0[state]); ++ if (repIndex == 1) ++ price += GET_PRICE_0(p->isRepG1[state]); ++ else ++ { ++ price += GET_PRICE_1(p->isRepG1[state]); ++ price += GET_PRICE(p->isRepG2[state], repIndex - 2); ++ } ++ } ++ return price; ++} ++ ++static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) ++{ ++ return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + ++ GetPureRepPrice(p, repIndex, state, posState); ++} ++ ++static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) ++{ ++ UInt32 posMem = p->opt[cur].posPrev; ++ UInt32 backMem = p->opt[cur].backPrev; ++ p->optimumEndIndex = cur; ++ do ++ { ++ if (p->opt[cur].prev1IsChar) ++ { ++ MakeAsChar(&p->opt[posMem]) ++ p->opt[posMem].posPrev = posMem - 1; ++ if (p->opt[cur].prev2) ++ { ++ p->opt[posMem - 1].prev1IsChar = False; ++ p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; ++ p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; ++ } ++ } ++ { ++ UInt32 posPrev = posMem; ++ UInt32 backCur = backMem; ++ ++ backMem = p->opt[posPrev].backPrev; ++ posMem = p->opt[posPrev].posPrev; ++ ++ p->opt[posPrev].backPrev = backCur; ++ p->opt[posPrev].posPrev = cur; ++ cur = posPrev; ++ } ++ } ++ while (cur != 0); ++ *backRes = p->opt[0].backPrev; ++ p->optimumCurrentIndex = p->opt[0].posPrev; ++ return p->optimumCurrentIndex; ++} ++ ++#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) ++ ++static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; ++ UInt32 matchPrice, repMatchPrice, normalMatchPrice; ++ UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; ++ UInt32 *matches; ++ const Byte *data; ++ Byte curByte, matchByte; ++ if (p->optimumEndIndex != p->optimumCurrentIndex) ++ { ++ const COptimal *opt = &p->opt[p->optimumCurrentIndex]; ++ UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; ++ *backRes = opt->backPrev; ++ p->optimumCurrentIndex = opt->posPrev; ++ return lenRes; ++ } ++ p->optimumCurrentIndex = p->optimumEndIndex = 0; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ if (numAvail < 2) ++ { ++ *backRes = (UInt32)(-1); ++ return 1; ++ } ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ repMaxIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 lenTest; ++ const Byte *data2; ++ reps[i] = p->reps[i]; ++ data2 = data - (reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ { ++ repLens[i] = 0; ++ continue; ++ } ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ repLens[i] = lenTest; ++ if (lenTest > repLens[repMaxIndex]) ++ repMaxIndex = i; ++ } ++ if (repLens[repMaxIndex] >= p->numFastBytes) ++ { ++ UInt32 lenRes; ++ *backRes = repMaxIndex; ++ lenRes = repLens[repMaxIndex]; ++ MovePos(p, lenRes - 1); ++ return lenRes; ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) ++ { ++ *backRes = (UInt32)-1; ++ return 1; ++ } ++ ++ p->opt[0].state = (CState)p->state; ++ ++ posState = (position & p->pbMask); ++ ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + ++ (!IsCharState(p->state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ MakeAsChar(&p->opt[1]); ++ ++ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); ++ ++ if (matchByte == curByte) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); ++ if (shortRepPrice < p->opt[1].price) ++ { ++ p->opt[1].price = shortRepPrice; ++ MakeAsShortRep(&p->opt[1]); ++ } ++ } ++ lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); ++ ++ if (lenEnd < 2) ++ { ++ *backRes = p->opt[1].backPrev; ++ return 1; ++ } ++ ++ p->opt[1].posPrev = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ p->opt[0].backs[i] = reps[i]; ++ ++ len = lenEnd; ++ do ++ p->opt[len--].price = kInfinityPrice; ++ while (len >= 2); ++ ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 repLen = repLens[i]; ++ UInt32 price; ++ if (repLen < 2) ++ continue; ++ price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; ++ COptimal *opt = &p->opt[repLen]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = i; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--repLen >= 2); ++ } ++ ++ normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); ++ ++ len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); ++ if (len <= mainLen) ++ { ++ UInt32 offs = 0; ++ while (len > matches[offs]) ++ offs += 2; ++ for (; ; len++) ++ { ++ COptimal *opt; ++ UInt32 distance = matches[offs + 1]; ++ ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(len); ++ if (distance < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][distance]; ++ else ++ { ++ UInt32 slot; ++ GetPosSlot2(distance, slot); ++ curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; ++ } ++ opt = &p->opt[len]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = 0; ++ opt->backPrev = distance + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ if (len == matches[offs]) ++ { ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ } ++ } ++ } ++ ++ cur = 0; ++ ++ #ifdef SHOW_STAT2 ++ if (position >= 0) ++ { ++ unsigned i; ++ printf("\n pos = %4X", position); ++ for (i = cur; i <= lenEnd; i++) ++ printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); ++ } ++ #endif ++ ++ for (;;) ++ { ++ UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; ++ UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; ++ Bool nextIsChar; ++ Byte curByte, matchByte; ++ const Byte *data; ++ COptimal *curOpt; ++ COptimal *nextOpt; ++ ++ cur++; ++ if (cur == lenEnd) ++ return Backward(p, backRes, cur); ++ ++ newLen = ReadMatchDistances(p, &numPairs); ++ if (newLen >= p->numFastBytes) ++ { ++ p->numPairs = numPairs; ++ p->longestMatchLength = newLen; ++ return Backward(p, backRes, cur); ++ } ++ position++; ++ curOpt = &p->opt[cur]; ++ posPrev = curOpt->posPrev; ++ if (curOpt->prev1IsChar) ++ { ++ posPrev--; ++ if (curOpt->prev2) ++ { ++ state = p->opt[curOpt->posPrev2].state; ++ if (curOpt->backPrev2 < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ state = kLiteralNextStates[state]; ++ } ++ else ++ state = p->opt[posPrev].state; ++ if (posPrev == cur - 1) ++ { ++ if (IsShortRep(curOpt)) ++ state = kShortRepNextStates[state]; ++ else ++ state = kLiteralNextStates[state]; ++ } ++ else ++ { ++ UInt32 pos; ++ const COptimal *prevOpt; ++ if (curOpt->prev1IsChar && curOpt->prev2) ++ { ++ posPrev = curOpt->posPrev2; ++ pos = curOpt->backPrev2; ++ state = kRepNextStates[state]; ++ } ++ else ++ { ++ pos = curOpt->backPrev; ++ if (pos < LZMA_NUM_REPS) ++ state = kRepNextStates[state]; ++ else ++ state = kMatchNextStates[state]; ++ } ++ prevOpt = &p->opt[posPrev]; ++ if (pos < LZMA_NUM_REPS) ++ { ++ UInt32 i; ++ reps[0] = prevOpt->backs[pos]; ++ for (i = 1; i <= pos; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ for (; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i]; ++ } ++ else ++ { ++ UInt32 i; ++ reps[0] = (pos - LZMA_NUM_REPS); ++ for (i = 1; i < LZMA_NUM_REPS; i++) ++ reps[i] = prevOpt->backs[i - 1]; ++ } ++ } ++ curOpt->state = (CState)state; ++ ++ curOpt->backs[0] = reps[0]; ++ curOpt->backs[1] = reps[1]; ++ curOpt->backs[2] = reps[2]; ++ curOpt->backs[3] = reps[3]; ++ ++ curPrice = curOpt->price; ++ nextIsChar = False; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ curByte = *data; ++ matchByte = *(data - (reps[0] + 1)); ++ ++ posState = (position & p->pbMask); ++ ++ curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); ++ { ++ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); ++ curAnd1Price += ++ (!IsCharState(state) ? ++ LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : ++ LitEnc_GetPrice(probs, curByte, p->ProbPrices)); ++ } ++ ++ nextOpt = &p->opt[cur + 1]; ++ ++ if (curAnd1Price < nextOpt->price) ++ { ++ nextOpt->price = curAnd1Price; ++ nextOpt->posPrev = cur; ++ MakeAsChar(nextOpt); ++ nextIsChar = True; ++ } ++ ++ matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); ++ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); ++ ++ if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) ++ { ++ UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); ++ if (shortRepPrice <= nextOpt->price) ++ { ++ nextOpt->price = shortRepPrice; ++ nextOpt->posPrev = cur; ++ MakeAsShortRep(nextOpt); ++ nextIsChar = True; ++ } ++ } ++ numAvailFull = p->numAvail; ++ { ++ UInt32 temp = kNumOpts - 1 - cur; ++ if (temp < numAvailFull) ++ numAvailFull = temp; ++ } ++ ++ if (numAvailFull < 2) ++ continue; ++ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); ++ ++ if (!nextIsChar && matchByte != curByte) /* speed optimization */ ++ { ++ /* try Literal + rep0 */ ++ UInt32 temp; ++ UInt32 lenTest2; ++ const Byte *data2 = data - (reps[0] + 1); ++ UInt32 limit = p->numFastBytes + 1; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ ++ for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); ++ lenTest2 = temp - 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kLiteralNextStates[state]; ++ UInt32 posStateNext = (position + 1) & p->pbMask; ++ UInt32 nextRepMatchPrice = curAnd1Price + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = False; ++ } ++ } ++ } ++ } ++ ++ startLen = 2; /* speed optimization */ ++ { ++ UInt32 repIndex; ++ for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) ++ { ++ UInt32 lenTest; ++ UInt32 lenTestTemp; ++ UInt32 price; ++ const Byte *data2 = data - (reps[repIndex] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); ++ while (lenEnd < cur + lenTest) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ lenTestTemp = lenTest; ++ price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); ++ do ++ { ++ UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; ++ COptimal *opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = repIndex; ++ opt->prev1IsChar = False; ++ } ++ } ++ while (--lenTest >= 2); ++ lenTest = lenTestTemp; ++ ++ if (repIndex == 0) ++ startLen = lenTest + 1; ++ ++ /* if (_maxMode) */ ++ { ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kRepNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = ++ price + p->repLenEnc.prices[posState][lenTest - 2] + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (position + lenTest + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = repIndex; ++ } ++ } ++ } ++ } ++ } ++ } ++ /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ ++ if (newLen > numAvail) ++ { ++ newLen = numAvail; ++ for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); ++ matches[numPairs] = newLen; ++ numPairs += 2; ++ } ++ if (newLen >= startLen) ++ { ++ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); ++ UInt32 offs, curBack, posSlot; ++ UInt32 lenTest; ++ while (lenEnd < cur + newLen) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ ++ offs = 0; ++ while (startLen > matches[offs]) ++ offs += 2; ++ curBack = matches[offs + 1]; ++ GetPosSlot2(curBack, posSlot); ++ for (lenTest = /*2*/ startLen; ; lenTest++) ++ { ++ UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; ++ UInt32 lenToPosState = GetLenToPosState(lenTest); ++ COptimal *opt; ++ if (curBack < kNumFullDistances) ++ curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; ++ else ++ curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; ++ ++ opt = &p->opt[cur + lenTest]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur; ++ opt->backPrev = curBack + LZMA_NUM_REPS; ++ opt->prev1IsChar = False; ++ } ++ ++ if (/*_maxMode && */lenTest == matches[offs]) ++ { ++ /* Try Match + Literal + Rep0 */ ++ const Byte *data2 = data - (curBack + 1); ++ UInt32 lenTest2 = lenTest + 1; ++ UInt32 limit = lenTest2 + p->numFastBytes; ++ UInt32 nextRepMatchPrice; ++ if (limit > numAvailFull) ++ limit = numAvailFull; ++ for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); ++ lenTest2 -= lenTest + 1; ++ if (lenTest2 >= 2) ++ { ++ UInt32 state2 = kMatchNextStates[state]; ++ UInt32 posStateNext = (position + lenTest) & p->pbMask; ++ UInt32 curAndLenCharPrice = curAndLenPrice + ++ GET_PRICE_0(p->isMatch[state2][posStateNext]) + ++ LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), ++ data[lenTest], data2[lenTest], p->ProbPrices); ++ state2 = kLiteralNextStates[state2]; ++ posStateNext = (posStateNext + 1) & p->pbMask; ++ nextRepMatchPrice = curAndLenCharPrice + ++ GET_PRICE_1(p->isMatch[state2][posStateNext]) + ++ GET_PRICE_1(p->isRep[state2]); ++ ++ /* for (; lenTest2 >= 2; lenTest2--) */ ++ { ++ UInt32 offset = cur + lenTest + 1 + lenTest2; ++ UInt32 curAndLenPrice; ++ COptimal *opt; ++ while (lenEnd < offset) ++ p->opt[++lenEnd].price = kInfinityPrice; ++ curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); ++ opt = &p->opt[offset]; ++ if (curAndLenPrice < opt->price) ++ { ++ opt->price = curAndLenPrice; ++ opt->posPrev = cur + lenTest + 1; ++ opt->backPrev = 0; ++ opt->prev1IsChar = True; ++ opt->prev2 = True; ++ opt->posPrev2 = cur; ++ opt->backPrev2 = curBack + LZMA_NUM_REPS; ++ } ++ } ++ } ++ offs += 2; ++ if (offs == numPairs) ++ break; ++ curBack = matches[offs + 1]; ++ if (curBack >= kNumFullDistances) ++ GetPosSlot2(curBack, posSlot); ++ } ++ } ++ } ++ } ++} ++ ++#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) ++ ++static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) ++{ ++ UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; ++ const Byte *data; ++ const UInt32 *matches; ++ ++ if (p->additionalOffset == 0) ++ mainLen = ReadMatchDistances(p, &numPairs); ++ else ++ { ++ mainLen = p->longestMatchLength; ++ numPairs = p->numPairs; ++ } ++ ++ numAvail = p->numAvail; ++ *backRes = (UInt32)-1; ++ if (numAvail < 2) ++ return 1; ++ if (numAvail > LZMA_MATCH_LEN_MAX) ++ numAvail = LZMA_MATCH_LEN_MAX; ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ ++ repLen = repIndex = 0; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ for (len = 2; len < numAvail && data[len] == data2[len]; len++); ++ if (len >= p->numFastBytes) ++ { ++ *backRes = i; ++ MovePos(p, len - 1); ++ return len; ++ } ++ if (len > repLen) ++ { ++ repIndex = i; ++ repLen = len; ++ } ++ } ++ ++ matches = p->matches; ++ if (mainLen >= p->numFastBytes) ++ { ++ *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 1); ++ return mainLen; ++ } ++ ++ mainDist = 0; /* for GCC */ ++ if (mainLen >= 2) ++ { ++ mainDist = matches[numPairs - 1]; ++ while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) ++ { ++ if (!ChangePair(matches[numPairs - 3], mainDist)) ++ break; ++ numPairs -= 2; ++ mainLen = matches[numPairs - 2]; ++ mainDist = matches[numPairs - 1]; ++ } ++ if (mainLen == 2 && mainDist >= 0x80) ++ mainLen = 1; ++ } ++ ++ if (repLen >= 2 && ( ++ (repLen + 1 >= mainLen) || ++ (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || ++ (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) ++ { ++ *backRes = repIndex; ++ MovePos(p, repLen - 1); ++ return repLen; ++ } ++ ++ if (mainLen < 2 || numAvail <= 2) ++ return 1; ++ ++ p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); ++ if (p->longestMatchLength >= 2) ++ { ++ UInt32 newDistance = matches[p->numPairs - 1]; ++ if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || ++ (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || ++ (p->longestMatchLength > mainLen + 1) || ++ (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) ++ return 1; ++ } ++ ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; ++ for (i = 0; i < LZMA_NUM_REPS; i++) ++ { ++ UInt32 len, limit; ++ const Byte *data2 = data - (p->reps[i] + 1); ++ if (data[0] != data2[0] || data[1] != data2[1]) ++ continue; ++ limit = mainLen - 1; ++ for (len = 2; len < limit && data[len] == data2[len]; len++); ++ if (len >= limit) ++ return 1; ++ } ++ *backRes = mainDist + LZMA_NUM_REPS; ++ MovePos(p, mainLen - 2); ++ return mainLen; ++} ++ ++static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) ++{ ++ UInt32 len; ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ len = LZMA_MATCH_LEN_MIN; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); ++ RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); ++} ++ ++static SRes CheckErrors(CLzmaEnc *p) ++{ ++ if (p->result != SZ_OK) ++ return p->result; ++ if (p->rc.res != SZ_OK) ++ p->result = SZ_ERROR_WRITE; ++ if (p->matchFinderBase.result != SZ_OK) ++ p->result = SZ_ERROR_READ; ++ if (p->result != SZ_OK) ++ p->finished = True; ++ return p->result; ++} ++ ++static SRes Flush(CLzmaEnc *p, UInt32 nowPos) ++{ ++ /* ReleaseMFStream(); */ ++ p->finished = True; ++ if (p->writeEndMark) ++ WriteEndMarker(p, nowPos & p->pbMask); ++ RangeEnc_FlushData(&p->rc); ++ RangeEnc_FlushStream(&p->rc); ++ return CheckErrors(p); ++} ++ ++static void FillAlignPrices(CLzmaEnc *p) ++{ ++ UInt32 i; ++ for (i = 0; i < kAlignTableSize; i++) ++ p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); ++ p->alignPriceCount = 0; ++} ++ ++static void FillDistancesPrices(CLzmaEnc *p) ++{ ++ UInt32 tempPrices[kNumFullDistances]; ++ UInt32 i, lenToPosState; ++ for (i = kStartPosModelIndex; i < kNumFullDistances; i++) ++ { ++ UInt32 posSlot = GetPosSlot1(i); ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); ++ } ++ ++ for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) ++ { ++ UInt32 posSlot; ++ const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; ++ UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; ++ for (posSlot = 0; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); ++ for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) ++ posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); ++ ++ { ++ UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; ++ UInt32 i; ++ for (i = 0; i < kStartPosModelIndex; i++) ++ distancesPrices[i] = posSlotPrices[i]; ++ for (; i < kNumFullDistances; i++) ++ distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; ++ } ++ } ++ p->matchPriceCount = 0; ++} ++ ++static void LzmaEnc_Construct(CLzmaEnc *p) ++{ ++ RangeEnc_Construct(&p->rc); ++ MatchFinder_Construct(&p->matchFinderBase); ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Construct(&p->matchFinderMt); ++ p->matchFinderMt.MatchFinder = &p->matchFinderBase; ++ #endif ++ ++ { ++ CLzmaEncProps props; ++ LzmaEncProps_Init(&props); ++ LzmaEnc_SetProps(p, &props); ++ } ++ ++ #ifndef LZMA_LOG_BSR ++ LzmaEnc_FastPosInit(p->g_FastPos); ++ #endif ++ ++ LzmaEnc_InitPriceTables(p->ProbPrices); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) ++{ ++ void *p; ++ p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); ++ if (p != 0) ++ LzmaEnc_Construct((CLzmaEnc *)p); ++ return p; ++} ++ ++static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->litProbs); ++ alloc->Free(alloc, p->saveState.litProbs); ++ p->litProbs = 0; ++ p->saveState.litProbs = 0; ++} ++ ++static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ #ifndef _7ZIP_ST ++ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); ++ #endif ++ MatchFinder_Free(&p->matchFinderBase, allocBig); ++ LzmaEnc_FreeLits(p, alloc); ++ RangeEnc_Free(&p->rc, alloc); ++} ++ ++void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); ++ alloc->Free(alloc, p); ++} ++ ++static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) ++{ ++ UInt32 nowPos32, startPos32; ++ if (p->needInit) ++ { ++ p->matchFinder.Init(p->matchFinderObj); ++ p->needInit = 0; ++ } ++ ++ if (p->finished) ++ return p->result; ++ RINOK(CheckErrors(p)); ++ ++ nowPos32 = (UInt32)p->nowPos64; ++ startPos32 = nowPos32; ++ ++ if (p->nowPos64 == 0) ++ { ++ UInt32 numPairs; ++ Byte curByte; ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ return Flush(p, nowPos32); ++ ReadMatchDistances(p, &numPairs); ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); ++ p->state = kLiteralNextStates[p->state]; ++ curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); ++ LitEnc_Encode(&p->rc, p->litProbs, curByte); ++ p->additionalOffset--; ++ nowPos32++; ++ } ++ ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) ++ for (;;) ++ { ++ UInt32 pos, len, posState; ++ ++ if (p->fastMode) ++ len = GetOptimumFast(p, &pos); ++ else ++ len = GetOptimum(p, nowPos32, &pos); ++ ++ #ifdef SHOW_STAT2 ++ printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); ++ #endif ++ ++ posState = nowPos32 & p->pbMask; ++ if (len == 1 && pos == (UInt32)-1) ++ { ++ Byte curByte; ++ CLzmaProb *probs; ++ const Byte *data; ++ ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); ++ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++ curByte = *data; ++ probs = LIT_PROBS(nowPos32, *(data - 1)); ++ if (IsCharState(p->state)) ++ LitEnc_Encode(&p->rc, probs, curByte); ++ else ++ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); ++ p->state = kLiteralNextStates[p->state]; ++ } ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); ++ if (pos < LZMA_NUM_REPS) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); ++ if (pos == 0) ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); ++ RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); ++ } ++ else ++ { ++ UInt32 distance = p->reps[pos]; ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); ++ if (pos == 1) ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); ++ else ++ { ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); ++ RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); ++ if (pos == 3) ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ } ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = distance; ++ } ++ if (len == 1) ++ p->state = kShortRepNextStates[p->state]; ++ else ++ { ++ LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ p->state = kRepNextStates[p->state]; ++ } ++ } ++ else ++ { ++ UInt32 posSlot; ++ RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); ++ p->state = kMatchNextStates[p->state]; ++ LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); ++ pos -= LZMA_NUM_REPS; ++ GetPosSlot(pos, posSlot); ++ RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); ++ ++ if (posSlot >= kStartPosModelIndex) ++ { ++ UInt32 footerBits = ((posSlot >> 1) - 1); ++ UInt32 base = ((2 | (posSlot & 1)) << footerBits); ++ UInt32 posReduced = pos - base; ++ ++ if (posSlot < kEndPosModelIndex) ++ RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); ++ else ++ { ++ RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); ++ RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); ++ p->alignPriceCount++; ++ } ++ } ++ p->reps[3] = p->reps[2]; ++ p->reps[2] = p->reps[1]; ++ p->reps[1] = p->reps[0]; ++ p->reps[0] = pos; ++ p->matchPriceCount++; ++ } ++ } ++ p->additionalOffset -= len; ++ nowPos32 += len; ++ if (p->additionalOffset == 0) ++ { ++ UInt32 processed; ++ if (!p->fastMode) ++ { ++ if (p->matchPriceCount >= (1 << 7)) ++ FillDistancesPrices(p); ++ if (p->alignPriceCount >= kAlignTableSize) ++ FillAlignPrices(p); ++ } ++ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) ++ break; ++ processed = nowPos32 - startPos32; ++ if (useLimits) ++ { ++ if (processed + kNumOpts + 300 >= maxUnpackSize || ++ RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) ++ break; ++ } ++ else if (processed >= (1 << 15)) ++ { ++ p->nowPos64 += nowPos32 - startPos32; ++ return CheckErrors(p); ++ } ++ } ++ } ++ p->nowPos64 += nowPos32 - startPos32; ++ return Flush(p, nowPos32); ++} ++ ++#define kBigHashDicLimit ((UInt32)1 << 24) ++ ++static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 beforeSize = kNumOpts; ++ Bool btMode; ++ if (!RangeEnc_Alloc(&p->rc, alloc)) ++ return SZ_ERROR_MEM; ++ btMode = (p->matchFinderBase.btMode != 0); ++ #ifndef _7ZIP_ST ++ p->mtMode = (p->multiThread && !p->fastMode && btMode); ++ #endif ++ ++ { ++ unsigned lclp = p->lc + p->lp; ++ if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); ++ if (p->litProbs == 0 || p->saveState.litProbs == 0) ++ { ++ LzmaEnc_FreeLits(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ p->lclp = lclp; ++ } ++ } ++ ++ p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); ++ ++ if (beforeSize + p->dictSize < keepWindowSize) ++ beforeSize = keepWindowSize - p->dictSize; ++ ++ #ifndef _7ZIP_ST ++ if (p->mtMode) ++ { ++ RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); ++ p->matchFinderObj = &p->matchFinderMt; ++ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); ++ } ++ else ++ #endif ++ { ++ if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) ++ return SZ_ERROR_MEM; ++ p->matchFinderObj = &p->matchFinderBase; ++ MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); ++ } ++ return SZ_OK; ++} ++ ++static void LzmaEnc_Init(CLzmaEnc *p) ++{ ++ UInt32 i; ++ p->state = 0; ++ for (i = 0 ; i < LZMA_NUM_REPS; i++) ++ p->reps[i] = 0; ++ ++ RangeEnc_Init(&p->rc); ++ ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ UInt32 j; ++ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) ++ { ++ p->isMatch[i][j] = kProbInitValue; ++ p->isRep0Long[i][j] = kProbInitValue; ++ } ++ p->isRep[i] = kProbInitValue; ++ p->isRepG0[i] = kProbInitValue; ++ p->isRepG1[i] = kProbInitValue; ++ p->isRepG2[i] = kProbInitValue; ++ } ++ ++ { ++ UInt32 num = 0x300 << (p->lp + p->lc); ++ for (i = 0; i < num; i++) ++ p->litProbs[i] = kProbInitValue; ++ } ++ ++ { ++ for (i = 0; i < kNumLenToPosStates; i++) ++ { ++ CLzmaProb *probs = p->posSlotEncoder[i]; ++ UInt32 j; ++ for (j = 0; j < (1 << kNumPosSlotBits); j++) ++ probs[j] = kProbInitValue; ++ } ++ } ++ { ++ for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) ++ p->posEncoders[i] = kProbInitValue; ++ } ++ ++ LenEnc_Init(&p->lenEnc.p); ++ LenEnc_Init(&p->repLenEnc.p); ++ ++ for (i = 0; i < (1 << kNumAlignBits); i++) ++ p->posAlignEncoder[i] = kProbInitValue; ++ ++ p->optimumEndIndex = 0; ++ p->optimumCurrentIndex = 0; ++ p->additionalOffset = 0; ++ ++ p->pbMask = (1 << p->pb) - 1; ++ p->lpMask = (1 << p->lp) - 1; ++} ++ ++static void LzmaEnc_InitPrices(CLzmaEnc *p) ++{ ++ if (!p->fastMode) ++ { ++ FillDistancesPrices(p); ++ FillAlignPrices(p); ++ } ++ ++ p->lenEnc.tableSize = ++ p->repLenEnc.tableSize = ++ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; ++ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); ++ LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); ++} ++ ++static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ UInt32 i; ++ for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) ++ if (p->dictSize <= ((UInt32)1 << i)) ++ break; ++ p->distTableSize = i * 2; ++ ++ p->finished = False; ++ p->result = SZ_OK; ++ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ p->nowPos64 = 0; ++ return SZ_OK; ++} ++ ++static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) ++{ ++ p->matchFinderBase.directInput = 1; ++ p->matchFinderBase.bufferBase = (Byte *)src; ++ p->matchFinderBase.directInputRem = srcLen; ++} ++ ++static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++ UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ p->needInit = 1; ++ ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ ++static void LzmaEnc_Finish(CLzmaEncHandle pp) ++{ ++ #ifndef _7ZIP_ST ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ if (p->mtMode) ++ MatchFinderMt_ReleaseStream(&p->matchFinderMt); ++ #else ++ pp = pp; ++ #endif ++} ++ ++typedef struct ++{ ++ ISeqOutStream funcTable; ++ Byte *data; ++ SizeT rem; ++ Bool overflow; ++} CSeqOutStreamBuf; ++ ++static size_t MyWrite(void *pp, const void *data, size_t size) ++{ ++ CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; ++ if (p->rem < size) ++ { ++ size = p->rem; ++ p->overflow = True; ++ } ++ memcpy(p->data, data, size); ++ p->rem -= size; ++ p->data += size; ++ return size; ++} ++ ++static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) ++{ ++ SRes res = SZ_OK; ++ ++ #ifndef _7ZIP_ST ++ Byte allocaDummy[0x300]; ++ int i = 0; ++ for (i = 0; i < 16; i++) ++ allocaDummy[i] = (Byte)i; ++ #endif ++ ++ for (;;) ++ { ++ res = LzmaEnc_CodeOneBlock(p, False, 0, 0); ++ if (res != SZ_OK || p->finished != 0) ++ break; ++ if (progress != 0) ++ { ++ res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); ++ if (res != SZ_OK) ++ { ++ res = SZ_ERROR_PROGRESS; ++ break; ++ } ++ } ++ } ++ LzmaEnc_Finish(p); ++ return res; ++} ++ ++SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ int i; ++ UInt32 dictSize = p->dictSize; ++ if (*size < LZMA_PROPS_SIZE) ++ return SZ_ERROR_PARAM; ++ *size = LZMA_PROPS_SIZE; ++ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); ++ ++ for (i = 11; i <= 30; i++) ++ { ++ if (dictSize <= ((UInt32)2 << i)) ++ { ++ dictSize = (2 << i); ++ break; ++ } ++ if (dictSize <= ((UInt32)3 << i)) ++ { ++ dictSize = (3 << i); ++ break; ++ } ++ } ++ ++ for (i = 0; i < 4; i++) ++ props[1 + i] = (Byte)(dictSize >> (8 * i)); ++ return SZ_OK; ++} ++ ++SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ SRes res; ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ ++ CSeqOutStreamBuf outStream; ++ ++ LzmaEnc_SetInputBuf(p, src, srcLen); ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = writeEndMark; ++ ++ p->rc.outStream = &outStream.funcTable; ++ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); ++ if (res == SZ_OK) ++ res = LzmaEnc_Encode2(p, progress); ++ ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ return res; ++} +--- /dev/null ++++ b/lib/lzma/Makefile +@@ -0,0 +1,7 @@ ++lzma_compress-objs := LzFind.o LzmaEnc.o ++lzma_decompress-objs := LzmaDec.o ++ ++obj-$(CONFIG_LZMA_COMPRESS) += lzma_compress.o ++obj-$(CONFIG_LZMA_DECOMPRESS) += lzma_decompress.o ++ ++EXTRA_CFLAGS += -Iinclude/linux -Iinclude/linux/lzma -include types.h diff --git a/target/linux/generic/pending-6.1/532-jffs2_eofdetect.patch b/target/linux/generic/pending-6.1/532-jffs2_eofdetect.patch new file mode 100644 index 00000000000..744fbd0e217 --- /dev/null +++ b/target/linux/generic/pending-6.1/532-jffs2_eofdetect.patch @@ -0,0 +1,65 @@ +From: Felix Fietkau +Subject: fs: jffs2: EOF marker + +Signed-off-by: Felix Fietkau +--- + fs/jffs2/build.c | 10 ++++++++++ + fs/jffs2/scan.c | 21 +++++++++++++++++++-- + 2 files changed, 29 insertions(+), 2 deletions(-) + +--- a/fs/jffs2/build.c ++++ b/fs/jffs2/build.c +@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct + dbg_fsbuild("scanned flash completely\n"); + jffs2_dbg_dump_block_lists_nolock(c); + ++ if (c->flags & (1 << 7)) { ++ printk("%s(): unlocking the mtd device... ", __func__); ++ mtd_unlock(c->mtd, 0, c->mtd->size); ++ printk("done.\n"); ++ ++ printk("%s(): erasing all blocks after the end marker... ", __func__); ++ jffs2_erase_pending_blocks(c, -1); ++ printk("done.\n"); ++ } ++ + dbg_fsbuild("pass 1 starting\n"); + c->flags |= JFFS2_SB_FLAG_BUILDING; + /* Now scan the directory tree, increasing nlink according to every dirent found. */ +--- a/fs/jffs2/scan.c ++++ b/fs/jffs2/scan.c +@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in + /* reset summary info for next eraseblock scan */ + jffs2_sum_reset_collected(s); + +- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), +- buf_size, s); ++ if (c->flags & (1 << 7)) { ++ if (mtd_block_isbad(c->mtd, jeb->offset)) ++ ret = BLK_STATE_BADBLOCK; ++ else ++ ret = BLK_STATE_ALLFF; ++ } else ++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), ++ buf_size, s); + + if (ret < 0) + goto out; +@@ -567,6 +573,17 @@ full_scan: + return err; + } + ++ if ((buf[0] == 0xde) && ++ (buf[1] == 0xad) && ++ (buf[2] == 0xc0) && ++ (buf[3] == 0xde)) { ++ /* end of filesystem. erase everything after this point */ ++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset); ++ c->flags |= (1 << 7); ++ ++ return BLK_STATE_ALLFF; ++ } ++ + /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ + ofs = 0; + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); diff --git a/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch new file mode 100644 index 00000000000..a88e3d7d9a7 --- /dev/null +++ b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch @@ -0,0 +1,88 @@ +From: Felix Fietkau +Subject: netfilter: add support for flushing conntrack via /proc + +lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314 +Signed-off-by: Felix Fietkau +--- + net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++- + 1 file changed, 58 insertions(+), 1 deletion(-) + +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + #ifdef CONFIG_SYSCTL + #include +@@ -462,6 +463,56 @@ static int ct_cpu_seq_show(struct seq_fi + return 0; + } + ++struct kill_request { ++ u16 family; ++ union nf_inet_addr addr; ++}; ++ ++static int kill_matching(struct nf_conn *i, void *data) ++{ ++ struct kill_request *kr = data; ++ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (!kr->family) ++ return 1; ++ ++ if (t1->src.l3num != kr->family) ++ return 0; ++ ++ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) || ++ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3)); ++} ++ ++static int ct_file_write(struct file *file, char *buf, size_t count) ++{ ++ struct seq_file *seq = file->private_data; ++ struct net *net = seq_file_net(seq); ++ struct kill_request kr = { }; ++ ++ if (count == 0) ++ return 0; ++ ++ if (count >= INET6_ADDRSTRLEN) ++ count = INET6_ADDRSTRLEN - 1; ++ ++ if (strnchr(buf, count, ':')) { ++ kr.family = AF_INET6; ++ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } else if (strnchr(buf, count, '.')) { ++ kr.family = AF_INET; ++ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL)) ++ return -EINVAL; ++ } ++ ++ nf_ct_iterate_cleanup_net(net, kill_matching, &kr, 0, 0); ++ ++ return 0; ++} ++ + static const struct seq_operations ct_cpu_seq_ops = { + .start = ct_cpu_seq_start, + .next = ct_cpu_seq_next, +@@ -475,8 +526,9 @@ static int nf_conntrack_standalone_init_ + kuid_t root_uid; + kgid_t root_gid; + +- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops, +- sizeof(struct ct_iter_state)); ++ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net, ++ &ct_seq_ops, &ct_file_write, ++ sizeof(struct ct_iter_state), NULL); + if (!pde) + goto out_nf_conntrack; + diff --git a/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch new file mode 100644 index 00000000000..c1e050e935e --- /dev/null +++ b/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch @@ -0,0 +1,110 @@ +From: Felix Fietkau +Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0 + +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 + + net/ipv4/netfilter/ip_tables.c | 37 +++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h ++++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h +@@ -89,6 +89,7 @@ struct ipt_ip { + #define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */ + #define IPT_F_GOTO 0x02 /* Set if jump is a goto */ + #define IPT_F_MASK 0x03 /* All possible flag bits mask. */ ++#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */ + + /* Values for "inv" field in struct ipt_ip. */ + #define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */ +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -50,6 +50,9 @@ ip_packet_match(const struct iphdr *ip, + { + unsigned long ret; + ++ if (ipinfo->flags & IPT_F_NO_DEF_MATCH) ++ return true; ++ + if (NF_INVF(ipinfo, IPT_INV_SRCIP, + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || + NF_INVF(ipinfo, IPT_INV_DSTIP, +@@ -80,6 +83,29 @@ ip_packet_match(const struct iphdr *ip, + return true; + } + ++static void ++ip_checkdefault(struct ipt_ip *ip) ++{ ++ static const char iface_mask[IFNAMSIZ] = {}; ++ ++ if (ip->invflags || ip->flags & IPT_F_FRAG) ++ return; ++ ++ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0) ++ return; ++ ++ if (ip->smsk.s_addr || ip->dmsk.s_addr) ++ return; ++ ++ if (ip->proto) ++ return; ++ ++ ip->flags |= IPT_F_NO_DEF_MATCH; ++} ++ + static bool + ip_checkentry(const struct ipt_ip *ip) + { +@@ -524,6 +550,8 @@ find_check_entry(struct ipt_entry *e, st + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + ++ ip_checkdefault(&e->ip); ++ + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) + return -ENOMEM; + +@@ -818,6 +846,7 @@ copy_entries_to_user(unsigned int total_ + const struct xt_table_info *private = table->private; + int ret = 0; + const void *loc_cpu_entry; ++ u8 flags; + + counters = alloc_counters(table); + if (IS_ERR(counters)) +@@ -845,6 +874,14 @@ copy_entries_to_user(unsigned int total_ + goto free_counters; + } + ++ flags = e->ip.flags & IPT_F_MASK; ++ if (copy_to_user(userptr + off ++ + offsetof(struct ipt_entry, ip.flags), ++ &flags, sizeof(flags)) != 0) { ++ ret = -EFAULT; ++ goto free_counters; ++ } ++ + for (i = sizeof(struct ipt_entry); + i < e->target_offset; + i += m->u.match_size) { +@@ -1222,12 +1259,15 @@ compat_copy_entry_to_user(struct ipt_ent + compat_uint_t origsize; + const struct xt_entry_match *ematch; + int ret = 0; ++ u8 flags = e->ip.flags & IPT_F_MASK; + + origsize = *size; + ce = *dstptr; + if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 || + copy_to_user(&ce->counters, &counters[i], +- sizeof(counters[i])) != 0) ++ sizeof(counters[i])) != 0 || ++ copy_to_user(&ce->ip.flags, &flags, ++ sizeof(flags)) != 0) + return -EFAULT; + + *dstptr += sizeof(struct compat_ipt_entry); diff --git a/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch new file mode 100644 index 00000000000..baf738a8d20 --- /dev/null +++ b/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch @@ -0,0 +1,106 @@ +From: Felix Fietkau +Subject: netfilter: match bypass default table + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++----------- + 1 file changed, 58 insertions(+), 21 deletions(-) + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -246,6 +246,33 @@ struct ipt_entry *ipt_next_entry(const s + return (void *)entry + entry->next_offset; + } + ++static bool ++ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict) ++{ ++ struct xt_entry_target *t; ++ struct xt_standard_target *st; ++ ++ if (e->target_offset != sizeof(struct ipt_entry)) ++ return false; ++ ++ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH)) ++ return false; ++ ++ t = ipt_get_target(e); ++ if (t->u.kernel.target->target) ++ return false; ++ ++ st = (struct xt_standard_target *) t; ++ if (st->verdict == XT_RETURN) ++ return false; ++ ++ if (st->verdict >= 0) ++ return false; ++ ++ *verdict = (unsigned)(-st->verdict) - 1; ++ return true; ++} ++ + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ + unsigned int + ipt_do_table(struct sk_buff *skb, +@@ -266,27 +293,28 @@ ipt_do_table(struct sk_buff *skb, + unsigned int addend; + + /* Initialization */ ++ WARN_ON(!(table->valid_hooks & (1 << hook))); ++ local_bh_disable(); ++ private = READ_ONCE(table->private); /* Address dependency. */ ++ cpu = smp_processor_id(); ++ table_base = private->entries; ++ ++ e = get_entry(table_base, private->hook_entry[hook]); ++ if (ipt_handle_default_rule(e, &verdict)) { ++ struct xt_counters *counter; ++ ++ counter = xt_get_this_cpu_counter(&e->counters); ++ ADD_COUNTER(*counter, skb->len, 1); ++ local_bh_enable(); ++ return verdict; ++ } ++ + stackidx = 0; + ip = ip_hdr(skb); + indev = state->in ? state->in->name : nulldevname; + outdev = state->out ? state->out->name : nulldevname; +- /* We handle fragments by dealing with the first fragment as +- * if it was a normal packet. All other fragments are treated +- * normally, except that they will NEVER match rules that ask +- * things we don't know, ie. tcp syn flag or ports). If the +- * rule is also a fragment-specific rule, non-fragments won't +- * match it. */ +- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; +- acpar.thoff = ip_hdrlen(skb); +- acpar.hotdrop = false; +- acpar.state = state; + +- WARN_ON(!(table->valid_hooks & (1 << hook))); +- local_bh_disable(); + addend = xt_write_recseq_begin(); +- private = READ_ONCE(table->private); /* Address dependency. */ +- cpu = smp_processor_id(); +- table_base = private->entries; + jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; + + /* Switch to alternate jumpstack if we're being invoked via TEE. +@@ -299,7 +327,16 @@ ipt_do_table(struct sk_buff *skb, + if (static_key_false(&xt_tee_enabled)) + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); + +- e = get_entry(table_base, private->hook_entry[hook]); ++ /* We handle fragments by dealing with the first fragment as ++ * if it was a normal packet. All other fragments are treated ++ * normally, except that they will NEVER match rules that ask ++ * things we don't know, ie. tcp syn flag or ports). If the ++ * rule is also a fragment-specific rule, non-fragments won't ++ * match it. */ ++ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET; ++ acpar.thoff = ip_hdrlen(skb); ++ acpar.hotdrop = false; ++ acpar.state = state; + + do { + const struct xt_entry_target *t; diff --git a/target/linux/generic/pending-6.1/612-netfilter_match_reduce_memory_access.patch b/target/linux/generic/pending-6.1/612-netfilter_match_reduce_memory_access.patch new file mode 100644 index 00000000000..79da6778b68 --- /dev/null +++ b/target/linux/generic/pending-6.1/612-netfilter_match_reduce_memory_access.patch @@ -0,0 +1,22 @@ +From: Felix Fietkau +Subject: netfilter: reduce match memory access + +Signed-off-by: Felix Fietkau +--- + net/ipv4/netfilter/ip_tables.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -53,9 +53,9 @@ ip_packet_match(const struct iphdr *ip, + if (ipinfo->flags & IPT_F_NO_DEF_MATCH) + return true; + +- if (NF_INVF(ipinfo, IPT_INV_SRCIP, ++ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr && + (ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) || +- NF_INVF(ipinfo, IPT_INV_DSTIP, ++ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr && + (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr)) + return false; + diff --git a/target/linux/generic/pending-6.1/620-net_sched-codel-do-not-defer-queue-length-update.patch b/target/linux/generic/pending-6.1/620-net_sched-codel-do-not-defer-queue-length-update.patch new file mode 100644 index 00000000000..4b4825ae3b9 --- /dev/null +++ b/target/linux/generic/pending-6.1/620-net_sched-codel-do-not-defer-queue-length-update.patch @@ -0,0 +1,86 @@ +From: Konstantin Khlebnikov +Date: Mon, 21 Aug 2017 11:14:14 +0300 +Subject: [PATCH] net_sched/codel: do not defer queue length update + +When codel wants to drop last packet in ->dequeue() it cannot call +qdisc_tree_reduce_backlog() right away - it will notify parent qdisc +about zero qlen and HTB/HFSC will deactivate class. The same class will +be deactivated second time by caller of ->dequeue(). Currently codel and +fq_codel defer update. This triggers warning in HFSC when it's qlen != 0 +but there is no active classes. + +This patch update parent queue length immediately: just temporary increase +qlen around qdisc_tree_reduce_backlog() to prevent first class deactivation +if we have skb to return. + +This might open another problem in HFSC - now operation peek could fail and +deactivate parent class. + +Signed-off-by: Konstantin Khlebnikov +Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581 +--- + +--- a/net/sched/sch_codel.c ++++ b/net/sched/sch_codel.c +@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque + &q->stats, qdisc_pkt_len, codel_get_enqueue_time, + drop_func, dequeue_func); + +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. ++ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate ++ * parent class, dequeue in parent qdisc will do the same if we ++ * return skb. Temporary increment qlen if we have skb. + */ +- if (q->stats.drop_count && sch->q.qlen) { +- qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len); ++ if (q->stats.drop_count) { ++ if (skb) ++ sch->q.qlen++; ++ qdisc_tree_reduce_backlog(sch, q->stats.drop_count, ++ q->stats.drop_len); ++ if (skb) ++ sch->q.qlen--; + q->stats.drop_count = 0; + q->stats.drop_len = 0; + } +--- a/net/sched/sch_fq_codel.c ++++ b/net/sched/sch_fq_codel.c +@@ -304,6 +304,21 @@ begin: + &flow->cvars, &q->cstats, qdisc_pkt_len, + codel_get_enqueue_time, drop_func, dequeue_func); + ++ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate ++ * parent class, dequeue in parent qdisc will do the same if we ++ * return skb. Temporary increment qlen if we have skb. ++ */ ++ if (q->cstats.drop_count) { ++ if (skb) ++ sch->q.qlen++; ++ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, ++ q->cstats.drop_len); ++ if (skb) ++ sch->q.qlen--; ++ q->cstats.drop_count = 0; ++ q->cstats.drop_len = 0; ++ } ++ + if (!skb) { + /* force a pass through old_flows to prevent starvation */ + if ((head == &q->new_flows) && !list_empty(&q->old_flows)) +@@ -314,15 +329,6 @@ begin: + } + qdisc_bstats_update(sch, skb); + flow->deficit -= qdisc_pkt_len(skb); +- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, +- * or HTB crashes. Defer it for next round. +- */ +- if (q->cstats.drop_count && sch->q.qlen) { +- qdisc_tree_reduce_backlog(sch, q->cstats.drop_count, +- q->cstats.drop_len); +- q->cstats.drop_count = 0; +- q->cstats.drop_len = 0; +- } + return skb; + } + diff --git a/target/linux/generic/pending-6.1/630-packet_socket_type.patch b/target/linux/generic/pending-6.1/630-packet_socket_type.patch new file mode 100644 index 00000000000..2d2c7b6cc55 --- /dev/null +++ b/target/linux/generic/pending-6.1/630-packet_socket_type.patch @@ -0,0 +1,138 @@ +From: Felix Fietkau +Subject: net: add an optimization for dealing with raw sockets + +lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6 +Signed-off-by: Felix Fietkau +--- + include/uapi/linux/if_packet.h | 3 +++ + net/packet/af_packet.c | 34 +++++++++++++++++++++++++++------- + net/packet/internal.h | 1 + + 3 files changed, 31 insertions(+), 7 deletions(-) + +--- a/include/uapi/linux/if_packet.h ++++ b/include/uapi/linux/if_packet.h +@@ -33,6 +33,8 @@ struct sockaddr_ll { + #define PACKET_KERNEL 7 /* To kernel space */ + /* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ + #define PACKET_FASTROUTE 6 /* Fastrouted frame */ ++#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */ ++ + + /* Packet socket options */ + +@@ -59,6 +61,7 @@ struct sockaddr_ll { + #define PACKET_ROLLOVER_STATS 21 + #define PACKET_FANOUT_DATA 22 + #define PACKET_IGNORE_OUTGOING 23 ++#define PACKET_RECV_TYPE 24 + + #define PACKET_FANOUT_HASH 0 + #define PACKET_FANOUT_LB 1 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1826,6 +1826,7 @@ static int packet_rcv_spkt(struct sk_buf + { + struct sock *sk; + struct sockaddr_pkt *spkt; ++ struct packet_sock *po; + + /* + * When we registered the protocol we saved the socket in the data +@@ -1833,6 +1834,7 @@ static int packet_rcv_spkt(struct sk_buf + */ + + sk = pt->af_packet_priv; ++ po = pkt_sk(sk); + + /* + * Yank back the headers [hope the device set this +@@ -1845,7 +1847,7 @@ static int packet_rcv_spkt(struct sk_buf + * so that this procedure is noop. + */ + +- if (skb->pkt_type == PACKET_LOOPBACK) ++ if (!(po->pkt_type & (1 << skb->pkt_type))) + goto out; + + if (!net_eq(dev_net(dev), sock_net(sk))) +@@ -2093,12 +2095,12 @@ static int packet_rcv(struct sk_buff *sk + unsigned int snaplen, res; + bool is_drop_n_account = false; + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -2224,12 +2226,12 @@ static int tpacket_rcv(struct sk_buff *s + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); + BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); + +- if (skb->pkt_type == PACKET_LOOPBACK) +- goto drop; +- + sk = pt->af_packet_priv; + po = pkt_sk(sk); + ++ if (!(po->pkt_type & (1 << skb->pkt_type))) ++ goto drop; ++ + if (!net_eq(dev_net(dev), sock_net(sk))) + goto drop; + +@@ -3342,6 +3344,7 @@ static int packet_create(struct net *net + mutex_init(&po->pg_vec_lock); + po->rollover = NULL; + po->prot_hook.func = packet_rcv; ++ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK); + + if (sock->type == SOCK_PACKET) + po->prot_hook.func = packet_rcv_spkt; +@@ -3979,6 +3982,16 @@ packet_setsockopt(struct socket *sock, i + WRITE_ONCE(po->xmit, val ? packet_direct_xmit : dev_queue_xmit); + return 0; + } ++ case PACKET_RECV_TYPE: ++ { ++ unsigned int val; ++ if (optlen != sizeof(val)) ++ return -EINVAL; ++ if (copy_from_sockptr(&val, optval, sizeof(val))) ++ return -EFAULT; ++ po->pkt_type = val & ~BIT(PACKET_LOOPBACK); ++ return 0; ++ } + default: + return -ENOPROTOOPT; + } +@@ -4035,6 +4048,13 @@ static int packet_getsockopt(struct sock + case PACKET_VNET_HDR: + val = po->has_vnet_hdr; + break; ++ case PACKET_RECV_TYPE: ++ if (len > sizeof(unsigned int)) ++ len = sizeof(unsigned int); ++ val = po->pkt_type; ++ ++ data = &val; ++ break; + case PACKET_VERSION: + val = po->tp_version; + break; +--- a/net/packet/internal.h ++++ b/net/packet/internal.h +@@ -136,6 +136,7 @@ struct packet_sock { + int (*xmit)(struct sk_buff *skb); + struct packet_type prot_hook ____cacheline_aligned_in_smp; + atomic_t tp_drops ____cacheline_aligned_in_smp; ++ unsigned int pkt_type; + }; + + static inline struct packet_sock *pkt_sk(struct sock *sk) diff --git a/target/linux/generic/pending-6.1/655-increase_skb_pad.patch b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch new file mode 100644 index 00000000000..5d100270a90 --- /dev/null +++ b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch @@ -0,0 +1,20 @@ +From: Felix Fietkau +Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance + +lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd +Signed-off-by: Felix Fietkau +--- + include/linux/skbuff.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2821,7 +2821,7 @@ static inline int pskb_network_may_pull( + * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) + */ + #ifndef NET_SKB_PAD +-#define NET_SKB_PAD max(32, L1_CACHE_BYTES) ++#define NET_SKB_PAD max(64, L1_CACHE_BYTES) + #endif + + int ___pskb_trim(struct sk_buff *skb, unsigned int len); diff --git a/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch new file mode 100644 index 00000000000..2f6fbd59e43 --- /dev/null +++ b/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -0,0 +1,511 @@ +From: Steven Barth +Subject: Add support for MAP-E FMRs (mesh mode) + +MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication +between MAP CEs (mesh mode) without the need to forward such data to a +border relay. This is similar to how 6rd works but for IPv4 over IPv6. + +Signed-off-by: Steven Barth +--- + include/net/ip6_tunnel.h | 13 ++ + include/uapi/linux/if_tunnel.h | 13 ++ + net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 291 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_tunnel.h ++++ b/include/net/ip6_tunnel.h +@@ -18,6 +18,18 @@ + /* determine capability on a per-packet basis */ + #define IP6_TNL_F_CAP_PER_PACKET 0x40000 + ++/* IPv6 tunnel FMR */ ++struct __ip6_tnl_fmr { ++ struct __ip6_tnl_fmr *next; /* next fmr in list */ ++ struct in6_addr ip6_prefix; ++ struct in_addr ip4_prefix; ++ ++ __u8 ip6_prefix_len; ++ __u8 ip4_prefix_len; ++ __u8 ea_len; ++ __u8 offset; ++}; ++ + struct __ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ +@@ -29,6 +41,7 @@ struct __ip6_tnl_parm { + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ ++ struct __ip6_tnl_fmr *fmrs; /* FMRs */ + + __be16 i_flags; + __be16 o_flags; +--- a/include/uapi/linux/if_tunnel.h ++++ b/include/uapi/linux/if_tunnel.h +@@ -77,10 +77,23 @@ enum { + IFLA_IPTUN_ENCAP_DPORT, + IFLA_IPTUN_COLLECT_METADATA, + IFLA_IPTUN_FWMARK, ++ IFLA_IPTUN_FMRS, + __IFLA_IPTUN_MAX, + }; + #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) + ++enum { ++ IFLA_IPTUN_FMR_UNSPEC, ++ IFLA_IPTUN_FMR_IP6_PREFIX, ++ IFLA_IPTUN_FMR_IP4_PREFIX, ++ IFLA_IPTUN_FMR_IP6_PREFIX_LEN, ++ IFLA_IPTUN_FMR_IP4_PREFIX_LEN, ++ IFLA_IPTUN_FMR_EA_LEN, ++ IFLA_IPTUN_FMR_OFFSET, ++ __IFLA_IPTUN_FMR_MAX, ++}; ++#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1) ++ + enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, +--- a/net/ipv6/ip6_tunnel.c ++++ b/net/ipv6/ip6_tunnel.c +@@ -11,6 +11,9 @@ + * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c + * + * RFC 2473 ++ * ++ * Changes: ++ * Steven Barth : MAP-E FMR support + */ + + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +@@ -67,9 +70,9 @@ static bool log_ecn_error = true; + module_param(log_ecn_error, bool, 0644); + MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); + +-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) ++static u32 HASH(const struct in6_addr *addr) + { +- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); ++ u32 hash = ipv6_addr_hash(addr); + + return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT); + } +@@ -114,17 +117,33 @@ static struct ip6_tnl * + ip6_tnl_lookup(struct net *net, int link, + const struct in6_addr *remote, const struct in6_addr *local) + { +- unsigned int hash = HASH(remote, local); ++ unsigned int hash = HASH(local); + struct ip6_tnl *t, *cand = NULL; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(local, &t->parms.laddr) || +- !ipv6_addr_equal(remote, &t->parms.raddr) || + !(t->dev->flags & IFF_UP)) + continue; + ++ if (!ipv6_addr_equal(remote, &t->parms.raddr)) { ++ struct __ip6_tnl_fmr *fmr; ++ bool found = false; ++ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix, ++ fmr->ip6_prefix_len)) ++ continue; ++ ++ found = true; ++ break; ++ } ++ ++ if (!found) ++ continue; ++ } ++ + if (link == t->parms.link) + return t; + else +@@ -132,7 +151,7 @@ ip6_tnl_lookup(struct net *net, int link + } + + memset(&any, 0, sizeof(any)); +- hash = HASH(&any, local); ++ hash = HASH(local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(local, &t->parms.laddr) || + !ipv6_addr_any(&t->parms.raddr) || +@@ -145,7 +164,7 @@ ip6_tnl_lookup(struct net *net, int link + cand = t; + } + +- hash = HASH(remote, &any); ++ hash = HASH(&any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (!ipv6_addr_equal(remote, &t->parms.raddr) || + !ipv6_addr_any(&t->parms.laddr) || +@@ -194,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; +- h = HASH(remote, local); ++ h = HASH(local); + } + return &ip6n->tnls[prio][h]; + } +@@ -378,6 +397,12 @@ ip6_tnl_dev_uninit(struct net_device *de + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else +@@ -790,6 +815,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, + } + EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); + ++/** ++ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR ++ * @dest: destination IPv6 address buffer ++ * @skb: received socket buffer ++ * @fmr: MAP FMR ++ * @xmit: Calculate for xmit or rcv ++ **/ ++static void ip4ip6_fmr_calc(struct in6_addr *dest, ++ const struct iphdr *iph, const uint8_t *end, ++ const struct __ip6_tnl_fmr *fmr, bool xmit) ++{ ++ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len); ++ u8 *portp = NULL; ++ bool use_dest_addr; ++ const struct iphdr *dsth = iph; ++ ++ if ((u8*)dsth >= end) ++ return; ++ ++ /* find significant IP header */ ++ if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ if (ih && ((u8*)&ih[1]) <= end && ( ++ ih->type == ICMP_DEST_UNREACH || ++ ih->type == ICMP_SOURCE_QUENCH || ++ ih->type == ICMP_TIME_EXCEEDED || ++ ih->type == ICMP_PARAMETERPROB || ++ ih->type == ICMP_REDIRECT)) ++ dsth = (const struct iphdr*)&ih[1]; ++ } ++ ++ /* in xmit-path use dest port by default and source port only if ++ this is an ICMP reply to something else; vice versa in rcv-path */ ++ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph); ++ ++ /* get dst port */ ++ if (((u8*)&dsth[1]) <= end && ( ++ dsth->protocol == IPPROTO_UDP || ++ dsth->protocol == IPPROTO_TCP || ++ dsth->protocol == IPPROTO_SCTP || ++ dsth->protocol == IPPROTO_DCCP)) { ++ /* for UDP, TCP, SCTP and DCCP source and dest port ++ follow IPv4 header directly */ ++ portp = ((u8*)dsth) + dsth->ihl * 4; ++ ++ if (use_dest_addr) ++ portp += sizeof(u16); ++ } else if (iph->protocol == IPPROTO_ICMP) { ++ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4); ++ ++ /* use icmp identifier as port */ ++ if (((u8*)&ih) <= end && ( ++ (use_dest_addr && ( ++ ih->type == ICMP_ECHOREPLY || ++ ih->type == ICMP_TIMESTAMPREPLY || ++ ih->type == ICMP_INFO_REPLY || ++ ih->type == ICMP_ADDRESSREPLY)) || ++ (!use_dest_addr && ( ++ ih->type == ICMP_ECHO || ++ ih->type == ICMP_TIMESTAMP || ++ ih->type == ICMP_INFO_REQUEST || ++ ih->type == ICMP_ADDRESS) ++ ))) ++ portp = (u8*)&ih->un.echo.id; ++ } ++ ++ if ((portp && &portp[2] <= end) || psidlen == 0) { ++ int frombyte = fmr->ip6_prefix_len / 8; ++ int fromrem = fmr->ip6_prefix_len % 8; ++ int bytes = sizeof(struct in6_addr) - frombyte; ++ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr; ++ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len); ++ u64 t = 0; ++ ++ /* extract PSID from port and add it to eabits */ ++ u16 psidbits = 0; ++ if (psidlen > 0) { ++ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]); ++ psidbits >>= 16 - psidlen - fmr->offset; ++ psidbits = (u16)(psidbits << (16 - psidlen)); ++ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen)); ++ } ++ ++ /* rewrite destination address */ ++ *dest = fmr->ip6_prefix; ++ memcpy(&dest->s6_addr[10], addr, sizeof(*addr)); ++ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen)); ++ ++ if (bytes > sizeof(u64)) ++ bytes = sizeof(u64); ++ ++ /* insert eabits */ ++ memcpy(&t, &dest->s6_addr[frombyte], bytes); ++ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1) ++ << (64 - fmr->ea_len - fromrem)); ++ t = cpu_to_be64(t | (eabits >> fromrem)); ++ memcpy(&dest->s6_addr[frombyte], &t, bytes); ++ } ++} ++ ++ + static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, +@@ -843,6 +969,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl + skb_reset_network_header(skb); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + ++ if (tpi->proto == htons(ETH_P_IP) && tunnel->parms.fmrs && ++ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) { ++ /* Packet didn't come from BR, so lookup FMR */ ++ struct __ip6_tnl_fmr *fmr; ++ struct in6_addr expected = tunnel->parms.raddr; ++ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next) ++ if (ipv6_prefix_equal(&ipv6h->saddr, ++ &fmr->ip6_prefix, fmr->ip6_prefix_len)) ++ break; ++ ++ /* Check that IPv6 matches IPv4 source to prevent spoofing */ ++ if (fmr) ++ ip4ip6_fmr_calc(&expected, ip_hdr(skb), ++ skb_tail_pointer(skb), fmr, false); ++ ++ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) { ++ rcu_read_unlock(); ++ goto drop; ++ } ++ } ++ + __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); + + err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); +@@ -994,6 +1141,7 @@ static void init_tel_txopt(struct ipv6_t + opt->ops.opt_nflen = 8; + } + ++ + /** + * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device +@@ -1274,6 +1422,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str + u8 protocol) + { + struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *fmr; + struct ipv6hdr *ipv6h; + const struct iphdr *iph; + int encap_limit = -1; +@@ -1373,6 +1522,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str + fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield); + ++ /* try to find matching FMR */ ++ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) { ++ unsigned mshift = 32 - fmr->ip4_prefix_len; ++ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift == ++ ntohl(ip_hdr(skb)->daddr) >> mshift) ++ break; ++ } ++ ++ /* change dstaddr according to FMR */ ++ if (fmr) ++ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true); ++ + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) + return -1; + +@@ -1526,6 +1687,14 @@ ip6_tnl_change(struct ip6_tnl *t, const + t->parms.link = p->link; + t->parms.proto = p->proto; + t->parms.fwmark = p->fwmark; ++ ++ while (t->parms.fmrs) { ++ struct __ip6_tnl_fmr *next = t->parms.fmrs->next; ++ kfree(t->parms.fmrs); ++ t->parms.fmrs = next; ++ } ++ t->parms.fmrs = p->fmrs; ++ + dst_cache_reset(&t->dst_cache); + ip6_tnl_link_config(t); + return 0; +@@ -1564,6 +1733,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; ++ p->fmrs = NULL; + memcpy(p->name, u->name, sizeof(u->name)); + } + +@@ -1950,6 +2120,15 @@ static int ip6_tnl_validate(struct nlatt + return 0; + } + ++static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = { ++ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) }, ++ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 }, ++ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 } ++}; ++ + static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) + { +@@ -1987,6 +2166,46 @@ static void ip6_tnl_netlink_parms(struct + + if (data[IFLA_IPTUN_FWMARK]) + parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); ++ ++ if (data[IFLA_IPTUN_FMRS]) { ++ unsigned rem; ++ struct nlattr *fmr; ++ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) { ++ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c; ++ struct __ip6_tnl_fmr *nfmr; ++ ++ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX, ++ fmr, ip6_tnl_fmr_policy, NULL); ++ ++ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL))) ++ continue; ++ ++ nfmr->offset = 6; ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX])) ++ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX], ++ sizeof(nfmr->ip6_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX])) ++ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX], ++ sizeof(nfmr->ip4_prefix)); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN])) ++ nfmr->ip6_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN])) ++ nfmr->ip4_prefix_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN])) ++ nfmr->ea_len = nla_get_u8(c); ++ ++ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET])) ++ nfmr->offset = nla_get_u8(c); ++ ++ nfmr->next = parms->fmrs; ++ parms->fmrs = nfmr; ++ } ++ } + } + + static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[], +@@ -2102,6 +2321,12 @@ static void ip6_tnl_dellink(struct net_d + + static size_t ip6_tnl_get_size(const struct net_device *dev) + { ++ const struct ip6_tnl *t = netdev_priv(dev); ++ struct __ip6_tnl_fmr *c; ++ int fmrs = 0; ++ for (c = t->parms.fmrs; c; c = c->next) ++ ++fmrs; ++ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + +@@ -2131,6 +2356,24 @@ static size_t ip6_tnl_get_size(const str + nla_total_size(0) + + /* IFLA_IPTUN_FWMARK */ + nla_total_size(4) + ++ /* IFLA_IPTUN_FMRS */ ++ nla_total_size(0) + ++ ( ++ /* nest */ ++ nla_total_size(0) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX */ ++ nla_total_size(sizeof(struct in6_addr)) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX */ ++ nla_total_size(sizeof(struct in_addr)) + ++ /* IFLA_IPTUN_FMR_EA_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */ ++ nla_total_size(1) + ++ /* IFLA_IPTUN_FMR_OFFSET */ ++ nla_total_size(1) ++ ) * fmrs + + 0; + } + +@@ -2138,6 +2381,9 @@ static int ip6_tnl_fill_info(struct sk_b + { + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; ++ struct __ip6_tnl_fmr *c; ++ int fmrcnt = 0; ++ struct nlattr *fmrs; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || +@@ -2147,9 +2393,27 @@ static int ip6_tnl_fill_info(struct sk_b + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || + nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || +- nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark)) ++ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) || ++ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS))) + goto nla_put_failure; + ++ for (c = parm->fmrs; c; c = c->next) { ++ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt); ++ if (!fmr || ++ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX, ++ sizeof(c->ip6_prefix), &c->ip6_prefix) || ++ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX, ++ sizeof(c->ip4_prefix), &c->ip4_prefix) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) || ++ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset)) ++ goto nla_put_failure; ++ ++ nla_nest_end(skb, fmr); ++ } ++ nla_nest_end(skb, fmrs); ++ + if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || +@@ -2189,6 +2453,7 @@ static const struct nla_policy ip6_tnl_p + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, + [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, ++ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED }, + }; + + static struct rtnl_link_ops ip6_link_ops __read_mostly = { diff --git a/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch new file mode 100644 index 00000000000..86bd9664e55 --- /dev/null +++ b/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -0,0 +1,263 @@ +From: Jonas Gorski +Subject: ipv6: allow rejecting with "source address failed policy" + +RFC6204 L-14 requires rejecting traffic from invalid addresses with +ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/ +egress policy) on the LAN side, so add an appropriate rule for that. + +Signed-off-by: Jonas Gorski +--- + include/net/netns/ipv6.h | 1 + + include/uapi/linux/fib_rules.h | 4 +++ + include/uapi/linux/rtnetlink.h | 1 + + net/ipv4/fib_semantics.c | 4 +++ + net/ipv4/fib_trie.c | 1 + + net/ipv4/ipmr.c | 1 + + net/ipv6/fib6_rules.c | 4 +++ + net/ipv6/ip6mr.c | 2 ++ + net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++- + 9 files changed, 75 insertions(+), 1 deletion(-) + +--- a/include/net/netns/ipv6.h ++++ b/include/net/netns/ipv6.h +@@ -85,6 +85,7 @@ struct netns_ipv6 { + unsigned int fib6_routes_require_src; + #endif + struct rt6_info *ip6_prohibit_entry; ++ struct rt6_info *ip6_policy_failed_entry; + struct rt6_info *ip6_blk_hole_entry; + struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -82,6 +82,10 @@ enum { + FR_ACT_BLACKHOLE, /* Drop without notification */ + FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ + FR_ACT_PROHIBIT, /* Drop with EACCES */ ++ FR_ACT_RES9, ++ FR_ACT_RES10, ++ FR_ACT_RES11, ++ FR_ACT_POLICY_FAILED, /* Drop with EACCES */ + __FR_ACT_MAX, + }; + +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -256,6 +256,7 @@ enum { + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ ++ RTN_POLICY_FAILED, /* Failed ingress/egress policy */ + __RTN_MAX + }; + +--- a/net/ipv4/fib_semantics.c ++++ b/net/ipv4/fib_semantics.c +@@ -143,6 +143,10 @@ const struct fib_prop fib_props[RTN_MAX + .error = -EINVAL, + .scope = RT_SCOPE_NOWHERE, + }, ++ [RTN_POLICY_FAILED] = { ++ .error = -EACCES, ++ .scope = RT_SCOPE_UNIVERSE, ++ }, + }; + + static void rt_fibinfo_free(struct rtable __rcu **rtp) +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -2772,6 +2772,7 @@ static const char *const rtn_type_names[ + [RTN_THROW] = "THROW", + [RTN_NAT] = "NAT", + [RTN_XRESOLVE] = "XRESOLVE", ++ [RTN_POLICY_FAILED] = "POLICY_FAILED", + }; + + static inline const char *rtn_type(char *buf, size_t len, unsigned int t) +--- a/net/ipv4/ipmr.c ++++ b/net/ipv4/ipmr.c +@@ -175,6 +175,7 @@ static int ipmr_rule_action(struct fib_r + case FR_ACT_UNREACHABLE: + return -ENETUNREACH; + case FR_ACT_PROHIBIT: ++ case FR_ACT_POLICY_FAILED: + return -EACCES; + case FR_ACT_BLACKHOLE: + default: +--- a/net/ipv6/fib6_rules.c ++++ b/net/ipv6/fib6_rules.c +@@ -220,6 +220,10 @@ static int __fib6_rule_action(struct fib + err = -EACCES; + rt = net->ipv6.ip6_prohibit_entry; + goto discard_pkt; ++ case FR_ACT_POLICY_FAILED: ++ err = -EACCES; ++ rt = net->ipv6.ip6_policy_failed_entry; ++ goto discard_pkt; + } + + tb_id = fib_rule_get_table(rule, arg); +--- a/net/ipv6/ip6mr.c ++++ b/net/ipv6/ip6mr.c +@@ -163,6 +163,8 @@ static int ip6mr_rule_action(struct fib_ + return -ENETUNREACH; + case FR_ACT_PROHIBIT: + return -EACCES; ++ case FR_ACT_POLICY_FAILED: ++ return -EACCES; + case FR_ACT_BLACKHOLE: + default: + return -EINVAL; +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -97,6 +97,8 @@ static int ip6_pkt_discard(struct sk_bu + static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static int ip6_pkt_prohibit(struct sk_buff *skb); + static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); ++static int ip6_pkt_policy_failed(struct sk_buff *skb); ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb); + static void ip6_link_failure(struct sk_buff *skb); + static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu, +@@ -312,6 +314,18 @@ static const struct rt6_info ip6_prohibi + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), + }; + ++static const struct rt6_info ip6_policy_failed_entry_template = { ++ .dst = { ++ .__refcnt = ATOMIC_INIT(1), ++ .__use = 1, ++ .obsolete = DST_OBSOLETE_FORCE_CHK, ++ .error = -EACCES, ++ .input = ip6_pkt_policy_failed, ++ .output = ip6_pkt_policy_failed_out, ++ }, ++ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), ++}; ++ + static const struct rt6_info ip6_blk_hole_entry_template = { + .dst = { + .__refcnt = ATOMIC_INIT(1), +@@ -1033,6 +1047,7 @@ static const int fib6_prop[RTN_MAX + 1] + [RTN_BLACKHOLE] = -EINVAL, + [RTN_UNREACHABLE] = -EHOSTUNREACH, + [RTN_PROHIBIT] = -EACCES, ++ [RTN_POLICY_FAILED] = -EACCES, + [RTN_THROW] = -EAGAIN, + [RTN_NAT] = -EINVAL, + [RTN_XRESOLVE] = -EINVAL, +@@ -1068,6 +1083,10 @@ static void ip6_rt_init_dst_reject(struc + rt->dst.output = ip6_pkt_prohibit_out; + rt->dst.input = ip6_pkt_prohibit; + break; ++ case RTN_POLICY_FAILED: ++ rt->dst.output = ip6_pkt_policy_failed_out; ++ rt->dst.input = ip6_pkt_policy_failed; ++ break; + case RTN_THROW: + case RTN_UNREACHABLE: + default: +@@ -4560,6 +4579,17 @@ static int ip6_pkt_prohibit_out(struct n + return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); + } + ++static int ip6_pkt_policy_failed(struct sk_buff *skb) ++{ ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES); ++} ++ ++static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb) ++{ ++ skb->dev = skb_dst(skb)->dev; ++ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES); ++} ++ + /* + * Allocate a dst for local (unicast / anycast) address. + */ +@@ -5047,7 +5077,8 @@ static int rtm_to_fib6_config(struct sk_ + if (rtm->rtm_type == RTN_UNREACHABLE || + rtm->rtm_type == RTN_BLACKHOLE || + rtm->rtm_type == RTN_PROHIBIT || +- rtm->rtm_type == RTN_THROW) ++ rtm->rtm_type == RTN_THROW || ++ rtm->rtm_type == RTN_POLICY_FAILED) + cfg->fc_flags |= RTF_REJECT; + + if (rtm->rtm_type == RTN_LOCAL) +@@ -6301,6 +6332,8 @@ static int ip6_route_dev_notify(struct n + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); ++ net->ipv6.ip6_policy_failed_entry->dst.dev = dev; ++ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif +@@ -6312,6 +6345,7 @@ static int ip6_route_dev_notify(struct n + in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); ++ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev); + in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); + #endif + } +@@ -6503,6 +6537,8 @@ static int __net_init ip6_route_net_init + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.fib6_has_custom_rules = false; ++ ++ + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*net->ipv6.ip6_prohibit_entry), + GFP_KERNEL); +@@ -6513,11 +6549,21 @@ static int __net_init ip6_route_net_init + ip6_template_metrics, true); + INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached); + ++ net->ipv6.ip6_policy_failed_entry = ++ kmemdup(&ip6_policy_failed_entry_template, ++ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL); ++ if (!net->ipv6.ip6_policy_failed_entry) ++ goto out_ip6_prohibit_entry; ++ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops; ++ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst, ++ ip6_template_metrics, true); ++ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->rt6i_uncached); ++ + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*net->ipv6.ip6_blk_hole_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_blk_hole_entry) +- goto out_ip6_prohibit_entry; ++ goto out_ip6_policy_failed_entry; + net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; + dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, + ip6_template_metrics, true); +@@ -6544,6 +6590,8 @@ out: + return ret; + + #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++out_ip6_policy_failed_entry: ++ kfree(net->ipv6.ip6_policy_failed_entry); + out_ip6_prohibit_entry: + kfree(net->ipv6.ip6_prohibit_entry); + out_ip6_null_entry: +@@ -6563,6 +6611,7 @@ static void __net_exit ip6_route_net_exi + kfree(net->ipv6.ip6_null_entry); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); ++ kfree(net->ipv6.ip6_policy_failed_entry); + kfree(net->ipv6.ip6_blk_hole_entry); + #endif + dst_entries_destroy(&net->ipv6.ip6_dst_ops); +@@ -6646,6 +6695,9 @@ void __init ip6_route_init_special_entri + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev = ++ in6_dev_get(init_net.loopback_dev); + #endif + } + diff --git a/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch new file mode 100644 index 00000000000..bea43b2bada --- /dev/null +++ b/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -0,0 +1,50 @@ +From: Jonas Gorski +Subject: net: provide defines for _POLICY_FAILED until all code is updated + +Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination +unreachable, conflicting with our name. + +Add appropriate defines to allow our code to build with the new +name until we have updated our local patches for older kernels +and userspace packages. + +Signed-off-by: Jonas Gorski +--- + include/uapi/linux/fib_rules.h | 2 ++ + include/uapi/linux/icmpv6.h | 2 ++ + include/uapi/linux/rtnetlink.h | 2 ++ + 3 files changed, 6 insertions(+) + +--- a/include/uapi/linux/fib_rules.h ++++ b/include/uapi/linux/fib_rules.h +@@ -89,6 +89,8 @@ enum { + __FR_ACT_MAX, + }; + ++#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED ++ + #define FR_ACT_MAX (__FR_ACT_MAX - 1) + + #endif +--- a/include/uapi/linux/icmpv6.h ++++ b/include/uapi/linux/icmpv6.h +@@ -126,6 +126,8 @@ struct icmp6hdr { + #define ICMPV6_POLICY_FAIL 5 + #define ICMPV6_REJECT_ROUTE 6 + ++#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL ++ + /* + * Codes for Time Exceeded + */ +--- a/include/uapi/linux/rtnetlink.h ++++ b/include/uapi/linux/rtnetlink.h +@@ -260,6 +260,8 @@ enum { + __RTN_MAX + }; + ++#define RTN_FAILED_POLICY RTN_POLICY_FAILED ++ + #define RTN_MAX (__RTN_MAX - 1) + + diff --git a/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch new file mode 100644 index 00000000000..091e65f31e0 --- /dev/null +++ b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -0,0 +1,149 @@ +From: Felix Fietkau +Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses + +Signed-off-by: Felix Fietkau +--- + include/linux/netdevice.h | 2 ++ + include/linux/skbuff.h | 3 ++- + net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ + net/ethernet/eth.c | 18 +++++++++++++++++- + 4 files changed, 69 insertions(+), 2 deletions(-) + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2098,6 +2098,8 @@ struct net_device { + struct netdev_hw_addr_list mc; + struct netdev_hw_addr_list dev_addrs; + ++ unsigned char local_addr_mask[MAX_ADDR_LEN]; ++ + #ifdef CONFIG_SYSFS + struct kset *queues_kset; + #endif +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -893,6 +893,7 @@ struct sk_buff { + #ifdef CONFIG_IPV6_NDISC_NODETYPE + __u8 ndisc_nodetype:2; + #endif ++ __u8 gro_skip:1; + + __u8 ipvs_property:1; + __u8 inner_protocol_type:1; +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -6065,6 +6065,9 @@ static enum gro_result dev_gro_receive(s + int same_flow; + int grow; + ++ if (skb->gro_skip) ++ goto normal; ++ + if (netif_elide_gro(skb->dev)) + goto normal; + +@@ -8079,6 +8082,48 @@ static void __netdev_adjacent_dev_unlink + &upper_dev->adj_list.lower); + } + ++static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr, ++ struct net_device *dev) ++{ ++ int i; ++ ++ for (i = 0; i < dev->addr_len; i++) ++ mask[i] |= addr[i] ^ dev->dev_addr[i]; ++} ++ ++static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev, ++ struct net_device *lower) ++{ ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ netdev_for_each_upper_dev_rcu(dev, cur, iter) { ++ __netdev_addr_mask(mask, cur->dev_addr, lower); ++ __netdev_upper_mask(mask, cur, lower); ++ } ++} ++ ++static void __netdev_update_addr_mask(struct net_device *dev) ++{ ++ unsigned char mask[MAX_ADDR_LEN]; ++ struct net_device *cur; ++ struct list_head *iter; ++ ++ memset(mask, 0, sizeof(mask)); ++ __netdev_upper_mask(mask, dev, dev); ++ memcpy(dev->local_addr_mask, mask, dev->addr_len); ++ ++ netdev_for_each_lower_dev(dev, cur, iter) ++ __netdev_update_addr_mask(cur); ++} ++ ++static void netdev_update_addr_mask(struct net_device *dev) ++{ ++ rcu_read_lock(); ++ __netdev_update_addr_mask(dev); ++ rcu_read_unlock(); ++} ++ + static int __netdev_upper_dev_link(struct net_device *dev, + struct net_device *upper_dev, bool master, + void *upper_priv, void *upper_info, +@@ -8130,6 +8175,7 @@ static int __netdev_upper_dev_link(struc + if (ret) + return ret; + ++ netdev_update_addr_mask(dev); + ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, + &changeupper_info.info); + ret = notifier_to_errno(ret); +@@ -8226,6 +8272,7 @@ static void __netdev_upper_dev_unlink(st + + __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); + ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, + &changeupper_info.info); + +@@ -9045,6 +9092,7 @@ int dev_set_mac_address(struct net_devic + if (err) + return err; + dev->addr_assign_type = NET_ADDR_SET; ++ netdev_update_addr_mask(dev); + call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); + add_device_randomness(dev->dev_addr, dev->addr_len); + return 0; +--- a/net/ethernet/eth.c ++++ b/net/ethernet/eth.c +@@ -142,6 +142,18 @@ u32 eth_get_headlen(const struct net_dev + } + EXPORT_SYMBOL(eth_get_headlen); + ++static inline bool ++eth_check_local_mask(const void *addr1, const void *addr2, const void *mask) ++{ ++ const u16 *a1 = addr1; ++ const u16 *a2 = addr2; ++ const u16 *m = mask; ++ ++ return (((a1[0] ^ a2[0]) & ~m[0]) | ++ ((a1[1] ^ a2[1]) & ~m[1]) | ++ ((a1[2] ^ a2[2]) & ~m[2])); ++} ++ + /** + * eth_type_trans - determine the packet's protocol ID. + * @skb: received socket data +@@ -173,6 +185,10 @@ __be16 eth_type_trans(struct sk_buff *sk + } else { + skb->pkt_type = PACKET_OTHERHOST; + } ++ ++ if (eth_check_local_mask(eth->h_dest, dev->dev_addr, ++ dev->local_addr_mask)) ++ skb->gro_skip = 1; + } + + /* diff --git a/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch b/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch new file mode 100644 index 00000000000..fe6faddc7d7 --- /dev/null +++ b/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch @@ -0,0 +1,89 @@ +From 844c273286f328acf0dab5fbd5d864366b4904dc Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 30 Mar 2021 18:21:14 +0200 +Subject: [PATCH] of_net: add mac-address-increment support + +Lots of embedded devices use the mac-address of other interface +extracted from nvmem cells and increments it by one or two. Add two +bindings to integrate this and directly use the right mac-address for +the interface. Some example are some routers that use the gmac +mac-address stored in the art partition and increments it by one for the +wifi. mac-address-increment-byte bindings is used to tell what byte of +the mac-address has to be increased (if not defined the last byte is +increased) and mac-address-increment tells how much the byte decided +early has to be increased. + +Signed-off-by: Ansuel Smith +--- + net/core/of_net.c | 43 +++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 39 insertions(+), 4 deletions(-) + +--- a/net/core/of_net.c ++++ b/net/core/of_net.c +@@ -119,27 +119,62 @@ static int of_get_mac_addr_nvmem(struct + * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists + * but is all zeros. + * ++ * DT can tell the system to increment the mac-address after is extracted by ++ * using: ++ * - mac-address-increment-byte to decide what byte to increase ++ * (if not defined is increased the last byte) ++ * - mac-address-increment to decide how much to increase. The value WILL ++ * overflow to other bytes if the increment is over 255 or the total ++ * increment will exceed 255 of the current byte. ++ * (example 00:01:02:03:04:ff + 1 == 00:01:02:03:05:00) ++ * (example 00:01:02:03:04:fe + 5 == 00:01:02:03:05:03) ++ * + * Return: 0 on success and errno in case of error. + */ + int of_get_mac_address(struct device_node *np, u8 *addr) + { ++ u32 inc_idx, mac_inc, mac_val; + int ret; + ++ /* Check first if the increment byte is present and valid. ++ * If not set assume to increment the last byte if found. ++ */ ++ if (of_property_read_u32(np, "mac-address-increment-byte", &inc_idx)) ++ inc_idx = 5; ++ if (inc_idx < 3 || inc_idx > 5) ++ return -EINVAL; ++ + if (!np) + return -ENODEV; + + ret = of_get_mac_addr(np, "mac-address", addr); + if (!ret) +- return 0; ++ goto found; + + ret = of_get_mac_addr(np, "local-mac-address", addr); + if (!ret) +- return 0; ++ goto found; + + ret = of_get_mac_addr(np, "address", addr); + if (!ret) +- return 0; ++ goto found; ++ ++ ret = of_get_mac_addr_nvmem(np, addr); ++ if (ret) ++ return ret; ++ ++found: ++ if (!of_property_read_u32(np, "mac-address-increment", &mac_inc)) { ++ /* Convert to a contiguous value */ ++ mac_val = (addr[3] << 16) + (addr[4] << 8) + addr[5]; ++ mac_val += mac_inc << 8 * (5-inc_idx); ++ ++ /* Apply the incremented value handling overflow case */ ++ addr[3] = (mac_val >> 16) & 0xff; ++ addr[4] = (mac_val >> 8) & 0xff; ++ addr[5] = (mac_val >> 0) & 0xff; ++ } + +- return of_get_mac_addr_nvmem(np, addr); ++ return ret; + } + EXPORT_SYMBOL(of_get_mac_address); diff --git a/target/linux/generic/pending-6.1/683-of_net-add-mac-address-to-of-tree.patch b/target/linux/generic/pending-6.1/683-of_net-add-mac-address-to-of-tree.patch new file mode 100644 index 00000000000..f7ef06a14ad --- /dev/null +++ b/target/linux/generic/pending-6.1/683-of_net-add-mac-address-to-of-tree.patch @@ -0,0 +1,55 @@ +From 8585756342caa6d27008d1ad0c18023e4211a40a Mon Sep 17 00:00:00 2001 +From: OpenWrt community +Date: Wed, 13 Jul 2022 12:22:48 +0200 +Subject: [PATCH] of/of_net: write back netdev MAC-address to device-tree + +The label-mac logic relies on the mac-address property of a netdev +devices of-node. However, the mac address can also be stored as a +different property or read from e.g. an mtd device. + +Create this node when reading a mac-address from OF if it does not +already exist and copy the mac-address used for the device to this +property. This way, the MAC address can be accessed using procfs. + +--- + net/core/of_net.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/net/core/of_net.c ++++ b/net/core/of_net.c +@@ -95,6 +95,27 @@ static int of_get_mac_addr_nvmem(struct + return 0; + } + ++static int of_add_mac_address(struct device_node *np, u8* addr) ++{ ++ struct property *prop; ++ ++ prop = kzalloc(sizeof(*prop), GFP_KERNEL); ++ if (!prop) ++ return -ENOMEM; ++ ++ prop->name = "mac-address"; ++ prop->length = ETH_ALEN; ++ prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL); ++ if (!prop->value || of_update_property(np, prop)) ++ goto free; ++ ++ return 0; ++free: ++ kfree(prop->value); ++ kfree(prop); ++ return -ENOMEM; ++} ++ + /** + * of_get_mac_address() + * @np: Caller's Device Node +@@ -175,6 +196,7 @@ found: + addr[5] = (mac_val >> 0) & 0xff; + } + ++ of_add_mac_address(np, addr); + return ret; + } + EXPORT_SYMBOL(of_get_mac_address); diff --git a/target/linux/generic/pending-6.1/684-of_net-do-mac-address-increment-only-once.patch b/target/linux/generic/pending-6.1/684-of_net-do-mac-address-increment-only-once.patch new file mode 100644 index 00000000000..44d88e31a2e --- /dev/null +++ b/target/linux/generic/pending-6.1/684-of_net-do-mac-address-increment-only-once.patch @@ -0,0 +1,31 @@ +From dd07dd394d8bfdb5d527fab18ca54f20815ec4e4 Mon Sep 17 00:00:00 2001 +From: Will Moss +Date: Wed, 3 Aug 2022 13:48:55 +0000 +Subject: [PATCH] of_net: do mac-address-increment only once + +Remove mac-address-increment and mac-address-increment-byte +DT property after incrementing process to make sure MAC address +would not get incremented more if this function is stared again. +It could happen if device initialization is deferred after +unsuccessful attempt. + +Signed-off-by: Will Moss +--- + drivers/of/of_net.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/core/of_net.c ++++ b/net/core/of_net.c +@@ -194,6 +194,12 @@ found: + addr[3] = (mac_val >> 16) & 0xff; + addr[4] = (mac_val >> 8) & 0xff; + addr[5] = (mac_val >> 0) & 0xff; ++ ++ /* Remove mac-address-increment and mac-address-increment-byte ++ * DT property to make sure MAC address would not get incremented ++ * more if this function is stared again. */ ++ of_remove_property(np, of_find_property(np, "mac-address-increment", NULL)); ++ of_remove_property(np, of_find_property(np, "mac-address-increment-byte", NULL)); + } + + of_add_mac_address(np, addr); diff --git a/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch new file mode 100644 index 00000000000..488c6a8d92c --- /dev/null +++ b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch @@ -0,0 +1,106 @@ +From: Pablo Neira Ayuso +Date: Thu, 25 Jan 2018 12:58:55 +0100 +Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from + nf_flow_table + +Move the code that deals with device events to the core. + +Signed-off-by: Pablo Neira Ayuso +--- + +--- a/net/netfilter/nf_flow_table_core.c ++++ b/net/netfilter/nf_flow_table_core.c +@@ -613,13 +613,41 @@ void nf_flow_table_free(struct nf_flowta + } + EXPORT_SYMBOL_GPL(nf_flow_table_free); + ++static int nf_flow_table_netdev_event(struct notifier_block *this, ++ unsigned long event, void *ptr) ++{ ++ struct net_device *dev = netdev_notifier_info_to_dev(ptr); ++ ++ if (event != NETDEV_DOWN) ++ return NOTIFY_DONE; ++ ++ nf_flow_table_cleanup(dev); ++ ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block flow_offload_netdev_notifier = { ++ .notifier_call = nf_flow_table_netdev_event, ++}; ++ + static int __init nf_flow_table_module_init(void) + { +- return nf_flow_table_offload_init(); ++ int ret; ++ ++ ret = nf_flow_table_offload_init(); ++ if (ret) ++ return ret; ++ ++ ret = register_netdevice_notifier(&flow_offload_netdev_notifier); ++ if (ret) ++ nf_flow_table_offload_exit(); ++ ++ return ret; + } + + static void __exit nf_flow_table_module_exit(void) + { ++ unregister_netdevice_notifier(&flow_offload_netdev_notifier); + nf_flow_table_offload_exit(); + } + +--- a/net/netfilter/nft_flow_offload.c ++++ b/net/netfilter/nft_flow_offload.c +@@ -444,47 +444,14 @@ static struct nft_expr_type nft_flow_off + .owner = THIS_MODULE, + }; + +-static int flow_offload_netdev_event(struct notifier_block *this, +- unsigned long event, void *ptr) +-{ +- struct net_device *dev = netdev_notifier_info_to_dev(ptr); +- +- if (event != NETDEV_DOWN) +- return NOTIFY_DONE; +- +- nf_flow_table_cleanup(dev); +- +- return NOTIFY_DONE; +-} +- +-static struct notifier_block flow_offload_netdev_notifier = { +- .notifier_call = flow_offload_netdev_event, +-}; +- + static int __init nft_flow_offload_module_init(void) + { +- int err; +- +- err = register_netdevice_notifier(&flow_offload_netdev_notifier); +- if (err) +- goto err; +- +- err = nft_register_expr(&nft_flow_offload_type); +- if (err < 0) +- goto register_expr; +- +- return 0; +- +-register_expr: +- unregister_netdevice_notifier(&flow_offload_netdev_notifier); +-err: +- return err; ++ return nft_register_expr(&nft_flow_offload_type); + } + + static void __exit nft_flow_offload_module_exit(void) + { + nft_unregister_expr(&nft_flow_offload_type); +- unregister_netdevice_notifier(&flow_offload_netdev_notifier); + } + + module_init(nft_flow_offload_module_init); diff --git a/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch new file mode 100644 index 00000000000..a4e3d265033 --- /dev/null +++ b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -0,0 +1,41 @@ +From: Felix Fietkau +Date: Mon, 21 Mar 2022 20:39:59 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: enable threaded NAPI + +This can improve performance under load by ensuring that NAPI processing is +not pinned on CPU 0. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2992,8 +2992,8 @@ static irqreturn_t mtk_handle_irq_rx(int + + eth->rx_events++; + if (likely(napi_schedule_prep(ð->rx_napi))) { +- __napi_schedule(ð->rx_napi); + mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); ++ __napi_schedule(ð->rx_napi); + } + + return IRQ_HANDLED; +@@ -3005,8 +3005,8 @@ static irqreturn_t mtk_handle_irq_tx(int + + eth->tx_events++; + if (likely(napi_schedule_prep(ð->tx_napi))) { +- __napi_schedule(ð->tx_napi); + mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); ++ __napi_schedule(ð->tx_napi); + } + + return IRQ_HANDLED; +@@ -4673,6 +4673,8 @@ static int mtk_probe(struct platform_dev + * for NAPI to work + */ + init_dummy_netdev(ð->dummy_dev); ++ eth->dummy_dev.threaded = 1; ++ strcpy(eth->dummy_dev.name, "mtk_eth"); + netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, + NAPI_POLL_WEIGHT); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, diff --git a/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch new file mode 100644 index 00000000000..5baccf73cb8 --- /dev/null +++ b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -0,0 +1,38 @@ +From: Gabor Juhos +Subject: generic: add detach callback to struct phy_driver + +lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867 + +Signed-off-by: Gabor Juhos +--- + drivers/net/phy/phy_device.c | 3 +++ + include/linux/phy.h | 6 ++++++ + 2 files changed, 9 insertions(+) + +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1748,6 +1748,9 @@ void phy_detach(struct phy_device *phyde + struct module *ndev_owner = NULL; + struct mii_bus *bus; + ++ if (phydev->drv && phydev->drv->detach) ++ phydev->drv->detach(phydev); ++ + if (phydev->sysfs_links) { + if (dev) + sysfs_remove_link(&dev->dev.kobj, "phydev"); +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -823,6 +823,12 @@ struct phy_driver { + /** @handle_interrupt: Override default interrupt handling */ + irqreturn_t (*handle_interrupt)(struct phy_device *phydev); + ++ /* ++ * Called before an ethernet device is detached ++ * from the PHY. ++ */ ++ void (*detach)(struct phy_device *phydev); ++ + /** @remove: Clears up any memory if needed */ + void (*remove)(struct phy_device *phydev); + diff --git a/target/linux/generic/pending-6.1/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch b/target/linux/generic/pending-6.1/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch new file mode 100644 index 00000000000..d444b2027cb --- /dev/null +++ b/target/linux/generic/pending-6.1/705-net-dsa-tag_mtk-add-padding-for-tx-packets.patch @@ -0,0 +1,28 @@ +From: Felix Fietkau +Date: Fri, 6 May 2022 21:38:42 +0200 +Subject: [PATCH] net: dsa: tag_mtk: add padding for tx packets + +Padding for transmitted packets needs to account for the special tag. +With not enough padding, garbage bytes are inserted by the switch at the +end of small packets. + +Fixes: 5cd8985a1909 ("net-next: dsa: add Mediatek tag RX/TX handler") +Signed-off-by: Felix Fietkau +--- + +--- a/net/dsa/tag_mtk.c ++++ b/net/dsa/tag_mtk.c +@@ -27,6 +27,13 @@ static struct sk_buff *mtk_tag_xmit(stru + + skb_set_queue_mapping(skb, dp->index); + ++ /* The Ethernet switch we are interfaced with needs packets to be at ++ * least 64 bytes (including FCS) otherwise their padding might be ++ * corrupted. With tags enabled, we need to make sure that packets are ++ * at least 68 bytes (including FCS and tag). ++ */ ++ eth_skb_pad(skb); ++ + /* Build the special tag after the MAC Source Address. If VLAN header + * is present, it's required that VLAN header and special tag is + * being combined. Only in this way we can allow the switch can parse diff --git a/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch new file mode 100644 index 00000000000..2a2ca7f1fae --- /dev/null +++ b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch @@ -0,0 +1,174 @@ +From: Felix Fietkau +Date: Fri, 27 Aug 2021 12:22:32 +0200 +Subject: [PATCH] bridge: add knob for filtering rx/tx BPDU packets on a port + +Some devices (e.g. wireless APs) can't have devices behind them be part of +a bridge topology with redundant links, due to address limitations. +Additionally, broadcast traffic on these devices is somewhat expensive, due to +the low data rate and wakeups of clients in powersave mode. +This knob can be used to ensure that BPDU packets are never sent or forwarded +to/from these devices + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/if_bridge.h ++++ b/include/linux/if_bridge.h +@@ -58,6 +58,7 @@ struct br_ip_list { + #define BR_MRP_LOST_CONT BIT(18) + #define BR_MRP_LOST_IN_CONT BIT(19) + #define BR_TX_FWD_OFFLOAD BIT(20) ++#define BR_BPDU_FILTER BIT(21) + + #define BR_DEFAULT_AGEING_TIME (300 * HZ) + +--- a/net/bridge/br_forward.c ++++ b/net/bridge/br_forward.c +@@ -199,6 +199,7 @@ out: + void br_flood(struct net_bridge *br, struct sk_buff *skb, + enum br_pkt_type pkt_type, bool local_rcv, bool local_orig) + { ++ const unsigned char *dest = eth_hdr(skb)->h_dest; + struct net_bridge_port *prev = NULL; + struct net_bridge_port *p; + +@@ -214,6 +215,10 @@ void br_flood(struct net_bridge *br, str + case BR_PKT_MULTICAST: + if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev) + continue; ++ if ((p->flags & BR_BPDU_FILTER) && ++ unlikely(is_link_local_ether_addr(dest) && ++ dest[5] == 0)) ++ continue; + break; + case BR_PKT_BROADCAST: + if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) +--- a/net/bridge/br_input.c ++++ b/net/bridge/br_input.c +@@ -326,6 +326,8 @@ static rx_handler_result_t br_handle_fra + fwd_mask |= p->group_fwd_mask; + switch (dest[5]) { + case 0x00: /* Bridge Group Address */ ++ if (p->flags & BR_BPDU_FILTER) ++ goto drop; + /* If STP is turned off, + then must forward to keep loop detection */ + if (p->br->stp_enabled == BR_NO_STP || +--- a/net/bridge/br_sysfs_if.c ++++ b/net/bridge/br_sysfs_if.c +@@ -240,6 +240,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCA + BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD); + BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS); + BRPORT_ATTR_FLAG(isolated, BR_ISOLATED); ++BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER); + + #ifdef CONFIG_BRIDGE_IGMP_SNOOPING + static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf) +@@ -292,6 +293,7 @@ static const struct brport_attribute *br + &brport_attr_group_fwd_mask, + &brport_attr_neigh_suppress, + &brport_attr_isolated, ++ &brport_attr_bpdu_filter, + &brport_attr_backup_port, + NULL + }; +--- a/net/bridge/br_stp_bpdu.c ++++ b/net/bridge/br_stp_bpdu.c +@@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_brid + { + unsigned char buf[35]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -127,7 +128,8 @@ void br_send_tcn_bpdu(struct net_bridge_ + { + unsigned char buf[4]; + +- if (p->br->stp_enabled != BR_KERNEL_STP) ++ if (p->br->stp_enabled != BR_KERNEL_STP || ++ (p->flags & BR_BPDU_FILTER)) + return; + + buf[0] = 0; +@@ -172,6 +174,9 @@ void br_stp_rcv(const struct stp_proto * + if (!(br->dev->flags & IFF_UP)) + goto out; + ++ if (p->flags & BR_BPDU_FILTER) ++ goto out; ++ + if (p->state == BR_STATE_DISABLED) + goto out; + +--- a/include/uapi/linux/if_link.h ++++ b/include/uapi/linux/if_link.h +@@ -536,6 +536,7 @@ enum { + IFLA_BRPORT_MRP_IN_OPEN, + IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, + IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, ++ IFLA_BRPORT_BPDU_FILTER, + __IFLA_BRPORT_MAX + }; + #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) +--- a/net/bridge/br_netlink.c ++++ b/net/bridge/br_netlink.c +@@ -184,6 +184,7 @@ static inline size_t br_port_info_size(v + + nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */ + + nla_total_size(1) /* IFLA_BRPORT_NEIGH_SUPPRESS */ + + nla_total_size(1) /* IFLA_BRPORT_ISOLATED */ ++ + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */ + + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ + + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ + + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ +@@ -269,7 +270,8 @@ static int br_port_fill_attrs(struct sk_ + BR_MRP_LOST_CONT)) || + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, + !!(p->flags & BR_MRP_LOST_IN_CONT)) || +- nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) ++ nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || ++ nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER))) + return -EMSGSIZE; + + timerval = br_timer_value(&p->message_age_timer); +@@ -829,6 +831,7 @@ static const struct nla_policy br_port_p + [IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 }, + [IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 }, + [IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT] = { .type = NLA_U32 }, ++ [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 }, + }; + + /* Change the state of the port and notify spanning tree */ +@@ -893,6 +896,7 @@ static int br_setport(struct net_bridge_ + br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); + br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS); + br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); ++ br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER); + + changed_mask = old_flags ^ p->flags; + +--- a/net/core/rtnetlink.c ++++ b/net/core/rtnetlink.c +@@ -55,7 +55,7 @@ + #include + + #define RTNL_MAX_TYPE 50 +-#define RTNL_SLAVE_MAX_TYPE 40 ++#define RTNL_SLAVE_MAX_TYPE 41 + + struct rtnl_link { + rtnl_doit_func doit; +@@ -4700,7 +4700,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu + brport_nla_put_flag(skb, flags, mask, + IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || + brport_nla_put_flag(skb, flags, mask, +- IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) { ++ IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD) || ++ brport_nla_put_flag(skb, flags, mask, ++ IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER)) { + nla_nest_cancel(skb, protinfo); + goto nla_put_failure; + } diff --git a/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch b/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch new file mode 100644 index 00000000000..c93fe42273e --- /dev/null +++ b/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch @@ -0,0 +1,106 @@ +From ace6abaa0f9203083fe4c0a6a74da2d96410b625 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Sat, 13 Aug 2022 12:49:33 +0200 +Subject: [PATCH 01/10] net: phy: realtek: rtl8221: allow to configure SERDES + mode + +The rtl8221 supports multiple SERDES modes: +- SGMII +- 2500base-x +- HiSGMII + +Further it supports rate adaption on SERDES links to allow +slow ethernet speeds (10/100/1000mbit) to work on 2500base-x/HiSGMII +links without reducing the SERDES speed. + +When operating without rate adapters the SERDES link will follow the +ethernet speed. + +Signed-off-by: Alexander Couzens +--- + drivers/net/phy/realtek.c | 48 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -53,6 +53,15 @@ + RTL8201F_ISR_LINK) + #define RTL8201F_IER 0x13 + ++#define RTL8221B_MMD_SERDES_CTRL MDIO_MMD_VEND1 ++#define RTL8221B_MMD_PHY_CTRL MDIO_MMD_VEND2 ++#define RTL8221B_SERDES_OPTION 0x697a ++#define RTL8221B_SERDES_OPTION_MODE_MASK GENMASK(5, 0) ++#define RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII 0 ++#define RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII 1 ++#define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2 ++#define RTL8221B_SERDES_OPTION_MODE_HISGMII 3 ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -841,6 +850,48 @@ static irqreturn_t rtl9000a_handle_inter + return IRQ_HANDLED; + } + ++static int rtl8221b_config_init(struct phy_device *phydev) ++{ ++ u16 option_mode; ++ ++ switch (phydev->interface) { ++ case PHY_INTERFACE_MODE_2500BASEX: ++ if (!phydev->is_c45) { ++ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX; ++ break; ++ } ++ fallthrough; ++ case PHY_INTERFACE_MODE_SGMII: ++ option_mode = RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII; ++ break; ++ default: ++ return 0; ++ } ++ ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, ++ 0x75f3, 0); ++ ++ phy_modify_mmd_changed(phydev, RTL8221B_MMD_SERDES_CTRL, ++ RTL8221B_SERDES_OPTION, ++ RTL8221B_SERDES_OPTION_MODE_MASK, option_mode); ++ switch (option_mode) { ++ case RTL8221B_SERDES_OPTION_MODE_2500BASEX_SGMII: ++ case RTL8221B_SERDES_OPTION_MODE_2500BASEX: ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd455); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020); ++ break; ++ case RTL8221B_SERDES_OPTION_MODE_HISGMII_SGMII: ++ case RTL8221B_SERDES_OPTION_MODE_HISGMII: ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6a04, 0x0503); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f10, 0xd433); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x6f11, 0x8020); ++ break; ++ } ++ ++ return 0; ++} ++ + static struct phy_driver realtek_drvs[] = { + { + PHY_ID_MATCH_EXACT(0x00008201), +@@ -981,6 +1032,7 @@ static struct phy_driver realtek_drvs[] + PHY_ID_MATCH_EXACT(0x001cc849), + .name = "RTL8221B-VB-CG 2.5Gbps PHY", + .get_features = rtl822x_get_features, ++ .config_init = rtl8221b_config_init, + .config_aneg = rtl822x_config_aneg, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, +@@ -992,6 +1044,7 @@ static struct phy_driver realtek_drvs[] + .name = "RTL8221B-VM-CG 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, ++ .config_init = rtl8221b_config_init, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, diff --git a/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch b/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch new file mode 100644 index 00000000000..211a8ed297f --- /dev/null +++ b/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch @@ -0,0 +1,61 @@ +From 312753d0aadba0f58841ae513b80fdbabc887523 Mon Sep 17 00:00:00 2001 +From: Chukun Pan +Date: Wed, 8 Feb 2023 16:32:18 +0800 +Subject: [PATCH] net: phy: realtek: support switching between SGMII and + 2500BASE-X for RTL822x series + +After commit ace6aba ("net: phy: realtek: rtl8221: allow to configure +SERDES mode"), the rtl8221 phy can work in SGMII and 2500base-x modes +respectively. So add interface automatic switching for rtl8221 phy to +match various wire speeds. + +Signed-off-by: Chukun Pan +--- + drivers/net/phy/realtek.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -676,6 +676,25 @@ static int rtl822x_config_aneg(struct ph + return __genphy_config_aneg(phydev, ret); + } + ++static void rtl822x_update_interface(struct phy_device *phydev) ++{ ++ /* Automatically switch SERDES interface between ++ * SGMII and 2500-BaseX according to speed. ++ */ ++ switch (phydev->speed) { ++ case SPEED_2500: ++ phydev->interface = PHY_INTERFACE_MODE_2500BASEX; ++ break; ++ case SPEED_1000: ++ case SPEED_100: ++ case SPEED_10: ++ phydev->interface = PHY_INTERFACE_MODE_SGMII; ++ break; ++ default: ++ break; ++ } ++} ++ + static int rtl822x_read_status(struct phy_device *phydev) + { + int ret; +@@ -694,11 +713,14 @@ static int rtl822x_read_status(struct ph + phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); + } + +- ret = genphy_read_status(phydev); ++ ret = rtlgen_read_status(phydev); + if (ret < 0) + return ret; + +- return rtlgen_get_speed(phydev); ++ if (phydev->is_c45 && phydev->link) ++ rtl822x_update_interface(phydev); ++ ++ return 0; + } + + static bool rtlgen_supports_2_5gbps(struct phy_device *phydev) diff --git a/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch b/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch new file mode 100644 index 00000000000..d93ee0685b2 --- /dev/null +++ b/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch @@ -0,0 +1,28 @@ +From 3fb8841513c4ec3a2e5d366df86230c45f239a57 Mon Sep 17 00:00:00 2001 +From: Alexander Couzens +Date: Sat, 13 Aug 2022 13:08:22 +0200 +Subject: [PATCH 03/10] net: mt7531: ensure all MACs are powered down before + reset + +The datasheet [1] explicit describes it as requirement for a reset. + +[1] MT7531 Reference Manual for Development Board rev 1.0, page 735 + +Signed-off-by: Alexander Couzens +--- + drivers/net/dsa/mt7530.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2347,6 +2347,10 @@ mt7531_setup(struct dsa_switch *ds) + return -ENODEV; + } + ++ /* all MACs must be forced link-down before sw reset */ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) ++ mt7530_write(priv, MT7530_PMCR_P(i), MT7531_FORCE_LNK); ++ + /* Reset the switch through internal reset */ + mt7530_write(priv, MT7530_SYS_CTRL, + SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST | diff --git a/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch b/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch new file mode 100644 index 00000000000..69418183510 --- /dev/null +++ b/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch @@ -0,0 +1,65 @@ +From 85cd45580f5e3b26068cccb7d6173f200e754dc0 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 2 Apr 2023 23:56:16 +0100 +Subject: [PATCH 1/2] net: phy: realtek: use genphy_soft_reset for 2.5G PHYs + +Some vendor bootloaders do weird things with those PHYs which result in +link modes being reported wrongly. Start from a clean sheet by resetting +the PHY. + +Reported-by: Yevhen Kolomeiko +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -1018,6 +1018,7 @@ static struct phy_driver realtek_drvs[] + .write_page = rtl821x_write_page, + .read_mmd = rtl822x_read_mmd, + .write_mmd = rtl822x_write_mmd, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc840), + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", +@@ -1030,6 +1031,7 @@ static struct phy_driver realtek_drvs[] + .write_page = rtl821x_write_page, + .read_mmd = rtl822x_read_mmd, + .write_mmd = rtl822x_write_mmd, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc838), + .name = "RTL8226-CG 2.5Gbps PHY", +@@ -1040,6 +1042,7 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc848), + .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", +@@ -1050,6 +1053,7 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc849), + .name = "RTL8221B-VB-CG 2.5Gbps PHY", +@@ -1061,6 +1065,7 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc84a), + .name = "RTL8221B-VM-CG 2.5Gbps PHY", +@@ -1072,6 +1077,7 @@ static struct phy_driver realtek_drvs[] + .resume = rtlgen_resume, + .read_page = rtl821x_read_page, + .write_page = rtl821x_write_page, ++ .soft_reset = genphy_soft_reset, + }, { + PHY_ID_MATCH_EXACT(0x001cc961), + .name = "RTL8366RB Gigabit Ethernet", diff --git a/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch b/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch new file mode 100644 index 00000000000..1370c6324bb --- /dev/null +++ b/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch @@ -0,0 +1,43 @@ +From 2b1b8c4c215af7988136401c902338d091d408a1 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 01:21:57 +0300 +Subject: [PATCH 2/2] net: phy: realtek: disable SGMII in-band AN for 2.5G PHYs + +MAC drivers don't use SGMII in-band autonegotiation unless told to do so +in device tree using 'managed = "in-band-status"'. When using MDIO to +access a PHY, in-band-status is unneeded as we have link-status via +MDIO. Switch off SGMII in-band autonegotiation using magic values. + +Reported-by: Chen Minqiang +Reported-by: Chukun Pan +Reported-by: Yevhen Kolomeiko +Tested-by: Yevhen Kolomeiko +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -875,6 +875,7 @@ static irqreturn_t rtl9000a_handle_inter + static int rtl8221b_config_init(struct phy_device *phydev) + { + u16 option_mode; ++ int val; + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_2500BASEX: +@@ -911,6 +912,13 @@ static int rtl8221b_config_init(struct p + break; + } + ++ /* Disable SGMII AN */ ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7588, 0x2); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7589, 0x71d0); ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587, 0x3); ++ phy_read_mmd_poll_timeout(phydev, RTL8221B_MMD_SERDES_CTRL, 0x7587, ++ val, !(val & BIT(0)), 500, 100000, false); ++ + return 0; + } + diff --git a/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch b/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch new file mode 100644 index 00000000000..31f0622327b --- /dev/null +++ b/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch @@ -0,0 +1,35 @@ +From 4dd2cc9b91ecb25f278a2c55e07e6455e9000e6b Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 01:21:14 +0100 +Subject: [PATCH] net: phy: realtek: make sure paged read is protected by mutex + +As we cannot rely on phy_read_paged function before the PHY is +identified, the paged read in rtlgen_supports_2_5gbps needs to be open +coded as it is being called by the match_phy_device function, ie. before +.read_page and .write_page have been populated. + +Make sure it is also protected by the MDIO bus mutex and use +rtl821x_write_page instead of 3 individually locked MDIO bus operations. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -727,9 +727,11 @@ static bool rtlgen_supports_2_5gbps(stru + { + int val; + +- phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61); +- val = phy_read(phydev, 0x13); +- phy_write(phydev, RTL821x_PAGE_SELECT, 0); ++ mutex_lock(&phydev->mdio.bus->mdio_lock); ++ rtl821x_write_page(phydev, 0xa61); ++ val = __phy_read(phydev, 0x13); ++ rtl821x_write_page(phydev, 0); ++ mutex_unlock(&phydev->mdio.bus->mdio_lock); + + return val >= 0 && val & RTL_SUPPORTS_2500FULL; + } diff --git a/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch b/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch new file mode 100644 index 00000000000..a24b4dd79a1 --- /dev/null +++ b/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch @@ -0,0 +1,60 @@ +From 92c8b9d558160d94b981dd8a2b9c47657627ffdc Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 01:23:08 +0100 +Subject: [PATCH 2/3] net: phy: realtek: use inline functions for 10GbE + advertisement + +Use existing generic inline functions to encode local advertisement +of 10GbE link modes as well as to decode link-partner advertisement. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 22 +++++----------------- + 1 file changed, 5 insertions(+), 17 deletions(-) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -68,10 +68,6 @@ + #define RTL_SUPPORTS_5000FULL BIT(14) + #define RTL_SUPPORTS_2500FULL BIT(13) + #define RTL_SUPPORTS_10000FULL BIT(0) +-#define RTL_ADV_2500FULL BIT(7) +-#define RTL_LPADV_10000FULL BIT(11) +-#define RTL_LPADV_5000FULL BIT(6) +-#define RTL_LPADV_2500FULL BIT(5) + + #define RTL9000A_GINMR 0x14 + #define RTL9000A_GINMR_LINK_STATUS BIT(4) +@@ -661,14 +657,11 @@ static int rtl822x_config_aneg(struct ph + int ret = 0; + + if (phydev->autoneg == AUTONEG_ENABLE) { +- u16 adv2500 = 0; +- +- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, +- phydev->advertising)) +- adv2500 = RTL_ADV_2500FULL; +- + ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12, +- RTL_ADV_2500FULL, adv2500); ++ MDIO_AN_10GBT_CTRL_ADV10G | ++ MDIO_AN_10GBT_CTRL_ADV5G | ++ MDIO_AN_10GBT_CTRL_ADV2_5G, ++ linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising)); + if (ret < 0) + return ret; + } +@@ -705,12 +698,7 @@ static int rtl822x_read_status(struct ph + if (lpadv < 0) + return lpadv; + +- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, +- phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, +- phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL); +- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, +- phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); ++ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); + } + + ret = rtlgen_read_status(phydev); diff --git a/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch b/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch new file mode 100644 index 00000000000..084ee4b6450 --- /dev/null +++ b/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch @@ -0,0 +1,28 @@ +From 929bb4d3cfbc7878326c0771a01a636d49c54b40 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 01:25:39 +0100 +Subject: [PATCH 3/3] net: phy: realtek: check validity of 10GbE link-partner + advertisement + +Only use link-partner advertisement bits for 10GbE modes if they are +actually valid. Check LOCALOK and REMOTEOK bits and clear 10GbE modes +unless both of them are set. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -698,6 +698,10 @@ static int rtl822x_read_status(struct ph + if (lpadv < 0) + return lpadv; + ++ if (!(lpadv & MDIO_AN_10GBT_STAT_REMOK) || ++ !(lpadv & MDIO_AN_10GBT_STAT_LOCOK)) ++ lpadv = 0; ++ + mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv); + } + diff --git a/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch b/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch new file mode 100644 index 00000000000..87102d38187 --- /dev/null +++ b/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch @@ -0,0 +1,100 @@ +From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 22 Apr 2023 03:26:01 +0100 +Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x + +Setup Link Down Power Saving Mode according the DTS property +just like for RTL821x 1GE PHYs. + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/realtek.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -62,6 +62,10 @@ + #define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2 + #define RTL8221B_SERDES_OPTION_MODE_HISGMII 3 + ++#define RTL8221B_PHYCR1 0xa430 ++#define RTL8221B_PHYCR1_ALDPS_EN BIT(2) ++#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12) ++ + #define RTL8366RB_POWER_SAVE 0x15 + #define RTL8366RB_POWER_SAVE_ON BIT(12) + +@@ -740,6 +744,25 @@ static int rtl8226_match_phy_device(stru + rtlgen_supports_2_5gbps(phydev); + } + ++static int rtl822x_probe(struct phy_device *phydev) ++{ ++ struct device *dev = &phydev->mdio.dev; ++ int val; ++ ++ val = phy_read_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, RTL8221B_PHYCR1); ++ if (val < 0) ++ return val; ++ ++ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable")) ++ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN; ++ else ++ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN); ++ ++ phy_write_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, RTL8221B_PHYCR1, val); ++ ++ return 0; ++} ++ + static int rtlgen_resume(struct phy_device *phydev) + { + int ret = genphy_resume(phydev); +@@ -1013,6 +1036,7 @@ static struct phy_driver realtek_drvs[] + .match_phy_device = rtl8226_match_phy_device, + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, +@@ -1026,6 +1050,7 @@ static struct phy_driver realtek_drvs[] + .name = "RTL8226B_RTL8221B 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, +@@ -1039,6 +1064,7 @@ static struct phy_driver realtek_drvs[] + .name = "RTL8226-CG 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, +@@ -1050,6 +1076,7 @@ static struct phy_driver realtek_drvs[] + .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, +@@ -1062,6 +1089,7 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_init = rtl8221b_config_init, + .config_aneg = rtl822x_config_aneg, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, +@@ -1074,6 +1102,7 @@ static struct phy_driver realtek_drvs[] + .get_features = rtl822x_get_features, + .config_aneg = rtl822x_config_aneg, + .config_init = rtl8221b_config_init, ++ .probe = rtl822x_probe, + .read_status = rtl822x_read_status, + .suspend = genphy_suspend, + .resume = rtlgen_resume, diff --git a/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch new file mode 100644 index 00000000000..6d414bfbade --- /dev/null +++ b/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch @@ -0,0 +1,63 @@ +From 0de82310d2b32e78ff79d42c08b1122a6ede3778 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 30 Apr 2023 00:15:41 +0100 +Subject: [PATCH] net: phy: realtek: detect early version of RTL8221B + +Early versions (?) of the RTL8221B PHY cannot be identified in a regular +Clause-45 bus scan as the PHY doesn't report the implemented MMDs +correctly but returns 0 instead. +Implement custom identify function using the PKGID instead of iterating +over the implemented MMDs. + +Signed-off-by: Daniel Golle + +--- a/drivers/net/phy/realtek.c ++++ b/drivers/net/phy/realtek.c +@@ -744,6 +744,38 @@ static int rtl8226_match_phy_device(stru + rtlgen_supports_2_5gbps(phydev); + } + ++static int rtl8221b_vb_cg_match_phy_device(struct phy_device *phydev) ++{ ++ int val; ++ u32 id; ++ ++ if (phydev->mdio.bus->probe_capabilities >= MDIOBUS_C45) { ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1); ++ if (val < 0) ++ return 0; ++ ++ id = val << 16; ++ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2); ++ if (val < 0) ++ return 0; ++ ++ id |= val; ++ } else { ++ val = phy_read(phydev, MII_PHYSID1); ++ if (val < 0) ++ return 0; ++ ++ id = val << 16; ++ val = phy_read(phydev, MII_PHYSID2); ++ if (val < 0) ++ return 0; ++ ++ id |= val; ++ } ++ ++ return (id == 0x001cc849); ++} ++ + static int rtl822x_probe(struct phy_device *phydev) + { + struct device *dev = &phydev->mdio.dev; +@@ -1084,7 +1116,7 @@ static struct phy_driver realtek_drvs[] + .write_page = rtl821x_write_page, + .soft_reset = genphy_soft_reset, + }, { +- PHY_ID_MATCH_EXACT(0x001cc849), ++ .match_phy_device = rtl8221b_vb_cg_match_phy_device, + .name = "RTL8221B-VB-CG 2.5Gbps PHY", + .get_features = rtl822x_get_features, + .config_init = rtl8221b_config_init, diff --git a/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch new file mode 100644 index 00000000000..60c32b67057 --- /dev/null +++ b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -0,0 +1,428 @@ +From patchwork Wed Nov 2 00:58:01 2022 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 13027653 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +Date: Wed, 2 Nov 2022 00:58:01 +0000 +From: Daniel Golle +To: Felix Fietkau , John Crispin , + Sean Wang , + Mark Lee , + "David S. Miller" , + Eric Dumazet , + Jakub Kicinski , + Paolo Abeni , + Matthias Brugger , + netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-mediatek@lists.infradead.org, linux-kernel@vger.kernel.org +Subject: [PATCH v4] net: ethernet: mediatek: ppe: add support for flow + accounting +Message-ID: +MIME-Version: 1.0 +Content-Disposition: inline +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +The PPE units found in MT7622 and newer support packet and byte +accounting of hw-offloaded flows. Add support for reading those +counters as found in MediaTek's SDK[1]. + +[1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/bc6a6a375c800dc2b80e1a325a2c732d1737df92 +Signed-off-by: Daniel Golle +--- +v4: declare function mtk_mib_entry_read as static +v3: don't bother to set 'false' values in any zero-initialized struct + use mtk_foe_entry_ib2 + both changes were requested by Felix Fietkau + +v2: fix wrong variable name in return value check spotted by Denis Kirjanov + + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + + drivers/net/ethernet/mediatek/mtk_ppe.c | 110 +++++++++++++++++- + drivers/net/ethernet/mediatek/mtk_ppe.h | 23 +++- + .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 9 +- + .../net/ethernet/mediatek/mtk_ppe_offload.c | 7 ++ + drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 14 +++ + 7 files changed, 166 insertions(+), 5 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4642,8 +4642,8 @@ static int mtk_probe(struct platform_dev + for (i = 0; i < num_ppe; i++) { + u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; + +- eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, +- eth->soc->offload_version, i); ++ eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, i); ++ + if (!eth->ppe[i]) { + err = -ENOMEM; + goto err_free_dev; +@@ -4770,6 +4770,7 @@ static const struct mtk_soc_data mt7622_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 2, ++ .has_accounting = true, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), +@@ -4807,6 +4808,7 @@ static const struct mtk_soc_data mt7629_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7629_CLKS_BITMAP, + .required_pctl = false, ++ .has_accounting = true, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4827,6 +4829,7 @@ static const struct mtk_soc_data mt7981_ + .offload_version = 2, + .hash_offset = 4, + .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .has_accounting = true, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +@@ -4847,6 +4850,7 @@ static const struct mtk_soc_data mt7986_ + .offload_version = 2, + .hash_offset = 4, + .foe_entry_size = sizeof(struct mtk_foe_entry), ++ .has_accounting = true, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1014,6 +1014,8 @@ struct mtk_reg_map { + * the extra setup for those pins used by GMAC. + * @hash_offset Flow table hash offset. + * @foe_entry_size Foe table entry size. ++ * @has_accounting Bool indicating support for accounting of ++ * offloaded flows. + * @txd_size Tx DMA descriptor size. + * @rxd_size Rx DMA descriptor size. + * @rx_irq_done_mask Rx irq done register mask. +@@ -1031,6 +1033,7 @@ struct mtk_soc_data { + u8 hash_offset; + u16 foe_entry_size; + netdev_features_t hw_features; ++ bool has_accounting; + struct { + u32 txd_size; + u32 rxd_size; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -74,6 +74,48 @@ static int mtk_ppe_wait_busy(struct mtk_ + return ret; + } + ++static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe) ++{ ++ int ret; ++ u32 val; ++ ++ ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, ++ !(val & MTK_PPE_MIB_SER_CR_ST), ++ 20, MTK_PPE_WAIT_TIMEOUT_US); ++ ++ if (ret) ++ dev_err(ppe->dev, "MIB table busy"); ++ ++ return ret; ++} ++ ++static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) ++{ ++ u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high; ++ u32 val, cnt_r0, cnt_r1, cnt_r2; ++ int ret; ++ ++ val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; ++ ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); ++ ++ ret = mtk_ppe_mib_wait_busy(ppe); ++ if (ret) ++ return ret; ++ ++ cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); ++ cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); ++ cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2); ++ ++ byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0); ++ byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); ++ pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); ++ pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); ++ *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; ++ *packets = (pkt_cnt_high << 16) | pkt_cnt_low; ++ ++ return 0; ++} ++ + static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) + { + ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); +@@ -464,6 +506,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + hwe->ib1 &= ~MTK_FOE_IB1_STATE; + hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); ++ if (ppe->accounting) { ++ struct mtk_foe_accounting *acct; ++ ++ acct = ppe->acct_table + entry->hash * sizeof(*acct); ++ acct->packets = 0; ++ acct->bytes = 0; ++ } + } + entry->hash = 0xffff; + +@@ -571,6 +620,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + wmb(); + hwe->ib1 = entry->ib1; + ++ if (ppe->accounting) ++ *mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT; ++ + dma_wmb(); + + mtk_ppe_cache_clear(ppe); +@@ -762,11 +814,39 @@ int mtk_ppe_prepare_reset(struct mtk_ppe + return mtk_ppe_wait_busy(ppe); + } + +-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, +- int version, int index) ++struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, ++ struct mtk_foe_accounting *diff) ++{ ++ struct mtk_foe_accounting *acct; ++ int size = sizeof(struct mtk_foe_accounting); ++ u64 bytes, packets; ++ ++ if (!ppe->accounting) ++ return NULL; ++ ++ if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) ++ return NULL; ++ ++ acct = ppe->acct_table + index * size; ++ ++ acct->bytes += bytes; ++ acct->packets += packets; ++ ++ if (diff) { ++ diff->bytes = bytes; ++ diff->packets = packets; ++ } ++ ++ return acct; ++} ++ ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + { ++ bool accounting = eth->soc->has_accounting; + const struct mtk_soc_data *soc = eth->soc; ++ struct mtk_foe_accounting *acct; + struct device *dev = eth->dev; ++ struct mtk_mib_entry *mib; + struct mtk_ppe *ppe; + u32 foe_flow_size; + void *foe; +@@ -783,7 +863,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + ppe->base = base; + ppe->eth = eth; + ppe->dev = dev; +- ppe->version = version; ++ ppe->version = eth->soc->offload_version; ++ ppe->accounting = accounting; + + foe = dmam_alloc_coherent(ppe->dev, + MTK_PPE_ENTRIES * soc->foe_entry_size, +@@ -799,6 +880,23 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + if (!ppe->foe_flow) + return NULL; + ++ if (accounting) { ++ mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), ++ &ppe->mib_phys, GFP_KERNEL); ++ if (!mib) ++ return NULL; ++ ++ ppe->mib_table = mib; ++ ++ acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct), ++ GFP_KERNEL); ++ ++ if (!acct) ++ return NULL; ++ ++ ppe->acct_table = acct; ++ } ++ + mtk_ppe_debugfs_init(ppe, index); + + return ppe; +@@ -913,6 +1011,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe) + ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); + ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); + } ++ ++ if (ppe->accounting && ppe->mib_phys) { ++ ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys); ++ ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN, ++ MTK_PPE_MIB_CFG_EN); ++ ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR, ++ MTK_PPE_MIB_CFG_RD_CLR); ++ ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN, ++ MTK_PPE_MIB_CFG_RD_CLR); ++ } + } + + int mtk_ppe_stop(struct mtk_ppe *ppe) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -57,6 +57,7 @@ enum { + #define MTK_FOE_IB2_MULTICAST BIT(8) + + #define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12) ++#define MTK_FOE_IB2_MIB_CNT BIT(15) + #define MTK_FOE_IB2_WDMA_DEVIDX BIT(16) + #define MTK_FOE_IB2_WDMA_WINFO BIT(17) + +@@ -285,16 +286,34 @@ struct mtk_flow_entry { + unsigned long cookie; + }; + ++struct mtk_mib_entry { ++ u32 byt_cnt_l; ++ u16 byt_cnt_h; ++ u32 pkt_cnt_l; ++ u8 pkt_cnt_h; ++ u8 _rsv0; ++ u32 _rsv1; ++} __packed; ++ ++struct mtk_foe_accounting { ++ u64 bytes; ++ u64 packets; ++}; ++ + struct mtk_ppe { + struct mtk_eth *eth; + struct device *dev; + void __iomem *base; + int version; + char dirname[5]; ++ bool accounting; + + void *foe_table; + dma_addr_t foe_phys; + ++ struct mtk_mib_entry *mib_table; ++ dma_addr_t mib_phys; ++ + u16 foe_check_time[MTK_PPE_ENTRIES]; + struct hlist_head *foe_flow; + +@@ -303,8 +322,7 @@ struct mtk_ppe { + void *acct_table; + }; + +-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, +- int version, int index); ++struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index); + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); +@@ -358,5 +376,7 @@ int mtk_foe_entry_commit(struct mtk_ppe + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); ++struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, ++ struct mtk_foe_accounting *diff); + + #endif +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -82,6 +82,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file + struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); + struct mtk_foe_mac_info *l2; + struct mtk_flow_addr_info ai = {}; ++ struct mtk_foe_accounting *acct; + unsigned char h_source[ETH_ALEN]; + unsigned char h_dest[ETH_ALEN]; + int type, state; +@@ -95,6 +96,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file + if (bind && state != MTK_FOE_STATE_BIND) + continue; + ++ acct = mtk_foe_entry_get_mib(ppe, i, NULL); ++ + type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); + seq_printf(m, "%05x %s %7s", i, + mtk_foe_entry_state_str(state), +@@ -153,9 +156,11 @@ mtk_ppe_debugfs_foe_show(struct seq_file + *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo); + + seq_printf(m, " eth=%pM->%pM etype=%04x" +- " vlan=%d,%d ib1=%08x ib2=%08x\n", ++ " vlan=%d,%d ib1=%08x ib2=%08x" ++ " packets=%llu bytes=%llu\n", + h_source, h_dest, ntohs(l2->etype), +- l2->vlan1, l2->vlan2, entry->ib1, ib2); ++ l2->vlan1, l2->vlan2, entry->ib1, ib2, ++ acct ? acct->packets : 0, acct ? acct->bytes : 0); + } + + return 0; +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -497,6 +497,7 @@ static int + mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) + { + struct mtk_flow_entry *entry; ++ struct mtk_foe_accounting diff; + u32 idle; + + entry = rhashtable_lookup(ð->flow_table, &f->cookie, +@@ -507,6 +508,13 @@ mtk_flow_offload_stats(struct mtk_eth *e + idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); + f->stats.lastused = jiffies - idle * HZ; + ++ if (entry->hash != 0xFFFF && ++ mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, ++ &diff)) { ++ f->stats.pkts += diff.packets; ++ f->stats.bytes += diff.bytes; ++ } ++ + return 0; + } + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h +@@ -149,6 +149,20 @@ enum { + + #define MTK_PPE_MIB_TB_BASE 0x338 + ++#define MTK_PPE_MIB_SER_CR 0x33C ++#define MTK_PPE_MIB_SER_CR_ST BIT(16) ++#define MTK_PPE_MIB_SER_CR_ADDR GENMASK(13, 0) ++ ++#define MTK_PPE_MIB_SER_R0 0x340 ++#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW GENMASK(31, 0) ++ ++#define MTK_PPE_MIB_SER_R1 0x344 ++#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16) ++#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0) ++ ++#define MTK_PPE_MIB_SER_R2 0x348 ++#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0) ++ + #define MTK_PPE_MIB_CACHE_CTL 0x350 + #define MTK_PPE_MIB_CACHE_CTL_EN BIT(0) + #define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2) diff --git a/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch b/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch new file mode 100644 index 00000000000..35b296a2553 --- /dev/null +++ b/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch @@ -0,0 +1,201 @@ +From: Felix Fietkau +Date: Sun, 20 Nov 2022 23:01:00 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: drop generic vlan rx offload, + only use DSA untagging + +Through testing I found out that hardware vlan rx offload support seems to +have some hardware issues. At least when using multiple MACs and when receiving +tagged packets on the secondary MAC, the hardware can sometimes start to emit +wrong tags on the first MAC as well. + +In order to avoid such issues, drop the feature configuration and use the +offload feature only for DSA hardware untagging on MT7621/MT7622 devices which +only use one MAC. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1850,9 +1850,7 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; +- bool has_hwaccel_tag = false; + struct net_device *netdev; +- u16 vlan_proto, vlan_tci; + dma_addr_t dma_addr; + u32 hash, reason; + int mac = 0; +@@ -1987,36 +1985,21 @@ static int mtk_poll_rx(struct napi_struc + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); + +- if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) +- mtk_ppe_check_skb(eth->ppe[0], skb, hash); +- +- if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { +- if (trxd.rxd3 & RX_DMA_VTAG_V2) { +- vlan_proto = RX_DMA_VPID(trxd.rxd4); +- vlan_tci = RX_DMA_VID(trxd.rxd4); +- has_hwaccel_tag = true; +- } +- } else if (trxd.rxd2 & RX_DMA_VTAG) { +- vlan_proto = RX_DMA_VPID(trxd.rxd3); +- vlan_tci = RX_DMA_VID(trxd.rxd3); +- has_hwaccel_tag = true; +- } +- } +- + /* When using VLAN untagging in combination with DSA, the + * hardware treats the MTK special tag as a VLAN and untags it. + */ +- if (has_hwaccel_tag && netdev_uses_dsa(netdev)) { +- unsigned int port = vlan_proto & GENMASK(2, 0); ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && ++ (trxd.rxd2 & RX_DMA_VTAG) && netdev_uses_dsa(netdev)) { ++ unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0); + + if (port < ARRAY_SIZE(eth->dsa_meta) && + eth->dsa_meta[port]) + skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); +- } else if (has_hwaccel_tag) { +- __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tci); + } + ++ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) ++ mtk_ppe_check_skb(eth->ppe[0], skb, hash); ++ + skb_record_rx_queue(skb, 0); + napi_gro_receive(napi, skb); + +@@ -2831,29 +2814,11 @@ static netdev_features_t mtk_fix_feature + + static int mtk_set_features(struct net_device *dev, netdev_features_t features) + { +- struct mtk_mac *mac = netdev_priv(dev); +- struct mtk_eth *eth = mac->hw; + netdev_features_t diff = dev->features ^ features; +- int i; + + if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO)) + mtk_hwlro_netdev_disable(dev); + +- /* Set RX VLAN offloading */ +- if (!(diff & NETIF_F_HW_VLAN_CTAG_RX)) +- return 0; +- +- mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX), +- MTK_CDMP_EG_CTRL); +- +- /* sync features with other MAC */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { +- if (!eth->netdev[i] || eth->netdev[i] == dev) +- continue; +- eth->netdev[i]->features &= ~NETIF_F_HW_VLAN_CTAG_RX; +- eth->netdev[i]->features |= features & NETIF_F_HW_VLAN_CTAG_RX; +- } +- + return 0; + } + +@@ -3167,30 +3132,6 @@ static int mtk_open(struct net_device *d + struct mtk_eth *eth = mac->hw; + int i, err; + +- if (mtk_uses_dsa(dev) && !eth->prog) { +- for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { +- struct metadata_dst *md_dst = eth->dsa_meta[i]; +- +- if (md_dst) +- continue; +- +- md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, +- GFP_KERNEL); +- if (!md_dst) +- return -ENOMEM; +- +- md_dst->u.port_info.port_id = i; +- eth->dsa_meta[i] = md_dst; +- } +- } else { +- /* Hardware special tag parsing needs to be disabled if at least +- * one MAC does not use DSA. +- */ +- u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); +- val &= ~MTK_CDMP_STAG_EN; +- mtk_w32(eth, val, MTK_CDMP_IG_CTRL); +- } +- + err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); + if (err) { + netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, +@@ -3231,6 +3172,35 @@ static int mtk_open(struct net_device *d + phylink_start(mac->phylink); + netif_tx_start_all_queues(dev); + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ return 0; ++ ++ if (mtk_uses_dsa(dev) && !eth->prog) { ++ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { ++ struct metadata_dst *md_dst = eth->dsa_meta[i]; ++ ++ if (md_dst) ++ continue; ++ ++ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, ++ GFP_KERNEL); ++ if (!md_dst) ++ return -ENOMEM; ++ ++ md_dst->u.port_info.port_id = i; ++ eth->dsa_meta[i] = md_dst; ++ } ++ } else { ++ /* Hardware special tag parsing needs to be disabled if at least ++ * one MAC does not use DSA. ++ */ ++ u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); ++ val &= ~MTK_CDMP_STAG_EN; ++ mtk_w32(eth, val, MTK_CDMP_IG_CTRL); ++ ++ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL); ++ } ++ + return 0; + } + +@@ -3715,10 +3685,9 @@ static int mtk_hw_init(struct mtk_eth *e + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); +- } + +- /* Enable RX VLan Offloading */ +- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); ++ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); ++ } + + /* set interrupt delays based on current Net DIM sample */ + mtk_dim_rx(ð->rx_dim.work); +@@ -4365,7 +4334,7 @@ static int mtk_add_mac(struct mtk_eth *e + eth->netdev[id]->hw_features |= NETIF_F_LRO; + + eth->netdev[id]->vlan_features = eth->soc->hw_features & +- ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); ++ ~NETIF_F_HW_VLAN_CTAG_TX; + eth->netdev[id]->features |= eth->soc->hw_features; + eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops; + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -48,7 +48,6 @@ + #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ + NETIF_F_RXCSUM | \ + NETIF_F_HW_VLAN_CTAG_TX | \ +- NETIF_F_HW_VLAN_CTAG_RX | \ + NETIF_F_SG | NETIF_F_TSO | \ + NETIF_F_TSO6 | \ + NETIF_F_IPV6_CSUM |\ diff --git a/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch new file mode 100644 index 00000000000..fbf0cb5735e --- /dev/null +++ b/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch @@ -0,0 +1,94 @@ +From: Felix Fietkau +Date: Thu, 3 Nov 2022 12:38:49 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with sending + small fragments + +When lots of frames are sent with a number of very small fragments, an +internal FIFO can overflow, causing the DMA engine to lock up lock up and +transmit attempts time out. + +Fix this on MT7986 by increasing the reserved FIFO space. +Fix this on older chips by detecting the presence of small fragments and use +skb_gso_segment + skb_linearize to deal with them. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1423,12 +1423,28 @@ static void mtk_wake_queue(struct mtk_et + } + } + ++static bool mtk_skb_has_small_frag(struct sk_buff *skb) ++{ ++ int min_size = 16; ++ int i; ++ ++ if (skb_headlen(skb) < min_size) ++ return true; ++ ++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) ++ if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size) ++ return true; ++ ++ return false; ++} ++ + static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + struct mtk_tx_ring *ring = ð->tx_ring; + struct net_device_stats *stats = &dev->stats; ++ struct sk_buff *segs, *next; + bool gso = false; + int tx_num; + +@@ -1450,6 +1466,18 @@ static netdev_tx_t mtk_start_xmit(struct + return NETDEV_TX_BUSY; + } + ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && ++ skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) { ++ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO); ++ if (IS_ERR(segs)) ++ goto drop; ++ ++ if (segs) { ++ consume_skb(skb); ++ skb = segs; ++ } ++ } ++ + /* TSO: fill MSS info in tcp checksum field */ + if (skb_is_gso(skb)) { + if (skb_cow_head(skb, 0)) { +@@ -1465,8 +1493,14 @@ static netdev_tx_t mtk_start_xmit(struct + } + } + +- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) +- goto drop; ++ skb_list_walk_safe(skb, skb, next) { ++ if ((!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && ++ mtk_skb_has_small_frag(skb) && skb_linearize(skb)) || ++ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) { ++ stats->tx_dropped++; ++ dev_kfree_skb_any(skb); ++ } ++ } + + if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) + netif_tx_stop_all_queues(dev); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -258,7 +258,7 @@ + #define MTK_CHK_DDONE_EN BIT(28) + #define MTK_DMAD_WR_WDONE BIT(26) + #define MTK_WCOMP_EN BIT(24) +-#define MTK_RESV_BUF (0x40 << 16) ++#define MTK_RESV_BUF (0x80 << 16) + #define MTK_MUTLI_CNT (0x4 << 12) + #define MTK_LEAKY_BUCKET_EN BIT(11) + diff --git a/target/linux/generic/pending-6.1/732-02-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch b/target/linux/generic/pending-6.1/732-02-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch new file mode 100644 index 00000000000..3c6359ee419 --- /dev/null +++ b/target/linux/generic/pending-6.1/732-02-net-ethernet-mtk_eth_soc-set-NETIF_F_ALL_TSO.patch @@ -0,0 +1,21 @@ +From: Felix Fietkau +Date: Fri, 28 Oct 2022 12:54:48 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: set NETIF_F_ALL_TSO + +Significantly improves performance by avoiding unnecessary segmentation + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -48,8 +48,7 @@ + #define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \ + NETIF_F_RXCSUM | \ + NETIF_F_HW_VLAN_CTAG_TX | \ +- NETIF_F_SG | NETIF_F_TSO | \ +- NETIF_F_TSO6 | \ ++ NETIF_F_SG | NETIF_F_ALL_TSO | \ + NETIF_F_IPV6_CSUM |\ + NETIF_F_HW_TC) + #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) diff --git a/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch b/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch new file mode 100644 index 00000000000..0aa9382b6bd --- /dev/null +++ b/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch @@ -0,0 +1,42 @@ +From: Felix Fietkau +Date: Wed, 29 Mar 2023 16:02:54 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: fix remaining throughput + regression + +Based on further tests, it seems that the QDMA shaper is not able to +perform shaping close to the MAC link rate without throughput loss. +This cannot be compensated by increasing the shaping rate, so it seems +to be an internal limit. + +Fix the remaining throughput regression by detecting that condition and +limiting shaping to ports with lower link speed. + +This patch intentionally ignores link speed gain from TRGMII, because +even on such links, shaping to 1000 Mbit/s incurs some throughput +degradation. + +Fixes: f63959c7eec3 ("net: ethernet: mtk_eth_soc: implement multi-queue support for per-port queues") +Reported-by: Frank Wunderlich +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -667,6 +667,7 @@ static void mtk_mac_link_up(struct phyli + MAC_MCR_FORCE_RX_FC); + + /* Configure speed */ ++ mac->speed = speed; + switch (speed) { + case SPEED_2500: + case SPEED_1000: +@@ -3145,6 +3146,9 @@ found: + if (dp->index >= MTK_QDMA_NUM_QUEUES) + return NOTIFY_DONE; + ++ if (mac->speed > 0 && mac->speed <= s.base.speed) ++ s.base.speed = 0; ++ + mtk_set_queue_speed(eth, dp->index + 3, s.base.speed); + + return NOTIFY_DONE; diff --git a/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch b/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch new file mode 100644 index 00000000000..9ef65ec16f7 --- /dev/null +++ b/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch @@ -0,0 +1,33 @@ +From: Felix Fietkau +Date: Tue, 27 Dec 2022 15:02:51 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: ppe: fix L2 offloading with DSA + untagging offload enabled + +Check for skb metadata in order to detect the case where the DSA header is not +present. + +Fixes: 2d7605a72906 ("net: ethernet: mtk_eth_soc: enable hardware DSA untagging") +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include "mtk_eth_soc.h" + #include "mtk_ppe.h" +@@ -757,7 +758,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe + skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) + goto out; + +- tag += 4; ++ if (!skb_metadata_dst(skb)) ++ tag += 4; ++ + if (get_unaligned_be16(tag) != ETH_P_8021Q) + break; + diff --git a/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch new file mode 100644 index 00000000000..4f765c5c145 --- /dev/null +++ b/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -0,0 +1,266 @@ +From: Felix Fietkau +Date: Mon, 20 Mar 2023 11:44:30 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add code for offloading flows + from wlan devices + +WED version 2 (on MT7986 and later) can offload flows originating from wireless +devices. In order to make that work, ndo_setup_tc needs to be implemented on +the netdevs. This adds the required code to offload flows coming in from WED, +while keeping track of the incoming wed index used for selecting the correct +PPE device. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1277,6 +1277,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk + int mtk_eth_offload_init(struct mtk_eth *eth); + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, + void *type_data); ++int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls, ++ int ppe_index); ++void mtk_flow_offload_cleanup(struct mtk_eth *eth, struct list_head *list); + void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev); + + +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -235,7 +235,8 @@ out: + } + + static int +-mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f) ++mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, ++ int ppe_index) + { + struct flow_rule *rule = flow_cls_offload_flow_rule(f); + struct flow_action_entry *act; +@@ -452,6 +453,7 @@ mtk_flow_offload_replace(struct mtk_eth + entry->cookie = f->cookie; + memcpy(&entry->data, &foe, sizeof(entry->data)); + entry->wed_index = wed_index; ++ entry->ppe_index = ppe_index; + + err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry); + if (err < 0) +@@ -520,25 +522,15 @@ mtk_flow_offload_stats(struct mtk_eth *e + + static DEFINE_MUTEX(mtk_flow_offload_mutex); + +-static int +-mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) ++int mtk_flow_offload_cmd(struct mtk_eth *eth, struct flow_cls_offload *cls, ++ int ppe_index) + { +- struct flow_cls_offload *cls = type_data; +- struct net_device *dev = cb_priv; +- struct mtk_mac *mac = netdev_priv(dev); +- struct mtk_eth *eth = mac->hw; + int err; + +- if (!tc_can_offload(dev)) +- return -EOPNOTSUPP; +- +- if (type != TC_SETUP_CLSFLOWER) +- return -EOPNOTSUPP; +- + mutex_lock(&mtk_flow_offload_mutex); + switch (cls->command) { + case FLOW_CLS_REPLACE: +- err = mtk_flow_offload_replace(eth, cls); ++ err = mtk_flow_offload_replace(eth, cls, ppe_index); + break; + case FLOW_CLS_DESTROY: + err = mtk_flow_offload_destroy(eth, cls); +@@ -556,6 +548,23 @@ mtk_eth_setup_tc_block_cb(enum tc_setup_ + } + + static int ++mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) ++{ ++ struct flow_cls_offload *cls = type_data; ++ struct net_device *dev = cb_priv; ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ ++ if (!tc_can_offload(dev)) ++ return -EOPNOTSUPP; ++ ++ if (type != TC_SETUP_CLSFLOWER) ++ return -EOPNOTSUPP; ++ ++ return mtk_flow_offload_cmd(eth, cls, 0); ++} ++ ++static int + mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f) + { + struct mtk_mac *mac = netdev_priv(dev); +--- a/drivers/net/ethernet/mediatek/mtk_wed.c ++++ b/drivers/net/ethernet/mediatek/mtk_wed.c +@@ -13,6 +13,8 @@ + #include + #include + #include ++#include ++#include + #include "mtk_eth_soc.h" + #include "mtk_wed_regs.h" + #include "mtk_wed.h" +@@ -41,6 +43,11 @@ + static struct mtk_wed_hw *hw_list[2]; + static DEFINE_MUTEX(hw_lock); + ++struct mtk_wed_flow_block_priv { ++ struct mtk_wed_hw *hw; ++ struct net_device *dev; ++}; ++ + static void + wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) + { +@@ -1752,6 +1759,99 @@ out: + mutex_unlock(&hw_lock); + } + ++static int ++mtk_wed_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv) ++{ ++ struct mtk_wed_flow_block_priv *priv = cb_priv; ++ struct flow_cls_offload *cls = type_data; ++ struct mtk_wed_hw *hw = priv->hw; ++ ++ if (!tc_can_offload(priv->dev)) ++ return -EOPNOTSUPP; ++ ++ if (type != TC_SETUP_CLSFLOWER) ++ return -EOPNOTSUPP; ++ ++ return mtk_flow_offload_cmd(hw->eth, cls, hw->index); ++} ++ ++static int ++mtk_wed_setup_tc_block(struct mtk_wed_hw *hw, struct net_device *dev, ++ struct flow_block_offload *f) ++{ ++ struct mtk_wed_flow_block_priv *priv; ++ static LIST_HEAD(block_cb_list); ++ struct flow_block_cb *block_cb; ++ struct mtk_eth *eth = hw->eth; ++ flow_setup_cb_t *cb; ++ ++ if (!eth->soc->offload_version) ++ return -EOPNOTSUPP; ++ ++ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) ++ return -EOPNOTSUPP; ++ ++ cb = mtk_wed_setup_tc_block_cb; ++ f->driver_block_list = &block_cb_list; ++ ++ switch (f->command) { ++ case FLOW_BLOCK_BIND: ++ block_cb = flow_block_cb_lookup(f->block, cb, dev); ++ if (block_cb) { ++ flow_block_cb_incref(block_cb); ++ return 0; ++ } ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->hw = hw; ++ priv->dev = dev; ++ block_cb = flow_block_cb_alloc(cb, dev, priv, NULL); ++ if (IS_ERR(block_cb)) { ++ kfree(priv); ++ return PTR_ERR(block_cb); ++ } ++ ++ flow_block_cb_incref(block_cb); ++ flow_block_cb_add(block_cb, f); ++ list_add_tail(&block_cb->driver_list, &block_cb_list); ++ return 0; ++ case FLOW_BLOCK_UNBIND: ++ block_cb = flow_block_cb_lookup(f->block, cb, dev); ++ if (!block_cb) ++ return -ENOENT; ++ ++ if (!flow_block_cb_decref(block_cb)) { ++ flow_block_cb_remove(block_cb, f); ++ list_del(&block_cb->driver_list); ++ kfree(block_cb->cb_priv); ++ } ++ return 0; ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ ++static int ++mtk_wed_setup_tc(struct mtk_wed_device *wed, struct net_device *dev, ++ enum tc_setup_type type, void *type_data) ++{ ++ struct mtk_wed_hw *hw = wed->hw; ++ ++ if (hw->version < 2) ++ return -EOPNOTSUPP; ++ ++ switch (type) { ++ case TC_SETUP_BLOCK: ++ case TC_SETUP_FT: ++ return mtk_wed_setup_tc_block(hw, dev, type_data); ++ default: ++ return -EOPNOTSUPP; ++ } ++} ++ + void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, + void __iomem *wdma, phys_addr_t wdma_phy, + int index) +@@ -1771,6 +1871,7 @@ void mtk_wed_add_hw(struct device_node * + .irq_set_mask = mtk_wed_irq_set_mask, + .detach = mtk_wed_detach, + .ppe_check = mtk_wed_ppe_check, ++ .setup_tc = mtk_wed_setup_tc, + }; + struct device_node *eth_np = eth->dev->of_node; + struct platform_device *pdev; +--- a/include/linux/soc/mediatek/mtk_wed.h ++++ b/include/linux/soc/mediatek/mtk_wed.h +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + #define MTK_WED_TX_QUEUES 2 + #define MTK_WED_RX_QUEUES 2 +@@ -180,6 +181,8 @@ struct mtk_wed_ops { + + u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask); + void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask); ++ int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev, ++ enum tc_setup_type type, void *type_data); + }; + + extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops; +@@ -238,6 +241,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_devic + (_dev)->ops->msg_update(_dev, _id, _msg, _len) + #define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev) + #define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev) ++#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) \ ++ (_dev)->ops->setup_tc(_dev, _netdev, _type, _type_data) + #else + static inline bool mtk_wed_device_active(struct mtk_wed_device *dev) + { +@@ -256,6 +261,7 @@ static inline bool mtk_wed_device_active + #define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV + #define mtk_wed_device_stop(_dev) do {} while (0) + #define mtk_wed_device_dma_reset(_dev) do {} while (0) ++#define mtk_wed_device_setup_tc(_dev, _netdev, _type, _type_data) -EOPNOTSUPP + #endif + + #endif diff --git a/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch b/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch new file mode 100644 index 00000000000..6e17e4dc529 --- /dev/null +++ b/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch @@ -0,0 +1,37 @@ +From: Felix Fietkau +Date: Mon, 20 Mar 2023 15:37:55 +0100 +Subject: [PATCH] net: ethernet: mediatek: mtk_ppe: prefer newly added l2 + flows over existing ones + +When a device is roaming between interfaces and a new flow entry is created, +we should assume that its output device is more up to date than whatever +entry existed already. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -639,10 +639,20 @@ void mtk_foe_entry_clear(struct mtk_ppe + static int + mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { ++ struct mtk_flow_entry *prev; ++ + entry->type = MTK_FLOW_TYPE_L2; + +- return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node, +- mtk_flow_l2_ht_params); ++ prev = rhashtable_lookup_get_insert_fast(&ppe->l2_flows, &entry->l2_node, ++ mtk_flow_l2_ht_params); ++ if (likely(!prev)) ++ return 0; ++ ++ if (IS_ERR(prev)) ++ return PTR_ERR(prev); ++ ++ return rhashtable_replace_fast(&ppe->l2_flows, &prev->l2_node, ++ &entry->l2_node, mtk_flow_l2_ht_params); + } + + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) diff --git a/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch b/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch new file mode 100644 index 00000000000..29d6e0b0991 --- /dev/null +++ b/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch @@ -0,0 +1,331 @@ +From: Felix Fietkau +Date: Thu, 23 Mar 2023 10:24:11 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: improve keeping track of + offloaded flows + +Unify tracking of L2 and L3 flows. Use the generic list field in struct +mtk_foe_entry for tracking L2 subflows. Preparation for improving +flow accounting support. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -466,42 +466,43 @@ int mtk_foe_entry_set_queue(struct mtk_e + return 0; + } + ++static int ++mtk_flow_entry_match_len(struct mtk_eth *eth, struct mtk_foe_entry *entry) ++{ ++ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); ++ ++ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) ++ return offsetof(struct mtk_foe_entry, ipv6._rsv); ++ else ++ return offsetof(struct mtk_foe_entry, ipv4.ib2); ++} ++ + static bool + mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, +- struct mtk_foe_entry *data) ++ struct mtk_foe_entry *data, int len) + { +- int type, len; +- + if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) + return false; + +- type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); +- if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) +- len = offsetof(struct mtk_foe_entry, ipv6._rsv); +- else +- len = offsetof(struct mtk_foe_entry, ipv4.ib2); +- + return !memcmp(&entry->data.data, &data->data, len - 4); + } + + static void +-__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ bool set_state) + { +- struct hlist_head *head; + struct hlist_node *tmp; + + if (entry->type == MTK_FLOW_TYPE_L2) { + rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, + mtk_flow_l2_ht_params); + +- head = &entry->l2_flows; +- hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) +- __mtk_foe_entry_clear(ppe, entry); ++ hlist_for_each_entry_safe(entry, tmp, &entry->l2_flows, l2_list) ++ __mtk_foe_entry_clear(ppe, entry, set_state); + return; + } + +- hlist_del_init(&entry->list); +- if (entry->hash != 0xffff) { ++ if (entry->hash != 0xffff && set_state) { + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); + + hwe->ib1 &= ~MTK_FOE_IB1_STATE; +@@ -520,7 +521,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) + return; + +- hlist_del_init(&entry->l2_data.list); ++ hlist_del_init(&entry->l2_list); ++ hlist_del_init(&entry->list); + kfree(entry); + } + +@@ -536,66 +538,55 @@ static int __mtk_foe_entry_idle_time(str + return now - timestamp; + } + ++static bool ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++{ ++ struct mtk_foe_entry foe = {}; ++ struct mtk_foe_entry *hwe; ++ u16 hash = entry->hash; ++ int len; ++ ++ if (hash == 0xffff) ++ return false; ++ ++ hwe = mtk_foe_get_entry(ppe, hash); ++ len = mtk_flow_entry_match_len(ppe->eth, &entry->data); ++ memcpy(&foe, hwe, len); ++ ++ if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) ++ return false; ++ ++ entry->data.ib1 = foe.ib1; ++ ++ return true; ++} ++ + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); + struct mtk_flow_entry *cur; +- struct mtk_foe_entry *hwe; + struct hlist_node *tmp; + int idle; + + idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { ++ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; +- u32 ib1; +- +- hwe = mtk_foe_get_entry(ppe, cur->hash); +- ib1 = READ_ONCE(hwe->ib1); + +- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { +- cur->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, cur); ++ if (!mtk_flow_entry_update(ppe, cur)) { ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +- cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); ++ cur_idle = __mtk_foe_entry_idle_time(ppe, cur->data.ib1); + if (cur_idle >= idle) + continue; + + idle = cur_idle; + entry->data.ib1 &= ~ib1_ts_mask; +- entry->data.ib1 |= hwe->ib1 & ib1_ts_mask; +- } +-} +- +-static void +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- struct mtk_foe_entry foe = {}; +- struct mtk_foe_entry *hwe; +- +- spin_lock_bh(&ppe_lock); +- +- if (entry->type == MTK_FLOW_TYPE_L2) { +- mtk_flow_entry_update_l2(ppe, entry); +- goto out; ++ entry->data.ib1 |= cur->data.ib1 & ib1_ts_mask; + } +- +- if (entry->hash == 0xffff) +- goto out; +- +- hwe = mtk_foe_get_entry(ppe, entry->hash); +- memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); +- if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { +- entry->hash = 0xffff; +- goto out; +- } +- +- entry->data.ib1 = foe.ib1; +- +-out: +- spin_unlock_bh(&ppe_lock); + } + + static void +@@ -632,7 +623,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + spin_lock_bh(&ppe_lock); +- __mtk_foe_entry_clear(ppe, entry); ++ __mtk_foe_entry_clear(ppe, entry, true); ++ hlist_del_init(&entry->list); + spin_unlock_bh(&ppe_lock); + } + +@@ -679,8 +671,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ + { + const struct mtk_soc_data *soc = ppe->eth->soc; + struct mtk_flow_entry *flow_info; +- struct mtk_foe_entry foe = {}, *hwe; + struct mtk_foe_mac_info *l2; ++ struct mtk_foe_entry *hwe; + u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; + int type; + +@@ -688,30 +680,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ + if (!flow_info) + return; + +- flow_info->l2_data.base_flow = entry; + flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; + flow_info->hash = hash; + hlist_add_head(&flow_info->list, + &ppe->foe_flow[hash / soc->hash_offset]); +- hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); ++ hlist_add_head(&flow_info->l2_list, &entry->l2_flows); + + hwe = mtk_foe_get_entry(ppe, hash); +- memcpy(&foe, hwe, soc->foe_entry_size); +- foe.ib1 &= ib1_mask; +- foe.ib1 |= entry->data.ib1 & ~ib1_mask; ++ memcpy(&flow_info->data, hwe, soc->foe_entry_size); ++ flow_info->data.ib1 &= ib1_mask; ++ flow_info->data.ib1 |= entry->data.ib1 & ~ib1_mask; + +- l2 = mtk_foe_entry_l2(ppe->eth, &foe); ++ l2 = mtk_foe_entry_l2(ppe->eth, &flow_info->data); + memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); + +- type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); ++ type = mtk_get_ib1_pkt_type(ppe->eth, flow_info->data.ib1); + if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) +- memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); ++ memcpy(&flow_info->data.ipv4.new, &flow_info->data.ipv4.orig, ++ sizeof(flow_info->data.ipv4.new)); + else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) + l2->etype = ETH_P_IPV6; + +- *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; ++ *mtk_foe_entry_ib2(ppe->eth, &flow_info->data) = entry->data.bridge.ib2; + +- __mtk_foe_entry_commit(ppe, &foe, hash); ++ __mtk_foe_entry_commit(ppe, &flow_info->data, hash); + } + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) +@@ -721,9 +713,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe + struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); + struct mtk_flow_entry *entry; + struct mtk_foe_bridge key = {}; ++ struct mtk_foe_entry foe = {}; + struct hlist_node *n; + struct ethhdr *eh; + bool found = false; ++ int entry_len; + u8 *tag; + + spin_lock_bh(&ppe_lock); +@@ -731,20 +725,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe + if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) + goto out; + +- hlist_for_each_entry_safe(entry, n, head, list) { +- if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { +- if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == +- MTK_FOE_STATE_BIND)) +- continue; +- +- entry->hash = 0xffff; +- __mtk_foe_entry_clear(ppe, entry); +- continue; +- } ++ entry_len = mtk_flow_entry_match_len(ppe->eth, hwe); ++ memcpy(&foe, hwe, entry_len); + +- if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { ++ hlist_for_each_entry_safe(entry, n, head, list) { ++ if (found || ++ !mtk_flow_entry_match(ppe->eth, entry, &foe, entry_len)) { + if (entry->hash != 0xffff) +- entry->hash = 0xffff; ++ __mtk_foe_entry_clear(ppe, entry, false); + continue; + } + +@@ -795,9 +783,17 @@ out: + + int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { +- mtk_flow_entry_update(ppe, entry); ++ int idle; ++ ++ spin_lock_bh(&ppe_lock); ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry); ++ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ spin_unlock_bh(&ppe_lock); + +- return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ return idle; + } + + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -265,7 +265,12 @@ enum { + + struct mtk_flow_entry { + union { +- struct hlist_node list; ++ /* regular flows + L2 subflows */ ++ struct { ++ struct hlist_node list; ++ struct hlist_node l2_list; ++ }; ++ /* L2 flows */ + struct { + struct rhash_head l2_node; + struct hlist_head l2_flows; +@@ -275,13 +280,7 @@ struct mtk_flow_entry { + s8 wed_index; + u8 ppe_index; + u16 hash; +- union { +- struct mtk_foe_entry data; +- struct { +- struct mtk_flow_entry *base_flow; +- struct hlist_node list; +- } l2_data; +- }; ++ struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; + }; diff --git a/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch new file mode 100644 index 00000000000..fdc3d520c11 --- /dev/null +++ b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch @@ -0,0 +1,333 @@ +From: Felix Fietkau +Date: Thu, 23 Mar 2023 11:05:22 +0100 +Subject: [PATCH] net: ethernet: mediatek: fix ppe flow accounting for L2 + flows + +For L2 flows, the packet/byte counters should report the sum of the +counters of their subflows, both current and expired. +In order to make this work, change the way that accounting data is tracked. +Reset counters when a flow enters bind. Once it expires (or enters unbind), +store the last counter value in struct mtk_flow_entry. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -80,9 +80,9 @@ static int mtk_ppe_mib_wait_busy(struct + int ret; + u32 val; + +- ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val, +- !(val & MTK_PPE_MIB_SER_CR_ST), +- 20, MTK_PPE_WAIT_TIMEOUT_US); ++ ret = readl_poll_timeout_atomic(ppe->base + MTK_PPE_MIB_SER_CR, val, ++ !(val & MTK_PPE_MIB_SER_CR_ST), ++ 20, MTK_PPE_WAIT_TIMEOUT_US); + + if (ret) + dev_err(ppe->dev, "MIB table busy"); +@@ -90,18 +90,32 @@ static int mtk_ppe_mib_wait_busy(struct + return ret; + } + +-static int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets) ++static inline struct mtk_foe_accounting * ++mtk_ppe_acct_data(struct mtk_ppe *ppe, u16 index) ++{ ++ if (!ppe->acct_table) ++ return NULL; ++ ++ return ppe->acct_table + index * sizeof(struct mtk_foe_accounting); ++} ++ ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index) + { + u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high; + u32 val, cnt_r0, cnt_r1, cnt_r2; ++ struct mtk_foe_accounting *acct; + int ret; + + val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST; + ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val); + ++ acct = mtk_ppe_acct_data(ppe, index); ++ if (!acct) ++ return NULL; ++ + ret = mtk_ppe_mib_wait_busy(ppe); + if (ret) +- return ret; ++ return acct; + + cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0); + cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1); +@@ -111,10 +125,11 @@ static int mtk_mib_entry_read(struct mtk + byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1); + pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1); + pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2); +- *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low; +- *packets = (pkt_cnt_high << 16) | pkt_cnt_low; + +- return 0; ++ acct->bytes += ((u64)byte_cnt_high << 32) | byte_cnt_low; ++ acct->packets += (pkt_cnt_high << 16) | pkt_cnt_low; ++ ++ return acct; + } + + static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) +@@ -508,13 +523,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + hwe->ib1 &= ~MTK_FOE_IB1_STATE; + hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); +- if (ppe->accounting) { +- struct mtk_foe_accounting *acct; +- +- acct = ppe->acct_table + entry->hash * sizeof(*acct); +- acct->packets = 0; +- acct->bytes = 0; +- } + } + entry->hash = 0xffff; + +@@ -539,11 +547,14 @@ static int __mtk_foe_entry_idle_time(str + } + + static bool +-mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) ++mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ u64 *packets, u64 *bytes) + { ++ struct mtk_foe_accounting *acct; + struct mtk_foe_entry foe = {}; + struct mtk_foe_entry *hwe; + u16 hash = entry->hash; ++ bool ret = false; + int len; + + if (hash == 0xffff) +@@ -554,18 +565,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp + memcpy(&foe, hwe, len); + + if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || +- FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) +- return false; ++ FIELD_GET(MTK_FOE_IB1_STATE, foe.ib1) != MTK_FOE_STATE_BIND) { ++ acct = mtk_ppe_acct_data(ppe, hash); ++ if (acct) { ++ entry->prev_packets += acct->packets; ++ entry->prev_bytes += acct->bytes; ++ } ++ ++ goto out; ++ } + + entry->data.ib1 = foe.ib1; ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ ret = true; ++ ++out: ++ if (acct) { ++ *packets += acct->packets; ++ *bytes += acct->bytes; ++ } + +- return true; ++ return ret; + } + + static void + mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) + { + u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); ++ u64 *packets = &entry->packets; ++ u64 *bytes = &entry->bytes; + struct mtk_flow_entry *cur; + struct hlist_node *tmp; + int idle; +@@ -574,7 +602,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe + hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { + int cur_idle; + +- if (!mtk_flow_entry_update(ppe, cur)) { ++ if (!mtk_flow_entry_update(ppe, cur, packets, bytes)) { ++ entry->prev_packets += cur->prev_packets; ++ entry->prev_bytes += cur->prev_bytes; + __mtk_foe_entry_clear(ppe, entry, false); + continue; + } +@@ -589,10 +619,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe + } + } + ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle) ++{ ++ entry->packets = entry->prev_packets; ++ entry->bytes = entry->prev_bytes; ++ ++ spin_lock_bh(&ppe_lock); ++ ++ if (entry->type == MTK_FLOW_TYPE_L2) ++ mtk_flow_entry_update_l2(ppe, entry); ++ else ++ mtk_flow_entry_update(ppe, entry, &entry->packets, &entry->bytes); ++ ++ *idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); ++ ++ spin_unlock_bh(&ppe_lock); ++} ++ + static void + __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, + u16 hash) + { ++ struct mtk_foe_accounting *acct; + struct mtk_eth *eth = ppe->eth; + u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; +@@ -617,6 +666,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + + dma_wmb(); + ++ acct = mtk_ppe_mib_entry_read(ppe, hash); ++ if (acct) { ++ acct->packets = 0; ++ acct->bytes = 0; ++ } ++ + mtk_ppe_cache_clear(ppe); + } + +@@ -781,21 +836,6 @@ out: + spin_unlock_bh(&ppe_lock); + } + +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) +-{ +- int idle; +- +- spin_lock_bh(&ppe_lock); +- if (entry->type == MTK_FLOW_TYPE_L2) +- mtk_flow_entry_update_l2(ppe, entry); +- else +- mtk_flow_entry_update(ppe, entry); +- idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); +- spin_unlock_bh(&ppe_lock); +- +- return idle; +-} +- + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) + { + if (!ppe) +@@ -823,32 +863,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe + return mtk_ppe_wait_busy(ppe); + } + +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff) +-{ +- struct mtk_foe_accounting *acct; +- int size = sizeof(struct mtk_foe_accounting); +- u64 bytes, packets; +- +- if (!ppe->accounting) +- return NULL; +- +- if (mtk_mib_entry_read(ppe, index, &bytes, &packets)) +- return NULL; +- +- acct = ppe->acct_table + index * size; +- +- acct->bytes += bytes; +- acct->packets += packets; +- +- if (diff) { +- diff->bytes = bytes; +- diff->packets = packets; +- } +- +- return acct; +-} +- + struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) + { + bool accounting = eth->soc->has_accounting; +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -283,6 +283,8 @@ struct mtk_flow_entry { + struct mtk_foe_entry data; + struct rhash_head node; + unsigned long cookie; ++ u64 prev_packets, prev_bytes; ++ u64 packets, bytes; + }; + + struct mtk_mib_entry { +@@ -325,6 +327,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ + void mtk_ppe_start(struct mtk_ppe *ppe); + int mtk_ppe_stop(struct mtk_ppe *ppe); + int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); ++struct mtk_foe_accounting *mtk_ppe_mib_entry_read(struct mtk_ppe *ppe, u16 index); + + void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); + +@@ -373,9 +376,8 @@ int mtk_foe_entry_set_queue(struct mtk_e + unsigned int queue); + int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); +-int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); + int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); +-struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, +- struct mtk_foe_accounting *diff); ++void mtk_foe_entry_get_stats(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, ++ int *idle); + + #endif +--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c +@@ -96,7 +96,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file + if (bind && state != MTK_FOE_STATE_BIND) + continue; + +- acct = mtk_foe_entry_get_mib(ppe, i, NULL); ++ acct = mtk_ppe_mib_entry_read(ppe, i); + + type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); + seq_printf(m, "%05x %s %7s", i, +--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +@@ -499,24 +499,21 @@ static int + mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) + { + struct mtk_flow_entry *entry; +- struct mtk_foe_accounting diff; +- u32 idle; ++ u64 packets, bytes; ++ int idle; + + entry = rhashtable_lookup(ð->flow_table, &f->cookie, + mtk_flow_ht_params); + if (!entry) + return -ENOENT; + +- idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); ++ packets = entry->packets; ++ bytes = entry->bytes; ++ mtk_foe_entry_get_stats(eth->ppe[entry->ppe_index], entry, &idle); ++ f->stats.pkts += entry->packets - packets; ++ f->stats.bytes += entry->bytes - bytes; + f->stats.lastused = jiffies - idle * HZ; + +- if (entry->hash != 0xFFFF && +- mtk_foe_entry_get_mib(eth->ppe[entry->ppe_index], entry->hash, +- &diff)) { +- f->stats.pkts += diff.packets; +- f->stats.bytes += diff.bytes; +- } +- + return 0; + } + diff --git a/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch b/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch new file mode 100644 index 00000000000..30839319c7d --- /dev/null +++ b/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch @@ -0,0 +1,21 @@ +From: Felix Fietkau +Date: Thu, 23 Mar 2023 11:19:14 +0100 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add missing ppe cache flush when + deleting a flow + +The cache needs to be flushed to ensure that the hardware stops offloading +the flow immediately. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -523,6 +523,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp + hwe->ib1 &= ~MTK_FOE_IB1_STATE; + hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); + dma_wmb(); ++ mtk_ppe_cache_clear(ppe); + } + entry->hash = 0xffff; + diff --git a/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch b/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch new file mode 100644 index 00000000000..3dfa193e707 --- /dev/null +++ b/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch @@ -0,0 +1,51 @@ +From: Felix Fietkau +Date: Thu, 23 Mar 2023 21:45:43 +0100 +Subject: [PATCH] net: ethernet: mediatek: fix ppe flow accounting for v1 + hardware + +Older chips (like MT7622) use a different bit in ib2 to enable hardware +counter support. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.c ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.c +@@ -646,6 +646,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + struct mtk_eth *eth = ppe->eth; + u16 timestamp = mtk_eth_timestamp(eth); + struct mtk_foe_entry *hwe; ++ u32 val; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; +@@ -662,8 +663,13 @@ __mtk_foe_entry_commit(struct mtk_ppe *p + wmb(); + hwe->ib1 = entry->ib1; + +- if (ppe->accounting) +- *mtk_foe_entry_ib2(eth, hwe) |= MTK_FOE_IB2_MIB_CNT; ++ if (ppe->accounting) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ val = MTK_FOE_IB2_MIB_CNT_V2; ++ else ++ val = MTK_FOE_IB2_MIB_CNT; ++ *mtk_foe_entry_ib2(eth, hwe) |= val; ++ } + + dma_wmb(); + +--- a/drivers/net/ethernet/mediatek/mtk_ppe.h ++++ b/drivers/net/ethernet/mediatek/mtk_ppe.h +@@ -55,9 +55,10 @@ enum { + #define MTK_FOE_IB2_PSE_QOS BIT(4) + #define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5) + #define MTK_FOE_IB2_MULTICAST BIT(8) ++#define MTK_FOE_IB2_MIB_CNT BIT(10) + + #define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12) +-#define MTK_FOE_IB2_MIB_CNT BIT(15) ++#define MTK_FOE_IB2_MIB_CNT_V2 BIT(15) + #define MTK_FOE_IB2_WDMA_DEVIDX BIT(16) + #define MTK_FOE_IB2_WDMA_WINFO BIT(17) + diff --git a/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch b/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch new file mode 100644 index 00000000000..6f28e19a483 --- /dev/null +++ b/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch @@ -0,0 +1,35 @@ +From: Alexander Duyck +Date: Thu, 26 Jan 2023 11:06:59 -0800 +Subject: [PATCH] skb: Do mix page pool and page referenced frags in GRO + +GSO should not merge page pool recycled frames with standard reference +counted frames. Traditionally this didn't occur, at least not often. +However as we start looking at adding support for wireless adapters there +becomes the potential to mix the two due to A-MSDU repartitioning frames in +the receive path. There are possibly other places where this may have +occurred however I suspect they must be few and far between as we have not +seen this issue until now. + +Fixes: 53e0961da1c7 ("page_pool: add frag page recycling support in page pool") +Reported-by: Felix Fietkau +Signed-off-by: Alexander Duyck +--- + +--- a/net/core/skbuff.c ++++ b/net/core/skbuff.c +@@ -4347,6 +4347,15 @@ int skb_gro_receive(struct sk_buff *p, s + if (unlikely(p->len + len >= 65536 || NAPI_GRO_CB(skb)->flush)) + return -E2BIG; + ++ /* Do not splice page pool based packets w/ non-page pool ++ * packets. This can result in reference count issues as page ++ * pool pages will not decrement the reference count and will ++ * instead be immediately returned to the pool or have frag ++ * count decremented. ++ */ ++ if (p->pp_recycle != skb->pp_recycle) ++ return -ETOOMANYREFS; ++ + lp = NAPI_GRO_CB(p)->last; + pinfo = skb_shinfo(lp); + diff --git a/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch new file mode 100644 index 00000000000..fc83416b2a9 --- /dev/null +++ b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch @@ -0,0 +1,232 @@ +From: Felix Fietkau +Date: Thu, 16 Feb 2023 18:39:04 +0100 +Subject: [PATCH] net/core: add optional threading for backlog processing + +When dealing with few flows or an imbalance on CPU utilization, static RPS +CPU assignment can be too inflexible. Add support for enabling threaded NAPI +for backlog processing in order to allow the scheduler to better balance +processing. This helps better spread the load across idle CPUs. + +Signed-off-by: Felix Fietkau +--- + +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -502,6 +502,7 @@ static inline bool napi_complete(struct + } + + int dev_set_threaded(struct net_device *dev, bool threaded); ++int backlog_set_threaded(bool threaded); + + /** + * napi_disable - prevent NAPI from scheduling +@@ -3365,6 +3366,7 @@ struct softnet_data { + unsigned int processed; + unsigned int time_squeeze; + unsigned int received_rps; ++ unsigned int process_queue_empty; + #ifdef CONFIG_RPS + struct softnet_data *rps_ipi_list; + #endif +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4574,7 +4574,7 @@ static int rps_ipi_queued(struct softnet + #ifdef CONFIG_RPS + struct softnet_data *mysd = this_cpu_ptr(&softnet_data); + +- if (sd != mysd) { ++ if (sd != mysd && !test_bit(NAPI_STATE_THREADED, &sd->backlog.state)) { + sd->rps_ipi_next = mysd->rps_ipi_list; + mysd->rps_ipi_list = sd; + +@@ -5755,6 +5755,8 @@ static DEFINE_PER_CPU(struct work_struct + /* Network device is going away, flush any packets still pending */ + static void flush_backlog(struct work_struct *work) + { ++ unsigned int process_queue_empty; ++ bool threaded, flush_processq; + struct sk_buff *skb, *tmp; + struct softnet_data *sd; + +@@ -5770,9 +5772,18 @@ static void flush_backlog(struct work_st + input_queue_head_incr(sd); + } + } ++ ++ threaded = test_bit(NAPI_STATE_THREADED, &sd->backlog.state); ++ flush_processq = threaded && ++ !skb_queue_empty_lockless(&sd->process_queue); ++ if (flush_processq) ++ process_queue_empty = sd->process_queue_empty; + rps_unlock(sd); + local_irq_enable(); + ++ if (threaded) ++ goto out; ++ + skb_queue_walk_safe(&sd->process_queue, skb, tmp) { + if (skb->dev->reg_state == NETREG_UNREGISTERING) { + __skb_unlink(skb, &sd->process_queue); +@@ -5780,7 +5791,18 @@ static void flush_backlog(struct work_st + input_queue_head_incr(sd); + } + } ++ ++out: + local_bh_enable(); ++ ++ while (flush_processq) { ++ msleep(1); ++ local_irq_disable(); ++ rps_lock(sd); ++ flush_processq = process_queue_empty == sd->process_queue_empty; ++ rps_unlock(sd); ++ local_irq_enable(); ++ } + } + + static bool flush_required(int cpu) +@@ -6463,6 +6485,7 @@ static int process_backlog(struct napi_s + + local_irq_disable(); + rps_lock(sd); ++ sd->process_queue_empty++; + if (skb_queue_empty(&sd->input_pkt_queue)) { + /* + * Inline a custom version of __napi_complete(). +@@ -6472,7 +6495,8 @@ static int process_backlog(struct napi_s + * We can use a plain write instead of clear_bit(), + * and we dont need an smp_mb() memory barrier. + */ +- napi->state = 0; ++ napi->state &= ~(NAPIF_STATE_SCHED | ++ NAPIF_STATE_SCHED_THREADED); + again = false; + } else { + skb_queue_splice_tail_init(&sd->input_pkt_queue, +@@ -6889,6 +6913,57 @@ int dev_set_threaded(struct net_device * + } + EXPORT_SYMBOL(dev_set_threaded); + ++int backlog_set_threaded(bool threaded) ++{ ++ static bool backlog_threaded; ++ int err = 0; ++ int i; ++ ++ if (backlog_threaded == threaded) ++ return 0; ++ ++ for_each_possible_cpu(i) { ++ struct softnet_data *sd = &per_cpu(softnet_data, i); ++ struct napi_struct *n = &sd->backlog; ++ ++ if (n->thread) ++ continue; ++ n->thread = kthread_run(napi_threaded_poll, n, "napi/backlog-%d", i); ++ if (IS_ERR(n->thread)) { ++ err = PTR_ERR(n->thread); ++ pr_err("kthread_run failed with err %d\n", err); ++ n->thread = NULL; ++ threaded = false; ++ break; ++ } ++ ++ } ++ ++ backlog_threaded = threaded; ++ ++ /* Make sure kthread is created before THREADED bit ++ * is set. ++ */ ++ smp_mb__before_atomic(); ++ ++ for_each_possible_cpu(i) { ++ struct softnet_data *sd = &per_cpu(softnet_data, i); ++ struct napi_struct *n = &sd->backlog; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ rps_lock(sd); ++ if (threaded) ++ n->state |= NAPIF_STATE_THREADED; ++ else ++ n->state &= ~NAPIF_STATE_THREADED; ++ rps_unlock(sd); ++ local_irq_restore(flags); ++ } ++ ++ return err; ++} ++ + void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) + { +@@ -11367,6 +11442,9 @@ static int dev_cpu_dead(unsigned int old + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_enable(); + ++ if (test_bit(NAPI_STATE_THREADED, &oldsd->backlog.state)) ++ return 0; ++ + #ifdef CONFIG_RPS + remsd = oldsd->rps_ipi_list; + oldsd->rps_ipi_list = NULL; +@@ -11706,6 +11784,7 @@ static int __init net_dev_init(void) + sd->cpu = i; + #endif + ++ INIT_LIST_HEAD(&sd->backlog.poll_list); + init_gro_hash(&sd->backlog); + sd->backlog.poll = process_backlog; + sd->backlog.weight = weight_p; +--- a/net/core/sysctl_net_core.c ++++ b/net/core/sysctl_net_core.c +@@ -28,6 +28,7 @@ static int int_3600 = 3600; + static int min_sndbuf = SOCK_MIN_SNDBUF; + static int min_rcvbuf = SOCK_MIN_RCVBUF; + static int max_skb_frags = MAX_SKB_FRAGS; ++static int backlog_threaded; + static long long_one __maybe_unused = 1; + static long long_max __maybe_unused = LONG_MAX; + +@@ -114,6 +115,23 @@ static int rps_sock_flow_sysctl(struct c + } + #endif /* CONFIG_RPS */ + ++static int backlog_threaded_sysctl(struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ static DEFINE_MUTEX(backlog_threaded_mutex); ++ int ret; ++ ++ mutex_lock(&backlog_threaded_mutex); ++ ++ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); ++ if (write && !ret) ++ ret = backlog_set_threaded(backlog_threaded); ++ ++ mutex_unlock(&backlog_threaded_mutex); ++ ++ return ret; ++} ++ + #ifdef CONFIG_NET_FLOW_LIMIT + static DEFINE_MUTEX(flow_limit_update_mutex); + +@@ -470,6 +488,15 @@ static struct ctl_table net_core_table[] + .proc_handler = rps_sock_flow_sysctl + }, + #endif ++ { ++ .procname = "backlog_threaded", ++ .data = &backlog_threaded, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = backlog_threaded_sysctl, ++ .extra1 = SYSCTL_ZERO, ++ .extra2 = SYSCTL_ONE ++ }, + #ifdef CONFIG_NET_FLOW_LIMIT + { + .procname = "flow_limit_cpu_bitmap", diff --git a/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch new file mode 100644 index 00000000000..18933de3a03 --- /dev/null +++ b/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch @@ -0,0 +1,27 @@ +From: Tobias Waldekranz +Subject: [RFC net-next 7/7] net: dsa: mv88e6xxx: Request assisted learning on CPU port +Date: Sat, 16 Jan 2021 02:25:15 +0100 +Archived-At: + +While the hardware is capable of performing learning on the CPU port, +it requires alot of additions to the bridge's forwarding path in order +to handle multi-destination traffic correctly. + +Until that is in place, opt for the next best thing and let DSA sync +the relevant addresses down to the hardware FDB. + +Signed-off-by: Tobias Waldekranz +--- + drivers/net/dsa/mv88e6xxx/chip.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -6333,6 +6333,7 @@ static int mv88e6xxx_register_switch(str + ds->ops = &mv88e6xxx_switch_ops; + ds->ageing_time_min = chip->info->age_time_coeff; + ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; ++ ds->assisted_learning_on_cpu_port = true; + + /* Some chips support up to 32, but that requires enabling the + * 5-bit port mode, which we do not support. 640k^W16 ought to diff --git a/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch b/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch new file mode 100644 index 00000000000..ca963d1260c --- /dev/null +++ b/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch @@ -0,0 +1,174 @@ +From patchwork Sun Mar 19 22:08:05 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13180645 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id A7A46C6FD1F + for ; Sun, 19 Mar 2023 22:08:15 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S230223AbjCSWIN (ORCPT ); + Sun, 19 Mar 2023 18:08:13 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32878 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S229565AbjCSWIM (ORCPT + ); Sun, 19 Mar 2023 18:08:12 -0400 +Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com + [IPv6:2a00:1450:4864:20::42e]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 605D3E062; + Sun, 19 Mar 2023 15:08:10 -0700 (PDT) +Received: by mail-wr1-x42e.google.com with SMTP id h17so8695188wrt.8; + Sun, 19 Mar 2023 15:08:10 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679263689; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=GmPK75Q9ZD3h3IYflWYuDwS99V2e532KgDlnNucAoJg=; + b=PSdrywW48P4Lq8z9wOSPXFB/ZdO/JfuyiGlw3Gz1Iriy+Smo/cBnJ0Ve9zKkX3AKTO + Tr7/g8xhSQX8sU5WAOEPC13uVjKpO4VZsamXHTmMKL4mmfII3K/piAsQcMQkkNpgouab + Ci9yr+7ASSmqEUHIbYTM6sl6a47rPwqk3b3DcTIE2CwJsPPNXnpQ/aSVbJAcEdhcZICc + X4rAmjrYjcsl8coFIGHHPlrMH9ShekQWxB84vEb6bO1nXOORNPizOHuY1vJ3wa3WgXsx + YwlvutMFVIUXfgL2ZwCmQAKWJPiAaFk+CCk3oxSeOYoAzkjcbMyapz9VnooStfvR2aV3 + k+2g== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679263689; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=GmPK75Q9ZD3h3IYflWYuDwS99V2e532KgDlnNucAoJg=; + b=NGjqrGERyaxRwINtevHaY97h9X9W+1UY62YYwotqwv5+cfvB8myjBbD3WH2WzaqMes + o9MMER9RE8/arW3jIVlBv4ORDUuEZ7AeGgy5UbFyQZIPHlp+hJ/sxFrGvYUwamg4Qrr9 + ojargh8ORsEiMeqaf+5AkmEagNhrrV3ax0pUuWDzbJ3vXGoHjfCetHz5xyNL46dvXBfb + l/OZqjv9IYob552uUoUmCy/TbEQDqvmjkFrROFK9gtBNxgxUJkwbyiWIOVsf6RR8OarP + f7bbvSJYkvTvzx2u/g0Up7NW5ZyihMGBmDs377M3yW6AnSxW6jlfl30QmMU1aEigYXvy + v3mA== +X-Gm-Message-State: AO0yUKUm1PYmYa4xlHuVD23mZcZm83a+xbhcbs0Xryi3yF/+UnjM4Cho + GAfqSh5MZ/rlOAm3Vnpn//9hOG5Lc8vLYg== +X-Google-Smtp-Source: + AK7set+5pTahGGgk1hF/mHGkGBhsMf0//oQjZd4QFHx+HaeSgP5f6q7g0bRUcTX8kRtgHH0T7l1/hQ== +X-Received: by 2002:a5d:474f:0:b0:2d6:2ae8:70d with SMTP id + o15-20020a5d474f000000b002d62ae8070dmr2382593wrs.39.1679263688549; + Sun, 19 Mar 2023 15:08:08 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + d6-20020a5d6dc6000000b002c53f6c7599sm7354727wrz.29.2023.03.19.15.08.07 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Sun, 19 Mar 2023 15:08:07 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: f.fainelli@gmail.com, jonas.gorski@gmail.com, andrew@lunn.ch, + olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, netdev@vger.kernel.org, + linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v2] net: dsa: b53: add support for BCM63xx RGMIIs +Date: Sun, 19 Mar 2023 23:08:05 +0100 +Message-Id: <20230319220805.124024-1-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230319183330.761251-1-noltari@gmail.com> +References: <20230319183330.761251-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +BCM63xx RGMII ports require additional configuration in order to work. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Andrew Lunn +--- + v2: add changes suggested by Andrew: + - Use a switch statement. + - Use dev_dbg() instead of dev_info(). + + drivers/net/dsa/b53/b53_common.c | 46 ++++++++++++++++++++++++++++++++ + drivers/net/dsa/b53/b53_priv.h | 1 + + 2 files changed, 47 insertions(+) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1209,6 +1209,46 @@ static void b53_force_port_config(struct + b53_write8(dev, B53_CTRL_PAGE, off, reg); + } + ++static void b53_adjust_63xx_rgmii(struct dsa_switch *ds, int port, ++ phy_interface_t interface) ++{ ++ struct b53_device *dev = ds->priv; ++ u8 rgmii_ctrl = 0, off; ++ ++ if (port == dev->imp_port) ++ off = B53_RGMII_CTRL_IMP; ++ else ++ off = B53_RGMII_CTRL_P(port); ++ ++ b53_read8(dev, B53_CTRL_PAGE, off, &rgmii_ctrl); ++ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_RGMII_ID: ++ rgmii_ctrl |= (RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC); ++ break; ++ case PHY_INTERFACE_MODE_RGMII_RXID: ++ rgmii_ctrl &= ~(RGMII_CTRL_DLL_TXC); ++ rgmii_ctrl |= RGMII_CTRL_DLL_RXC; ++ break; ++ case PHY_INTERFACE_MODE_RGMII_TXID: ++ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC); ++ rgmii_ctrl |= RGMII_CTRL_DLL_TXC; ++ break; ++ case PHY_INTERFACE_MODE_RGMII: ++ default: ++ rgmii_ctrl &= ~(RGMII_CTRL_DLL_RXC | RGMII_CTRL_DLL_TXC); ++ break; ++ } ++ ++ if (port != dev->imp_port) ++ rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; ++ ++ b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); ++ ++ dev_dbg(ds->dev, "Configured port %d for %s\n", port, ++ phy_modes(interface)); ++} ++ + static void b53_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) + { +@@ -1235,6 +1275,9 @@ static void b53_adjust_link(struct dsa_s + tx_pause, rx_pause); + b53_force_link(dev, port, phydev->link); + ++ if (is63xx(dev) && port >= B53_63XX_RGMII0) ++ b53_adjust_63xx_rgmii(ds, port, phydev->interface); ++ + if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { + if (port == dev->imp_port) + off = B53_RGMII_CTRL_IMP; +@@ -1419,6 +1462,9 @@ void b53_phylink_mac_link_up(struct dsa_ + { + struct b53_device *dev = ds->priv; + ++ if (is63xx(dev) && port >= B53_63XX_RGMII0) ++ b53_adjust_63xx_rgmii(ds, port, interface); ++ + if (mode == MLO_AN_PHY) + return; + +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -206,6 +206,7 @@ static inline int is58xx(struct b53_devi + dev->chip_id == BCM7278_DEVICE_ID; + } + ++#define B53_63XX_RGMII0 4 + #define B53_CPU_PORT_25 5 + #define B53_CPU_PORT 8 + diff --git a/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch b/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch new file mode 100644 index 00000000000..e2da4e7f055 --- /dev/null +++ b/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch @@ -0,0 +1,108 @@ +From patchwork Tue Mar 21 17:33:57 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13183003 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 823A1C761AF + for ; Tue, 21 Mar 2023 17:35:06 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S230490AbjCURfE (ORCPT ); + Tue, 21 Mar 2023 13:35:04 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47440 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S230357AbjCURex (ORCPT + ); Tue, 21 Mar 2023 13:34:53 -0400 +Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com + [IPv6:2a00:1450:4864:20::430]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C9A45559D8; + Tue, 21 Mar 2023 10:34:26 -0700 (PDT) +Received: by mail-wr1-x430.google.com with SMTP id m2so14547588wrh.6; + Tue, 21 Mar 2023 10:34:26 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679420063; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=cUvnluVaZPzfEQB9fMRuYo+4/361t/7po7nyUBBJfxc=; + b=F0pa8JmQZ1FeXVtdpCygur8UmLrgKwxCcjaMn312u5zNvsXsEPeCAIDqP2tvNNTwv/ + UYjaNaoZ77HSvv/gSqeG808AXGyNs1PvLuHZYuUTJRNuLaMixKtkNFi4ypheCdk0WCiE + IWz0DIm6ojmdwMqafDUKQ6Qwkv5R0vo8Wh5vpjimEmCelOyMvfuLZNqubsiGqpnCguBp + uWlmKh95/VubCGgiGG2xK1IXQayL14ENuWseDds7nVpVK50NycrFgJbL17Bd6qJKYkbo + m70IC+9jM0hjwKXpyi6ipCBNcW+1E6JIwILVC04Xi+BTpOGhbUAQ59Yn2hyq7tQM7dzs + 4PLg== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679420063; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=cUvnluVaZPzfEQB9fMRuYo+4/361t/7po7nyUBBJfxc=; + b=SCX78yTuGjdnE5nuL0p7+kxGnOzsCExsigLdaV+x/JswmwxSpZvxn223i1yM95klj9 + Rk0RnXqATLF1wZA7L1YmbeZ66zxUwW/osnCjJHPeEF8AGgjK/qawtLl/HJQHN67NaRNQ + bDsRn2nWQ2GRTRFpvD+iGRy4uyQCDu9HFxLbn43fBsBmRnXWGPQP5cEb90tL83/Onp4D + Lx/XcyZOh9QRfJNhj+G1BAeRCLRA/sdA0W3Ecu5SCFs+LtS6uvLVGWDKEDfnZhYY8Xqf + Mx9evWzdW2OorEN2FI6+xTglvnEBcVhHIJ7XEGAhCG6ocgMZeck++774S8RWumWl8xpy + /K9Q== +X-Gm-Message-State: AO0yUKUORAlGfbkNwnYmQnTWcGPqW6sp4g9WfgQmRZGCV+9tCB0OebSP + ICq6v4YPmUPNRl/WNnVCbps= +X-Google-Smtp-Source: + AK7set8pFDl8fHRwGPhAguqxIfqnQ4PY+b57IHEsybIaQ/HPNwdJ1cs1+IPBGHe3TL14dTS4aVNpHA== +X-Received: by 2002:a5d:6991:0:b0:2ce:aab5:f96b with SMTP id + g17-20020a5d6991000000b002ceaab5f96bmr2965175wru.67.1679420062764; + Tue, 21 Mar 2023 10:34:22 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + b13-20020a056000054d00b002da1261aa44sm184775wrf.48.2023.03.21.10.34.21 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Tue, 21 Mar 2023 10:34:21 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: f.fainelli@gmail.com, jonas.gorski@gmail.com, andrew@lunn.ch, + olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, netdev@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v2 2/4] net: dsa: b53: mmap: add more 63xx SoCs +Date: Tue, 21 Mar 2023 18:33:57 +0100 +Message-Id: <20230321173359.251778-3-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230321173359.251778-1-noltari@gmail.com> +References: <20230320155024.164523-1-noltari@gmail.com> + <20230321173359.251778-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +BCM6318, BCM6362 and BCM63268 are SoCs with a B53 MMAP switch. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Florian Fainelli +--- + v2: no changes. + + drivers/net/dsa/b53/b53_mmap.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/net/dsa/b53/b53_mmap.c ++++ b/drivers/net/dsa/b53/b53_mmap.c +@@ -347,8 +347,11 @@ static void b53_mmap_shutdown(struct pla + + static const struct of_device_id b53_mmap_of_table[] = { + { .compatible = "brcm,bcm3384-switch" }, ++ { .compatible = "brcm,bcm6318-switch" }, + { .compatible = "brcm,bcm6328-switch" }, ++ { .compatible = "brcm,bcm6362-switch" }, + { .compatible = "brcm,bcm6368-switch" }, ++ { .compatible = "brcm,bcm63268-switch" }, + { .compatible = "brcm,bcm63xx-switch" }, + { /* sentinel */ }, + }; diff --git a/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch b/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch new file mode 100644 index 00000000000..456643f05d6 --- /dev/null +++ b/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch @@ -0,0 +1,195 @@ +From patchwork Tue Mar 21 17:33:58 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13183004 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id B2B12C74A5B + for ; Tue, 21 Mar 2023 17:35:12 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S230297AbjCURfK (ORCPT ); + Tue, 21 Mar 2023 13:35:10 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47438 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S230374AbjCURex (ORCPT + ); Tue, 21 Mar 2023 13:34:53 -0400 +Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com + [IPv6:2a00:1450:4864:20::432]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C906B5550A; + Tue, 21 Mar 2023 10:34:26 -0700 (PDT) +Received: by mail-wr1-x432.google.com with SMTP id y14so14546846wrq.4; + Tue, 21 Mar 2023 10:34:26 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679420064; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=vnvnwWc5Tmg09HBQo/m9RbRM6yM8KLx8r1VA+Abfg3k=; + b=eFv+mwe94Y2YZMiJP5gydXVrGlbIAR5HCrY0rdcoGoMPzQUHLFckZeYCgEKudI55I7 + gMLZYCtLwvDXvKeHM2AUigsq2YuJSeF5QwICPrhTnMwUGBg4yyyltrc3+J0lSd6/4kQv + h0yM1Oo4v0d8CuqjBU6bXienIk34AFVJfsPq+vWQTjAbUL7ht4WHZ2Ez2MFoTvZpkIJA + 5iWMyVoMbugZl6eqNRjvDHFmtBtrZIv8AFs10r2Ca6+Yxm+aq0v33DRkbSVVqgFPNEzy + q5QOXOeLBPL6BvyovOpmVSWGoHf1zFV7lrzcqi+uc+FuYxQ9dyN3ND73DrrhWSkLaSg9 + r8yA== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679420064; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=vnvnwWc5Tmg09HBQo/m9RbRM6yM8KLx8r1VA+Abfg3k=; + b=jIRB8pIlrLA/ovhnEoePs/6SX8fn6l7l4fY2CxX2pLrTbP1JI8AAetPavvrNVQTr2M + Vm0iLbKyL/VpTq9+bSN1SMjaoi4lAMj0pgafoHrwABMVZpFauYvtCfSYTstZ2pw4Dr1j + wYQGj3BUSpFIYHtSIDMkb5449WA3T3TONhaQLRFAUCBD6gAFyEky5fY+DIHrGaj352B6 + 9ST/tkqHgPpuFlmromr42KQWoTFU+Pj0Uhyp7ru4BsnF7tTshWroZZIHUJmSACudEadr + fBPiuurX9jgp9zNqj8Oy0HjiVUnULFCapj8yICGp5s44uDAK/XFqFXpOuJ8ptS6uPazU + xUwg== +X-Gm-Message-State: AO0yUKX2w6QZfaGDHtlZAlY/U8F8VuJa3HwlgXbxgGChgdgvIoFThawv + oDyFAhWbVfe4DxwXTwxgJ/I= +X-Google-Smtp-Source: + AK7set+sH60XiJYup7bqrZTzFJVNe1YGcX/UTfjWV9xfGwNyodc34cHvKpqNagw5J+vEpv6CKvNHaA== +X-Received: by 2002:adf:f344:0:b0:2cd:de25:1c76 with SMTP id + e4-20020adff344000000b002cdde251c76mr12989754wrp.17.1679420064464; + Tue, 21 Mar 2023 10:34:24 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + b13-20020a056000054d00b002da1261aa44sm184775wrf.48.2023.03.21.10.34.22 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Tue, 21 Mar 2023 10:34:23 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: f.fainelli@gmail.com, jonas.gorski@gmail.com, andrew@lunn.ch, + olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, netdev@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v2 3/4] net: dsa: b53: mmap: allow passing a chip ID +Date: Tue, 21 Mar 2023 18:33:58 +0100 +Message-Id: <20230321173359.251778-4-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230321173359.251778-1-noltari@gmail.com> +References: <20230320155024.164523-1-noltari@gmail.com> + <20230321173359.251778-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +BCM6318 and BCM63268 SoCs require a special handling for their RGMIIs, so we +should be able to identify them as a special BCM63xx switch. + +Signed-off-by: Álvaro Fernández Rojas +--- + v2: + - Add missing chip to b53_switch_chips[]. + - Fix device_get_match_data() casting warning. + - Add BCM63268_DEVICE_ID to BCM6318 too. + - Add BCM6318 in commit description. + + drivers/net/dsa/b53/b53_common.c | 13 +++++++++++++ + drivers/net/dsa/b53/b53_mmap.c | 32 +++++++++++++++++++++++--------- + drivers/net/dsa/b53/b53_priv.h | 9 ++++++++- + 3 files changed, 44 insertions(+), 10 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2461,6 +2461,19 @@ static const struct b53_chip_data b53_sw + .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, + }, + { ++ .chip_id = BCM63268_DEVICE_ID, ++ .dev_name = "BCM63268", ++ .vlans = 4096, ++ .enabled_ports = 0, /* pdata must provide them */ ++ .arl_bins = 4, ++ .arl_buckets = 1024, ++ .imp_port = 8, ++ .vta_regs = B53_VTA_REGS_63XX, ++ .duplex_reg = B53_DUPLEX_STAT_63XX, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, ++ }, ++ { + .chip_id = BCM53010_DEVICE_ID, + .dev_name = "BCM53010", + .vlans = 4096, +--- a/drivers/net/dsa/b53/b53_mmap.c ++++ b/drivers/net/dsa/b53/b53_mmap.c +@@ -262,7 +262,7 @@ static int b53_mmap_probe_of(struct plat + return -ENOMEM; + + pdata->regs = mem; +- pdata->chip_id = BCM63XX_DEVICE_ID; ++ pdata->chip_id = (u32)(unsigned long)device_get_match_data(dev); + pdata->big_endian = of_property_read_bool(np, "big-endian"); + + of_ports = of_get_child_by_name(np, "ports"); +@@ -346,14 +346,28 @@ static void b53_mmap_shutdown(struct pla + } + + static const struct of_device_id b53_mmap_of_table[] = { +- { .compatible = "brcm,bcm3384-switch" }, +- { .compatible = "brcm,bcm6318-switch" }, +- { .compatible = "brcm,bcm6328-switch" }, +- { .compatible = "brcm,bcm6362-switch" }, +- { .compatible = "brcm,bcm6368-switch" }, +- { .compatible = "brcm,bcm63268-switch" }, +- { .compatible = "brcm,bcm63xx-switch" }, +- { /* sentinel */ }, ++ { ++ .compatible = "brcm,bcm3384-switch", ++ .data = (void *)BCM63XX_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm6318-switch", ++ .data = (void *)BCM63268_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm6328-switch", ++ .data = (void *)BCM63XX_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm6362-switch", ++ .data = (void *)BCM63XX_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm6368-switch", ++ .data = (void *)BCM63XX_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm63268-switch", ++ .data = (void *)BCM63268_DEVICE_ID, ++ }, { ++ .compatible = "brcm,bcm63xx-switch", ++ .data = (void *)BCM63XX_DEVICE_ID, ++ }, { /* sentinel */ } + }; + MODULE_DEVICE_TABLE(of, b53_mmap_of_table); + +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -75,6 +75,7 @@ enum { + BCM53125_DEVICE_ID = 0x53125, + BCM53128_DEVICE_ID = 0x53128, + BCM63XX_DEVICE_ID = 0x6300, ++ BCM63268_DEVICE_ID = 0x63268, + BCM53010_DEVICE_ID = 0x53010, + BCM53011_DEVICE_ID = 0x53011, + BCM53012_DEVICE_ID = 0x53012, +@@ -186,7 +187,13 @@ static inline int is531x5(struct b53_dev + + static inline int is63xx(struct b53_device *dev) + { +- return dev->chip_id == BCM63XX_DEVICE_ID; ++ return dev->chip_id == BCM63XX_DEVICE_ID || ++ dev->chip_id == BCM63268_DEVICE_ID; ++} ++ ++static inline int is63268(struct b53_device *dev) ++{ ++ return dev->chip_id == BCM63268_DEVICE_ID; + } + + static inline int is5301x(struct b53_device *dev) diff --git a/target/linux/generic/pending-6.1/775-net-dsa-b53-add-BCM63268-RGMII-configuration.patch b/target/linux/generic/pending-6.1/775-net-dsa-b53-add-BCM63268-RGMII-configuration.patch new file mode 100644 index 00000000000..d90d757fb2c --- /dev/null +++ b/target/linux/generic/pending-6.1/775-net-dsa-b53-add-BCM63268-RGMII-configuration.patch @@ -0,0 +1,123 @@ +From patchwork Tue Mar 21 17:33:59 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13183005 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 31BE4C761A6 + for ; Tue, 21 Mar 2023 17:35:16 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S229674AbjCURfN (ORCPT ); + Tue, 21 Mar 2023 13:35:13 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47684 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S230327AbjCURfB (ORCPT + ); Tue, 21 Mar 2023 13:35:01 -0400 +Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com + [IPv6:2a00:1450:4864:20::436]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E1D855507D; + Tue, 21 Mar 2023 10:34:27 -0700 (PDT) +Received: by mail-wr1-x436.google.com with SMTP id i9so14537769wrp.3; + Tue, 21 Mar 2023 10:34:27 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679420066; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=asmFs22xWYwR1Ql9m/IrNv+MPUNDn8hSjmwDRYvO7mE=; + b=Cqj2C6aG5vEOlhh9N3ybvDA0CV38nhQODnfdnr7utNddd323iDagoJty1Wmi3MAzj1 + 5ORmYT5fQvUnild7C4RhcCNTBn+MoYZ+wDZwZYelu6BKHkW11YFK949ax5B50by+ASR2 + z+rGI3wR5fVXd4VDgmcsT6zF5x69wKyhbhqIfrhG9BVFTctfaBgDS/l+bX1C56kSqv82 + bQkKSSAehSLGpFoCU3q62OGoZVi3jDe6HDb5M1Dp2mgHhqsW19otZpJ57DjtZ1CmtPai + o7T/ew6WoIYSl6whBmV36jeNaDJ3TItOBrKc4nMJBDWaCg4DNzUSe0ei5Xz7Oik5lb3p + y9ew== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679420066; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=asmFs22xWYwR1Ql9m/IrNv+MPUNDn8hSjmwDRYvO7mE=; + b=UdI2iQNBYwRf40ivf3ROR132t95BU/p3RUzXdZLCyz6c6JWtECQ5byyGeEwoX10n5u + HlepoNTJxMFLYrAHGvNLDPpWPuLXMa645S1mCVZ7NyWp8W96XzSynNZPeXHuJdb464QU + A7UTRSW3mlvKe9OR3EcB2CfBZv0yHWR0ldbnxcxGUFw8z78PNqpOVnITtjBdfpGesJ9c + VJw+fiM6hCcahor4nk9LLcAryPm8xmhDLxBKaLILO8wyTUiHY8G9hsXnFCtcpetnF5wS + pW13beAE+odb7ZZaXZUYpWGYhCe/hLzNjbo8YpgzHwadZthxPrT5YvNIYwyrvoViLM0n + KDRQ== +X-Gm-Message-State: AO0yUKW+9H/kqcAUyWeZhZJhiJjsBcYn1THmZaSDrPrk/pNuGXJXGtJd + NgsGZW8iSqLEv81yK+U5Os8= +X-Google-Smtp-Source: + AK7set/lzQZwCSxVaOe5dZ+7TR3xaQty/vg5xvZDpRW8TwTiPQblIbw5kJJTPLp67RySehrPIlCqSg== +X-Received: by 2002:a5d:65c9:0:b0:2ce:ac31:54ff with SMTP id + e9-20020a5d65c9000000b002ceac3154ffmr2776515wrw.2.1679420066191; + Tue, 21 Mar 2023 10:34:26 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + b13-20020a056000054d00b002da1261aa44sm184775wrf.48.2023.03.21.10.34.24 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Tue, 21 Mar 2023 10:34:25 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: f.fainelli@gmail.com, jonas.gorski@gmail.com, andrew@lunn.ch, + olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, + kuba@kernel.org, pabeni@redhat.com, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, netdev@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= , + Simon Horman +Subject: [PATCH v2 4/4] net: dsa: b53: add BCM63268 RGMII configuration +Date: Tue, 21 Mar 2023 18:33:59 +0100 +Message-Id: <20230321173359.251778-5-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230321173359.251778-1-noltari@gmail.com> +References: <20230320155024.164523-1-noltari@gmail.com> + <20230321173359.251778-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +BCM63268 requires special RGMII configuration to work. + +Signed-off-by: Álvaro Fernández Rojas +Reviewed-by: Florian Fainelli +Reviewed-by: Simon Horman +--- + v2: no changes. + + drivers/net/dsa/b53/b53_common.c | 6 +++++- + drivers/net/dsa/b53/b53_regs.h | 1 + + 2 files changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -1240,8 +1240,12 @@ static void b53_adjust_63xx_rgmii(struct + break; + } + +- if (port != dev->imp_port) ++ if (port != dev->imp_port) { ++ if (is63268(dev)) ++ rgmii_ctrl |= RGMII_CTRL_MII_OVERRIDE; ++ + rgmii_ctrl |= RGMII_CTRL_ENABLE_GMII; ++ } + + b53_write8(dev, B53_CTRL_PAGE, off, rgmii_ctrl); + +--- a/drivers/net/dsa/b53/b53_regs.h ++++ b/drivers/net/dsa/b53/b53_regs.h +@@ -138,6 +138,7 @@ + + #define B53_RGMII_CTRL_IMP 0x60 + #define RGMII_CTRL_ENABLE_GMII BIT(7) ++#define RGMII_CTRL_MII_OVERRIDE BIT(6) + #define RGMII_CTRL_TIMING_SEL BIT(2) + #define RGMII_CTRL_DLL_RXC BIT(1) + #define RGMII_CTRL_DLL_TXC BIT(0) diff --git a/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch b/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch new file mode 100644 index 00000000000..53494eca6ed --- /dev/null +++ b/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch @@ -0,0 +1,189 @@ +From patchwork Fri Mar 24 08:41:38 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13186549 +X-Patchwork-Delegate: kuba@kernel.org +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id EF744C76195 + for ; Fri, 24 Mar 2023 08:42:01 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S231807AbjCXImA (ORCPT ); + Fri, 24 Mar 2023 04:42:00 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32956 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S231272AbjCXIly (ORCPT + ); Fri, 24 Mar 2023 04:41:54 -0400 +Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com + [IPv6:2a00:1450:4864:20::535]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 113A517CF3; + Fri, 24 Mar 2023 01:41:46 -0700 (PDT) +Received: by mail-ed1-x535.google.com with SMTP id ek18so4877175edb.6; + Fri, 24 Mar 2023 01:41:45 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679647304; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=OfUWRaFIQIQw/lRivER+LHryfdLliXzvabGrcmkQVEU=; + b=JMrl6Eay1FS0JZqgPHsbcVzuNAbFELc0SLNGyzYtOVQXcI+YwKDM9Ls7I9PsQVEPoZ + CthomCTYoz5G9DU7uBuia207rnjOhssZJRu0syrCoU+O/ZiQyGLJDvq61z5oZJxC2S40 + kzRsUsC6MRjn64DKPWmxhsSTMKLzn2+P233LKNFbHtfi3NWF5Qu/85sUkxMurnfUgja0 + qQhl25qYY7ZIvmlFHYefaI5UkITQFuiybrqJW9tztCdHf/gS+f33YkkvQ8njmMQa1DW0 + ppedfOUotX+6kmHZGX1yea2V5ezEGGvRourZtYMoecTiD0E5d1J1bKhktKslVLIDm0ig + oc2g== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679647304; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=OfUWRaFIQIQw/lRivER+LHryfdLliXzvabGrcmkQVEU=; + b=b3Gmga5ZDbnmQfnw1GCz+eU2JwgsVzfciZuSmfYAiVxpW4c6cur3MHbpzDPhi99wzA + ZYAM7ryLv88rXl/tQB5g2Nte5rvMfxUeHXsT/JpsRcSSocFRbRrk0QJyiA/Xj86NiD5N + C1sKz50Im190FmrvPcBh6OHQbv/3MQyE+1fQx+9q3jW5rQiAWQaYk4Ng8GlWA7gtG3jB + fHO6Fuoenn32pgkveJbQLYL/2t2f53wGf3QLQ3IeKW7jdfIHNThwrwqBMxdHoIDaTBT9 + UWMeJuiYtylIibo/3zbORbWOgIERlWxZRf3BCOFpnzUn4eBzio4LgjtNxZ77ITRxsmbk + 3+Hg== +X-Gm-Message-State: AAQBX9dfyBfbR7Sdd5wqxMiAv3Yhk47pK1XzD87MZyAF3AxyoFyKcMaF + EbwJLyRvTGQEFdVWCGw1eMU= +X-Google-Smtp-Source: + AKy350bpDVLq7k1FxG2Mek/VIobZL4KhufiKx8qfmpxpcWmLI3bLg8wfQKEAKJRNJBleo/7CZuCL5g== +X-Received: by 2002:aa7:c711:0:b0:4a2:588f:b3c5 with SMTP id + i17-20020aa7c711000000b004a2588fb3c5mr2261236edq.21.1679647304260; + Fri, 24 Mar 2023 01:41:44 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + z21-20020a50cd15000000b004acbda55f6bsm10323728edi.27.2023.03.24.01.41.43 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Fri, 24 Mar 2023 01:41:43 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: paul.geurts@prodrive-technologies.com, f.fainelli@gmail.com, + jonas.gorski@gmail.com, andrew@lunn.ch, olteanv@gmail.com, + davem@davemloft.net, edumazet@google.com, kuba@kernel.org, + pabeni@redhat.com, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, netdev@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v2 2/2] net: dsa: b53: mdio: add support for BCM53134 +Date: Fri, 24 Mar 2023 09:41:38 +0100 +Message-Id: <20230324084138.664285-3-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230324084138.664285-1-noltari@gmail.com> +References: <20230323121804.2249605-1-noltari@gmail.com> + <20230324084138.664285-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: netdev@vger.kernel.org +X-Patchwork-Delegate: kuba@kernel.org + +From: Paul Geurts + +Add support for the BCM53134 Ethernet switch in the existing b53 dsa driver. +BCM53134 is very similar to the BCM58XX series. + +Signed-off-by: Paul Geurts +Signed-off-by: Álvaro Fernández Rojas +--- + v2: add BCM53134 to is531x5() and remove special RGMII config + + drivers/net/dsa/b53/b53_common.c | 15 +++++++++++++++ + drivers/net/dsa/b53/b53_mdio.c | 5 ++++- + drivers/net/dsa/b53/b53_priv.h | 7 +++++-- + 3 files changed, 24 insertions(+), 3 deletions(-) + +--- a/drivers/net/dsa/b53/b53_common.c ++++ b/drivers/net/dsa/b53/b53_common.c +@@ -2609,6 +2609,20 @@ static const struct b53_chip_data b53_sw + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, ++ { ++ .chip_id = BCM53134_DEVICE_ID, ++ .dev_name = "BCM53134", ++ .vlans = 4096, ++ .enabled_ports = 0x12f, ++ .imp_port = 8, ++ .cpu_port = B53_CPU_PORT, ++ .vta_regs = B53_VTA_REGS, ++ .arl_bins = 4, ++ .arl_buckets = 1024, ++ .duplex_reg = B53_DUPLEX_STAT_GE, ++ .jumbo_pm_reg = B53_JUMBO_PORT_MASK, ++ .jumbo_size_reg = B53_JUMBO_MAX_SIZE, ++ }, + }; + + static int b53_switch_init(struct b53_device *dev) +@@ -2785,6 +2799,7 @@ int b53_switch_detect(struct b53_device + case BCM53012_DEVICE_ID: + case BCM53018_DEVICE_ID: + case BCM53019_DEVICE_ID: ++ case BCM53134_DEVICE_ID: + dev->chip_id = id32; + break; + default: +--- a/drivers/net/dsa/b53/b53_mdio.c ++++ b/drivers/net/dsa/b53/b53_mdio.c +@@ -286,6 +286,7 @@ static const struct b53_io_ops b53_mdio_ + #define B53_BRCM_OUI_2 0x03625c00 + #define B53_BRCM_OUI_3 0x00406000 + #define B53_BRCM_OUI_4 0x01410c00 ++#define B53_BRCM_OUI_5 0xae025000 + + static int b53_mdio_probe(struct mdio_device *mdiodev) + { +@@ -313,7 +314,8 @@ static int b53_mdio_probe(struct mdio_de + if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 && +- (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) { ++ (phy_id & 0xfffffc00) != B53_BRCM_OUI_4 && ++ (phy_id & 0xfffffc00) != B53_BRCM_OUI_5) { + dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); + return -ENODEV; + } +@@ -377,6 +379,7 @@ static const struct of_device_id b53_of_ + { .compatible = "brcm,bcm53115" }, + { .compatible = "brcm,bcm53125" }, + { .compatible = "brcm,bcm53128" }, ++ { .compatible = "brcm,bcm53134" }, + { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5389" }, + { .compatible = "brcm,bcm5395" }, +--- a/drivers/net/dsa/b53/b53_priv.h ++++ b/drivers/net/dsa/b53/b53_priv.h +@@ -85,6 +85,7 @@ enum { + BCM583XX_DEVICE_ID = 0x58300, + BCM7445_DEVICE_ID = 0x7445, + BCM7278_DEVICE_ID = 0x7278, ++ BCM53134_DEVICE_ID = 0x5075, + }; + + #define B53_N_PORTS 9 +@@ -182,7 +183,8 @@ static inline int is531x5(struct b53_dev + { + return dev->chip_id == BCM53115_DEVICE_ID || + dev->chip_id == BCM53125_DEVICE_ID || +- dev->chip_id == BCM53128_DEVICE_ID; ++ dev->chip_id == BCM53128_DEVICE_ID || ++ dev->chip_id == BCM53134_DEVICE_ID; + } + + static inline int is63xx(struct b53_device *dev) +@@ -210,7 +212,8 @@ static inline int is58xx(struct b53_devi + return dev->chip_id == BCM58XX_DEVICE_ID || + dev->chip_id == BCM583XX_DEVICE_ID || + dev->chip_id == BCM7445_DEVICE_ID || +- dev->chip_id == BCM7278_DEVICE_ID; ++ dev->chip_id == BCM7278_DEVICE_ID || ++ dev->chip_id == BCM53134_DEVICE_ID; + } + + #define B53_63XX_RGMII0 4 diff --git a/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch b/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch new file mode 100644 index 00000000000..fcf7892c04e --- /dev/null +++ b/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch @@ -0,0 +1,61 @@ +From patchwork Thu Aug 5 22:23:30 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Daniel Golle +X-Patchwork-Id: 12422209 +Date: Thu, 5 Aug 2021 23:23:30 +0100 +From: Daniel Golle +To: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org, + linux-kernel@vger.kernel.org +Cc: "David S. Miller" , Andrew Lunn , + Michael Walle +Subject: [PATCH] ARM: kirkwood: add missing for ETH_ALEN +Message-ID: +MIME-Version: 1.0 +Content-Disposition: inline +X-BeenThere: linux-arm-kernel@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +List-Archive: +Sender: "linux-arm-kernel" + +After commit 83216e3988cd1 ("of: net: pass the dst buffer to +of_get_mac_address()") build fails for kirkwood as ETH_ALEN is not +defined. + +arch/arm/mach-mvebu/kirkwood.c: In function 'kirkwood_dt_eth_fixup': +arch/arm/mach-mvebu/kirkwood.c:87:13: error: 'ETH_ALEN' undeclared (first use in this function); did you mean 'ESTALE'? + u8 tmpmac[ETH_ALEN]; + ^~~~~~~~ + ESTALE +arch/arm/mach-mvebu/kirkwood.c:87:13: note: each undeclared identifier is reported only once for each function it appears in +arch/arm/mach-mvebu/kirkwood.c:87:6: warning: unused variable 'tmpmac' [-Wunused-variable] + u8 tmpmac[ETH_ALEN]; + ^~~~~~ +make[5]: *** [scripts/Makefile.build:262: arch/arm/mach-mvebu/kirkwood.o] Error 1 +make[5]: *** Waiting for unfinished jobs.... + +Add missing #include to fix this. + +Cc: David S. Miller +Cc: Andrew Lunn +Cc: Michael Walle +Reported-by: https://buildbot.openwrt.org/master/images/#/builders/56/builds/220/steps/44/logs/stdio +Fixes: 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()") +Signed-off-by: Daniel Golle +--- + arch/arm/mach-mvebu/kirkwood.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/arm/mach-mvebu/kirkwood.c ++++ b/arch/arm/mach-mvebu/kirkwood.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch b/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch new file mode 100644 index 00000000000..2f728fefd73 --- /dev/null +++ b/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch @@ -0,0 +1,48 @@ +From 5f7c5e1c0d7a79be144e5efc1f24728ddd7fc25c Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sat, 5 Nov 2022 20:02:56 +0100 +Subject: [PATCH 1/2] bus: mhi: core: add SBL state callback + +Add support for SBL state callback in MHI core. + +It is required for ath11k MHI devices in order to be able to set QRTR +instance ID in the SBL state so that QRTR instance ID-s dont conflict in +case of multiple PCI/MHI cards or AHB + PCI/MHI card. +Setting QRTR instance ID is only possible in SBL state and there is +currently no way to ensure that we are in that state, so provide a +callback that the controller can trigger off. + +Signed-off-by: Robert Marko +--- + drivers/bus/mhi/host/main.c | 1 + + include/linux/mhi.h | 2 ++ + 2 files changed, 3 insertions(+) + +--- a/drivers/bus/mhi/host/main.c ++++ b/drivers/bus/mhi/host/main.c +@@ -891,6 +891,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ + switch (event) { + case MHI_EE_SBL: + st = DEV_ST_TRANSITION_SBL; ++ mhi_cntrl->status_cb(mhi_cntrl, MHI_CB_EE_SBL_MODE); + break; + case MHI_EE_WFW: + case MHI_EE_AMSS: +--- a/include/linux/mhi.h ++++ b/include/linux/mhi.h +@@ -34,6 +34,7 @@ struct mhi_buf_info; + * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover) + * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state + * @MHI_CB_BW_REQ: Received a bandwidth switch request from device ++ * @MHI_CB_EE_SBL_MODE: MHI device entered SBL mode + */ + enum mhi_callback { + MHI_CB_IDLE, +@@ -45,6 +46,7 @@ enum mhi_callback { + MHI_CB_SYS_ERROR, + MHI_CB_FATAL_ERROR, + MHI_CB_BW_REQ, ++ MHI_CB_EE_SBL_MODE, + }; + + /** diff --git a/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch b/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch new file mode 100644 index 00000000000..f9b88db9955 --- /dev/null +++ b/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch @@ -0,0 +1,43 @@ +From 1d81e51d6d79d9098013b2e8cdd677bae998c5d8 Mon Sep 17 00:00:00 2001 +From: David Bauer +Date: Fri, 28 Apr 2023 02:22:59 +0200 +Subject: [PATCH 1/2] mt7530: register OF node for internal MDIO bus + +The MT753x switches provide a switch-internal MDIO bus for the embedded +PHYs. + +Register a OF sub-node on the switch OF-node for this internal MDIO bus. +This allows to configure the embedded PHYs using device-tree. + +Signed-off-by: David Bauer +--- + drivers/net/dsa/mt7530.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2081,10 +2081,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr + { + struct dsa_switch *ds = priv->ds; + struct device *dev = priv->dev; ++ struct device_node *np, *mnp; + struct mii_bus *bus; + static int idx; + int ret; + ++ np = priv->dev->of_node; ++ + bus = devm_mdiobus_alloc(dev); + if (!bus) + return -ENOMEM; +@@ -2101,7 +2104,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr + if (priv->irq) + mt7530_setup_mdio_irq(priv); + +- ret = devm_mdiobus_register(dev, bus); ++ mnp = of_get_child_by_name(np, "mdio"); ++ ret = devm_of_mdiobus_register(dev, bus, mnp); ++ of_node_put(mnp); + if (ret) { + dev_err(dev, "failed to register MDIO bus: %d\n", ret); + if (priv->irq) diff --git a/target/linux/generic/pending-6.1/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch b/target/linux/generic/pending-6.1/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch new file mode 100644 index 00000000000..478a2cb27d8 --- /dev/null +++ b/target/linux/generic/pending-6.1/800-bcma-get-SoC-device-struct-copy-its-DMA-params-to-th.patch @@ -0,0 +1,73 @@ +From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= +Subject: [PATCH] bcma: get SoC device struct & copy its DMA params to the + subdevices +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For bus devices to be fully usable it's required to set their DMA +parameters. + +For years it has been missing and remained unnoticed because of +mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask. +Kernel 4.19 came with a lot of DMA changes and caused a regression on +the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic +dma noncoherent ops for simple noncoherent platforms") DMA coherent +allocations just fail. Example: +[ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed +[ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA +[ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12 +[ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded + +This change fixes above regression in addition to the MIPS bcm47xx +commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC"). + +It also fixes another *old* GPIO regression caused by a parent pointing +to the NULL: +[ 0.157054] missing gpiochip .dev parent pointer +[ 0.157287] bcma: bus0: Error registering GPIO driver: -22 +introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to +use GPIOLIB_IRQCHIP"). + +Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms") +Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP") +Cc: linux-mips@linux-mips.org +Cc: Christoph Hellwig +Cc: Linus Walleij +Signed-off-by: Rafał Miłecki +--- + +--- a/drivers/bcma/host_soc.c ++++ b/drivers/bcma/host_soc.c +@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcm + struct bcma_bus *bus = &soc->bus; + int err; + ++ bus->dev = soc->dev; ++ + /* Scan bus and initialize it */ + err = bcma_bus_early_register(bus); + if (err) +--- a/drivers/bcma/main.c ++++ b/drivers/bcma/main.c +@@ -236,13 +236,17 @@ EXPORT_SYMBOL(bcma_core_irq); + + void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core) + { +- device_initialize(&core->dev); ++ struct device *dev = &core->dev; ++ ++ device_initialize(dev); + core->dev.release = bcma_release_core_dev; + core->dev.bus = &bcma_bus_type; +- dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index); ++ dev_set_name(dev, "bcma%d:%d", bus->num, core->core_index); + core->dev.parent = bus->dev; +- if (bus->dev) ++ if (bus->dev) { + bcma_of_fill_device(bus->dev, core); ++ dma_coerce_mask_and_coherent(dev, bus->dev->coherent_dma_mask); ++ } + + switch (bus->hosttype) { + case BCMA_HOSTTYPE_PCI: diff --git a/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch b/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch new file mode 100644 index 00000000000..c1e14b92714 --- /dev/null +++ b/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch @@ -0,0 +1,222 @@ +From fc23ea48ba52c24f201fe5ca0132ee1a3de5a70a Mon Sep 17 00:00:00 2001 +From: Mauri Sandberg +Date: Thu, 25 Mar 2021 11:48:05 +0200 +Subject: [PATCH 2/2] gpio: gpio-cascade: add generic GPIO cascade + +Adds support for building cascades of GPIO lines. That is, it allows +setups when there is one upstream line and multiple cascaded lines, out +of which one can be chosen at a time. The status of the upstream line +can be conveyed to the selected cascaded line or, vice versa, the status +of the cascaded line can be conveyed to the upstream line. + +A multiplexer is being used to select, which cascaded GPIO line is being +used at any given time. + +At the moment only input direction is supported. In future it should be +possible to add support for output direction, too. + +Signed-off-by: Mauri Sandberg +Reviewed-by: Linus Walleij +Reviewed-by: Andy Shevchenko +--- +v7 -> v8: + - rearrange members in struct gpio_cascade + - cosmetic changes in file header and in one function declaration + - added Reviewed-by tags by Linus and Andy +v6 -> v7: + - In Kconfig add info about module name + - adhere to new convention that allows lines longer than 80 chars + - use dev_probe_err with upstream gpio line too + - refactor for cleaner exit of probe function. +v5 -> v6: + - In Kconfig, remove dependency to OF_GPIO and select only MULTIPLEXER + - refactor code preferring one-liners + - clean up prints, removing them from success-path. + - don't explicitly set gpio_chip.of_node as it's done in the GPIO library + - use devm_gpiochip_add_data instead of gpiochip_add +v4 -> v5: + - renamed gpio-mux-input -> gpio-cascade. refactored code accordingly + here and there and changed to use new bindings and compatible string + - ambigious and vague 'pin' was rename to 'upstream_line' + - dropped Tested-by and Reviewed-by due to changes in bindings + - dropped Reported-by suggested by an automatic bot as it was not really + appropriate to begin with + - functionally it's the same as v4 +v3 -> v4: + - Changed author email + - Included Tested-by and Reviewed-by from Drew +v2 -> v3: + - use managed device resources + - update Kconfig description +v1 -> v2: + - removed .owner from platform_driver as per test bot's instruction + - added MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE + - added gpio_mux_input_get_direction as it's recommended for all chips + - removed because this is input only chip: gpio_mux_input_set_value + - removed because they are not needed for input/output only chips: + gpio_mux_input_direction_input + gpio_mux_input_direction_output + - fixed typo in an error message + - added info message about successful registration + - removed can_sleep flag as this does not sleep while getting GPIO value + like I2C or SPI do + - Updated description in Kconfig +--- + drivers/gpio/Kconfig | 15 +++++ + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-cascade.c | 117 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 133 insertions(+) + create mode 100644 drivers/gpio/gpio-cascade.c + +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -1683,4 +1683,19 @@ config GPIO_VIRTIO + + endmenu + ++comment "Other GPIO expanders" ++ ++config GPIO_CASCADE ++ tristate "General GPIO cascade" ++ select MULTIPLEXER ++ help ++ Say yes here to enable support for generic GPIO cascade. ++ ++ This allows building one-to-many cascades of GPIO lines using ++ different types of multiplexers readily available. At the ++ moment only input lines are supported. ++ ++ To build the driver as a module choose 'm' and the resulting module ++ will be called 'gpio-cascade'. ++ + endif +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd + obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o + obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o + obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o ++obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o + obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o + obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o + obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o +--- /dev/null ++++ b/drivers/gpio/gpio-cascade.c +@@ -0,0 +1,117 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * A generic GPIO cascade driver ++ * ++ * Copyright (C) 2021 Mauri Sandberg ++ * ++ * This allows building cascades of GPIO lines in a manner illustrated ++ * below: ++ * ++ * /|---- Cascaded GPIO line 0 ++ * Upstream | |---- Cascaded GPIO line 1 ++ * GPIO line ----+ | . ++ * | | . ++ * \|---- Cascaded GPIO line n ++ * ++ * A multiplexer is being used to select, which cascaded line is being ++ * addressed at any given time. ++ * ++ * At the moment only input mode is supported due to lack of means for ++ * testing output functionality. At least theoretically output should be ++ * possible with open drain constructions. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++struct gpio_cascade { ++ struct gpio_chip gpio_chip; ++ struct device *parent; ++ struct mux_control *mux_control; ++ struct gpio_desc *upstream_line; ++}; ++ ++static struct gpio_cascade *chip_to_cascade(struct gpio_chip *gc) ++{ ++ return container_of(gc, struct gpio_cascade, gpio_chip); ++} ++ ++static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset) ++{ ++ return GPIO_LINE_DIRECTION_IN; ++} ++ ++static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset) ++{ ++ struct gpio_cascade *cas = chip_to_cascade(gc); ++ int ret; ++ ++ ret = mux_control_select(cas->mux_control, offset); ++ if (ret) ++ return ret; ++ ++ ret = gpiod_get_value(cas->upstream_line); ++ mux_control_deselect(cas->mux_control); ++ return ret; ++} ++ ++static int gpio_cascade_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct gpio_cascade *cas; ++ struct mux_control *mc; ++ struct gpio_desc *upstream; ++ struct gpio_chip *gc; ++ ++ cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL); ++ if (!cas) ++ return -ENOMEM; ++ ++ mc = devm_mux_control_get(dev, NULL); ++ if (IS_ERR(mc)) ++ return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n"); ++ ++ cas->mux_control = mc; ++ upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN); ++ if (IS_ERR(upstream)) ++ return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n"); ++ ++ cas->upstream_line = upstream; ++ cas->parent = dev; ++ ++ gc = &cas->gpio_chip; ++ gc->get = gpio_cascade_get_value; ++ gc->get_direction = gpio_cascade_get_direction; ++ gc->base = -1; ++ gc->ngpio = mux_control_states(mc); ++ gc->label = dev_name(cas->parent); ++ gc->parent = cas->parent; ++ gc->owner = THIS_MODULE; ++ ++ platform_set_drvdata(pdev, cas); ++ return devm_gpiochip_add_data(dev, &cas->gpio_chip, NULL); ++} ++ ++static const struct of_device_id gpio_cascade_id[] = { ++ { .compatible = "gpio-cascade" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, gpio_cascade_id); ++ ++static struct platform_driver gpio_cascade_driver = { ++ .driver = { ++ .name = "gpio-cascade", ++ .of_match_table = gpio_cascade_id, ++ }, ++ .probe = gpio_cascade_probe, ++}; ++module_platform_driver(gpio_cascade_driver); ++ ++MODULE_AUTHOR("Mauri Sandberg "); ++MODULE_DESCRIPTION("Generic GPIO cascade"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/pending-6.1/802-nvmem-u-boot-env-align-endianness-of-crc32-values.patch b/target/linux/generic/pending-6.1/802-nvmem-u-boot-env-align-endianness-of-crc32-values.patch new file mode 100644 index 00000000000..9b111050eef --- /dev/null +++ b/target/linux/generic/pending-6.1/802-nvmem-u-boot-env-align-endianness-of-crc32-values.patch @@ -0,0 +1,47 @@ +From 0e71cac033bb7689c4dfa2e6814191337ef770f5 Mon Sep 17 00:00:00 2001 +From: INAGAKI Hiroshi +Date: Thu, 13 Oct 2022 00:51:33 +0900 +Subject: [PATCH] nvmem: u-boot-env: align endianness of crc32 values +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch fixes crc32 error on Big-Endianness system by conversion of +calculated crc32 value. + +Little-Endianness system: + + obtained crc32: Little +calculated crc32: Little + +Big-Endianness system: + + obtained crc32: Little +calculated crc32: Big + +log (APRESIA ApresiaLightGS120GT-SS, RTL8382M, Big-Endianness): + +[ 8.570000] u_boot_env 18001200.spi:flash@0:partitions:partition@c0000: Invalid calculated CRC32: 0x88cd6f09 (expected: 0x096fcd88) +[ 8.580000] u_boot_env: probe of 18001200.spi:flash@0:partitions:partition@c0000 failed with error -22 + +Fixes: f955dc1445069 ("nvmem: add driver handling U-Boot environment variables") + +Signed-off-by: INAGAKI Hiroshi +Acked-by: Rafał Miłecki +Tested-by: Christian Lamparter +Signed-off-by: Srinivas Kandagatla +--- + drivers/nvmem/u-boot-env.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/nvmem/u-boot-env.c ++++ b/drivers/nvmem/u-boot-env.c +@@ -182,7 +182,7 @@ static int u_boot_env_parse(struct u_boo + crc32_data_len = priv->mtd->size - crc32_data_offset; + data_len = priv->mtd->size - data_offset; + +- calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L; ++ calc = le32_to_cpu((__le32)crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L); + if (calc != crc32) { + dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32); + err = -EINVAL; diff --git a/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch b/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch new file mode 100644 index 00000000000..7edbd94f762 --- /dev/null +++ b/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch @@ -0,0 +1,62 @@ +From: Gabor Juhos +Subject: debloat: add kernel config option to disabling common PCI quirks + +Signed-off-by: Gabor Juhos +--- + drivers/pci/Kconfig | 6 ++++++ + drivers/pci/quirks.c | 6 ++++++ + 2 files changed, 12 insertions(+) + +--- a/drivers/pci/Kconfig ++++ b/drivers/pci/Kconfig +@@ -118,6 +118,13 @@ config XEN_PCIDEV_FRONTEND + The PCI device frontend driver allows the kernel to import arbitrary + PCI devices from a PCI backend to support PCI driver domains. + ++config PCI_DISABLE_COMMON_QUIRKS ++ bool "PCI disable common quirks" ++ depends on PCI ++ help ++ If you don't know what to do here, say N. ++ ++ + config PCI_ATS + bool + +--- a/drivers/pci/quirks.c ++++ b/drivers/pci/quirks.c +@@ -206,6 +206,7 @@ static void quirk_mmio_always_on(struct + DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + /* + * The Mellanox Tavor device gives false positive parity errors. Disable + * parity error reporting. +@@ -3363,6 +3364,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. + * To work around this, query the size it should be configured to by the +@@ -3388,6 +3391,8 @@ static void quirk_intel_ntb(struct pci_d + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); + DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + /* + * Some BIOS implementations leave the Intel GPU interrupts enabled, even + * though no one is handling them (e.g., if the i915 driver is never +@@ -3426,6 +3431,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); + ++#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ + /* + * PCI devices which are on Intel chips can skip the 10ms delay + * before entering D3 mode. diff --git a/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch new file mode 100644 index 00000000000..b498d9f700a --- /dev/null +++ b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch @@ -0,0 +1,115 @@ +From: Felix Fietkau +Subject: debloat: disable common USB quirks + +Signed-off-by: Felix Fietkau +--- + drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++ + drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++- + include/linux/usb/hcd.h | 7 +++++++ + 3 files changed, 40 insertions(+), 1 deletion(-) + +--- a/drivers/usb/host/pci-quirks.c ++++ b/drivers/usb/host/pci-quirks.c +@@ -128,6 +128,8 @@ struct amd_chipset_type { + u8 rev; + }; + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static struct amd_chipset_info { + struct pci_dev *nb_dev; + struct pci_dev *smbus_dev; +@@ -633,6 +635,10 @@ bool usb_amd_pt_check_port(struct device + } + EXPORT_SYMBOL_GPL(usb_amd_pt_check_port); + ++#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */ ++ ++#if IS_ENABLED(CONFIG_USB_UHCI_HCD) ++ + /* + * Make sure the controller is completely inactive, unable to + * generate interrupts or do DMA. +@@ -712,8 +718,17 @@ reset_needed: + uhci_reset_hc(pdev, base); + return 1; + } ++#else ++int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base) ++{ ++ return 0; ++} ++ ++#endif + EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS ++ + static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) + { + u16 cmd; +@@ -1285,3 +1300,4 @@ static void quirk_usb_early_handoff(stru + } + DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); ++#endif +--- a/drivers/usb/host/pci-quirks.h ++++ b/drivers/usb/host/pci-quirks.h +@@ -5,6 +5,9 @@ + #ifdef CONFIG_USB_PCI + void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); + int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); ++#endif /* CONFIG_USB_PCI */ ++ ++#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS) + int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); + bool usb_amd_hang_symptom_quirk(void); + bool usb_amd_prefetch_quirk(void); +@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev, + bool usb_amd_pt_check_port(struct device *device, int port); + #else + struct pci_dev; ++static inline int usb_amd_quirk_pll_check(void) ++{ ++ return 0; ++} ++static inline bool usb_amd_hang_symptom_quirk(void) ++{ ++ return false; ++} ++static inline bool usb_amd_prefetch_quirk(void) ++{ ++ return false; ++} + static inline void usb_amd_quirk_pll_disable(void) {} + static inline void usb_amd_quirk_pll_enable(void) {} + static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {} +@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port + { + return false; + } ++static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {} ++static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev) ++{ ++ return false; ++} + #endif /* CONFIG_USB_PCI */ + + #endif /* __LINUX_USB_PCI_QUIRKS_H */ +--- a/include/linux/usb/hcd.h ++++ b/include/linux/usb/hcd.h +@@ -498,7 +498,14 @@ extern int usb_hcd_pci_probe(struct pci_ + extern void usb_hcd_pci_remove(struct pci_dev *dev); + extern void usb_hcd_pci_shutdown(struct pci_dev *dev); + ++#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS + extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev); ++#else ++static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev) ++{ ++ return 0; ++} ++#endif + + #ifdef CONFIG_PM + extern const struct dev_pm_ops usb_hcd_pci_pm_ops; diff --git a/target/linux/generic/pending-6.1/820-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch b/target/linux/generic/pending-6.1/820-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch new file mode 100644 index 00000000000..33eb34c913e --- /dev/null +++ b/target/linux/generic/pending-6.1/820-w1-gpio-fix-problem-with-platfom-data-in-w1-gpio.patch @@ -0,0 +1,26 @@ +From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001 +From: Pawel Dembicki +Date: Sun, 18 Feb 2018 17:08:04 +0100 +Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio + +In devices, where fdt is used, is impossible to apply platform data +without proper fdt node. + +This patch allow to use platform data in devices with fdt. + +Signed-off-by: Pawel Dembicki +--- + drivers/w1/masters/w1-gpio.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform + enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN; + int err; + +- if (of_have_populated_dt()) { ++ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; diff --git a/target/linux/generic/pending-6.1/834-ledtrig-libata.patch b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch new file mode 100644 index 00000000000..9c85862a4bd --- /dev/null +++ b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch @@ -0,0 +1,149 @@ +From: Daniel Golle +Subject: libata: add ledtrig support + +This adds a LED trigger for each ATA port indicating disk activity. + +As this is needed only on specific platforms (NAS SoCs and such), +these platforms should define ARCH_WANTS_LIBATA_LEDS if there +are boards with LED(s) intended to indicate ATA disk activity and +need the OS to take care of that. +In that way, if not selected, LED trigger support not will be +included in libata-core and both, codepaths and structures remain +untouched. + +Signed-off-by: Daniel Golle +--- + drivers/ata/Kconfig | 16 ++++++++++++++++ + drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++ + include/linux/libata.h | 9 +++++++++ + 3 files changed, 66 insertions(+) + +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -67,6 +67,22 @@ config ATA_FORCE + + If unsure, say Y. + ++config ARCH_WANT_LIBATA_LEDS ++ bool ++ ++config ATA_LEDS ++ bool "support ATA port LED triggers" ++ depends on ARCH_WANT_LIBATA_LEDS ++ select NEW_LEDS ++ select LEDS_CLASS ++ select LEDS_TRIGGERS ++ default y ++ help ++ This option adds a LED trigger for each registered ATA port. ++ It is used to drive disk activity leds connected via GPIO. ++ ++ If unsure, say N. ++ + config ATA_ACPI + bool "ATA ACPI Support" + depends on ACPI +--- a/drivers/ata/libata-core.c ++++ b/drivers/ata/libata-core.c +@@ -656,6 +656,19 @@ u64 ata_tf_read_block(const struct ata_t + return block; + } + ++#ifdef CONFIG_ATA_LEDS ++#define LIBATA_BLINK_DELAY 20 /* ms */ ++static inline void ata_led_act(struct ata_port *ap) ++{ ++ unsigned long led_delay = LIBATA_BLINK_DELAY; ++ ++ if (unlikely(!ap->ledtrig)) ++ return; ++ ++ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0); ++} ++#endif ++ + /** + * ata_build_rw_tf - Build ATA taskfile for given read/write request + * @tf: Target ATA taskfile +@@ -4580,6 +4593,9 @@ struct ata_queued_cmd *ata_qc_new_init(s + if (tag < 0) + return NULL; + } ++#ifdef CONFIG_ATA_LEDS ++ ata_led_act(ap); ++#endif + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = qc->hw_tag = tag; +@@ -5358,6 +5374,9 @@ struct ata_port *ata_port_alloc(struct a + ap->stats.unhandled_irq = 1; + ap->stats.idle_irq = 1; + #endif ++#ifdef CONFIG_ATA_LEDS ++ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); ++#endif + ata_sff_port_init(ap); + + return ap; +@@ -5393,6 +5412,12 @@ static void ata_host_release(struct kref + + kfree(ap->pmp_link); + kfree(ap->slave_link); ++#ifdef CONFIG_ATA_LEDS ++ if (ap->ledtrig) { ++ led_trigger_unregister(ap->ledtrig); ++ kfree(ap->ledtrig); ++ }; ++#endif + kfree(ap); + host->ports[i] = NULL; + } +@@ -5799,7 +5824,23 @@ int ata_host_register(struct ata_host *h + host->ports[i]->print_id = atomic_inc_return(&ata_print_id); + host->ports[i]->local_port_no = i + 1; + } ++#ifdef CONFIG_ATA_LEDS ++ for (i = 0; i < host->n_ports; i++) { ++ if (unlikely(!host->ports[i]->ledtrig)) ++ continue; + ++ snprintf(host->ports[i]->ledtrig_name, ++ sizeof(host->ports[i]->ledtrig_name), "ata%u", ++ host->ports[i]->print_id); ++ ++ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name; ++ ++ if (led_trigger_register(host->ports[i]->ledtrig)) { ++ kfree(host->ports[i]->ledtrig); ++ host->ports[i]->ledtrig = NULL; ++ } ++ } ++#endif + /* Create associated sysfs transport objects */ + for (i = 0; i < host->n_ports; i++) { + rc = ata_tport_add(host->dev,host->ports[i]); +--- a/include/linux/libata.h ++++ b/include/linux/libata.h +@@ -23,6 +23,9 @@ + #include + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#endif + + /* + * Define if arch has non-standard setup. This is a _PCI_ standard +@@ -894,6 +897,12 @@ struct ata_port { + #ifdef CONFIG_ATA_ACPI + struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ + #endif ++ ++#ifdef CONFIG_ATA_LEDS ++ struct led_trigger *ledtrig; ++ char ledtrig_name[8]; ++#endif ++ + /* owned by EH */ + u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned; + }; diff --git a/target/linux/generic/pending-6.1/840-hwrng-bcm2835-set-quality-to-1000.patch b/target/linux/generic/pending-6.1/840-hwrng-bcm2835-set-quality-to-1000.patch new file mode 100644 index 00000000000..5ca8933d6fe --- /dev/null +++ b/target/linux/generic/pending-6.1/840-hwrng-bcm2835-set-quality-to-1000.patch @@ -0,0 +1,26 @@ +From d6988cf1d16faac56899918bb2b1be8d85155e3f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= +Date: Sat, 20 Feb 2021 18:36:38 +0100 +Subject: [PATCH] hwrng: bcm2835: set quality to 1000 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows devices without a high precission timer to reduce boot from >100s +to <30s. + +Signed-off-by: Álvaro Fernández Rojas +--- + drivers/char/hw_random/bcm2835-rng.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/char/hw_random/bcm2835-rng.c ++++ b/drivers/char/hw_random/bcm2835-rng.c +@@ -170,6 +170,7 @@ static int bcm2835_rng_probe(struct plat + priv->rng.init = bcm2835_rng_init; + priv->rng.read = bcm2835_rng_read; + priv->rng.cleanup = bcm2835_rng_cleanup; ++ priv->rng.quality = 1000; + + if (dev_of_node(dev)) { + rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node); diff --git a/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch new file mode 100644 index 00000000000..e180a385e11 --- /dev/null +++ b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch @@ -0,0 +1,102 @@ +From 663b9f99bb35dbc0c7b685f71ee3668a60d31320 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marek=20Beh=C3=BAn?= +Date: Mon, 10 Jan 2022 02:02:00 +0100 +Subject: [PATCH] PCI: aardvark: Make main irq_chip structure a static driver + structure +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Marc Zyngier says [1] that we should use struct irq_chip as a global +static struct in the driver. Even though the structure currently +contains a dynamic member (parent_device), Marc says [2] that he plans +to kill it and make the structure completely static. + +We have already converted others irq_chip structures in this driver in +this way, but we omitted this one because the .name member is +dynamically created from device's name, and the name is displayed in +sysfs, so changing it would break sysfs ABI. + +The rationale for changing the name (to "advk-INT") in spite of sysfs +ABI, and thus allowing to convert to a static structure, is that after +the other changes we made in this series, the IRQ chip is basically +something different: it no logner generates ERR and PME interrupts (they +are generated by emulated bridge's rp_irq_chip). + +[1] https://lore.kernel.org/linux-pci/877dbcvngf.wl-maz@kernel.org/ +[2] https://lore.kernel.org/linux-pci/874k6gvkhz.wl-maz@kernel.org/ + +Signed-off-by: Marek Behún +--- + drivers/pci/controller/pci-aardvark.c | 25 +++++++------------------ + 1 file changed, 7 insertions(+), 18 deletions(-) + +--- a/drivers/pci/controller/pci-aardvark.c ++++ b/drivers/pci/controller/pci-aardvark.c +@@ -275,7 +275,6 @@ struct advk_pcie { + u8 wins_count; + struct irq_domain *rp_irq_domain; + struct irq_domain *irq_domain; +- struct irq_chip irq_chip; + raw_spinlock_t irq_lock; + struct irq_domain *msi_domain; + struct irq_domain *msi_inner_domain; +@@ -1345,14 +1344,19 @@ static void advk_pcie_irq_unmask(struct + raw_spin_unlock_irqrestore(&pcie->irq_lock, flags); + } + ++static struct irq_chip advk_irq_chip = { ++ .name = "advk-INT", ++ .irq_mask = advk_pcie_irq_mask, ++ .irq_unmask = advk_pcie_irq_unmask, ++}; ++ + static int advk_pcie_irq_map(struct irq_domain *h, + unsigned int virq, irq_hw_number_t hwirq) + { + struct advk_pcie *pcie = h->host_data; + + irq_set_status_flags(virq, IRQ_LEVEL); +- irq_set_chip_and_handler(virq, &pcie->irq_chip, +- handle_level_irq); ++ irq_set_chip_and_handler(virq, &advk_irq_chip, handle_level_irq); + irq_set_chip_data(virq, pcie); + + return 0; +@@ -1411,7 +1415,6 @@ static int advk_pcie_init_irq_domain(str + struct device *dev = &pcie->pdev->dev; + struct device_node *node = dev->of_node; + struct device_node *pcie_intc_node; +- struct irq_chip *irq_chip; + int ret = 0; + + raw_spin_lock_init(&pcie->irq_lock); +@@ -1422,28 +1425,14 @@ static int advk_pcie_init_irq_domain(str + return -ENODEV; + } + +- irq_chip = &pcie->irq_chip; +- +- irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq", +- dev_name(dev)); +- if (!irq_chip->name) { +- ret = -ENOMEM; +- goto out_put_node; +- } +- +- irq_chip->irq_mask = advk_pcie_irq_mask; +- irq_chip->irq_unmask = advk_pcie_irq_unmask; +- + pcie->irq_domain = + irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX, + &advk_pcie_irq_domain_ops, pcie); + if (!pcie->irq_domain) { + dev_err(dev, "Failed to get a INTx IRQ domain\n"); + ret = -ENOMEM; +- goto out_put_node; + } + +-out_put_node: + of_node_put(pcie_intc_node); + return ret; + } diff --git a/target/linux/generic/pending-6.1/850-dt-bindings-clk-add-BCM63268-timer-clock-definitions.patch b/target/linux/generic/pending-6.1/850-dt-bindings-clk-add-BCM63268-timer-clock-definitions.patch new file mode 100644 index 00000000000..cc6f1e0d9db --- /dev/null +++ b/target/linux/generic/pending-6.1/850-dt-bindings-clk-add-BCM63268-timer-clock-definitions.patch @@ -0,0 +1,114 @@ +From patchwork Wed Mar 22 17:15:12 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13184389 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 73F2DC6FD1C + for ; Wed, 22 Mar 2023 17:15:59 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S231363AbjCVRP5 (ORCPT ); + Wed, 22 Mar 2023 13:15:57 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58824 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S231408AbjCVRPy (ORCPT + ); Wed, 22 Mar 2023 13:15:54 -0400 +Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com + [IPv6:2a00:1450:4864:20::32d]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 70E4C64B28; + Wed, 22 Mar 2023 10:15:24 -0700 (PDT) +Received: by mail-wm1-x32d.google.com with SMTP id n19so1740892wms.0; + Wed, 22 Mar 2023 10:15:24 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679505322; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=dEknM98Izmc8d/crPsoJ+ejZxfl78958Ei6SPYhYDHs=; + b=LTOQ75W3s5nYo+nEfiJAKqytSopONB4jCtU3zRygzPMasugVOrYFMsUR+WrpsAjuRT + v4HgWpJxEsIWeRXrUN9W21mFXhGgJLJXSxRnrio0CsZZBNMdkebbNOphgKXIWAdm+2iM + PzqAdGm5t38wT2mmm6V/9hCy90+12raHM82tNFdhhiezfg2cukVOKP3j/TeOVCwas0gQ + iFc+CuZB6y73zYXvMUMUpTsqI5vev4xJsSMHIQJVmUxJAwqhOBhN9JCRo7Ao+wayjn2d + Fxo6AV3A8v68nVfoQ0K0I+eWXG48nMCX45iWh/lVvVTOFcR99kn4va7NY1oVnPsh+WQz + WcLA== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679505322; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=dEknM98Izmc8d/crPsoJ+ejZxfl78958Ei6SPYhYDHs=; + b=wv2NSR1B5RnsdoEE7mgJSHAfSs1JHZbQ1HPMldyaGWAk1dcucqh/uDzM3Flz+ADRi1 + 19NoaB2Ur7QaWZejbuplnIOK/nte3PnmqJ9ZNw8HejmuS4eU8mB1V1aJUSKSPGsfUi4a + LYe3HSw87l0jrAC7ptdKvdUtzBoIkX0CeFvfguTQQkDhUTyAFIG144hY6uPXY9Mga96b + gnNe2dLCzHQLbEJpaDaavT7FEEcLDxaq7jNcR2xqEEZaIwfcew+Q05t4xL/3i8GAj9Ru + 6ivQjIbBKfYQF88o7KnOW9o1wjrGsk+Nd4Iy0OLZix3JQasCJGrKV7ib5awI9J39upYV + fa4A== +X-Gm-Message-State: AO0yUKWw75I1M5Vjrd4vXq4GTruQu0H84pycgyi2CT3bczTYRJpWmEWg + +bHDhvp1n5IWW85GI9vKWpbclB13a/S0RQ== +X-Google-Smtp-Source: + AK7set9T/2oJsVetUb2L4mPEWu8YqDrnK8EzHK5bJf1ABIa1Et8f7BFJ7AA3j14ITZuf8cH0HqlRtg== +X-Received: by 2002:a05:600c:2304:b0:3ed:2949:985b with SMTP id + 4-20020a05600c230400b003ed2949985bmr206833wmo.23.1679505322457; + Wed, 22 Mar 2023 10:15:22 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + v10-20020a05600c470a00b003ee11ac2288sm8414333wmo.21.2023.03.22.10.15.21 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Wed, 22 Mar 2023 10:15:22 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: mturquette@baylibre.com, sboyd@kernel.org, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, p.zabel@pengutronix.de, + f.fainelli@gmail.com, jonas.gorski@gmail.com, + william.zhang@broadcom.com, linux-clk@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= , + Rob Herring +Subject: [PATCH v4 1/4] dt-bindings: clk: add BCM63268 timer clock definitions +Date: Wed, 22 Mar 2023 18:15:12 +0100 +Message-Id: <20230322171515.120353-2-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230322171515.120353-1-noltari@gmail.com> +References: <20230322171515.120353-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: linux-clk@vger.kernel.org + +Add missing timer clock definitions for BCM63268. + +Signed-off-by: Álvaro Fernández Rojas +Acked-by: Rob Herring +--- + v4: no changes + v3: no changes + v2: change commit title, as suggested by Stephen Boyd + + include/dt-bindings/clock/bcm63268-clock.h | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- a/include/dt-bindings/clock/bcm63268-clock.h ++++ b/include/dt-bindings/clock/bcm63268-clock.h +@@ -27,4 +27,17 @@ + #define BCM63268_CLK_TBUS 27 + #define BCM63268_CLK_ROBOSW250 31 + ++#define BCM63268_TCLK_EPHY1 0 ++#define BCM63268_TCLK_EPHY2 1 ++#define BCM63268_TCLK_EPHY3 2 ++#define BCM63268_TCLK_GPHY1 3 ++#define BCM63268_TCLK_DSL 4 ++#define BCM63268_TCLK_WAKEON_EPHY 6 ++#define BCM63268_TCLK_WAKEON_DSL 7 ++#define BCM63268_TCLK_FAP1 11 ++#define BCM63268_TCLK_FAP2 15 ++#define BCM63268_TCLK_UTO_50 16 ++#define BCM63268_TCLK_UTO_EXTIN 17 ++#define BCM63268_TCLK_USB_REF 18 ++ + #endif /* __DT_BINDINGS_CLOCK_BCM63268_H */ diff --git a/target/linux/generic/pending-6.1/851-dt-bindings-reset-add-BCM63268-timer-reset-definitions.patch b/target/linux/generic/pending-6.1/851-dt-bindings-reset-add-BCM63268-timer-reset-definitions.patch new file mode 100644 index 00000000000..5f1be105ac7 --- /dev/null +++ b/target/linux/generic/pending-6.1/851-dt-bindings-reset-add-BCM63268-timer-reset-definitions.patch @@ -0,0 +1,107 @@ +From patchwork Wed Mar 22 17:15:13 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13184390 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id D0B1AC6FD1C + for ; Wed, 22 Mar 2023 17:16:08 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S231472AbjCVRQI (ORCPT ); + Wed, 22 Mar 2023 13:16:08 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58934 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S231435AbjCVRP5 (ORCPT + ); Wed, 22 Mar 2023 13:15:57 -0400 +Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com + [IPv6:2a00:1450:4864:20::329]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9655064863; + Wed, 22 Mar 2023 10:15:25 -0700 (PDT) +Received: by mail-wm1-x329.google.com with SMTP id + v4-20020a05600c470400b003ee4f06428fso2424553wmo.4; + Wed, 22 Mar 2023 10:15:25 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679505324; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=C7ykhArT1dO7P8wtmI92eo4c7KtPZI9w182/5+cB3T0=; + b=WRZRU2SM9n1LfUj4SgTPfQczADC2pfvoIrOsNpBLTym2eOfmkTetb/WbGSla5kw2Wb + SH5MIC2fFeScJg6T5FFAUOOLmRVW9xvl8Q3T3NKb3z/9wvPHO767nrdIbffRWMJFs7gW + wT/kuTpn8GYdfY0sZ/dMTkq41DVusEkxfX6GxtG85O98ZP8xMHQog8aPs9fRfUvI5ZKB + eGYcRz/Wn1cHhjey9jtWzQEEmZ/BT3b0HQTF9Tl88oofhiEgbyjFXr91+vRsLbsJpGXH + /1FjjaLG5DnonKubV9rmbuCU8KzwH331gi2KuRjvLD2V+OMewqSa5i+GvgVv8x2zC8y+ + /mLQ== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679505324; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=C7ykhArT1dO7P8wtmI92eo4c7KtPZI9w182/5+cB3T0=; + b=bhd0fNh0jDOMlGSC4F+p5igV8AUlGEPj2cXUwgdgqRfSSuUy9z+Li8cT0MbY/aWH5Z + qInRVA+R1cWV3ubrDyKag6oEc0LDU234bnMFcP9b7MRlrM8Dpit9TFSyqJU4sDUWNDs5 + KOe2k/SNIdat6munC9VOuEBDO0eB/UDMN+repKwXNdHChp/Toq9qMvW4Uy8uHxosbQlD + 8P88GbKFjynb1E8I8croGjfub7+y8PPsWB0xNUcafIv6xs3MnVOP1Mk4KwBCbqS509la + mfjsriXtIybO8XFqtn100ungjvbFWdogEplLdSPVdgAqdfF5J8gHxAoApoeYejYkL5/R + kOhQ== +X-Gm-Message-State: AO0yUKWdzr3dMmjKhD8tF+ec4Dfdq9VGZ/WCU4d85npKQvxSwhNPZZ1J + 5WYRIqivh0suFC1OqEidwenpiJYvXedYjw== +X-Google-Smtp-Source: + AK7set87ew2/mKWeShXTTW/YBbBJNR2zeGFV0CfuqLXhiJEU6tqFuyKcW+vFEoKHIbNUS8wRy1SzLA== +X-Received: by 2002:a05:600c:290:b0:3ee:6d88:774a with SMTP id + 16-20020a05600c029000b003ee6d88774amr160734wmk.14.1679505323514; + Wed, 22 Mar 2023 10:15:23 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + v10-20020a05600c470a00b003ee11ac2288sm8414333wmo.21.2023.03.22.10.15.22 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Wed, 22 Mar 2023 10:15:23 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: mturquette@baylibre.com, sboyd@kernel.org, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, p.zabel@pengutronix.de, + f.fainelli@gmail.com, jonas.gorski@gmail.com, + william.zhang@broadcom.com, linux-clk@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= , + Rob Herring +Subject: [PATCH v4 2/4] dt-bindings: reset: add BCM63268 timer reset + definitions +Date: Wed, 22 Mar 2023 18:15:13 +0100 +Message-Id: <20230322171515.120353-3-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230322171515.120353-1-noltari@gmail.com> +References: <20230322171515.120353-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: linux-clk@vger.kernel.org + +Add missing timer reset definitions for BCM63268. + +Signed-off-by: Álvaro Fernández Rojas +Acked-by: Rob Herring +--- + v4: no changes + v3: no changes + v2: change commit title, as suggested by Stephen Boyd + + include/dt-bindings/reset/bcm63268-reset.h | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/include/dt-bindings/reset/bcm63268-reset.h ++++ b/include/dt-bindings/reset/bcm63268-reset.h +@@ -23,4 +23,8 @@ + #define BCM63268_RST_PCIE_HARD 17 + #define BCM63268_RST_GPHY 18 + ++#define BCM63268_TRST_SW 29 ++#define BCM63268_TRST_HW 30 ++#define BCM63268_TRST_POR 31 ++ + #endif /* __DT_BINDINGS_RESET_BCM63268_H */ diff --git a/target/linux/generic/pending-6.1/852-clk-bcm-Add-BCM63268-timer-clock-and-reset-driver.patch b/target/linux/generic/pending-6.1/852-clk-bcm-Add-BCM63268-timer-clock-and-reset-driver.patch new file mode 100644 index 00000000000..7e500cd1b58 --- /dev/null +++ b/target/linux/generic/pending-6.1/852-clk-bcm-Add-BCM63268-timer-clock-and-reset-driver.patch @@ -0,0 +1,345 @@ +From patchwork Wed Mar 22 17:15:15 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 8bit +X-Patchwork-Submitter: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= + +X-Patchwork-Id: 13184392 +Return-Path: +X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on + aws-us-west-2-korg-lkml-1.web.codeaurora.org +Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) + by smtp.lore.kernel.org (Postfix) with ESMTP id 199D9C76196 + for ; Wed, 22 Mar 2023 17:16:11 +0000 (UTC) +Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand + id S231512AbjCVRQJ (ORCPT ); + Wed, 22 Mar 2023 13:16:09 -0400 +Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58942 "EHLO + lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org + with ESMTP id S231442AbjCVRP5 (ORCPT + ); Wed, 22 Mar 2023 13:15:57 -0400 +Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com + [IPv6:2a00:1450:4864:20::32c]) + by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1DDB36487D; + Wed, 22 Mar 2023 10:15:27 -0700 (PDT) +Received: by mail-wm1-x32c.google.com with SMTP id + i5-20020a05600c354500b003edd24054e0so6717370wmq.4; + Wed, 22 Mar 2023 10:15:27 -0700 (PDT) +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=gmail.com; s=20210112; t=1679505325; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:from:to:cc:subject:date + :message-id:reply-to; + bh=rkv/eZYA1ncHp5FnV2ZWc3hgYnAx28S86QA9vmcXFCY=; + b=Y1mva2Bt3sUbKxLgEUS331CJbGxUc4z8kTQW8qiHWGhYlFKtm+d5z4sT40E5BeZAnU + zmTbCI7jbroe9NYBxGUmSli6LNVDPjND80ChbhWTqbqMQTmeQFWut9KmeBWK6Oze2lC/ + XMSOorUzowjcU2xtHNrzoq2KH2pstW573lsB8WnzFVfhMaRkE9DfRr6WNyA7zC8DyxM5 + ezxlCQtCmgPfCqlyksbIDKrgrRf3GiUR0yUd6xRU+MssyvH1FkYGDCerPctDto6lGHBz + 8Y15jT3l6OnQMT6dkekgpPF5/XrSUY93u9g0B4U8+0dhNj+K7vmDen+jqdess+tpLnq/ + gFrA== +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; t=1679505325; + h=content-transfer-encoding:mime-version:references:in-reply-to + :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc + :subject:date:message-id:reply-to; + bh=rkv/eZYA1ncHp5FnV2ZWc3hgYnAx28S86QA9vmcXFCY=; + b=Ym4+u8bbTQGNkewUBrLf+89vE0EFJBQp2f1crwUxZFboKTROF9ltZonY1CGepo7b0B + fkx3TbWQy5X65g3ScuieqtClCI8WanPeNBJ48+JipJYO3ODVNBxnVaTuW/0FOIcahfqe + sG5GvggHhzRz+Yeybsbnupmzxnw8Ez0BpMl3p7zcjHL7BGZDdOOX2Zbw3zfyYa5sg2nX + UXYJT36zy2h39gxUsy9QkhQ76CG3w6omniohZpYidpojpiDjbOy0nKFky4kUe+YyA1fF + 4IBhjAm6mH+uh6wHSG1qj+NAXHs0xDDJps16PbJwAgL7Qt9K5WW+R/UAYPmHFgaRIHOw + /seA== +X-Gm-Message-State: AO0yUKXRtoYO8Nfus6Ca8lhM39P1Xn6TGkhatEfoISd1YNOkTJJN2hW+ + xRphLgxlzNfCLcVPlpGK9dk= +X-Google-Smtp-Source: + AK7set9VnMEykugk8ZYnkXuqK41bX1dzlvKsAXHEjr8i2NZBld0buKhQLcGYEcwxnBgVTtC7eRGfXw== +X-Received: by 2002:a1c:7c0b:0:b0:3e2:1dac:b071 with SMTP id + x11-20020a1c7c0b000000b003e21dacb071mr178053wmc.13.1679505325582; + Wed, 22 Mar 2023 10:15:25 -0700 (PDT) +Received: from atlantis.lan (255.red-79-146-124.dynamicip.rima-tde.net. + [79.146.124.255]) + by smtp.gmail.com with ESMTPSA id + v10-20020a05600c470a00b003ee11ac2288sm8414333wmo.21.2023.03.22.10.15.24 + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Wed, 22 Mar 2023 10:15:25 -0700 (PDT) +From: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +To: mturquette@baylibre.com, sboyd@kernel.org, robh+dt@kernel.org, + krzysztof.kozlowski+dt@linaro.org, p.zabel@pengutronix.de, + f.fainelli@gmail.com, jonas.gorski@gmail.com, + william.zhang@broadcom.com, linux-clk@vger.kernel.org, + devicetree@vger.kernel.org, linux-kernel@vger.kernel.org +Cc: =?utf-8?q?=C3=81lvaro_Fern=C3=A1ndez_Rojas?= +Subject: [PATCH v4 4/4] clk: bcm: Add BCM63268 timer clock and reset driver +Date: Wed, 22 Mar 2023 18:15:15 +0100 +Message-Id: <20230322171515.120353-5-noltari@gmail.com> +X-Mailer: git-send-email 2.30.2 +In-Reply-To: <20230322171515.120353-1-noltari@gmail.com> +References: <20230322171515.120353-1-noltari@gmail.com> +MIME-Version: 1.0 +Precedence: bulk +List-ID: +X-Mailing-List: linux-clk@vger.kernel.org + +Add driver for BCM63268 timer clock and reset controller. + +Signed-off-by: Álvaro Fernández Rojas +--- + v4: add changes suggested by Stephen Boyd: + - Usage of of_device_get_match_data() isn't needed. + - Use devm_clk_hw_register_gate(). + - Drop clk_hw_unregister_gate(). + v3: add missing include to fix build warning + v2: add changes suggested by Stephen Boyd + + drivers/clk/bcm/Kconfig | 9 ++ + drivers/clk/bcm/Makefile | 1 + + drivers/clk/bcm/clk-bcm63268-timer.c | 215 +++++++++++++++++++++++++++ + 3 files changed, 225 insertions(+) + create mode 100644 drivers/clk/bcm/clk-bcm63268-timer.c + +--- a/drivers/clk/bcm/Kconfig ++++ b/drivers/clk/bcm/Kconfig +@@ -37,6 +37,15 @@ config CLK_BCM_63XX_GATE + Enable common clock framework support for Broadcom BCM63xx DSL SoCs + based on the MIPS architecture + ++config CLK_BCM63268_TIMER ++ bool "Broadcom BCM63268 timer clock and reset support" ++ depends on BMIPS_GENERIC || COMPILE_TEST ++ default BMIPS_GENERIC ++ select RESET_CONTROLLER ++ help ++ Enable timer clock and reset support for Broadcom BCM63268 DSL SoCs ++ based on the MIPS architecture. ++ + config CLK_BCM_KONA + bool "Broadcom Kona CCU clock support" + depends on ARCH_BCM_MOBILE || COMPILE_TEST +--- a/drivers/clk/bcm/Makefile ++++ b/drivers/clk/bcm/Makefile +@@ -1,6 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o + obj-$(CONFIG_CLK_BCM_63XX_GATE) += clk-bcm63xx-gate.o ++obj-$(CONFIG_CLK_BCM63268_TIMER) += clk-bcm63268-timer.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o + obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o +--- /dev/null ++++ b/drivers/clk/bcm/clk-bcm63268-timer.c +@@ -0,0 +1,215 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * BCM63268 Timer Clock and Reset Controller Driver ++ * ++ * Copyright (C) 2023 Álvaro Fernández Rojas ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define BCM63268_TIMER_RESET_SLEEP_MIN_US 10000 ++#define BCM63268_TIMER_RESET_SLEEP_MAX_US 20000 ++ ++struct bcm63268_tclkrst_hw { ++ void __iomem *regs; ++ spinlock_t lock; ++ ++ struct reset_controller_dev rcdev; ++ struct clk_hw_onecell_data data; ++}; ++ ++struct bcm63268_tclk_table_entry { ++ const char * const name; ++ u8 bit; ++}; ++ ++static const struct bcm63268_tclk_table_entry bcm63268_timer_clocks[] = { ++ { ++ .name = "ephy1", ++ .bit = BCM63268_TCLK_EPHY1, ++ }, { ++ .name = "ephy2", ++ .bit = BCM63268_TCLK_EPHY2, ++ }, { ++ .name = "ephy3", ++ .bit = BCM63268_TCLK_EPHY3, ++ }, { ++ .name = "gphy1", ++ .bit = BCM63268_TCLK_GPHY1, ++ }, { ++ .name = "dsl", ++ .bit = BCM63268_TCLK_DSL, ++ }, { ++ .name = "wakeon_ephy", ++ .bit = BCM63268_TCLK_WAKEON_EPHY, ++ }, { ++ .name = "wakeon_dsl", ++ .bit = BCM63268_TCLK_WAKEON_DSL, ++ }, { ++ .name = "fap1_pll", ++ .bit = BCM63268_TCLK_FAP1, ++ }, { ++ .name = "fap2_pll", ++ .bit = BCM63268_TCLK_FAP2, ++ }, { ++ .name = "uto_50", ++ .bit = BCM63268_TCLK_UTO_50, ++ }, { ++ .name = "uto_extin", ++ .bit = BCM63268_TCLK_UTO_EXTIN, ++ }, { ++ .name = "usb_ref", ++ .bit = BCM63268_TCLK_USB_REF, ++ }, { ++ /* sentinel */ ++ } ++}; ++ ++static inline struct bcm63268_tclkrst_hw * ++to_bcm63268_timer_reset(struct reset_controller_dev *rcdev) ++{ ++ return container_of(rcdev, struct bcm63268_tclkrst_hw, rcdev); ++} ++ ++static int bcm63268_timer_reset_update(struct reset_controller_dev *rcdev, ++ unsigned long id, bool assert) ++{ ++ struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); ++ unsigned long flags; ++ uint32_t val; ++ ++ spin_lock_irqsave(&reset->lock, flags); ++ val = __raw_readl(reset->regs); ++ if (assert) ++ val &= ~BIT(id); ++ else ++ val |= BIT(id); ++ __raw_writel(val, reset->regs); ++ spin_unlock_irqrestore(&reset->lock, flags); ++ ++ return 0; ++} ++ ++static int bcm63268_timer_reset_assert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return bcm63268_timer_reset_update(rcdev, id, true); ++} ++ ++static int bcm63268_timer_reset_deassert(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ return bcm63268_timer_reset_update(rcdev, id, false); ++} ++ ++static int bcm63268_timer_reset_reset(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ bcm63268_timer_reset_update(rcdev, id, true); ++ usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, ++ BCM63268_TIMER_RESET_SLEEP_MAX_US); ++ ++ bcm63268_timer_reset_update(rcdev, id, false); ++ /* ++ * Ensure component is taken out reset state by sleeping also after ++ * deasserting the reset. Otherwise, the component may not be ready ++ * for operation. ++ */ ++ usleep_range(BCM63268_TIMER_RESET_SLEEP_MIN_US, ++ BCM63268_TIMER_RESET_SLEEP_MAX_US); ++ ++ return 0; ++} ++ ++static int bcm63268_timer_reset_status(struct reset_controller_dev *rcdev, ++ unsigned long id) ++{ ++ struct bcm63268_tclkrst_hw *reset = to_bcm63268_timer_reset(rcdev); ++ ++ return !(__raw_readl(reset->regs) & BIT(id)); ++} ++ ++static struct reset_control_ops bcm63268_timer_reset_ops = { ++ .assert = bcm63268_timer_reset_assert, ++ .deassert = bcm63268_timer_reset_deassert, ++ .reset = bcm63268_timer_reset_reset, ++ .status = bcm63268_timer_reset_status, ++}; ++ ++static int bcm63268_tclk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ const struct bcm63268_tclk_table_entry *entry; ++ struct bcm63268_tclkrst_hw *hw; ++ struct clk_hw *clk; ++ u8 maxbit = 0; ++ int i, ret; ++ ++ for (entry = bcm63268_timer_clocks; entry->name; entry++) ++ maxbit = max(maxbit, entry->bit); ++ maxbit++; ++ ++ hw = devm_kzalloc(&pdev->dev, struct_size(hw, data.hws, maxbit), ++ GFP_KERNEL); ++ if (!hw) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, hw); ++ ++ spin_lock_init(&hw->lock); ++ ++ hw->data.num = maxbit; ++ for (i = 0; i < maxbit; i++) ++ hw->data.hws[i] = ERR_PTR(-ENODEV); ++ ++ hw->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(hw->regs)) ++ return PTR_ERR(hw->regs); ++ ++ for (entry = bcm63268_timer_clocks; entry->name; entry++) { ++ clk = devm_clk_hw_register_gate(dev, entry->name, NULL, 0, ++ hw->regs, entry->bit, ++ CLK_GATE_BIG_ENDIAN, ++ &hw->lock); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ hw->data.hws[entry->bit] = clk; ++ } ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, ++ &hw->data); ++ if (ret) ++ return ret; ++ ++ hw->rcdev.of_node = dev->of_node; ++ hw->rcdev.ops = &bcm63268_timer_reset_ops; ++ ++ ret = devm_reset_controller_register(dev, &hw->rcdev); ++ if (ret) ++ dev_err(dev, "Failed to register reset controller\n"); ++ ++ return 0; ++} ++ ++static const struct of_device_id bcm63268_tclk_dt_ids[] = { ++ { .compatible = "brcm,bcm63268-timer-clocks" }, ++ { /* sentinel */ } ++}; ++ ++static struct platform_driver bcm63268_tclk = { ++ .probe = bcm63268_tclk_probe, ++ .driver = { ++ .name = "bcm63268-timer-clock", ++ .of_match_table = bcm63268_tclk_dt_ids, ++ }, ++}; ++builtin_platform_driver(bcm63268_tclk); diff --git a/target/linux/generic/pending-6.1/920-mangle_bootargs.patch b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch new file mode 100644 index 00000000000..5f0a106ae4e --- /dev/null +++ b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch @@ -0,0 +1,71 @@ +From: Imre Kaloz +Subject: init: add CONFIG_MANGLE_BOOTARGS and disable it by default + +Enabling this option renames the bootloader supplied root= +and rootfstype= variables, which might have to be know but +would break the automatisms OpenWrt uses. + +Signed-off-by: Imre Kaloz +--- + init/Kconfig | 9 +++++++++ + init/main.c | 24 ++++++++++++++++++++++++ + 2 files changed, 33 insertions(+) + +--- a/init/Kconfig ++++ b/init/Kconfig +@@ -1814,6 +1814,15 @@ config EMBEDDED + an embedded system so certain expert options are available + for configuration. + ++config MANGLE_BOOTARGS ++ bool "Rename offending bootargs" ++ depends on EXPERT ++ help ++ Sometimes the bootloader passed bogus root= and rootfstype= ++ parameters to the kernel, and while you want to ignore them, ++ you need to know the values f.e. to support dual firmware ++ layouts on the flash. ++ + config HAVE_PERF_EVENTS + bool + help +--- a/init/main.c ++++ b/init/main.c +@@ -616,6 +616,29 @@ static inline void setup_nr_cpu_ids(void + static inline void smp_prepare_cpus(unsigned int maxcpus) { } + #endif + ++#ifdef CONFIG_MANGLE_BOOTARGS ++static void __init mangle_bootargs(char *command_line) ++{ ++ char *rootdev; ++ char *rootfs; ++ ++ rootdev = strstr(command_line, "root=/dev/mtdblock"); ++ ++ if (rootdev) ++ strncpy(rootdev, "mangled_rootblock=", 18); ++ ++ rootfs = strstr(command_line, "rootfstype"); ++ ++ if (rootfs) ++ strncpy(rootfs, "mangled_fs", 10); ++ ++} ++#else ++static void __init mangle_bootargs(char *command_line) ++{ ++} ++#endif ++ + /* + * We need to store the untouched command line for future reference. + * We also need to store the touched command line since the parameter +@@ -956,6 +979,7 @@ asmlinkage __visible void __init __no_sa + pr_notice("%s", linux_banner); + early_security_init(); + setup_arch(&command_line); ++ mangle_bootargs(command_line); + setup_boot_config(); + setup_command_line(command_line); + setup_nr_cpu_ids(); From 3be6f3592efa3a81366fc643445786ef789b85de Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 22:49:57 +0200 Subject: [PATCH 59/88] generic: 6.1: drop backport patches Drop all backport patches that are now included in kernel 6.1. Signed-off-by: Christian Marangi --- ...ild-use-Wdeclaration-after-statement.patch | 73 - ...05-v5.17-02-Kbuild-move-to-std-gnu11.patch | 60 - ...-use-std-gnu11-for-KBUILD_USERCFLAGS.patch | 43 - ...-x86-arm64-add-arch_has_hw_pte_young.patch | 425 - ...dd-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch | 153 - ...-03-mm-vmscan.c-refactor-shrink_node.patch | 275 - ...inux-mm_inline.h-fold-__update_lru_s.patch | 82 - ...-v6.1-05-mm-multi-gen-LRU-groundwork.patch | 807 -- ...multi-gen-LRU-minimal-implementation.patch | 1447 ---- ...lti-gen-LRU-exploit-locality-in-rmap.patch | 491 -- ...lti-gen-LRU-support-page-table-walks.patch | 1687 ---- ...lti-gen-LRU-optimize-multiple-memcgs.patch | 315 - ...v6.1-10-mm-multi-gen-LRU-kill-switch.patch | 498 -- ...m-multi-gen-LRU-thrashing-prevention.patch | 226 - ...2-mm-multi-gen-LRU-debugfs-interface.patch | 579 -- ...don-t-sync-disk-for-each-aging-cycle.patch | 32 - ...-retry-pages-written-back-while-isol.patch | 124 - ...-move-lru_gen_add_mm-out-of-IRQ-off-.patch | 49 - ..._young-for-architectures-not-having-.patch | 96 - ...roduce-arch_has_hw_nonleaf_pmd_young.patch | 113 - ...RU-fix-crash-during-cgroup-migration.patch | 56 - ...-uasm-Enable-muhu-opcode-for-MIPS-R6.patch | 65 - ...rkaround-for-Loongson-2F-nop-CPU-err.patch | 31 - ...ips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch | 3078 ------- ...bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch | 1005 --- ...f-Add-JIT-workarounds-for-CPU-errata.patch | 120 - ...0-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch | 61 - ...f-Remove-old-BPF-JIT-implementations.patch | 387 - ...k-gate-Add-devm_clk_hw_register_gate.patch | 105 - ...to-define-reg_update_bits-for-no-bus.patch | 52 - ...63xx-use-more-precise-Kconfig-symbol.patch | 37 - ...resolve_btfids-Build-with-host-flags.patch | 49 - ...te-to-upstream-version-v1.6.1-19-g0a.patch | 997 --- ...or-setting-affinity-if-no-IRQ-parent.patch | 48 - ...-Support-reserved-memory-description.patch | 166 - ...-bcm63xx_wdt-fix-fallthrough-warning.patch | 33 - ...kernel-proc-add-CPU-option-reporting.patch | 162 - ...mp_processor_id-in-preemptible-in-sh.patch | 62 - ...spinand-Add-support-for-XTX-XT26G0xA.patch | 186 - ...mvebu-a3700-comphy-Remove-port-from-.patch | 219 - ...mvebu-a3700-comphy-Add-native-kernel.patch | 1552 ---- ...l-armada-37xx-Add-xtal-clock-to-comp.patch | 32 - ...mvebu-Make-SATA-PHY-optional-for-Arm.patch | 64 - ...xhci-mvebu-make-USB-3.0-PHY-optional.patch | 166 - ...ark-Fix-initialization-with-old-Marv.patch | 39 - ...mvebu-a3700-comphy-Remove-broken-res.patch | 194 - ...configurable-downshift-for-addresses.patch | 90 - ...efined-reg_base-to-be-added-to-every.patch | 95 - ..._base-and-reg_downshift-for-single-r.patch | 57 - ...platform_populate-for-MTD-partitions.patch | 72 - ...s-add-support-for-Sercomm-partitions.patch | 302 - ...ce-of-support-for-dynamic-partitions.patch | 106 - ...g-MTD-device-associated-with-a-speci.patch | 72 - ...e-check-partition-before-dereference.patch | 30 - ...sing-of_node_get-in-dynamic-partitio.patch | 101 - ...-Don-t-print-error-message-on-EPROBE.patch | 32 - ...x-allow-to-use-on-MediaTek-MIPS-SoCs.patch | 33 - ...device-add-support-for-GD5FxGQ4xExxG.patch | 58 - ...device-add-support-for-GD5F1GQ5RExxG.patch | 33 - ...device-add-support-for-GD5F-2-4-GQ5x.patch | 84 - ...device-add-support-for-GD5FxGM7xExxG.patch | 91 - ...9-mtd-spi-nor-support-eon-en25qh256a.patch | 49 - ...m-number-of-bitflips-for-each-read-r.patch | 73 - ...itialize-stats-in-struct-mtd_oob_ops.patch | 325 - ...ror-accounting-for-each-read-request.patch | 172 - ...-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch | 321 - ...v5.18-page_pool-Add-allocation-stats.patch | 165 - ...01-v5.18-page_pool-Add-recycle-stats.patch | 140 - ...d-function-to-batch-and-return-stats.patch | 77 - ...cycle-stats-to-page_pool_put_page_bu.patch | 55 - ...et-page_pool-introduce-ethtool-stats.patch | 147 - ...ce-flags-field-in-xdp_buff-xdp_frame.patch | 99 - ...gs-support-to-xdp_return_-buff-frame.patch | 137 - ...ize-metadata-to-skb_shared_info-for-.patch | 31 - ...-total-xdp_frame-len-running-ndo_xdp.patch | 65 - ...-veth-Allow-jumbo-frames-in-xdp-mode.patch | 40 - ...uce-tagger-owned-storage-for-private.patch | 279 - ...ocols-connect-to-individual-switches.patch | 274 - ..._eth_soc-add-support-for-coherent-DM.patch | 327 - ...ek-mt7622-add-support-for-coherent-D.patch | 30 - ..._eth_soc-add-support-for-Wireless-Et.patch | 1679 ---- ..._eth_soc-implement-flow-offloading-t.patch | 269 - ...ek-mt7622-introduce-nodes-for-Wirele.patch | 62 - ..._eth_soc-add-ipv6-flow-offload-suppo.patch | 79 - ..._eth_soc-support-TC_SETUP_BLOCK-for-.patch | 29 - ..._eth_soc-allocate-struct-mtk_ppe-sep.patch | 159 - ..._eth_soc-rework-hardware-flow-table-.patch | 424 - ..._eth_soc-remove-bridge-flow-offload-.patch | 44 - ..._eth_soc-support-creating-mac-addres.patch | 553 -- ..._eth_soc-wed-fix-sparse-endian-warni.patch | 56 - ..._eth_soc-fix-return-value-check-in-m.patch | 25 - ..._eth_soc-use-standard-property-for-c.patch | 35 - ..._eth_soc-use-after-free-in-__mtk_ppe.patch | 33 - ..._eth_soc-add-check-for-allocation-fa.patch | 22 - ...silence-the-GCC-12-array-bounds-warn.patch | 26 - ..._eth_soc-rely-on-GFP_KERNEL-for-dma_.patch | 52 - ..._eth_soc-move-tx-dma-desc-configurat.patch | 206 - ..._eth_soc-add-txd_size-to-mtk_soc_dat.patch | 167 - ..._eth_soc-rely-on-txd_size-in-mtk_tx_.patch | 78 - ..._eth_soc-rely-on-txd_size-in-mtk_des.patch | 109 - ..._eth_soc-rely-on-txd_size-in-txd_to_.patch | 39 - ..._eth_soc-add-rxd_size-to-mtk_soc_dat.patch | 102 - ..._eth_soc-rely-on-txd_size-field-in-m.patch | 46 - ..._eth_soc-rely-on-rxd_size-field-in-m.patch | 68 - ..._eth_soc-introduce-device-register-m.patch | 814 -- ..._eth_soc-introduce-MTK_NETSYS_V2-sup.patch | 917 -- ..._eth_soc-convert-ring-dma-pointer-to.patch | 135 - ..._eth_soc-convert-scratch_ring-pointe.patch | 33 - ..._eth_soc-introduce-support-for-mt798.patch | 138 - ..._eth_soc-fix-error-code-in-mtk_flow_.patch | 25 - ..._eth_soc-enable-rx-cksum-offload-for.patch | 47 - ...19-34-eth-mtk_ppe-fix-up-after-merge.patch | 28 - ...-users-of-bitmap_foo-to-linkmode_foo.patch | 948 --- ...ylink-add-MAC-phy_interface_t-bitmap.patch | 24 - ...supported_interfaces-for-phylink-val.patch | 98 - ...populate-supported_interfaces-member.patch | 63 - ...net-dsa-consolidate-phylink-creation.patch | 149 - ...phylink_get_interfaces-with-phylink_.patch | 51 - ...d-support-for-phylink-mac_select_pcs.patch | 59 - ...y-add-phy_interface_t-bitmap-support.patch | 61 - ...mac_select_pcs-method-to-phylink_mac.patch | 197 - ...-add-generic-validate-implementation.patch | 341 - ...e-helpers-for-iterating-through-port.patch | 68 - ...-net-phylink-add-pcs_validate-method.patch | 106 - ...k-add-legacy_pre_march2020-indicator.patch | 43 - ...-DSA-phylink-as-legacy_pre_march2020.patch | 36 - ...net-phylink-use-legacy_pre_march2020.patch | 115 - ...-fix-DSA-mac_select_pcs-introduction.patch | 88 - ...populate-supported_interfaces-member.patch | 48 - ...e-interface-checks-in-mvneta_validat.patch | 35 - ...op-use-of-phylink_helper_basex_speed.patch | 55 - ...-mvneta-use-phylink_generic_validate.patch | 72 - ...ark-as-a-legacy_pre_march2020-driver.patch | 29 - ...populate-supported_interfaces-member.patch | 43 - ...remove-interface-checks-in-mtk_valid.patch | 75 - ...drop-use-of-phylink_helper_basex_spe.patch | 42 - ...eth_soc-use-phylink_generic_validate.patch | 84 - ...mark-as-a-legacy_pre_march2020-drive.patch | 29 - ...remove-a-copy-of-the-NAPI_POLL_WEIGH.patch | 40 - ...9-mtk_eth_soc-remove-unused-mac-mode.patch | 35 - ...tk_eth_soc-remove-unused-sgmii-flags.patch | 40 - ...add-mask-and-update-PCS-speed-defini.patch | 40 - ...eth_soc-correct-802.3z-speed-setting.patch | 60 - ...th_soc-correct-802.3z-duplex-setting.patch | 101 - ...stop-passing-phylink-state-to-sgmii-.patch | 60 - ...mtk_eth_soc-provide-mtk_sgmii_config.patch | 89 - ...add-fixme-comment-for-state-speed-us.patch | 38 - ...c-move-MAC_MCR-setting-to-mac_finish.patch | 79 - ...move-restoration-of-SYSCFG0-to-mac_f.patch | 57 - ...convert-code-structure-to-suit-split.patch | 254 - ...soc-partially-convert-to-phylink_pcs.patch | 262 - ...terate-using-dsa_switch_for_each_use.patch | 106 - ...opulate-supported_interfaces-and-mac.patch | 166 - ...t-dsa-mt7530-remove-interface-checks.patch | 172 - ...rop-use-of-phylink_helper_basex_spee.patch | 34 - ...nly-indicate-linkmodes-that-can-be-s.patch | 86 - ...-switch-to-use-phylink_get_linkmodes.patch | 131 - ...530-partially-convert-to-phylink_pcs.patch | 385 - ...ove-autoneg-handling-to-PCS-validati.patch | 80 - ...19-net-dsa-mt7530-mark-as-non-legacy.patch | 34 - ...mt753x-fix-pcs-conversion-regression.patch | 116 - ...t7530-rework-mt7530_hw_vlan_-add-del.patch | 87 - ...et-dsa-mt7530-rework-mt753-01-_setup.patch | 75 - ...et-cpu-port-via-dp-cpu_dp-instead-of.patch | 117 - ..._eth_soc-rely-on-page_pool-for-singl.patch | 330 - ...et-mtk_eth_soc-add-basic-XDP-support.patch | 291 - ..._eth_soc-introduce-xdp-ethtool-count.patch | 110 - ...net-mtk_eth_soc-add-xmit-XDP-support.patch | 340 - ..._eth_soc-add-support-for-page_pool_g.patch | 95 - ..._eth_soc-introduce-mtk_xdp_frame_map.patch | 113 - ..._eth_soc-introduce-xdp-multi-frag-su.patch | 218 - ..._eth_soc-fix-hw-hash-reporting-for-M.patch | 74 - ..._eth_soc-fix-off-by-one-check-of-ARR.patch | 31 - ..._ppe-fix-possible-NULL-pointer-deref.patch | 27 - ...-ppe-fix-traffic-offload-with-bridge.patch | 64 - ..._eth_soc-remove-mtk_foe_entry_timest.patch | 33 - ..._eth_soc-enable-XDP-support-just-for.patch | 35 - ..._eth_soc-move-gdma_to_ppe-and-ppe_ba.patch | 127 - ..._eth_soc-move-ppe-table-hash-offset-.patch | 199 - ..._eth_soc-add-the-capability-to-run-m.patch | 318 - ..._eth_soc-move-wdma_base-definitions-.patch | 80 - ..._eth_soc-add-foe_entry_size-to-mtk_e.patch | 251 - ..._eth_soc-fix-typo-in-__mtk_foe_entry.patch | 27 - ..._eth_soc-check-max-allowed-value-in-.patch | 28 - ..._eth_wed-add-mtk_wed_configure_irq-a.patch | 189 - ..._eth_wed-add-wed-support-for-mt7986-.patch | 942 --- ...rnet-mtk_eth_wed-add-axi-bus-support.patch | 237 - ..._eth_soc-introduce-flow-offloading-s.patch | 882 -- ..._eth_soc-enable-flow-offloading-supp.patch | 26 - ..._eth_soc-fix-wrong-use-of-new-helper.patch | 46 - ..._eth_soc-fix-usage-of-foe_entry_size.patch | 49 - ..._eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch | 32 - ..._eth_soc-fix-state-in-__mtk_foe_entr.patch | 37 - ..._eth_soc-fix-possible-memory-leak-in.patch | 73 - ..._eth_wed-add-missing-put_device-in-m.patch | 47 - ...-mtk_eth_wed-add-missing-of_node_put.patch | 43 - ..._eth_soc-do-not-overwrite-mtu-config.patch | 98 - ..._eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch | 63 - ..._eth_soc-drop-packets-to-WDMA-if-the.patch | 37 - ..._eth_soc-Avoid-truncating-allocation.patch | 60 - ...-0001-net-bgmac-improve-handling-PHY.patch | 84 - ...t-bgmac-support-MDIO-described-in-DT.patch | 54 - ...dd-support-for-qca-8327-internal-phy.patch | 48 - ...3-Include-all-ports-in-enabled_ports.patch | 131 - ...-BCM5301x-workaround-for-a-wrong-CPU.patch | 42 - ...prove-flow-control-setup-on-BCM5301x.patch | 32 - ...t-dsa-b53-Drop-unused-cpu_port-field.patch | 205 - ...x-add-support-for-qca-8327-A-variant.patch | 65 - ...dd-resume-suspend-function-to-qca83x.patch | 45 - ...ix-spacing-and-improve-name-for-83xx.patch | 95 - ...hy-at803x-fix-resume-for-QCA8327-phy.patch | 131 - ...x-add-DAC-amplitude-fix-for-8327-phy.patch | 91 - ...nable-prefer-master-for-83xx-interna.patch | 27 - ...hy-at803x-better-describe-debug-regs.patch | 127 - ...-dsa-qca8k-add-mac-power-sel-support.patch | 80 - ...dsa-qca8k-Add-SGMII-clock-phase-prop.patch | 30 - ...k-add-support-for-sgmii-falling-edge.patch | 127 - ...dsa-qca8k-Document-support-for-CPU-p.patch | 29 - ...dsa-qca8k-add-support-for-cpu-port-6.patch | 153 - ...work-rgmii-delay-logic-and-scan-for-.patch | 295 - ...dsa-qca8k-Document-qca-sgmii-enable-.patch | 33 - ...-qca8k-add-explicit-SGMII-PLL-enable.patch | 65 - ...dsa-qca8k-Document-qca-led-open-drai.patch | 37 - ...qca8k-add-support-for-pws-config-reg.patch | 92 - ...dsa-qca8k-document-support-for-qca83.patch | 32 - ...et-dsa-qca8k-add-support-for-QCA8328.patch | 78 - ...8k-set-internal-delay-also-for-sgmii.patch | 159 - ...move-port-config-to-dedicated-struct.patch | 124 - ...ipq8064-mdio-fix-warning-with-new-qc.patch | 26 - ...net-dsa-qca8k-convert-to-YAML-schema.patch | 631 -- ...elay-applied-to-wrong-cpu-in-parse-p.patch | 28 - ...for-loop-in-setup-and-add-cpu-port-c.patch | 151 - ...sure-pad0-mac06-exchange-is-disabled.patch | 47 - ...ernal-delay-applied-to-the-wrong-PAD.patch | 48 - ...16-net-dsa-qca8k-fix-MTU-calculation.patch | 46 - ...redundant-check-in-parse_port_config.patch | 29 - ...vert-to-GENMASK_FIELD_PREP_FIELD_GET.patch | 507 -- ...move-extra-mutex_init-in-qca8k_setup.patch | 25 - ...move-regmap-init-in-probe-and-set-it.patch | 46 - ...k-initial-conversion-to-regmap-heper.patch | 249 - ...ca8k-add-additional-MIB-counter-and-.patch | 120 - ...ca8k-add-support-for-port-fast-aging.patch | 53 - ...sa-qca8k-add-set_ageing_time-support.patch | 78 - ...sa-qca8k-add-support-for-mdb_add-del.patch | 142 - ...sa-qca8k-add-support-for-mirror-mode.patch | 155 - ...t-next-net-dsa-qca8k-add-LAG-support.patch | 288 - ...dsa-qca8k-fix-warning-in-LAG-feature.patch | 40 - ...PHY-initialization-with-MTU-setup-in.patch | 52 - ...nl_lock-sections-in-dsa_slave_create.patch | 34 - ...op-updating-master-MTU-from-master.c.patch | 91 - ...l_mutex-when-calling-dsa_master_-set.patch | 78 - ...t-up-shared-ports-then-non-shared-po.patch | 118 - ...xt-net-dsa-setup-master-before-ports.patch | 115 - ...switch-operations-for-tracking-the-m.patch | 254 - ...aster-state-events-in-dsa_tree_-setu.patch | 89 - ...t-dsa-tag_qca-convert-to-FIELD-macro.patch | 86 - ...qca-move-define-to-include-linux-dsa.patch | 71 - ...ag_qca-enable-promisc_on_master-flag.patch | 27 - ...add-define-for-handling-mgmt-Etherne.patch | 110 - ...a-add-define-for-handling-MIB-packet.patch | 45 - ...add-support-for-handling-mgmt-and-MI.patch | 116 - ...8k-add-tracking-state-of-master-port.patch | 67 - ...d-support-for-mgmt-read-write-in-Eth.patch | 363 - ...d-support-for-mib-autocast-in-Ethern.patch | 226 - ...d-support-for-phy-read-write-with-mg.patch | 287 - ...qca8k-move-page-cache-to-driver-priv.patch | 208 - ...qca8k-cache-lo-and-hi-for-mdio-write.patch | 164 - ...d-support-for-larger-read-write-size.patch | 206 - ...troduce-qca8k_bulk_read-write-functi.patch | 104 - ...eck-correct-variable-in-qca8k_phy_et.patch | 28 - ...dsa-qca8k-fix-noderef.cocci-warnings.patch | 34 - ...8k-drop-MTU-tracking-from-qca8k_priv.patch | 79 - ...-qca8k-drop-port_sts-from-qca8k_priv.patch | 116 - ...8k-rework-and-simplify-mdiobus-logic.patch | 173 - ...-drop-dsa_switch_ops-from-qca8k_priv.patch | 39 - ...a8k-correctly-handle-mdio-read-error.patch | 33 - ...ify-bus-id-naming-with-legacy-and-OF.patch | 44 - ...net-dsa-qca8k-move-driver-to-qca-dir.patch | 7389 ----------------- ...-cache-match-data-to-speed-up-access.patch | 157 - ...k-make-mib-autocast-feature-optional.patch | 77 - ...qca8k-move-mib-struct-to-common-code.patch | 6532 --------------- ...ve-qca8k-read-write-rmw-and-reg-tabl.patch | 135 - ...ve-qca8k-bulk-read-write-helper-to-c.patch | 145 - ...ove-mib-init-function-to-common-code.patch | 137 - ...ve-port-set-status-eee-ethtool-stats.patch | 281 - ...move-bridge-functions-to-common-code.patch | 237 - ...ve-set-age-MTU-port-enable-disable-f.patch | 227 - ...ve-port-FDB-MDB-function-to-common-c.patch | 704 -- ...ve-port-mirror-functions-to-common-c.patch | 232 - ...ve-port-VLAN-functions-to-common-cod.patch | 448 - ...ve-port-LAG-functions-to-common-code.patch | 384 - ...ve-read_switch_id-function-to-common.patch | 102 - ...x-NULL-pointer-dereference-for-of_de.patch | 29 - ...N-filtering-syncing-out-of-dsa_switc.patch | 77 - ...cross-chip-syncing-of-VLAN-filtering.patch | 52 - ...-rtl8366rb-Support-bridge-offloading.patch | 141 - ...-dsa-rtl8366-Drop-custom-VLAN-set-up.patch | 118 - ...b-Rewrite-weird-VLAN-filering-enable.patch | 270 - ...-Drop-and-depromote-pointless-prints.patch | 51 - ...tl8366rb-Use-core-filtering-tracking.patch | 61 - ...rtl8366rb-Support-disabling-learning.patch | 115 - ...net-dsa-rtl8366rb-Support-fast-aging.patch | 57 - ...-rtl8366rb-Support-setting-STP-state.patch | 107 - ...icro-stmmac-move-queue-reset-to-dedi.patch | 142 - ...icro-stmmac-first-disable-all-queues.patch | 37 - ...icro-stmmac-move-dma-conf-to-dedicat.patch | 1289 --- ...icro-stmmac-generate-stmmac-dma-conf.patch | 1161 --- ...icro-stmmac-permit-MTU-change-with-i.patch | 73 - ...x-inband-mgmt-for-big-endian-systems.patch | 156 - ...x-ethtool-autocast-mib-for-big-endia.patch | 81 - ...x-wrong-length-value-for-mgmt-eth-pa.patch | 102 - ...sa-tag_qca-fix-wrong-MGMT_DATA2-size.patch | 34 - ...qca8k-cache-lo-and-hi-for-mdio-write.patch | 172 - ...-01-net-phy-at803x-add-fiber-support.patch | 193 - ...y-at803x-support-downstream-SFP-cage.patch | 95 - ...LL-pointer-dereference-on-AR9331-PHY.patch | 56 - ...ix-error-return-code-in-at803x_probe.patch | 31 - ...eric-Introduce-Sierra-EM919X-support.patch | 80 - ...ost-always-print-detected-modem-name.patch | 37 - ...-add-support-for-in-band-link-status.patch | 130 - ...e-implement-soft-state-polling-setup.patch | 98 - ...t-sfp-move-quirk-handling-into-sfp.c.patch | 291 - ...move-Alcatel-Lucent-3FE46541AA-fixup.patch | 69 - ....1-net-sfp-move-Huawei-MA5671A-fixup.patch | 48 - ...t-sfp-add-support-for-HALNy-GPON-SFP.patch | 79 - ...k-enabling-2500Base-x-for-HG-MXPD-48.patch | 37 - ....0-net-mii-add-mii_bmcr_encode_fixed.patch | 55 - ...net-usb-ax88179_178a-add-TSO-feature.patch | 68 - ...s-add-Broadcom-s-BCM63138-controller.patch | 125 - ...-add-support-for-BCM63138-controller.patch | 356 - ...-leds-bcm63138-unify-full-stops-in-d.patch | 30 - ...help-info-about-BCM63138-module-name.patch | 28 - ...eds-leds-bcm63138-get-rid-of-LED_OFF.patch | 30 - ...-rework-nvmem-cell-instance-creation.patch | 456 - ...-nvmem-cell-post-processing-callback.patch | 82 - ...cotp-add-support-for-post-processing.patch | 92 - ...support-minimum-one-byte-access-stri.patch | 47 - ...-Remove-unused-devm_nvmem_unregister.patch | 72 - ...em-core-Use-devm_add_action_or_reset.patch | 58 - ...-input-parameter-for-NULL-in-nvmem_u.patch | 30 - ...4-nvmem-qfprom-fix-kerneldoc-warning.patch | 29 - ...sunxi_sid-Add-support-for-D1-variant.patch | 38 - ...fuse-replace-unnecessary-devm_kstrdu.patch | 28 - ...-for-Layerscape-SFP-Security-Fuse-Pr.patch | 139 - ...rease-fuse-blow-timeout-to-prevent-w.patch | 32 - ...d-driver-for-OCOTP-in-Sunplus-SP7021.patch | 291 - ...-parse-NVRAM-content-into-NVMEM-cell.patch | 146 - ...mark-ACPI-device-ID-table-as-maybe-u.patch | 32 - ...em-sunplus-ocotp-staticize-sp_otp_v0.patch | 30 - ...cotp-drop-useless-probe-confirmation.patch | 27 - ...support-passing-DT-node-in-cell-info.patch | 41 - ...-find-Device-Tree-nodes-for-NVMEM-ce.patch | 38 - ...19-0006-nvmem-Add-Apple-eFuse-driver.patch | 130 - ...ng-pm_runtime_resume_and_get-instead.patch | 31 - .../805-v5.19-0008-nvmem-sfp-Use-regmap.patch | 109 - ...m-sfp-Add-support-for-TA-2.1-devices.patch | 38 - ...001-nvmem-microchip-otpc-add-support.patch | 389 - ...Simplify-with-devm_platform_get_and_.patch | 32 - ...-handling-U-Boot-environment-variabl.patch | 286 - ...-Use-kzalloc-for-allocating-only-one.patch | 29 - ...nvmem-prefix-all-symbols-with-NVMEM_.patch | 281 - ...m-sort-config-symbols-alphabetically.patch | 535 -- ...-find-Device-Tree-nodes-for-NVMEM-ce.patch | 31 - ...1-0008-nvmem-lan9662-otp-add-support.patch | 274 - ...em-u-boot-env-fix-crc32-casting-type.patch | 32 - ...em-lan9662-otp-Fix-compatible-string.patch | 34 - ...-fix-crc32_data_offset-on-redundant-.patch | 59 - ...p-Change-return-type-of-lan9662_otp_.patch | 35 - ...mem-brcm_nvram-Add-check-for-kzalloc.patch | 30 - ...nxi_sid-Always-use-32-bit-MMIO-reads.patch | 55 - ...mem-core-fix-device-node-refcounting.patch | 48 - ..._wwan-add-ZTE-MF286D-modem-19d2-1485.patch | 59 - ...Support-public-address-configuration.patch | 51 - ...Fix-application-of-sizeof-to-pointer.patch | 29 - ...Add-a-new-PID-VID-13d3-3567-for-MT79.patch | 70 - ...Add-a-new-PID-VID-0489-e0c8-for-MT79.patch | 68 - ...Add-a-new-VID-PID-0e8d-0608-for-MT79.patch | 66 - ...ll-of_parse_phandle-variants-static-.patch | 359 - ...a-ahci-fix-enum-constants-for-gcc-13.patch | 348 - ...PS-ath79-drop-_machine_restart-again.patch | 49 - ....18-hwmon-lm70-Add-ti-tmp125-support.patch | 71 - ...ether-export-usbnet_cdc_zte_rx_fixup.patch | 58 - ...e-the-bogus-MAC-fixup-for-ZTE-device.patch | 118 - ...-scope-of-bogus-MAC-address-detectio.patch | 63 - ...-spinand-winbond-fix-flash-detection.patch | 40 - ...6.1-mtd-spinand-winbond-add-W25N02KV.patch | 106 - 386 files changed, 76303 deletions(-) delete mode 100644 target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch delete mode 100644 target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch delete mode 100644 target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch delete mode 100644 target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch delete mode 100644 target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch delete mode 100644 target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch delete mode 100644 target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch delete mode 100644 target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch delete mode 100644 target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch delete mode 100644 target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch delete mode 100644 target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch delete mode 100644 target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch delete mode 100644 target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch delete mode 100644 target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch delete mode 100644 target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch delete mode 100644 target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch delete mode 100644 target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch delete mode 100644 target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch delete mode 100644 target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch delete mode 100644 target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch delete mode 100644 target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch delete mode 100644 target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch delete mode 100644 target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch delete mode 100644 target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch delete mode 100644 target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch delete mode 100644 target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch delete mode 100644 target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch delete mode 100644 target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch delete mode 100644 target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch delete mode 100644 target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch delete mode 100644 target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch delete mode 100644 target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch delete mode 100644 target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch delete mode 100644 target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch delete mode 100644 target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch delete mode 100644 target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch delete mode 100644 target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch delete mode 100644 target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch delete mode 100644 target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch delete mode 100644 target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch delete mode 100644 target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch delete mode 100644 target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch delete mode 100644 target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch delete mode 100644 target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch delete mode 100644 target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch delete mode 100644 target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch delete mode 100644 target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch delete mode 100644 target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch delete mode 100644 target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch delete mode 100644 target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch delete mode 100644 target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch delete mode 100644 target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch delete mode 100644 target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch delete mode 100644 target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch delete mode 100644 target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch delete mode 100644 target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch delete mode 100644 target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch delete mode 100644 target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch delete mode 100644 target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch delete mode 100644 target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch delete mode 100644 target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch delete mode 100644 target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch delete mode 100644 target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch delete mode 100644 target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch delete mode 100644 target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch delete mode 100644 target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch delete mode 100644 target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch delete mode 100644 target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch delete mode 100644 target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch delete mode 100644 target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch delete mode 100644 target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch delete mode 100644 target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch delete mode 100644 target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch delete mode 100644 target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch delete mode 100644 target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch delete mode 100644 target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch delete mode 100644 target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch delete mode 100644 target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch delete mode 100644 target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch delete mode 100644 target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch delete mode 100644 target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch delete mode 100644 target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch delete mode 100644 target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch delete mode 100644 target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch delete mode 100644 target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch delete mode 100644 target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch delete mode 100644 target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch delete mode 100644 target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch delete mode 100644 target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch delete mode 100644 target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch delete mode 100644 target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch delete mode 100644 target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch delete mode 100644 target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch delete mode 100644 target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch delete mode 100644 target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch delete mode 100644 target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch delete mode 100644 target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch delete mode 100644 target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch delete mode 100644 target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch delete mode 100644 target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch delete mode 100644 target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch delete mode 100644 target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch delete mode 100644 target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch delete mode 100644 target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch delete mode 100644 target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch delete mode 100644 target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch delete mode 100644 target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch delete mode 100644 target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch delete mode 100644 target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch delete mode 100644 target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch delete mode 100644 target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch delete mode 100644 target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch delete mode 100644 target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch delete mode 100644 target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch delete mode 100644 target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch delete mode 100644 target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch delete mode 100644 target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch delete mode 100644 target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch delete mode 100644 target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch delete mode 100644 target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch delete mode 100644 target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch delete mode 100644 target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch delete mode 100644 target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch delete mode 100644 target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch delete mode 100644 target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch delete mode 100644 target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch delete mode 100644 target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch delete mode 100644 target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch delete mode 100644 target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch delete mode 100644 target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch delete mode 100644 target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch delete mode 100644 target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch delete mode 100644 target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch delete mode 100644 target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch delete mode 100644 target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch delete mode 100644 target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch delete mode 100644 target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch delete mode 100644 target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch delete mode 100644 target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch delete mode 100644 target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch delete mode 100644 target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch delete mode 100644 target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch delete mode 100644 target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch delete mode 100644 target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch delete mode 100644 target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch delete mode 100644 target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch delete mode 100644 target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch delete mode 100644 target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch delete mode 100644 target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch delete mode 100644 target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch delete mode 100644 target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch delete mode 100644 target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch delete mode 100644 target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch delete mode 100644 target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch delete mode 100644 target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch delete mode 100644 target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch delete mode 100644 target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch delete mode 100644 target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch delete mode 100644 target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch delete mode 100644 target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch delete mode 100644 target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch delete mode 100644 target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch delete mode 100644 target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch delete mode 100644 target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch delete mode 100644 target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch delete mode 100644 target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch delete mode 100644 target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch delete mode 100644 target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch delete mode 100644 target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch delete mode 100644 target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch delete mode 100644 target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch delete mode 100644 target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch delete mode 100644 target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch delete mode 100644 target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch delete mode 100644 target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch delete mode 100644 target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch delete mode 100644 target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch delete mode 100644 target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch delete mode 100644 target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch delete mode 100644 target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch delete mode 100644 target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch delete mode 100644 target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch delete mode 100644 target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch delete mode 100644 target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch delete mode 100644 target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch delete mode 100644 target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch delete mode 100644 target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch delete mode 100644 target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch delete mode 100644 target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch delete mode 100644 target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch delete mode 100644 target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch delete mode 100644 target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch delete mode 100644 target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch delete mode 100644 target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch delete mode 100644 target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch delete mode 100644 target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch delete mode 100644 target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch delete mode 100644 target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch delete mode 100644 target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch delete mode 100644 target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch delete mode 100644 target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch delete mode 100644 target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch delete mode 100644 target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch delete mode 100644 target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch delete mode 100644 target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch delete mode 100644 target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch delete mode 100644 target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch delete mode 100644 target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch delete mode 100644 target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch delete mode 100644 target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch delete mode 100644 target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch delete mode 100644 target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch delete mode 100644 target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch delete mode 100644 target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch delete mode 100644 target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch delete mode 100644 target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch delete mode 100644 target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch delete mode 100644 target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch delete mode 100644 target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch delete mode 100644 target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch delete mode 100644 target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch delete mode 100644 target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch delete mode 100644 target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch delete mode 100644 target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch delete mode 100644 target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch delete mode 100644 target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch delete mode 100644 target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch delete mode 100644 target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch delete mode 100644 target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch delete mode 100644 target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch delete mode 100644 target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch delete mode 100644 target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch delete mode 100644 target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch delete mode 100644 target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch delete mode 100644 target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch delete mode 100644 target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch delete mode 100644 target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch delete mode 100644 target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch delete mode 100644 target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch delete mode 100644 target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch delete mode 100644 target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch delete mode 100644 target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch delete mode 100644 target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch delete mode 100644 target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch diff --git a/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch b/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch deleted file mode 100644 index b481dd30617..00000000000 --- a/target/linux/generic/backport-6.1/005-v5.17-01-Kbuild-use-Wdeclaration-after-statement.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 2fd7e7f9317d3048a14026816d081b08ba98ea8e Mon Sep 17 00:00:00 2001 -From: Mark Rutland -Date: Tue, 8 Mar 2022 22:56:13 +0100 -Subject: [PATCH 1/3] Kbuild: use -Wdeclaration-after-statement - -The kernel is moving from using `-std=gnu89` to `-std=gnu11`, permitting -the use of additional C11 features such as for-loop initial declarations. - -One contentious aspect of C99 is that it permits mixed declarations and -code, and for now at least, it seems preferable to enforce that -declarations must come first. - -These warnings were already enabled in the kernel itself, but not -for KBUILD_USERCFLAGS or the compat VDSO on arch/arm64, which uses -a separate set of CFLAGS. - -This patch fixes an existing violation in modpost.c, which is not -reported because of the missing flag in KBUILD_USERCFLAGS: - -| scripts/mod/modpost.c: In function ‘match’: -| scripts/mod/modpost.c:837:3: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] -| 837 | const char *endp = p + strlen(p) - 1; -| | ^~~~~ - -Signed-off-by: Mark Rutland -[arnd: don't add a duplicate flag to the default set, update changelog] -Signed-off-by: Arnd Bergmann -Reviewed-by: Nathan Chancellor -Reviewed-by: Nick Desaulniers -Tested-by: Sedat Dilek # LLVM/Clang v13.0.0 (x86-64) -Signed-off-by: Masahiro Yamada ---- - Makefile | 3 ++- - arch/arm64/kernel/vdso32/Makefile | 1 + - scripts/mod/modpost.c | 4 +++- - 3 files changed, 6 insertions(+), 2 deletions(-) - ---- a/Makefile -+++ b/Makefile -@@ -440,7 +440,8 @@ endif - HOSTPKG_CONFIG = pkg-config - - export KBUILD_USERCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \ -- -O2 -fomit-frame-pointer -std=gnu89 -+ -O2 -fomit-frame-pointer -std=gnu89 \ -+ -Wdeclaration-after-statement - export KBUILD_USERLDFLAGS := - - KBUILD_HOSTCFLAGS := $(KBUILD_USERCFLAGS) $(HOST_LFS_CFLAGS) $(HOSTCFLAGS) ---- a/arch/arm64/kernel/vdso32/Makefile -+++ b/arch/arm64/kernel/vdso32/Makefile -@@ -76,6 +76,7 @@ VDSO_CFLAGS += -Wall -Wundef -Wstrict-pr - -fno-strict-aliasing -fno-common \ - -Werror-implicit-function-declaration \ - -Wno-format-security \ -+ -Wdeclaration-after-statement \ - -std=gnu89 - VDSO_CFLAGS += -O2 - # Some useful compiler-dependent flags from top-level Makefile ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -833,8 +833,10 @@ static int match(const char *sym, const - { - const char *p; - while (*pat) { -+ const char *endp; -+ - p = *pat++; -- const char *endp = p + strlen(p) - 1; -+ endp = p + strlen(p) - 1; - - /* "*foo*" */ - if (*p == '*' && *endp == '*') { diff --git a/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch b/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch deleted file mode 100644 index 94fc52fd8e0..00000000000 --- a/target/linux/generic/backport-6.1/005-v5.17-02-Kbuild-move-to-std-gnu11.patch +++ /dev/null @@ -1,60 +0,0 @@ -From b810c8e719ea082e47c7a8f7cf878bc84fa2455d Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Tue, 8 Mar 2022 22:56:14 +0100 -Subject: [PATCH 2/3] Kbuild: move to -std=gnu11 - -During a patch discussion, Linus brought up the option of changing -the C standard version from gnu89 to gnu99, which allows using variable -declaration inside of a for() loop. While the C99, C11 and later standards -introduce many other features, most of these are already available in -gnu89 as GNU extensions as well. - -An earlier attempt to do this when gcc-5 started defaulting to --std=gnu11 failed because at the time that caused warnings about -designated initializers with older compilers. Now that gcc-5.1 is -the minimum compiler version used for building kernels, that is no -longer a concern. Similarly, the behavior of 'inline' functions changes -between gnu89 using gnu_inline behavior and gnu11 using standard c99+ -behavior, but this was taken care of by defining 'inline' to include -__attribute__((gnu_inline)) in order to allow building with clang a -while ago. - -Nathan Chancellor reported a new -Wdeclaration-after-statement -warning that appears in a system header on arm, this still needs a -workaround. - -The differences between gnu99, gnu11, gnu1x and gnu17 are fairly -minimal and mainly impact warnings at the -Wpedantic level that the -kernel never enables. Between these, gnu11 is the newest version -that is supported by all supported compiler versions, though it is -only the default on gcc-5, while all other supported versions of -gcc or clang default to gnu1x/gnu17. - -Link: https://lore.kernel.org/lkml/CAHk-=wiyCH7xeHcmiFJ-YgXUy2Jaj7pnkdKpcovt8fYbVFW3TA@mail.gmail.com/ -Link: https://github.com/ClangBuiltLinux/linux/issues/1603 -Suggested-by: Linus Torvalds -Acked-by: Marco Elver -Acked-by: Jani Nikula -Acked-by: David Sterba -Tested-by: Sedat Dilek -Reviewed-by: Alex Shi -Reviewed-by: Nick Desaulniers -Reviewed-by: Miguel Ojeda -Signed-off-by: Arnd Bergmann -Reviewed-by: Nathan Chancellor -Signed-off-by: Masahiro Yamada ---- - Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/Makefile -+++ b/Makefile -@@ -524,7 +524,7 @@ KBUILD_CFLAGS := -Wall -Wundef -Werror - -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE \ - -Werror=implicit-function-declaration -Werror=implicit-int \ - -Werror=return-type -Wno-format-security \ -- -std=gnu89 -+ -std=gnu11 - KBUILD_CPPFLAGS := -D__KERNEL__ - KBUILD_AFLAGS_KERNEL := - KBUILD_CFLAGS_KERNEL := diff --git a/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch b/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch deleted file mode 100644 index e34acbba171..00000000000 --- a/target/linux/generic/backport-6.1/005-v5.17-03-Kbuild-use-std-gnu11-for-KBUILD_USERCFLAGS.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 40337d6f3d677aee7ad3052ae662d3f53dd4d5cb Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Tue, 8 Mar 2022 22:56:15 +0100 -Subject: [PATCH 3/3] Kbuild: use -std=gnu11 for KBUILD_USERCFLAGS - -As we change the C language standard for the kernel from gnu89 to -gnu11, it makes sense to also update the version for user space -compilation. - -Some users have older native compilers than what they use for -kernel builds, so I considered using gnu99 as the default version -for wider compatibility with gcc-4.6 and earlier. - -However, testing with older compilers showed that we already require -HOSTCC version 5.1 as well because a lot of host tools include -linux/compiler.h that uses __has_attribute(): - - CC tools/objtool/exec-cmd.o -In file included from tools/include/linux/compiler_types.h:36:0, - from tools/include/linux/compiler.h:5, - from exec-cmd.c:2: -tools/include/linux/compiler-gcc.h:19:5: error: "__has_attribute" is not defined [-Werror=undef] - -Signed-off-by: Arnd Bergmann -Reviewed-by: Nathan Chancellor -Reviewed-by: Nick Desaulniers -Tested-by: Sedat Dilek -Signed-off-by: Masahiro Yamada ---- - Makefile | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/Makefile -+++ b/Makefile -@@ -440,7 +440,7 @@ endif - HOSTPKG_CONFIG = pkg-config - - export KBUILD_USERCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \ -- -O2 -fomit-frame-pointer -std=gnu89 \ -+ -O2 -fomit-frame-pointer -std=gnu11 \ - -Wdeclaration-after-statement - export KBUILD_USERLDFLAGS := - diff --git a/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch b/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch deleted file mode 100644 index df854ffd3d8..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-01-mm-x86-arm64-add-arch_has_hw_pte_young.patch +++ /dev/null @@ -1,425 +0,0 @@ -From a4103262b01a1b8704b37c01c7c813df91b7b119 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 01:59:58 -0600 -Subject: [PATCH 01/29] mm: x86, arm64: add arch_has_hw_pte_young() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Patch series "Multi-Gen LRU Framework", v14. - -What's new -========== -1. OpenWrt, in addition to Android, Arch Linux Zen, Armbian, ChromeOS, - Liquorix, post-factum and XanMod, is now shipping MGLRU on 5.15. -2. Fixed long-tailed direct reclaim latency seen on high-memory (TBs) - machines. The old direct reclaim backoff, which tries to enforce a - minimum fairness among all eligible memcgs, over-swapped by about - (total_mem>>DEF_PRIORITY)-nr_to_reclaim. The new backoff, which - pulls the plug on swapping once the target is met, trades some - fairness for curtailed latency: - https://lore.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com/ -3. Fixed minior build warnings and conflicts. More comments and nits. - -TLDR -==== -The current page reclaim is too expensive in terms of CPU usage and it -often makes poor choices about what to evict. This patchset offers an -alternative solution that is performant, versatile and -straightforward. - -Patchset overview -================= -The design and implementation overview is in patch 14: -https://lore.kernel.org/r/20220918080010.2920238-15-yuzhao@google.com/ - -01. mm: x86, arm64: add arch_has_hw_pte_young() -02. mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -Take advantage of hardware features when trying to clear the accessed -bit in many PTEs. - -03. mm/vmscan.c: refactor shrink_node() -04. Revert "include/linux/mm_inline.h: fold __update_lru_size() into - its sole caller" -Minor refactors to improve readability for the following patches. - -05. mm: multi-gen LRU: groundwork -Adds the basic data structure and the functions that insert pages to -and remove pages from the multi-gen LRU (MGLRU) lists. - -06. mm: multi-gen LRU: minimal implementation -A minimal implementation without optimizations. - -07. mm: multi-gen LRU: exploit locality in rmap -Exploits spatial locality to improve efficiency when using the rmap. - -08. mm: multi-gen LRU: support page table walks -Further exploits spatial locality by optionally scanning page tables. - -09. mm: multi-gen LRU: optimize multiple memcgs -Optimizes the overall performance for multiple memcgs running mixed -types of workloads. - -10. mm: multi-gen LRU: kill switch -Adds a kill switch to enable or disable MGLRU at runtime. - -11. mm: multi-gen LRU: thrashing prevention -12. mm: multi-gen LRU: debugfs interface -Provide userspace with features like thrashing prevention, working set -estimation and proactive reclaim. - -13. mm: multi-gen LRU: admin guide -14. mm: multi-gen LRU: design doc -Add an admin guide and a design doc. - -Benchmark results -================= -Independent lab results ------------------------ -Based on the popularity of searches [01] and the memory usage in -Google's public cloud, the most popular open-source memory-hungry -applications, in alphabetical order, are: - Apache Cassandra Memcached - Apache Hadoop MongoDB - Apache Spark PostgreSQL - MariaDB (MySQL) Redis - -An independent lab evaluated MGLRU with the most widely used benchmark -suites for the above applications. They posted 960 data points along -with kernel metrics and perf profiles collected over more than 500 -hours of total benchmark time. Their final reports show that, with 95% -confidence intervals (CIs), the above applications all performed -significantly better for at least part of their benchmark matrices. - -On 5.14: -1. Apache Spark [02] took 95% CIs [9.28, 11.19]% and [12.20, 14.93]% - less wall time to sort three billion random integers, respectively, - under the medium- and the high-concurrency conditions, when - overcommitting memory. There were no statistically significant - changes in wall time for the rest of the benchmark matrix. -2. MariaDB [03] achieved 95% CIs [5.24, 10.71]% and [20.22, 25.97]% - more transactions per minute (TPM), respectively, under the medium- - and the high-concurrency conditions, when overcommitting memory. - There were no statistically significant changes in TPM for the rest - of the benchmark matrix. -3. Memcached [04] achieved 95% CIs [23.54, 32.25]%, [20.76, 41.61]% - and [21.59, 30.02]% more operations per second (OPS), respectively, - for sequential access, random access and Gaussian (distribution) - access, when THP=always; 95% CIs [13.85, 15.97]% and - [23.94, 29.92]% more OPS, respectively, for random access and - Gaussian access, when THP=never. There were no statistically - significant changes in OPS for the rest of the benchmark matrix. -4. MongoDB [05] achieved 95% CIs [2.23, 3.44]%, [6.97, 9.73]% and - [2.16, 3.55]% more operations per second (OPS), respectively, for - exponential (distribution) access, random access and Zipfian - (distribution) access, when underutilizing memory; 95% CIs - [8.83, 10.03]%, [21.12, 23.14]% and [5.53, 6.46]% more OPS, - respectively, for exponential access, random access and Zipfian - access, when overcommitting memory. - -On 5.15: -5. Apache Cassandra [06] achieved 95% CIs [1.06, 4.10]%, [1.94, 5.43]% - and [4.11, 7.50]% more operations per second (OPS), respectively, - for exponential (distribution) access, random access and Zipfian - (distribution) access, when swap was off; 95% CIs [0.50, 2.60]%, - [6.51, 8.77]% and [3.29, 6.75]% more OPS, respectively, for - exponential access, random access and Zipfian access, when swap was - on. -6. Apache Hadoop [07] took 95% CIs [5.31, 9.69]% and [2.02, 7.86]% - less average wall time to finish twelve parallel TeraSort jobs, - respectively, under the medium- and the high-concurrency - conditions, when swap was on. There were no statistically - significant changes in average wall time for the rest of the - benchmark matrix. -7. PostgreSQL [08] achieved 95% CI [1.75, 6.42]% more transactions per - minute (TPM) under the high-concurrency condition, when swap was - off; 95% CIs [12.82, 18.69]% and [22.70, 46.86]% more TPM, - respectively, under the medium- and the high-concurrency - conditions, when swap was on. There were no statistically - significant changes in TPM for the rest of the benchmark matrix. -8. Redis [09] achieved 95% CIs [0.58, 5.94]%, [6.55, 14.58]% and - [11.47, 19.36]% more total operations per second (OPS), - respectively, for sequential access, random access and Gaussian - (distribution) access, when THP=always; 95% CIs [1.27, 3.54]%, - [10.11, 14.81]% and [8.75, 13.64]% more total OPS, respectively, - for sequential access, random access and Gaussian access, when - THP=never. - -Our lab results ---------------- -To supplement the above results, we ran the following benchmark suites -on 5.16-rc7 and found no regressions [10]. - fs_fio_bench_hdd_mq pft - fs_lmbench pgsql-hammerdb - fs_parallelio redis - fs_postmark stream - hackbench sysbenchthread - kernbench tpcc_spark - memcached unixbench - multichase vm-scalability - mutilate will-it-scale - nginx - -[01] https://trends.google.com -[02] https://lore.kernel.org/r/20211102002002.92051-1-bot@edi.works/ -[03] https://lore.kernel.org/r/20211009054315.47073-1-bot@edi.works/ -[04] https://lore.kernel.org/r/20211021194103.65648-1-bot@edi.works/ -[05] https://lore.kernel.org/r/20211109021346.50266-1-bot@edi.works/ -[06] https://lore.kernel.org/r/20211202062806.80365-1-bot@edi.works/ -[07] https://lore.kernel.org/r/20211209072416.33606-1-bot@edi.works/ -[08] https://lore.kernel.org/r/20211218071041.24077-1-bot@edi.works/ -[09] https://lore.kernel.org/r/20211122053248.57311-1-bot@edi.works/ -[10] https://lore.kernel.org/r/20220104202247.2903702-1-yuzhao@google.com/ - -Read-world applications -======================= -Third-party testimonials ------------------------- -Konstantin reported [11]: - I have Archlinux with 8G RAM + zswap + swap. While developing, I - have lots of apps opened such as multiple LSP-servers for different - langs, chats, two browsers, etc... Usually, my system gets quickly - to a point of SWAP-storms, where I have to kill LSP-servers, - restart browsers to free memory, etc, otherwise the system lags - heavily and is barely usable. - - 1.5 day ago I migrated from 5.11.15 kernel to 5.12 + the LRU - patchset, and I started up by opening lots of apps to create memory - pressure, and worked for a day like this. Till now I had not a - single SWAP-storm, and mind you I got 3.4G in SWAP. I was never - getting to the point of 3G in SWAP before without a single - SWAP-storm. - -Vaibhav from IBM reported [12]: - In a synthetic MongoDB Benchmark, seeing an average of ~19% - throughput improvement on POWER10(Radix MMU + 64K Page Size) with - MGLRU patches on top of 5.16 kernel for MongoDB + YCSB across - three different request distributions, namely, Exponential, Uniform - and Zipfan. - -Shuang from U of Rochester reported [13]: - With the MGLRU, fio achieved 95% CIs [38.95, 40.26]%, [4.12, 6.64]% - and [9.26, 10.36]% higher throughput, respectively, for random - access, Zipfian (distribution) access and Gaussian (distribution) - access, when the average number of jobs per CPU is 1; 95% CIs - [42.32, 49.15]%, [9.44, 9.89]% and [20.99, 22.86]% higher - throughput, respectively, for random access, Zipfian access and - Gaussian access, when the average number of jobs per CPU is 2. - -Daniel from Michigan Tech reported [14]: - With Memcached allocating ~100GB of byte-addressable Optante, - performance improvement in terms of throughput (measured as queries - per second) was about 10% for a series of workloads. - -Large-scale deployments ------------------------ -We've rolled out MGLRU to tens of millions of ChromeOS users and -about a million Android users. Google's fleetwide profiling [15] shows -an overall 40% decrease in kswapd CPU usage, in addition to -improvements in other UX metrics, e.g., an 85% decrease in the number -of low-memory kills at the 75th percentile and an 18% decrease in -app launch time at the 50th percentile. - -The downstream kernels that have been using MGLRU include: -1. Android [16] -2. Arch Linux Zen [17] -3. Armbian [18] -4. ChromeOS [19] -5. Liquorix [20] -6. OpenWrt [21] -7. post-factum [22] -8. XanMod [23] - -[11] https://lore.kernel.org/r/140226722f2032c86301fbd326d91baefe3d7d23.camel@yandex.ru/ -[12] https://lore.kernel.org/r/87czj3mux0.fsf@vajain21.in.ibm.com/ -[13] https://lore.kernel.org/r/20220105024423.26409-1-szhai2@cs.rochester.edu/ -[14] https://lore.kernel.org/r/CA+4-3vksGvKd18FgRinxhqHetBS1hQekJE2gwco8Ja-bJWKtFw@mail.gmail.com/ -[15] https://dl.acm.org/doi/10.1145/2749469.2750392 -[16] https://android.com -[17] https://archlinux.org -[18] https://armbian.com -[19] https://chromium.org -[20] https://liquorix.net -[21] https://openwrt.org -[22] https://codeberg.org/pf-kernel -[23] https://xanmod.org - -Summary -======= -The facts are: -1. The independent lab results and the real-world applications - indicate substantial improvements; there are no known regressions. -2. Thrashing prevention, working set estimation and proactive reclaim - work out of the box; there are no equivalent solutions. -3. There is a lot of new code; no smaller changes have been - demonstrated similar effects. - -Our options, accordingly, are: -1. Given the amount of evidence, the reported improvements will likely - materialize for a wide range of workloads. -2. Gauging the interest from the past discussions, the new features - will likely be put to use for both personal computers and data - centers. -3. Based on Google's track record, the new code will likely be well - maintained in the long term. It'd be more difficult if not - impossible to achieve similar effects with other approaches. - -This patch (of 14): - -Some architectures automatically set the accessed bit in PTEs, e.g., x86 -and arm64 v8.2. On architectures that do not have this capability, -clearing the accessed bit in a PTE usually triggers a page fault following -the TLB miss of this PTE (to emulate the accessed bit). - -Being aware of this capability can help make better decisions, e.g., -whether to spread the work out over a period of time to reduce bursty page -faults when trying to clear the accessed bit in many PTEs. - -Note that theoretically this capability can be unreliable, e.g., -hotplugged CPUs might be different from builtin ones. Therefore it should -not be used in architecture-independent code that involves correctness, -e.g., to determine whether TLB flushes are required (in combination with -the accessed bit). - -Link: https://lkml.kernel.org/r/20220918080010.2920238-1-yuzhao@google.com -Link: https://lkml.kernel.org/r/20220918080010.2920238-2-yuzhao@google.com -Signed-off-by: Yu Zhao -Reviewed-by: Barry Song -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Acked-by: Will Deacon -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: linux-arm-kernel@lists.infradead.org -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Miaohe Lin -Cc: Mike Rapoport -Cc: Qi Zheng -Signed-off-by: Andrew Morton ---- - arch/arm64/include/asm/pgtable.h | 14 ++------------ - arch/x86/include/asm/pgtable.h | 6 +++--- - include/linux/pgtable.h | 13 +++++++++++++ - mm/memory.c | 14 +------------- - 4 files changed, 19 insertions(+), 28 deletions(-) - ---- a/arch/arm64/include/asm/pgtable.h -+++ b/arch/arm64/include/asm/pgtable.h -@@ -999,23 +999,13 @@ static inline void update_mmu_cache(stru - * page after fork() + CoW for pfn mappings. We don't always have a - * hardware-managed access flag on arm64. - */ --static inline bool arch_faults_on_old_pte(void) --{ -- WARN_ON(preemptible()); -- -- return !cpu_has_hw_af(); --} --#define arch_faults_on_old_pte arch_faults_on_old_pte -+#define arch_has_hw_pte_young cpu_has_hw_af - - /* - * Experimentally, it's cheap to set the access flag in hardware and we - * benefit from prefaulting mappings as 'old' to start with. - */ --static inline bool arch_wants_old_prefaulted_pte(void) --{ -- return !arch_faults_on_old_pte(); --} --#define arch_wants_old_prefaulted_pte arch_wants_old_prefaulted_pte -+#define arch_wants_old_prefaulted_pte cpu_has_hw_af - - #endif /* !__ASSEMBLY__ */ - ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -1397,10 +1397,10 @@ static inline bool arch_has_pfn_modify_c - return boot_cpu_has_bug(X86_BUG_L1TF); - } - --#define arch_faults_on_old_pte arch_faults_on_old_pte --static inline bool arch_faults_on_old_pte(void) -+#define arch_has_hw_pte_young arch_has_hw_pte_young -+static inline bool arch_has_hw_pte_young(void) - { -- return false; -+ return true; - } - - #endif /* __ASSEMBLY__ */ ---- a/include/linux/pgtable.h -+++ b/include/linux/pgtable.h -@@ -259,6 +259,19 @@ static inline int pmdp_clear_flush_young - #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - #endif - -+#ifndef arch_has_hw_pte_young -+/* -+ * Return whether the accessed bit is supported on the local CPU. -+ * -+ * This stub assumes accessing through an old PTE triggers a page fault. -+ * Architectures that automatically set the access bit should overwrite it. -+ */ -+static inline bool arch_has_hw_pte_young(void) -+{ -+ return false; -+} -+#endif -+ - #ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR - static inline pte_t ptep_get_and_clear(struct mm_struct *mm, - unsigned long address, ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -121,18 +121,6 @@ int randomize_va_space __read_mostly = - 2; - #endif - --#ifndef arch_faults_on_old_pte --static inline bool arch_faults_on_old_pte(void) --{ -- /* -- * Those arches which don't have hw access flag feature need to -- * implement their own helper. By default, "true" means pagefault -- * will be hit on old pte. -- */ -- return true; --} --#endif -- - #ifndef arch_wants_old_prefaulted_pte - static inline bool arch_wants_old_prefaulted_pte(void) - { -@@ -2782,7 +2770,7 @@ static inline bool cow_user_page(struct - * On architectures with software "accessed" bits, we would - * take a double page fault, so mark it accessed here. - */ -- if (arch_faults_on_old_pte() && !pte_young(vmf->orig_pte)) { -+ if (!arch_has_hw_pte_young() && !pte_young(vmf->orig_pte)) { - pte_t entry; - - vmf->pte = pte_offset_map_lock(mm, vmf->pmd, addr, &vmf->ptl); diff --git a/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch b/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch deleted file mode 100644 index 9e0430ea2aa..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-02-mm-x86-add-CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 493de1c4b0f2cd909169401da8c445f6c8a7e29d Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 01:59:59 -0600 -Subject: [PATCH 02/29] mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Some architectures support the accessed bit in non-leaf PMD entries, e.g., -x86 sets the accessed bit in a non-leaf PMD entry when using it as part of -linear address translation [1]. Page table walkers that clear the -accessed bit may use this capability to reduce their search space. - -Note that: -1. Although an inline function is preferable, this capability is added - as a configuration option for consistency with the existing macros. -2. Due to the little interest in other varieties, this capability was - only tested on Intel and AMD CPUs. - -Thanks to the following developers for their efforts [2][3]. - Randy Dunlap - Stephen Rothwell - -[1]: Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 3 (June 2021), section 4.8 -[2] https://lore.kernel.org/r/bfdcc7c8-922f-61a9-aa15-7e7250f04af7@infradead.org/ -[3] https://lore.kernel.org/r/20220413151513.5a0d7a7e@canb.auug.org.au/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-3-yuzhao@google.com -Signed-off-by: Yu Zhao -Reviewed-by: Barry Song -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - arch/Kconfig | 8 ++++++++ - arch/x86/Kconfig | 1 + - arch/x86/include/asm/pgtable.h | 3 ++- - arch/x86/mm/pgtable.c | 5 ++++- - include/linux/pgtable.h | 4 ++-- - 5 files changed, 17 insertions(+), 4 deletions(-) - ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -1295,6 +1295,14 @@ config ARCH_HAS_ELFCORE_COMPAT - config ARCH_HAS_PARANOID_L1D_FLUSH - bool - -+config ARCH_HAS_NONLEAF_PMD_YOUNG -+ bool -+ help -+ Architectures that select this option are capable of setting the -+ accessed bit in non-leaf PMD entries when using them as part of linear -+ address translations. Page table walkers that clear the accessed bit -+ may use this capability to reduce their search space. -+ - source "kernel/gcov/Kconfig" - - source "scripts/gcc-plugins/Kconfig" ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -84,6 +84,7 @@ config X86 - select ARCH_HAS_PMEM_API if X86_64 - select ARCH_HAS_PTE_DEVMAP if X86_64 - select ARCH_HAS_PTE_SPECIAL -+ select ARCH_HAS_NONLEAF_PMD_YOUNG if PGTABLE_LEVELS > 2 - select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 - select ARCH_HAS_COPY_MC if X86_64 - select ARCH_HAS_SET_MEMORY ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -817,7 +817,8 @@ static inline unsigned long pmd_page_vad - - static inline int pmd_bad(pmd_t pmd) - { -- return (pmd_flags(pmd) & ~_PAGE_USER) != _KERNPG_TABLE; -+ return (pmd_flags(pmd) & ~(_PAGE_USER | _PAGE_ACCESSED)) != -+ (_KERNPG_TABLE & ~_PAGE_ACCESSED); - } - - static inline unsigned long pages_to_mb(unsigned long npg) ---- a/arch/x86/mm/pgtable.c -+++ b/arch/x86/mm/pgtable.c -@@ -550,7 +550,7 @@ int ptep_test_and_clear_young(struct vm_ - return ret; - } - --#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) - int pmdp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long addr, pmd_t *pmdp) - { -@@ -562,6 +562,9 @@ int pmdp_test_and_clear_young(struct vm_ - - return ret; - } -+#endif -+ -+#ifdef CONFIG_TRANSPARENT_HUGEPAGE - int pudp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long addr, pud_t *pudp) - { ---- a/include/linux/pgtable.h -+++ b/include/linux/pgtable.h -@@ -212,7 +212,7 @@ static inline int ptep_test_and_clear_yo - #endif - - #ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG --#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) - static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp) -@@ -233,7 +233,7 @@ static inline int pmdp_test_and_clear_yo - BUILD_BUG(); - return 0; - } --#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -+#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG */ - #endif - - #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH diff --git a/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch b/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch deleted file mode 100644 index b8d2917d26c..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-03-mm-vmscan.c-refactor-shrink_node.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 9e17efd11450d3d2069adaa3c58db9ac8ebd1c66 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:00 -0600 -Subject: [PATCH 03/29] mm/vmscan.c: refactor shrink_node() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch refactors shrink_node() to improve readability for the upcoming -changes to mm/vmscan.c. - -Link: https://lkml.kernel.org/r/20220918080010.2920238-4-yuzhao@google.com -Signed-off-by: Yu Zhao -Reviewed-by: Barry Song -Reviewed-by: Miaohe Lin -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - mm/vmscan.c | 198 +++++++++++++++++++++++++++------------------------- - 1 file changed, 104 insertions(+), 94 deletions(-) - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -2497,6 +2497,109 @@ enum scan_balance { - SCAN_FILE, - }; - -+static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc) -+{ -+ unsigned long file; -+ struct lruvec *target_lruvec; -+ -+ target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); -+ -+ /* -+ * Flush the memory cgroup stats, so that we read accurate per-memcg -+ * lruvec stats for heuristics. -+ */ -+ mem_cgroup_flush_stats(); -+ -+ /* -+ * Determine the scan balance between anon and file LRUs. -+ */ -+ spin_lock_irq(&target_lruvec->lru_lock); -+ sc->anon_cost = target_lruvec->anon_cost; -+ sc->file_cost = target_lruvec->file_cost; -+ spin_unlock_irq(&target_lruvec->lru_lock); -+ -+ /* -+ * Target desirable inactive:active list ratios for the anon -+ * and file LRU lists. -+ */ -+ if (!sc->force_deactivate) { -+ unsigned long refaults; -+ -+ refaults = lruvec_page_state(target_lruvec, -+ WORKINGSET_ACTIVATE_ANON); -+ if (refaults != target_lruvec->refaults[0] || -+ inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) -+ sc->may_deactivate |= DEACTIVATE_ANON; -+ else -+ sc->may_deactivate &= ~DEACTIVATE_ANON; -+ -+ /* -+ * When refaults are being observed, it means a new -+ * workingset is being established. Deactivate to get -+ * rid of any stale active pages quickly. -+ */ -+ refaults = lruvec_page_state(target_lruvec, -+ WORKINGSET_ACTIVATE_FILE); -+ if (refaults != target_lruvec->refaults[1] || -+ inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) -+ sc->may_deactivate |= DEACTIVATE_FILE; -+ else -+ sc->may_deactivate &= ~DEACTIVATE_FILE; -+ } else -+ sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; -+ -+ /* -+ * If we have plenty of inactive file pages that aren't -+ * thrashing, try to reclaim those first before touching -+ * anonymous pages. -+ */ -+ file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); -+ if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) -+ sc->cache_trim_mode = 1; -+ else -+ sc->cache_trim_mode = 0; -+ -+ /* -+ * Prevent the reclaimer from falling into the cache trap: as -+ * cache pages start out inactive, every cache fault will tip -+ * the scan balance towards the file LRU. And as the file LRU -+ * shrinks, so does the window for rotation from references. -+ * This means we have a runaway feedback loop where a tiny -+ * thrashing file LRU becomes infinitely more attractive than -+ * anon pages. Try to detect this based on file LRU size. -+ */ -+ if (!cgroup_reclaim(sc)) { -+ unsigned long total_high_wmark = 0; -+ unsigned long free, anon; -+ int z; -+ -+ free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); -+ file = node_page_state(pgdat, NR_ACTIVE_FILE) + -+ node_page_state(pgdat, NR_INACTIVE_FILE); -+ -+ for (z = 0; z < MAX_NR_ZONES; z++) { -+ struct zone *zone = &pgdat->node_zones[z]; -+ -+ if (!managed_zone(zone)) -+ continue; -+ -+ total_high_wmark += high_wmark_pages(zone); -+ } -+ -+ /* -+ * Consider anon: if that's low too, this isn't a -+ * runaway file reclaim problem, but rather just -+ * extreme pressure. Reclaim as per usual then. -+ */ -+ anon = node_page_state(pgdat, NR_INACTIVE_ANON); -+ -+ sc->file_is_tiny = -+ file + free <= total_high_wmark && -+ !(sc->may_deactivate & DEACTIVATE_ANON) && -+ anon >> sc->priority; -+ } -+} -+ - /* - * Determine how aggressively the anon and file LRU lists should be - * scanned. The relative value of each set of LRU lists is determined -@@ -2965,109 +3068,16 @@ static void shrink_node(pg_data_t *pgdat - unsigned long nr_reclaimed, nr_scanned; - struct lruvec *target_lruvec; - bool reclaimable = false; -- unsigned long file; - - target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); - - again: -- /* -- * Flush the memory cgroup stats, so that we read accurate per-memcg -- * lruvec stats for heuristics. -- */ -- mem_cgroup_flush_stats(); -- - memset(&sc->nr, 0, sizeof(sc->nr)); - - nr_reclaimed = sc->nr_reclaimed; - nr_scanned = sc->nr_scanned; - -- /* -- * Determine the scan balance between anon and file LRUs. -- */ -- spin_lock_irq(&target_lruvec->lru_lock); -- sc->anon_cost = target_lruvec->anon_cost; -- sc->file_cost = target_lruvec->file_cost; -- spin_unlock_irq(&target_lruvec->lru_lock); -- -- /* -- * Target desirable inactive:active list ratios for the anon -- * and file LRU lists. -- */ -- if (!sc->force_deactivate) { -- unsigned long refaults; -- -- refaults = lruvec_page_state(target_lruvec, -- WORKINGSET_ACTIVATE_ANON); -- if (refaults != target_lruvec->refaults[0] || -- inactive_is_low(target_lruvec, LRU_INACTIVE_ANON)) -- sc->may_deactivate |= DEACTIVATE_ANON; -- else -- sc->may_deactivate &= ~DEACTIVATE_ANON; -- -- /* -- * When refaults are being observed, it means a new -- * workingset is being established. Deactivate to get -- * rid of any stale active pages quickly. -- */ -- refaults = lruvec_page_state(target_lruvec, -- WORKINGSET_ACTIVATE_FILE); -- if (refaults != target_lruvec->refaults[1] || -- inactive_is_low(target_lruvec, LRU_INACTIVE_FILE)) -- sc->may_deactivate |= DEACTIVATE_FILE; -- else -- sc->may_deactivate &= ~DEACTIVATE_FILE; -- } else -- sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE; -- -- /* -- * If we have plenty of inactive file pages that aren't -- * thrashing, try to reclaim those first before touching -- * anonymous pages. -- */ -- file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE); -- if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE)) -- sc->cache_trim_mode = 1; -- else -- sc->cache_trim_mode = 0; -- -- /* -- * Prevent the reclaimer from falling into the cache trap: as -- * cache pages start out inactive, every cache fault will tip -- * the scan balance towards the file LRU. And as the file LRU -- * shrinks, so does the window for rotation from references. -- * This means we have a runaway feedback loop where a tiny -- * thrashing file LRU becomes infinitely more attractive than -- * anon pages. Try to detect this based on file LRU size. -- */ -- if (!cgroup_reclaim(sc)) { -- unsigned long total_high_wmark = 0; -- unsigned long free, anon; -- int z; -- -- free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); -- file = node_page_state(pgdat, NR_ACTIVE_FILE) + -- node_page_state(pgdat, NR_INACTIVE_FILE); -- -- for (z = 0; z < MAX_NR_ZONES; z++) { -- struct zone *zone = &pgdat->node_zones[z]; -- if (!managed_zone(zone)) -- continue; -- -- total_high_wmark += high_wmark_pages(zone); -- } -- -- /* -- * Consider anon: if that's low too, this isn't a -- * runaway file reclaim problem, but rather just -- * extreme pressure. Reclaim as per usual then. -- */ -- anon = node_page_state(pgdat, NR_INACTIVE_ANON); -- -- sc->file_is_tiny = -- file + free <= total_high_wmark && -- !(sc->may_deactivate & DEACTIVATE_ANON) && -- anon >> sc->priority; -- } -+ prepare_scan_count(pgdat, sc); - - shrink_node_memcgs(pgdat, sc); - diff --git a/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch b/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch deleted file mode 100644 index 2f277a56e1c..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-04-Revert-include-linux-mm_inline.h-fold-__update_lru_s.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 03705be42114db7cc5bd6eb7bf7e8703c94d4880 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:01 -0600 -Subject: [PATCH 04/29] Revert "include/linux/mm_inline.h: fold - __update_lru_size() into its sole caller" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This patch undoes the following refactor: commit 289ccba18af4 -("include/linux/mm_inline.h: fold __update_lru_size() into its sole -caller") - -The upcoming changes to include/linux/mm_inline.h will reuse -__update_lru_size(). - -Link: https://lkml.kernel.org/r/20220918080010.2920238-5-yuzhao@google.com -Signed-off-by: Yu Zhao -Reviewed-by: Miaohe Lin -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/mm_inline.h | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -24,7 +24,7 @@ static inline int page_is_file_lru(struc - return !PageSwapBacked(page); - } - --static __always_inline void update_lru_size(struct lruvec *lruvec, -+static __always_inline void __update_lru_size(struct lruvec *lruvec, - enum lru_list lru, enum zone_type zid, - int nr_pages) - { -@@ -33,6 +33,13 @@ static __always_inline void update_lru_s - __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); - __mod_zone_page_state(&pgdat->node_zones[zid], - NR_ZONE_LRU_BASE + lru, nr_pages); -+} -+ -+static __always_inline void update_lru_size(struct lruvec *lruvec, -+ enum lru_list lru, enum zone_type zid, -+ long nr_pages) -+{ -+ __update_lru_size(lruvec, lru, zid, nr_pages); - #ifdef CONFIG_MEMCG - mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages); - #endif diff --git a/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch b/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch deleted file mode 100644 index 237bd84875d..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-05-mm-multi-gen-LRU-groundwork.patch +++ /dev/null @@ -1,807 +0,0 @@ -From a9b328add8422921a0dbbef162730800e16e8cfd Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:02 -0600 -Subject: [PATCH 05/29] mm: multi-gen LRU: groundwork -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Evictable pages are divided into multiple generations for each lruvec. -The youngest generation number is stored in lrugen->max_seq for both -anon and file types as they are aged on an equal footing. The oldest -generation numbers are stored in lrugen->min_seq[] separately for anon -and file types as clean file pages can be evicted regardless of swap -constraints. These three variables are monotonically increasing. - -Generation numbers are truncated into order_base_2(MAX_NR_GENS+1) bits -in order to fit into the gen counter in page->flags. Each truncated -generation number is an index to lrugen->lists[]. The sliding window -technique is used to track at least MIN_NR_GENS and at most -MAX_NR_GENS generations. The gen counter stores a value within [1, -MAX_NR_GENS] while a page is on one of lrugen->lists[]. Otherwise it -stores 0. - -There are two conceptually independent procedures: "the aging", which -produces young generations, and "the eviction", which consumes old -generations. They form a closed-loop system, i.e., "the page reclaim". -Both procedures can be invoked from userspace for the purposes of working -set estimation and proactive reclaim. These techniques are commonly used -to optimize job scheduling (bin packing) in data centers [1][2]. - -To avoid confusion, the terms "hot" and "cold" will be applied to the -multi-gen LRU, as a new convention; the terms "active" and "inactive" will -be applied to the active/inactive LRU, as usual. - -The protection of hot pages and the selection of cold pages are based -on page access channels and patterns. There are two access channels: -one through page tables and the other through file descriptors. The -protection of the former channel is by design stronger because: -1. The uncertainty in determining the access patterns of the former - channel is higher due to the approximation of the accessed bit. -2. The cost of evicting the former channel is higher due to the TLB - flushes required and the likelihood of encountering the dirty bit. -3. The penalty of underprotecting the former channel is higher because - applications usually do not prepare themselves for major page - faults like they do for blocked I/O. E.g., GUI applications - commonly use dedicated I/O threads to avoid blocking rendering - threads. - -There are also two access patterns: one with temporal locality and the -other without. For the reasons listed above, the former channel is -assumed to follow the former pattern unless VM_SEQ_READ or VM_RAND_READ is -present; the latter channel is assumed to follow the latter pattern unless -outlying refaults have been observed [3][4]. - -The next patch will address the "outlying refaults". Three macros, i.e., -LRU_REFS_WIDTH, LRU_REFS_PGOFF and LRU_REFS_MASK, used later are added in -this patch to make the entire patchset less diffy. - -A page is added to the youngest generation on faulting. The aging needs -to check the accessed bit at least twice before handing this page over to -the eviction. The first check takes care of the accessed bit set on the -initial fault; the second check makes sure this page has not been used -since then. This protocol, AKA second chance, requires a minimum of two -generations, hence MIN_NR_GENS. - -[1] https://dl.acm.org/doi/10.1145/3297858.3304053 -[2] https://dl.acm.org/doi/10.1145/3503222.3507731 -[3] https://lwn.net/Articles/495543/ -[4] https://lwn.net/Articles/815342/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-6-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - fs/fuse/dev.c | 3 +- - include/linux/mm.h | 2 + - include/linux/mm_inline.h | 177 +++++++++++++++++++++++++++++- - include/linux/mmzone.h | 100 +++++++++++++++++ - include/linux/page-flags-layout.h | 13 ++- - include/linux/page-flags.h | 4 +- - include/linux/sched.h | 4 + - kernel/bounds.c | 5 + - mm/Kconfig | 8 ++ - mm/huge_memory.c | 3 +- - mm/memcontrol.c | 2 + - mm/memory.c | 25 +++++ - mm/mm_init.c | 6 +- - mm/mmzone.c | 2 + - mm/swap.c | 10 +- - mm/vmscan.c | 75 +++++++++++++ - 16 files changed, 425 insertions(+), 14 deletions(-) - ---- a/fs/fuse/dev.c -+++ b/fs/fuse/dev.c -@@ -785,7 +785,8 @@ static int fuse_check_page(struct page * - 1 << PG_active | - 1 << PG_workingset | - 1 << PG_reclaim | -- 1 << PG_waiters))) { -+ 1 << PG_waiters | -+ LRU_GEN_MASK | LRU_REFS_MASK))) { - dump_page(page, "fuse: trying to steal weird page"); - return 1; - } ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -1093,6 +1093,8 @@ vm_fault_t finish_mkwrite_fault(struct v - #define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) - #define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) - #define KASAN_TAG_PGOFF (LAST_CPUPID_PGOFF - KASAN_TAG_WIDTH) -+#define LRU_GEN_PGOFF (KASAN_TAG_PGOFF - LRU_GEN_WIDTH) -+#define LRU_REFS_PGOFF (LRU_GEN_PGOFF - LRU_REFS_WIDTH) - - /* - * Define the bit shifts to access each section. For non-existent ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -26,10 +26,13 @@ static inline int page_is_file_lru(struc - - static __always_inline void __update_lru_size(struct lruvec *lruvec, - enum lru_list lru, enum zone_type zid, -- int nr_pages) -+ long nr_pages) - { - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - -+ lockdep_assert_held(&lruvec->lru_lock); -+ WARN_ON_ONCE(nr_pages != (int)nr_pages); -+ - __mod_lruvec_state(lruvec, NR_LRU_BASE + lru, nr_pages); - __mod_zone_page_state(&pgdat->node_zones[zid], - NR_ZONE_LRU_BASE + lru, nr_pages); -@@ -86,11 +89,177 @@ static __always_inline enum lru_list pag - return lru; - } - -+#ifdef CONFIG_LRU_GEN -+ -+static inline bool lru_gen_enabled(void) -+{ -+ return true; -+} -+ -+static inline bool lru_gen_in_fault(void) -+{ -+ return current->in_lru_fault; -+} -+ -+static inline int lru_gen_from_seq(unsigned long seq) -+{ -+ return seq % MAX_NR_GENS; -+} -+ -+static inline int page_lru_gen(struct page *page) -+{ -+ unsigned long flags = READ_ONCE(page->flags); -+ -+ return ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+} -+ -+static inline bool lru_gen_is_active(struct lruvec *lruvec, int gen) -+{ -+ unsigned long max_seq = lruvec->lrugen.max_seq; -+ -+ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); -+ -+ /* see the comment on MIN_NR_GENS */ -+ return gen == lru_gen_from_seq(max_seq) || gen == lru_gen_from_seq(max_seq - 1); -+} -+ -+static inline void lru_gen_update_size(struct lruvec *lruvec, struct page *page, -+ int old_gen, int new_gen) -+{ -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int delta = thp_nr_pages(page); -+ enum lru_list lru = type * LRU_INACTIVE_FILE; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); -+ VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); -+ VM_WARN_ON_ONCE(old_gen == -1 && new_gen == -1); -+ -+ if (old_gen >= 0) -+ WRITE_ONCE(lrugen->nr_pages[old_gen][type][zone], -+ lrugen->nr_pages[old_gen][type][zone] - delta); -+ if (new_gen >= 0) -+ WRITE_ONCE(lrugen->nr_pages[new_gen][type][zone], -+ lrugen->nr_pages[new_gen][type][zone] + delta); -+ -+ /* addition */ -+ if (old_gen < 0) { -+ if (lru_gen_is_active(lruvec, new_gen)) -+ lru += LRU_ACTIVE; -+ __update_lru_size(lruvec, lru, zone, delta); -+ return; -+ } -+ -+ /* deletion */ -+ if (new_gen < 0) { -+ if (lru_gen_is_active(lruvec, old_gen)) -+ lru += LRU_ACTIVE; -+ __update_lru_size(lruvec, lru, zone, -delta); -+ return; -+ } -+} -+ -+static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) -+{ -+ unsigned long seq; -+ unsigned long flags; -+ int gen = page_lru_gen(page); -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ VM_WARN_ON_ONCE_PAGE(gen != -1, page); -+ -+ if (PageUnevictable(page)) -+ return false; -+ /* -+ * There are three common cases for this page: -+ * 1. If it's hot, e.g., freshly faulted in or previously hot and -+ * migrated, add it to the youngest generation. -+ * 2. If it's cold but can't be evicted immediately, i.e., an anon page -+ * not in swapcache or a dirty page pending writeback, add it to the -+ * second oldest generation. -+ * 3. Everything else (clean, cold) is added to the oldest generation. -+ */ -+ if (PageActive(page)) -+ seq = lrugen->max_seq; -+ else if ((type == LRU_GEN_ANON && !PageSwapCache(page)) || -+ (PageReclaim(page) && -+ (PageDirty(page) || PageWriteback(page)))) -+ seq = lrugen->min_seq[type] + 1; -+ else -+ seq = lrugen->min_seq[type]; -+ -+ gen = lru_gen_from_seq(seq); -+ flags = (gen + 1UL) << LRU_GEN_PGOFF; -+ /* see the comment on MIN_NR_GENS about PG_active */ -+ set_mask_bits(&page->flags, LRU_GEN_MASK | BIT(PG_active), flags); -+ -+ lru_gen_update_size(lruvec, page, -1, gen); -+ /* for rotate_reclaimable_page() */ -+ if (reclaiming) -+ list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); -+ else -+ list_add(&page->lru, &lrugen->lists[gen][type][zone]); -+ -+ return true; -+} -+ -+static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) -+{ -+ unsigned long flags; -+ int gen = page_lru_gen(page); -+ -+ if (gen < 0) -+ return false; -+ -+ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); -+ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); -+ -+ /* for migrate_page_states() */ -+ flags = !reclaiming && lru_gen_is_active(lruvec, gen) ? BIT(PG_active) : 0; -+ flags = set_mask_bits(&page->flags, LRU_GEN_MASK, flags); -+ gen = ((flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+ -+ lru_gen_update_size(lruvec, page, gen, -1); -+ list_del(&page->lru); -+ -+ return true; -+} -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static inline bool lru_gen_enabled(void) -+{ -+ return false; -+} -+ -+static inline bool lru_gen_in_fault(void) -+{ -+ return false; -+} -+ -+static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) -+{ -+ return false; -+} -+ -+static inline bool lru_gen_del_page(struct lruvec *lruvec, struct page *page, bool reclaiming) -+{ -+ return false; -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec) - { - enum lru_list lru = page_lru(page); - -+ if (lru_gen_add_page(lruvec, page, false)) -+ return; -+ - update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); - list_add(&page->lru, &lruvec->lists[lru]); - } -@@ -100,6 +269,9 @@ static __always_inline void add_page_to_ - { - enum lru_list lru = page_lru(page); - -+ if (lru_gen_add_page(lruvec, page, true)) -+ return; -+ - update_lru_size(lruvec, lru, page_zonenum(page), thp_nr_pages(page)); - list_add_tail(&page->lru, &lruvec->lists[lru]); - } -@@ -107,6 +279,9 @@ static __always_inline void add_page_to_ - static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec) - { -+ if (lru_gen_del_page(lruvec, page, false)) -+ return; -+ - list_del(&page->lru); - update_lru_size(lruvec, page_lru(page), page_zonenum(page), - -thp_nr_pages(page)); ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -294,6 +294,102 @@ enum lruvec_flags { - */ - }; - -+#endif /* !__GENERATING_BOUNDS_H */ -+ -+/* -+ * Evictable pages are divided into multiple generations. The youngest and the -+ * oldest generation numbers, max_seq and min_seq, are monotonically increasing. -+ * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An -+ * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the -+ * corresponding generation. The gen counter in page->flags stores gen+1 while -+ * a page is on one of lrugen->lists[]. Otherwise it stores 0. -+ * -+ * A page is added to the youngest generation on faulting. The aging needs to -+ * check the accessed bit at least twice before handing this page over to the -+ * eviction. The first check takes care of the accessed bit set on the initial -+ * fault; the second check makes sure this page hasn't been used since then. -+ * This process, AKA second chance, requires a minimum of two generations, -+ * hence MIN_NR_GENS. And to maintain ABI compatibility with the active/inactive -+ * LRU, e.g., /proc/vmstat, these two generations are considered active; the -+ * rest of generations, if they exist, are considered inactive. See -+ * lru_gen_is_active(). -+ * -+ * PG_active is always cleared while a page is on one of lrugen->lists[] so that -+ * the aging needs not to worry about it. And it's set again when a page -+ * considered active is isolated for non-reclaiming purposes, e.g., migration. -+ * See lru_gen_add_page() and lru_gen_del_page(). -+ * -+ * MAX_NR_GENS is set to 4 so that the multi-gen LRU can support twice the -+ * number of categories of the active/inactive LRU when keeping track of -+ * accesses through page tables. This requires order_base_2(MAX_NR_GENS+1) bits -+ * in page->flags. -+ */ -+#define MIN_NR_GENS 2U -+#define MAX_NR_GENS 4U -+ -+#ifndef __GENERATING_BOUNDS_H -+ -+struct lruvec; -+ -+#define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) -+#define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) -+ -+#ifdef CONFIG_LRU_GEN -+ -+enum { -+ LRU_GEN_ANON, -+ LRU_GEN_FILE, -+}; -+ -+/* -+ * The youngest generation number is stored in max_seq for both anon and file -+ * types as they are aged on an equal footing. The oldest generation numbers are -+ * stored in min_seq[] separately for anon and file types as clean file pages -+ * can be evicted regardless of swap constraints. -+ * -+ * Normally anon and file min_seq are in sync. But if swapping is constrained, -+ * e.g., out of swap space, file min_seq is allowed to advance and leave anon -+ * min_seq behind. -+ * -+ * The number of pages in each generation is eventually consistent and therefore -+ * can be transiently negative. -+ */ -+struct lru_gen_struct { -+ /* the aging increments the youngest generation number */ -+ unsigned long max_seq; -+ /* the eviction increments the oldest generation numbers */ -+ unsigned long min_seq[ANON_AND_FILE]; -+ /* the multi-gen LRU lists, lazily sorted on eviction */ -+ struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* the multi-gen LRU sizes, eventually consistent */ -+ long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+}; -+ -+void lru_gen_init_lruvec(struct lruvec *lruvec); -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_init_memcg(struct mem_cgroup *memcg); -+void lru_gen_exit_memcg(struct mem_cgroup *memcg); -+#endif -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static inline void lru_gen_init_lruvec(struct lruvec *lruvec) -+{ -+} -+ -+#ifdef CONFIG_MEMCG -+static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) -+{ -+} -+ -+static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) -+{ -+} -+#endif -+ -+#endif /* CONFIG_LRU_GEN */ -+ - struct lruvec { - struct list_head lists[NR_LRU_LISTS]; - /* per lruvec lru_lock for memcg */ -@@ -311,6 +407,10 @@ struct lruvec { - unsigned long refaults[ANON_AND_FILE]; - /* Various lruvec state flags (enum lruvec_flags) */ - unsigned long flags; -+#ifdef CONFIG_LRU_GEN -+ /* evictable pages divided into generations */ -+ struct lru_gen_struct lrugen; -+#endif - #ifdef CONFIG_MEMCG - struct pglist_data *pgdat; - #endif ---- a/include/linux/page-flags-layout.h -+++ b/include/linux/page-flags-layout.h -@@ -55,7 +55,8 @@ - #define SECTIONS_WIDTH 0 - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_SHIFT \ -+ <= BITS_PER_LONG - NR_PAGEFLAGS - #define NODES_WIDTH NODES_SHIFT - #elif defined(CONFIG_SPARSEMEM_VMEMMAP) - #error "Vmemmap: No space for nodes field in page flags" -@@ -89,8 +90,8 @@ - #define LAST_CPUPID_SHIFT 0 - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT \ -- <= BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ -+ KASAN_TAG_WIDTH + LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS - #define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT - #else - #define LAST_CPUPID_WIDTH 0 -@@ -100,10 +101,12 @@ - #define LAST_CPUPID_NOT_IN_PAGE_FLAGS - #endif - --#if ZONES_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH \ -- > BITS_PER_LONG - NR_PAGEFLAGS -+#if ZONES_WIDTH + LRU_GEN_WIDTH + SECTIONS_WIDTH + NODES_WIDTH + \ -+ KASAN_TAG_WIDTH + LAST_CPUPID_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS - #error "Not enough bits in page flags" - #endif - -+#define LRU_REFS_WIDTH 0 -+ - #endif - #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ ---- a/include/linux/page-flags.h -+++ b/include/linux/page-flags.h -@@ -845,7 +845,7 @@ static inline void ClearPageSlabPfmemall - 1UL << PG_private | 1UL << PG_private_2 | \ - 1UL << PG_writeback | 1UL << PG_reserved | \ - 1UL << PG_slab | 1UL << PG_active | \ -- 1UL << PG_unevictable | __PG_MLOCKED) -+ 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) - - /* - * Flags checked when a page is prepped for return by the page allocator. -@@ -856,7 +856,7 @@ static inline void ClearPageSlabPfmemall - * alloc-free cycle to prevent from reusing the page. - */ - #define PAGE_FLAGS_CHECK_AT_PREP \ -- (PAGEFLAGS_MASK & ~__PG_HWPOISON) -+ ((PAGEFLAGS_MASK & ~__PG_HWPOISON) | LRU_GEN_MASK | LRU_REFS_MASK) - - #define PAGE_FLAGS_PRIVATE \ - (1UL << PG_private | 1UL << PG_private_2) ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -911,6 +911,10 @@ struct task_struct { - #ifdef CONFIG_MEMCG - unsigned in_user_fault:1; - #endif -+#ifdef CONFIG_LRU_GEN -+ /* whether the LRU algorithm may apply to this access */ -+ unsigned in_lru_fault:1; -+#endif - #ifdef CONFIG_COMPAT_BRK - unsigned brk_randomized:1; - #endif ---- a/kernel/bounds.c -+++ b/kernel/bounds.c -@@ -22,6 +22,11 @@ int main(void) - DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); - #endif - DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); -+#ifdef CONFIG_LRU_GEN -+ DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); -+#else -+ DEFINE(LRU_GEN_WIDTH, 0); -+#endif - /* End of constants */ - - return 0; ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -897,6 +897,14 @@ config IO_MAPPING - config SECRETMEM - def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED - -+config LRU_GEN -+ bool "Multi-Gen LRU" -+ depends on MMU -+ # make sure page->flags has enough spare bits -+ depends on 64BIT || !SPARSEMEM || SPARSEMEM_VMEMMAP -+ help -+ A high performance LRU implementation to overcommit memory. -+ - source "mm/damon/Kconfig" - - endmenu ---- a/mm/huge_memory.c -+++ b/mm/huge_memory.c -@@ -2366,7 +2366,8 @@ static void __split_huge_page_tail(struc - #ifdef CONFIG_64BIT - (1L << PG_arch_2) | - #endif -- (1L << PG_dirty))); -+ (1L << PG_dirty) | -+ LRU_GEN_MASK | LRU_REFS_MASK)); - - /* ->mapping in first tail page is compound_mapcount */ - VM_BUG_ON_PAGE(tail > 2 && page_tail->mapping != TAIL_MAPPING, ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -5178,6 +5178,7 @@ static void __mem_cgroup_free(struct mem - - static void mem_cgroup_free(struct mem_cgroup *memcg) - { -+ lru_gen_exit_memcg(memcg); - memcg_wb_domain_exit(memcg); - __mem_cgroup_free(memcg); - } -@@ -5241,6 +5242,7 @@ static struct mem_cgroup *mem_cgroup_all - memcg->deferred_split_queue.split_queue_len = 0; - #endif - idr_replace(&mem_cgroup_idr, memcg, memcg->id.id); -+ lru_gen_init_memcg(memcg); - return memcg; - fail: - mem_cgroup_id_remove(memcg); ---- a/mm/memory.c -+++ b/mm/memory.c -@@ -4792,6 +4792,27 @@ static inline void mm_account_fault(stru - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs, address); - } - -+#ifdef CONFIG_LRU_GEN -+static void lru_gen_enter_fault(struct vm_area_struct *vma) -+{ -+ /* the LRU algorithm doesn't apply to sequential or random reads */ -+ current->in_lru_fault = !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)); -+} -+ -+static void lru_gen_exit_fault(void) -+{ -+ current->in_lru_fault = false; -+} -+#else -+static void lru_gen_enter_fault(struct vm_area_struct *vma) -+{ -+} -+ -+static void lru_gen_exit_fault(void) -+{ -+} -+#endif /* CONFIG_LRU_GEN */ -+ - /* - * By the time we get here, we already hold the mm semaphore - * -@@ -4823,11 +4844,15 @@ vm_fault_t handle_mm_fault(struct vm_are - if (flags & FAULT_FLAG_USER) - mem_cgroup_enter_user_fault(); - -+ lru_gen_enter_fault(vma); -+ - if (unlikely(is_vm_hugetlb_page(vma))) - ret = hugetlb_fault(vma->vm_mm, vma, address, flags); - else - ret = __handle_mm_fault(vma, address, flags); - -+ lru_gen_exit_fault(); -+ - if (flags & FAULT_FLAG_USER) { - mem_cgroup_exit_user_fault(); - /* ---- a/mm/mm_init.c -+++ b/mm/mm_init.c -@@ -65,14 +65,16 @@ void __init mminit_verify_pageflags_layo - - shift = 8 * sizeof(unsigned long); - width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH -- - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH; -+ - LAST_CPUPID_SHIFT - KASAN_TAG_WIDTH - LRU_GEN_WIDTH - LRU_REFS_WIDTH; - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", -- "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Flags %d\n", -+ "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d Gen %d Tier %d Flags %d\n", - SECTIONS_WIDTH, - NODES_WIDTH, - ZONES_WIDTH, - LAST_CPUPID_WIDTH, - KASAN_TAG_WIDTH, -+ LRU_GEN_WIDTH, -+ LRU_REFS_WIDTH, - NR_PAGEFLAGS); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", - "Section %d Node %d Zone %d Lastcpupid %d Kasantag %d\n", ---- a/mm/mmzone.c -+++ b/mm/mmzone.c -@@ -81,6 +81,8 @@ void lruvec_init(struct lruvec *lruvec) - - for_each_lru(lru) - INIT_LIST_HEAD(&lruvec->lists[lru]); -+ -+ lru_gen_init_lruvec(lruvec); - } - - #if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -446,6 +446,11 @@ void lru_cache_add(struct page *page) - VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); - VM_BUG_ON_PAGE(PageLRU(page), page); - -+ /* see the comment in lru_gen_add_page() */ -+ if (lru_gen_enabled() && !PageUnevictable(page) && -+ lru_gen_in_fault() && !(current->flags & PF_MEMALLOC)) -+ SetPageActive(page); -+ - get_page(page); - local_lock(&lru_pvecs.lock); - pvec = this_cpu_ptr(&lru_pvecs.lru_add); -@@ -547,7 +552,7 @@ static void lru_deactivate_file_fn(struc - - static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec) - { -- if (PageActive(page) && !PageUnevictable(page)) { -+ if (!PageUnevictable(page) && (PageActive(page) || lru_gen_enabled())) { - int nr_pages = thp_nr_pages(page); - - del_page_from_lru_list(page, lruvec); -@@ -661,7 +666,8 @@ void deactivate_file_page(struct page *p - */ - void deactivate_page(struct page *page) - { -- if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { -+ if (PageLRU(page) && !PageUnevictable(page) && -+ (PageActive(page) || lru_gen_enabled())) { - struct pagevec *pvec; - - local_lock(&lru_pvecs.lock); ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -2821,6 +2821,81 @@ static bool can_age_anon_pages(struct pg - return can_demote(pgdat->node_id, sc); - } - -+#ifdef CONFIG_LRU_GEN -+ -+/****************************************************************************** -+ * shorthand helpers -+ ******************************************************************************/ -+ -+#define for_each_gen_type_zone(gen, type, zone) \ -+ for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ -+ for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ -+ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) -+ -+static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) -+{ -+ struct pglist_data *pgdat = NODE_DATA(nid); -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) { -+ struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; -+ -+ /* for hotadd_new_pgdat() */ -+ if (!lruvec->pgdat) -+ lruvec->pgdat = pgdat; -+ -+ return lruvec; -+ } -+#endif -+ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); -+ -+ return pgdat ? &pgdat->__lruvec : NULL; -+} -+ -+/****************************************************************************** -+ * initialization -+ ******************************************************************************/ -+ -+void lru_gen_init_lruvec(struct lruvec *lruvec) -+{ -+ int gen, type, zone; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ lrugen->max_seq = MIN_NR_GENS + 1; -+ -+ for_each_gen_type_zone(gen, type, zone) -+ INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -+} -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_init_memcg(struct mem_cgroup *memcg) -+{ -+} -+ -+void lru_gen_exit_memcg(struct mem_cgroup *memcg) -+{ -+ int nid; -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(memcg, nid); -+ -+ VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, -+ sizeof(lruvec->lrugen.nr_pages))); -+ } -+} -+#endif -+ -+static int __init init_lru_gen(void) -+{ -+ BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); -+ BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); -+ -+ return 0; -+}; -+late_initcall(init_lru_gen); -+ -+#endif /* CONFIG_LRU_GEN */ -+ - static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) - { - unsigned long nr[NR_LRU_LISTS]; diff --git a/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch b/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch deleted file mode 100644 index f8a7d9bd7f6..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-06-mm-multi-gen-LRU-minimal-implementation.patch +++ /dev/null @@ -1,1447 +0,0 @@ -From b564b9471cd60ef1ee3961a224898ce4a9620d84 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:03 -0600 -Subject: [PATCH 06/29] mm: multi-gen LRU: minimal implementation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To avoid confusion, the terms "promotion" and "demotion" will be applied -to the multi-gen LRU, as a new convention; the terms "activation" and -"deactivation" will be applied to the active/inactive LRU, as usual. - -The aging produces young generations. Given an lruvec, it increments -max_seq when max_seq-min_seq+1 approaches MIN_NR_GENS. The aging promotes -hot pages to the youngest generation when it finds them accessed through -page tables; the demotion of cold pages happens consequently when it -increments max_seq. Promotion in the aging path does not involve any LRU -list operations, only the updates of the gen counter and -lrugen->nr_pages[]; demotion, unless as the result of the increment of -max_seq, requires LRU list operations, e.g., lru_deactivate_fn(). The -aging has the complexity O(nr_hot_pages), since it is only interested in -hot pages. - -The eviction consumes old generations. Given an lruvec, it increments -min_seq when lrugen->lists[] indexed by min_seq%MAX_NR_GENS becomes empty. -A feedback loop modeled after the PID controller monitors refaults over -anon and file types and decides which type to evict when both types are -available from the same generation. - -The protection of pages accessed multiple times through file descriptors -takes place in the eviction path. Each generation is divided into -multiple tiers. A page accessed N times through file descriptors is in -tier order_base_2(N). Tiers do not have dedicated lrugen->lists[], only -bits in page->flags. The aforementioned feedback loop also monitors -refaults over all tiers and decides when to protect pages in which tiers -(N>1), using the first tier (N=0,1) as a baseline. The first tier -contains single-use unmapped clean pages, which are most likely the best -choices. In contrast to promotion in the aging path, the protection of a -page in the eviction path is achieved by moving this page to the next -generation, i.e., min_seq+1, if the feedback loop decides so. This -approach has the following advantages: - -1. It removes the cost of activation in the buffered access path by - inferring whether pages accessed multiple times through file - descriptors are statistically hot and thus worth protecting in the - eviction path. -2. It takes pages accessed through page tables into account and avoids - overprotecting pages accessed multiple times through file - descriptors. (Pages accessed through page tables are in the first - tier, since N=0.) -3. More tiers provide better protection for pages accessed more than - twice through file descriptors, when under heavy buffered I/O - workloads. - -Server benchmark results: - Single workload: - fio (buffered I/O): +[30, 32]% - IOPS BW - 5.19-rc1: 2673k 10.2GiB/s - patch1-6: 3491k 13.3GiB/s - - Single workload: - memcached (anon): -[4, 6]% - Ops/sec KB/sec - 5.19-rc1: 1161501.04 45177.25 - patch1-6: 1106168.46 43025.04 - - Configurations: - CPU: two Xeon 6154 - Mem: total 256G - - Node 1 was only used as a ram disk to reduce the variance in the - results. - - patch drivers/block/brd.c < gfp_flags = GFP_NOIO | __GFP_ZERO | __GFP_HIGHMEM | __GFP_THISNODE; - > page = alloc_pages_node(1, gfp_flags, 0); - EOF - - cat >>/etc/systemd/system.conf <>/etc/memcached.conf </sys/fs/cgroup/user.slice/test/memory.max - echo $$ >/sys/fs/cgroup/user.slice/test/cgroup.procs - fio -name=mglru --numjobs=72 --directory=/mnt --size=1408m \ - --buffered=1 --ioengine=io_uring --iodepth=128 \ - --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ - --rw=randread --random_distribution=random --norandommap \ - --time_based --ramp_time=10m --runtime=5m --group_reporting - - cat memcached.sh - modprobe brd rd_nr=1 rd_size=113246208 - swapoff -a - mkswap /dev/ram0 - swapon /dev/ram0 - - memtier_benchmark -S /var/run/memcached/memcached.sock \ - -P memcache_binary -n allkeys --key-minimum=1 \ - --key-maximum=65000000 --key-pattern=P:P -c 1 -t 36 \ - --ratio 1:0 --pipeline 8 -d 2000 - - memtier_benchmark -S /var/run/memcached/memcached.sock \ - -P memcache_binary -n allkeys --key-minimum=1 \ - --key-maximum=65000000 --key-pattern=R:R -c 1 -t 36 \ - --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed - -Client benchmark results: - kswapd profiles: - 5.19-rc1 - 40.33% page_vma_mapped_walk (overhead) - 21.80% lzo1x_1_do_compress (real work) - 7.53% do_raw_spin_lock - 3.95% _raw_spin_unlock_irq - 2.52% vma_interval_tree_iter_next - 2.37% page_referenced_one - 2.28% vma_interval_tree_subtree_search - 1.97% anon_vma_interval_tree_iter_first - 1.60% ptep_clear_flush - 1.06% __zram_bvec_write - - patch1-6 - 39.03% lzo1x_1_do_compress (real work) - 18.47% page_vma_mapped_walk (overhead) - 6.74% _raw_spin_unlock_irq - 3.97% do_raw_spin_lock - 2.49% ptep_clear_flush - 2.48% anon_vma_interval_tree_iter_first - 1.92% page_referenced_one - 1.88% __zram_bvec_write - 1.48% memmove - 1.31% vma_interval_tree_iter_next - - Configurations: - CPU: single Snapdragon 7c - Mem: total 4G - - ChromeOS MemoryPressure [1] - -[1] https://chromium.googlesource.com/chromiumos/platform/tast-tests/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-7-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/mm_inline.h | 36 ++ - include/linux/mmzone.h | 41 ++ - include/linux/page-flags-layout.h | 5 +- - kernel/bounds.c | 2 + - mm/Kconfig | 11 + - mm/swap.c | 39 ++ - mm/vmscan.c | 792 +++++++++++++++++++++++++++++- - mm/workingset.c | 110 ++++- - 8 files changed, 1025 insertions(+), 11 deletions(-) - ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -106,6 +106,33 @@ static inline int lru_gen_from_seq(unsig - return seq % MAX_NR_GENS; - } - -+static inline int lru_hist_from_seq(unsigned long seq) -+{ -+ return seq % NR_HIST_GENS; -+} -+ -+static inline int lru_tier_from_refs(int refs) -+{ -+ VM_WARN_ON_ONCE(refs > BIT(LRU_REFS_WIDTH)); -+ -+ /* see the comment in page_lru_refs() */ -+ return order_base_2(refs + 1); -+} -+ -+static inline int page_lru_refs(struct page *page) -+{ -+ unsigned long flags = READ_ONCE(page->flags); -+ bool workingset = flags & BIT(PG_workingset); -+ -+ /* -+ * Return the number of accesses beyond PG_referenced, i.e., N-1 if the -+ * total number of accesses is N>1, since N=0,1 both map to the first -+ * tier. lru_tier_from_refs() will account for this off-by-one. Also see -+ * the comment on MAX_NR_TIERS. -+ */ -+ return ((flags & LRU_REFS_MASK) >> LRU_REFS_PGOFF) + workingset; -+} -+ - static inline int page_lru_gen(struct page *page) - { - unsigned long flags = READ_ONCE(page->flags); -@@ -158,6 +185,15 @@ static inline void lru_gen_update_size(s - __update_lru_size(lruvec, lru, zone, -delta); - return; - } -+ -+ /* promotion */ -+ if (!lru_gen_is_active(lruvec, old_gen) && lru_gen_is_active(lruvec, new_gen)) { -+ __update_lru_size(lruvec, lru, zone, -delta); -+ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, delta); -+ } -+ -+ /* demotion requires isolation, e.g., lru_deactivate_fn() */ -+ VM_WARN_ON_ONCE(lru_gen_is_active(lruvec, old_gen) && !lru_gen_is_active(lruvec, new_gen)); - } - - static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -327,6 +327,28 @@ enum lruvec_flags { - #define MIN_NR_GENS 2U - #define MAX_NR_GENS 4U - -+/* -+ * Each generation is divided into multiple tiers. A page accessed N times -+ * through file descriptors is in tier order_base_2(N). A page in the first tier -+ * (N=0,1) is marked by PG_referenced unless it was faulted in through page -+ * tables or read ahead. A page in any other tier (N>1) is marked by -+ * PG_referenced and PG_workingset. This implies a minimum of two tiers is -+ * supported without using additional bits in page->flags. -+ * -+ * In contrast to moving across generations which requires the LRU lock, moving -+ * across tiers only involves atomic operations on page->flags and therefore -+ * has a negligible cost in the buffered access path. In the eviction path, -+ * comparisons of refaulted/(evicted+protected) from the first tier and the -+ * rest infer whether pages accessed multiple times through file descriptors -+ * are statistically hot and thus worth protecting. -+ * -+ * MAX_NR_TIERS is set to 4 so that the multi-gen LRU can support twice the -+ * number of categories of the active/inactive LRU when keeping track of -+ * accesses through file descriptors. This uses MAX_NR_TIERS-2 spare bits in -+ * page->flags. -+ */ -+#define MAX_NR_TIERS 4U -+ - #ifndef __GENERATING_BOUNDS_H - - struct lruvec; -@@ -341,6 +363,16 @@ enum { - LRU_GEN_FILE, - }; - -+#define MIN_LRU_BATCH BITS_PER_LONG -+#define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) -+ -+/* whether to keep historical stats from evicted generations */ -+#ifdef CONFIG_LRU_GEN_STATS -+#define NR_HIST_GENS MAX_NR_GENS -+#else -+#define NR_HIST_GENS 1U -+#endif -+ - /* - * The youngest generation number is stored in max_seq for both anon and file - * types as they are aged on an equal footing. The oldest generation numbers are -@@ -363,6 +395,15 @@ struct lru_gen_struct { - struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; - /* the multi-gen LRU sizes, eventually consistent */ - long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* the exponential moving average of refaulted */ -+ unsigned long avg_refaulted[ANON_AND_FILE][MAX_NR_TIERS]; -+ /* the exponential moving average of evicted+protected */ -+ unsigned long avg_total[ANON_AND_FILE][MAX_NR_TIERS]; -+ /* the first tier doesn't need protection, hence the minus one */ -+ unsigned long protected[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS - 1]; -+ /* can be modified without holding the LRU lock */ -+ atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; -+ atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; - }; - - void lru_gen_init_lruvec(struct lruvec *lruvec); ---- a/include/linux/page-flags-layout.h -+++ b/include/linux/page-flags-layout.h -@@ -106,7 +106,10 @@ - #error "Not enough bits in page flags" - #endif - --#define LRU_REFS_WIDTH 0 -+/* see the comment on MAX_NR_TIERS */ -+#define LRU_REFS_WIDTH min(__LRU_REFS_WIDTH, BITS_PER_LONG - NR_PAGEFLAGS - \ -+ ZONES_WIDTH - LRU_GEN_WIDTH - SECTIONS_WIDTH - \ -+ NODES_WIDTH - KASAN_TAG_WIDTH - LAST_CPUPID_WIDTH) - - #endif - #endif /* _LINUX_PAGE_FLAGS_LAYOUT */ ---- a/kernel/bounds.c -+++ b/kernel/bounds.c -@@ -24,8 +24,10 @@ int main(void) - DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); - #ifdef CONFIG_LRU_GEN - DEFINE(LRU_GEN_WIDTH, order_base_2(MAX_NR_GENS + 1)); -+ DEFINE(__LRU_REFS_WIDTH, MAX_NR_TIERS - 2); - #else - DEFINE(LRU_GEN_WIDTH, 0); -+ DEFINE(__LRU_REFS_WIDTH, 0); - #endif - /* End of constants */ - ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -897,6 +897,7 @@ config IO_MAPPING - config SECRETMEM - def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED - -+# multi-gen LRU { - config LRU_GEN - bool "Multi-Gen LRU" - depends on MMU -@@ -905,6 +906,16 @@ config LRU_GEN - help - A high performance LRU implementation to overcommit memory. - -+config LRU_GEN_STATS -+ bool "Full stats for debugging" -+ depends on LRU_GEN -+ help -+ Do not enable this option unless you plan to look at historical stats -+ from evicted generations for debugging purpose. -+ -+ This option has a per-memcg and per-node memory overhead. -+# } -+ - source "mm/damon/Kconfig" - - endmenu ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -389,6 +389,40 @@ static void __lru_cache_activate_page(st - local_unlock(&lru_pvecs.lock); - } - -+#ifdef CONFIG_LRU_GEN -+static void page_inc_refs(struct page *page) -+{ -+ unsigned long new_flags, old_flags = READ_ONCE(page->flags); -+ -+ if (PageUnevictable(page)) -+ return; -+ -+ if (!PageReferenced(page)) { -+ SetPageReferenced(page); -+ return; -+ } -+ -+ if (!PageWorkingset(page)) { -+ SetPageWorkingset(page); -+ return; -+ } -+ -+ /* see the comment on MAX_NR_TIERS */ -+ do { -+ new_flags = old_flags & LRU_REFS_MASK; -+ if (new_flags == LRU_REFS_MASK) -+ break; -+ -+ new_flags += BIT(LRU_REFS_PGOFF); -+ new_flags |= old_flags & ~LRU_REFS_MASK; -+ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); -+} -+#else -+static void page_inc_refs(struct page *page) -+{ -+} -+#endif /* CONFIG_LRU_GEN */ -+ - /* - * Mark a page as having seen activity. - * -@@ -403,6 +437,11 @@ void mark_page_accessed(struct page *pag - { - page = compound_head(page); - -+ if (lru_gen_enabled()) { -+ page_inc_refs(page); -+ return; -+ } -+ - if (!PageReferenced(page)) { - SetPageReferenced(page); - } else if (PageUnevictable(page)) { ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -1142,9 +1142,11 @@ static int __remove_mapping(struct addre - - if (PageSwapCache(page)) { - swp_entry_t swap = { .val = page_private(page) }; -- mem_cgroup_swapout(page, swap); -+ -+ /* get a shadow entry before mem_cgroup_swapout() clears page_memcg() */ - if (reclaimed && !mapping_exiting(mapping)) - shadow = workingset_eviction(page, target_memcg); -+ mem_cgroup_swapout(page, swap); - __delete_from_swap_cache(page, swap, shadow); - xa_unlock_irq(&mapping->i_pages); - put_swap_page(page, swap); -@@ -2502,6 +2504,9 @@ static void prepare_scan_count(pg_data_t - unsigned long file; - struct lruvec *target_lruvec; - -+ if (lru_gen_enabled()) -+ return; -+ - target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); - - /* -@@ -2827,6 +2832,17 @@ static bool can_age_anon_pages(struct pg - * shorthand helpers - ******************************************************************************/ - -+#define LRU_REFS_FLAGS (BIT(PG_referenced) | BIT(PG_workingset)) -+ -+#define DEFINE_MAX_SEQ(lruvec) \ -+ unsigned long max_seq = READ_ONCE((lruvec)->lrugen.max_seq) -+ -+#define DEFINE_MIN_SEQ(lruvec) \ -+ unsigned long min_seq[ANON_AND_FILE] = { \ -+ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_ANON]), \ -+ READ_ONCE((lruvec)->lrugen.min_seq[LRU_GEN_FILE]), \ -+ } -+ - #define for_each_gen_type_zone(gen, type, zone) \ - for ((gen) = 0; (gen) < MAX_NR_GENS; (gen)++) \ - for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ -@@ -2852,6 +2868,745 @@ static struct lruvec __maybe_unused *get - return pgdat ? &pgdat->__lruvec : NULL; - } - -+static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) -+{ -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ -+ if (!can_demote(pgdat->node_id, sc) && -+ mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) -+ return 0; -+ -+ return mem_cgroup_swappiness(memcg); -+} -+ -+static int get_nr_gens(struct lruvec *lruvec, int type) -+{ -+ return lruvec->lrugen.max_seq - lruvec->lrugen.min_seq[type] + 1; -+} -+ -+static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) -+{ -+ /* see the comment on lru_gen_struct */ -+ return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && -+ get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && -+ get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; -+} -+ -+/****************************************************************************** -+ * refault feedback loop -+ ******************************************************************************/ -+ -+/* -+ * A feedback loop based on Proportional-Integral-Derivative (PID) controller. -+ * -+ * The P term is refaulted/(evicted+protected) from a tier in the generation -+ * currently being evicted; the I term is the exponential moving average of the -+ * P term over the generations previously evicted, using the smoothing factor -+ * 1/2; the D term isn't supported. -+ * -+ * The setpoint (SP) is always the first tier of one type; the process variable -+ * (PV) is either any tier of the other type or any other tier of the same -+ * type. -+ * -+ * The error is the difference between the SP and the PV; the correction is to -+ * turn off protection when SP>PV or turn on protection when SPlrugen; -+ int hist = lru_hist_from_seq(lrugen->min_seq[type]); -+ -+ pos->refaulted = lrugen->avg_refaulted[type][tier] + -+ atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ pos->total = lrugen->avg_total[type][tier] + -+ atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ pos->total += lrugen->protected[hist][type][tier - 1]; -+ pos->gain = gain; -+} -+ -+static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) -+{ -+ int hist, tier; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; -+ unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; -+ -+ lockdep_assert_held(&lruvec->lru_lock); -+ -+ if (!carryover && !clear) -+ return; -+ -+ hist = lru_hist_from_seq(seq); -+ -+ for (tier = 0; tier < MAX_NR_TIERS; tier++) { -+ if (carryover) { -+ unsigned long sum; -+ -+ sum = lrugen->avg_refaulted[type][tier] + -+ atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ WRITE_ONCE(lrugen->avg_refaulted[type][tier], sum / 2); -+ -+ sum = lrugen->avg_total[type][tier] + -+ atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ sum += lrugen->protected[hist][type][tier - 1]; -+ WRITE_ONCE(lrugen->avg_total[type][tier], sum / 2); -+ } -+ -+ if (clear) { -+ atomic_long_set(&lrugen->refaulted[hist][type][tier], 0); -+ atomic_long_set(&lrugen->evicted[hist][type][tier], 0); -+ if (tier) -+ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], 0); -+ } -+ } -+} -+ -+static bool positive_ctrl_err(struct ctrl_pos *sp, struct ctrl_pos *pv) -+{ -+ /* -+ * Return true if the PV has a limited number of refaults or a lower -+ * refaulted/total than the SP. -+ */ -+ return pv->refaulted < MIN_LRU_BATCH || -+ pv->refaulted * (sp->total + MIN_LRU_BATCH) * sp->gain <= -+ (sp->refaulted + 1) * pv->total * pv->gain; -+} -+ -+/****************************************************************************** -+ * the aging -+ ******************************************************************************/ -+ -+/* protect pages accessed multiple times through file descriptors */ -+static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) -+{ -+ int type = page_is_file_lru(page); -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ unsigned long new_flags, old_flags = READ_ONCE(page->flags); -+ -+ VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); -+ -+ do { -+ new_gen = (old_gen + 1) % MAX_NR_GENS; -+ -+ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); -+ new_flags |= (new_gen + 1UL) << LRU_GEN_PGOFF; -+ /* for end_page_writeback() */ -+ if (reclaiming) -+ new_flags |= BIT(PG_reclaim); -+ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); -+ -+ lru_gen_update_size(lruvec, page, old_gen, new_gen); -+ -+ return new_gen; -+} -+ -+static void inc_min_seq(struct lruvec *lruvec, int type) -+{ -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ reset_ctrl_pos(lruvec, type, true); -+ WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); -+} -+ -+static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) -+{ -+ int gen, type, zone; -+ bool success = false; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ DEFINE_MIN_SEQ(lruvec); -+ -+ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -+ -+ /* find the oldest populated generation */ -+ for (type = !can_swap; type < ANON_AND_FILE; type++) { -+ while (min_seq[type] + MIN_NR_GENS <= lrugen->max_seq) { -+ gen = lru_gen_from_seq(min_seq[type]); -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ if (!list_empty(&lrugen->lists[gen][type][zone])) -+ goto next; -+ } -+ -+ min_seq[type]++; -+ } -+next: -+ ; -+ } -+ -+ /* see the comment on lru_gen_struct */ -+ if (can_swap) { -+ min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); -+ min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); -+ } -+ -+ for (type = !can_swap; type < ANON_AND_FILE; type++) { -+ if (min_seq[type] == lrugen->min_seq[type]) -+ continue; -+ -+ reset_ctrl_pos(lruvec, type, true); -+ WRITE_ONCE(lrugen->min_seq[type], min_seq[type]); -+ success = true; -+ } -+ -+ return success; -+} -+ -+static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) -+{ -+ int prev, next; -+ int type, zone; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -+ -+ if (max_seq != lrugen->max_seq) -+ goto unlock; -+ -+ for (type = ANON_AND_FILE - 1; type >= 0; type--) { -+ if (get_nr_gens(lruvec, type) != MAX_NR_GENS) -+ continue; -+ -+ VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); -+ -+ inc_min_seq(lruvec, type); -+ } -+ -+ /* -+ * Update the active/inactive LRU sizes for compatibility. Both sides of -+ * the current max_seq need to be covered, since max_seq+1 can overlap -+ * with min_seq[LRU_GEN_ANON] if swapping is constrained. And if they do -+ * overlap, cold/hot inversion happens. -+ */ -+ prev = lru_gen_from_seq(lrugen->max_seq - 1); -+ next = lru_gen_from_seq(lrugen->max_seq + 1); -+ -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ enum lru_list lru = type * LRU_INACTIVE_FILE; -+ long delta = lrugen->nr_pages[prev][type][zone] - -+ lrugen->nr_pages[next][type][zone]; -+ -+ if (!delta) -+ continue; -+ -+ __update_lru_size(lruvec, lru, zone, delta); -+ __update_lru_size(lruvec, lru + LRU_ACTIVE, zone, -delta); -+ } -+ } -+ -+ for (type = 0; type < ANON_AND_FILE; type++) -+ reset_ctrl_pos(lruvec, type, false); -+ -+ /* make sure preceding modifications appear */ -+ smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); -+unlock: -+ spin_unlock_irq(&lruvec->lru_lock); -+} -+ -+static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, -+ struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) -+{ -+ int gen, type, zone; -+ unsigned long old = 0; -+ unsigned long young = 0; -+ unsigned long total = 0; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ -+ for (type = !can_swap; type < ANON_AND_FILE; type++) { -+ unsigned long seq; -+ -+ for (seq = min_seq[type]; seq <= max_seq; seq++) { -+ unsigned long size = 0; -+ -+ gen = lru_gen_from_seq(seq); -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) -+ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); -+ -+ total += size; -+ if (seq == max_seq) -+ young += size; -+ else if (seq + MIN_NR_GENS == max_seq) -+ old += size; -+ } -+ } -+ -+ /* try to scrape all its memory if this memcg was deleted */ -+ *nr_to_scan = mem_cgroup_online(memcg) ? (total >> sc->priority) : total; -+ -+ /* -+ * The aging tries to be lazy to reduce the overhead, while the eviction -+ * stalls when the number of generations reaches MIN_NR_GENS. Hence, the -+ * ideal number of generations is MIN_NR_GENS+1. -+ */ -+ if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) -+ return true; -+ if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) -+ return false; -+ -+ /* -+ * It's also ideal to spread pages out evenly, i.e., 1/(MIN_NR_GENS+1) -+ * of the total number of pages for each generation. A reasonable range -+ * for this average portion is [1/MIN_NR_GENS, 1/(MIN_NR_GENS+2)]. The -+ * aging cares about the upper bound of hot pages, while the eviction -+ * cares about the lower bound of cold pages. -+ */ -+ if (young * MIN_NR_GENS > total) -+ return true; -+ if (old * (MIN_NR_GENS + 2) < total) -+ return true; -+ -+ return false; -+} -+ -+static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+{ -+ bool need_aging; -+ unsigned long nr_to_scan; -+ int swappiness = get_swappiness(lruvec, sc); -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ VM_WARN_ON_ONCE(sc->memcg_low_reclaim); -+ -+ mem_cgroup_calculate_protection(NULL, memcg); -+ -+ if (mem_cgroup_below_min(memcg)) -+ return; -+ -+ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); -+ if (need_aging) -+ inc_max_seq(lruvec, max_seq, swappiness); -+} -+ -+static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -+{ -+ struct mem_cgroup *memcg; -+ -+ VM_WARN_ON_ONCE(!current_is_kswapd()); -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ -+ age_lruvec(lruvec, sc); -+ -+ cond_resched(); -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+} -+ -+/****************************************************************************** -+ * the eviction -+ ******************************************************************************/ -+ -+static bool sort_page(struct lruvec *lruvec, struct page *page, int tier_idx) -+{ -+ bool success; -+ int gen = page_lru_gen(page); -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int delta = thp_nr_pages(page); -+ int refs = page_lru_refs(page); -+ int tier = lru_tier_from_refs(refs); -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); -+ -+ /* unevictable */ -+ if (!page_evictable(page)) { -+ success = lru_gen_del_page(lruvec, page, true); -+ VM_WARN_ON_ONCE_PAGE(!success, page); -+ SetPageUnevictable(page); -+ add_page_to_lru_list(page, lruvec); -+ __count_vm_events(UNEVICTABLE_PGCULLED, delta); -+ return true; -+ } -+ -+ /* dirty lazyfree */ -+ if (type == LRU_GEN_FILE && PageAnon(page) && PageDirty(page)) { -+ success = lru_gen_del_page(lruvec, page, true); -+ VM_WARN_ON_ONCE_PAGE(!success, page); -+ SetPageSwapBacked(page); -+ add_page_to_lru_list_tail(page, lruvec); -+ return true; -+ } -+ -+ /* protected */ -+ if (tier > tier_idx) { -+ int hist = lru_hist_from_seq(lrugen->min_seq[type]); -+ -+ gen = page_inc_gen(lruvec, page, false); -+ list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); -+ -+ WRITE_ONCE(lrugen->protected[hist][type][tier - 1], -+ lrugen->protected[hist][type][tier - 1] + delta); -+ __mod_lruvec_state(lruvec, WORKINGSET_ACTIVATE_BASE + type, delta); -+ return true; -+ } -+ -+ /* waiting for writeback */ -+ if (PageLocked(page) || PageWriteback(page) || -+ (type == LRU_GEN_FILE && PageDirty(page))) { -+ gen = page_inc_gen(lruvec, page, true); -+ list_move(&page->lru, &lrugen->lists[gen][type][zone]); -+ return true; -+ } -+ -+ return false; -+} -+ -+static bool isolate_page(struct lruvec *lruvec, struct page *page, struct scan_control *sc) -+{ -+ bool success; -+ -+ /* unmapping inhibited */ -+ if (!sc->may_unmap && page_mapped(page)) -+ return false; -+ -+ /* swapping inhibited */ -+ if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && -+ (PageDirty(page) || -+ (PageAnon(page) && !PageSwapCache(page)))) -+ return false; -+ -+ /* raced with release_pages() */ -+ if (!get_page_unless_zero(page)) -+ return false; -+ -+ /* raced with another isolation */ -+ if (!TestClearPageLRU(page)) { -+ put_page(page); -+ return false; -+ } -+ -+ /* see the comment on MAX_NR_TIERS */ -+ if (!PageReferenced(page)) -+ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, 0); -+ -+ /* for shrink_page_list() */ -+ ClearPageReclaim(page); -+ ClearPageReferenced(page); -+ -+ success = lru_gen_del_page(lruvec, page, true); -+ VM_WARN_ON_ONCE_PAGE(!success, page); -+ -+ return true; -+} -+ -+static int scan_pages(struct lruvec *lruvec, struct scan_control *sc, -+ int type, int tier, struct list_head *list) -+{ -+ int gen, zone; -+ enum vm_event_item item; -+ int sorted = 0; -+ int scanned = 0; -+ int isolated = 0; -+ int remaining = MAX_LRU_BATCH; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ -+ VM_WARN_ON_ONCE(!list_empty(list)); -+ -+ if (get_nr_gens(lruvec, type) == MIN_NR_GENS) -+ return 0; -+ -+ gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ for (zone = sc->reclaim_idx; zone >= 0; zone--) { -+ LIST_HEAD(moved); -+ int skipped = 0; -+ struct list_head *head = &lrugen->lists[gen][type][zone]; -+ -+ while (!list_empty(head)) { -+ struct page *page = lru_to_page(head); -+ int delta = thp_nr_pages(page); -+ -+ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); -+ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); -+ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); -+ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); -+ -+ scanned += delta; -+ -+ if (sort_page(lruvec, page, tier)) -+ sorted += delta; -+ else if (isolate_page(lruvec, page, sc)) { -+ list_add(&page->lru, list); -+ isolated += delta; -+ } else { -+ list_move(&page->lru, &moved); -+ skipped += delta; -+ } -+ -+ if (!--remaining || max(isolated, skipped) >= MIN_LRU_BATCH) -+ break; -+ } -+ -+ if (skipped) { -+ list_splice(&moved, head); -+ __count_zid_vm_events(PGSCAN_SKIP, zone, skipped); -+ } -+ -+ if (!remaining || isolated >= MIN_LRU_BATCH) -+ break; -+ } -+ -+ item = current_is_kswapd() ? PGSCAN_KSWAPD : PGSCAN_DIRECT; -+ if (!cgroup_reclaim(sc)) { -+ __count_vm_events(item, isolated); -+ __count_vm_events(PGREFILL, sorted); -+ } -+ __count_memcg_events(memcg, item, isolated); -+ __count_memcg_events(memcg, PGREFILL, sorted); -+ __count_vm_events(PGSCAN_ANON + type, isolated); -+ -+ /* -+ * There might not be eligible pages due to reclaim_idx, may_unmap and -+ * may_writepage. Check the remaining to prevent livelock if it's not -+ * making progress. -+ */ -+ return isolated || !remaining ? scanned : 0; -+} -+ -+static int get_tier_idx(struct lruvec *lruvec, int type) -+{ -+ int tier; -+ struct ctrl_pos sp, pv; -+ -+ /* -+ * To leave a margin for fluctuations, use a larger gain factor (1:2). -+ * This value is chosen because any other tier would have at least twice -+ * as many refaults as the first tier. -+ */ -+ read_ctrl_pos(lruvec, type, 0, 1, &sp); -+ for (tier = 1; tier < MAX_NR_TIERS; tier++) { -+ read_ctrl_pos(lruvec, type, tier, 2, &pv); -+ if (!positive_ctrl_err(&sp, &pv)) -+ break; -+ } -+ -+ return tier - 1; -+} -+ -+static int get_type_to_scan(struct lruvec *lruvec, int swappiness, int *tier_idx) -+{ -+ int type, tier; -+ struct ctrl_pos sp, pv; -+ int gain[ANON_AND_FILE] = { swappiness, 200 - swappiness }; -+ -+ /* -+ * Compare the first tier of anon with that of file to determine which -+ * type to scan. Also need to compare other tiers of the selected type -+ * with the first tier of the other type to determine the last tier (of -+ * the selected type) to evict. -+ */ -+ read_ctrl_pos(lruvec, LRU_GEN_ANON, 0, gain[LRU_GEN_ANON], &sp); -+ read_ctrl_pos(lruvec, LRU_GEN_FILE, 0, gain[LRU_GEN_FILE], &pv); -+ type = positive_ctrl_err(&sp, &pv); -+ -+ read_ctrl_pos(lruvec, !type, 0, gain[!type], &sp); -+ for (tier = 1; tier < MAX_NR_TIERS; tier++) { -+ read_ctrl_pos(lruvec, type, tier, gain[type], &pv); -+ if (!positive_ctrl_err(&sp, &pv)) -+ break; -+ } -+ -+ *tier_idx = tier - 1; -+ -+ return type; -+} -+ -+static int isolate_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ int *type_scanned, struct list_head *list) -+{ -+ int i; -+ int type; -+ int scanned; -+ int tier = -1; -+ DEFINE_MIN_SEQ(lruvec); -+ -+ /* -+ * Try to make the obvious choice first. When anon and file are both -+ * available from the same generation, interpret swappiness 1 as file -+ * first and 200 as anon first. -+ */ -+ if (!swappiness) -+ type = LRU_GEN_FILE; -+ else if (min_seq[LRU_GEN_ANON] < min_seq[LRU_GEN_FILE]) -+ type = LRU_GEN_ANON; -+ else if (swappiness == 1) -+ type = LRU_GEN_FILE; -+ else if (swappiness == 200) -+ type = LRU_GEN_ANON; -+ else -+ type = get_type_to_scan(lruvec, swappiness, &tier); -+ -+ for (i = !swappiness; i < ANON_AND_FILE; i++) { -+ if (tier < 0) -+ tier = get_tier_idx(lruvec, type); -+ -+ scanned = scan_pages(lruvec, sc, type, tier, list); -+ if (scanned) -+ break; -+ -+ type = !type; -+ tier = -1; -+ } -+ -+ *type_scanned = type; -+ -+ return scanned; -+} -+ -+static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) -+{ -+ int type; -+ int scanned; -+ int reclaimed; -+ LIST_HEAD(list); -+ struct page *page; -+ enum vm_event_item item; -+ struct reclaim_stat stat; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(lruvec); -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ scanned = isolate_pages(lruvec, sc, swappiness, &type, &list); -+ -+ scanned += try_to_inc_min_seq(lruvec, swappiness); -+ -+ if (get_nr_gens(lruvec, !swappiness) == MIN_NR_GENS) -+ scanned = 0; -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ -+ if (list_empty(&list)) -+ return scanned; -+ -+ reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); -+ -+ list_for_each_entry(page, &list, lru) { -+ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ -+ if (PageWorkingset(page)) -+ SetPageReferenced(page); -+ -+ /* don't add rejected pages to the oldest generation */ -+ if (PageReclaim(page) && -+ (PageDirty(page) || PageWriteback(page))) -+ ClearPageActive(page); -+ else -+ SetPageActive(page); -+ } -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ move_pages_to_lru(lruvec, &list); -+ -+ item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; -+ if (!cgroup_reclaim(sc)) -+ __count_vm_events(item, reclaimed); -+ __count_memcg_events(memcg, item, reclaimed); -+ __count_vm_events(PGSTEAL_ANON + type, reclaimed); -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ -+ mem_cgroup_uncharge_list(&list); -+ free_unref_page_list(&list); -+ -+ sc->nr_reclaimed += reclaimed; -+ -+ return scanned; -+} -+ -+static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, -+ bool can_swap) -+{ -+ bool need_aging; -+ unsigned long nr_to_scan; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (mem_cgroup_below_min(memcg) || -+ (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) -+ return 0; -+ -+ need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); -+ if (!need_aging) -+ return nr_to_scan; -+ -+ /* skip the aging path at the default priority */ -+ if (sc->priority == DEF_PRIORITY) -+ goto done; -+ -+ /* leave the work to lru_gen_age_node() */ -+ if (current_is_kswapd()) -+ return 0; -+ -+ inc_max_seq(lruvec, max_seq, can_swap); -+done: -+ return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; -+} -+ -+static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+{ -+ struct blk_plug plug; -+ unsigned long scanned = 0; -+ -+ lru_add_drain(); -+ -+ blk_start_plug(&plug); -+ -+ while (true) { -+ int delta; -+ int swappiness; -+ unsigned long nr_to_scan; -+ -+ if (sc->may_swap) -+ swappiness = get_swappiness(lruvec, sc); -+ else if (!cgroup_reclaim(sc) && get_swappiness(lruvec, sc)) -+ swappiness = 1; -+ else -+ swappiness = 0; -+ -+ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); -+ if (!nr_to_scan) -+ break; -+ -+ delta = evict_pages(lruvec, sc, swappiness); -+ if (!delta) -+ break; -+ -+ scanned += delta; -+ if (scanned >= nr_to_scan) -+ break; -+ -+ cond_resched(); -+ } -+ -+ blk_finish_plug(&plug); -+} -+ - /****************************************************************************** - * initialization - ******************************************************************************/ -@@ -2894,6 +3649,16 @@ static int __init init_lru_gen(void) - }; - late_initcall(init_lru_gen); - -+#else /* !CONFIG_LRU_GEN */ -+ -+static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -+{ -+} -+ -+static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+{ -+} -+ - #endif /* CONFIG_LRU_GEN */ - - static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -2907,6 +3672,11 @@ static void shrink_lruvec(struct lruvec - bool proportional_reclaim; - struct blk_plug plug; - -+ if (lru_gen_enabled()) { -+ lru_gen_shrink_lruvec(lruvec, sc); -+ return; -+ } -+ - get_scan_count(lruvec, sc, nr); - - /* Record the original scan target for proportional adjustments later */ -@@ -3372,6 +4142,9 @@ static void snapshot_refaults(struct mem - struct lruvec *target_lruvec; - unsigned long refaults; - -+ if (lru_gen_enabled()) -+ return; -+ - target_lruvec = mem_cgroup_lruvec(target_memcg, pgdat); - refaults = lruvec_page_state(target_lruvec, WORKINGSET_ACTIVATE_ANON); - target_lruvec->refaults[0] = refaults; -@@ -3736,12 +4509,16 @@ unsigned long try_to_free_mem_cgroup_pag - } - #endif - --static void age_active_anon(struct pglist_data *pgdat, -- struct scan_control *sc) -+static void kswapd_age_node(struct pglist_data *pgdat, struct scan_control *sc) - { - struct mem_cgroup *memcg; - struct lruvec *lruvec; - -+ if (lru_gen_enabled()) { -+ lru_gen_age_node(pgdat, sc); -+ return; -+ } -+ - if (!can_age_anon_pages(pgdat, sc)) - return; - -@@ -4058,12 +4835,11 @@ restart: - sc.may_swap = !nr_boost_reclaim; - - /* -- * Do some background aging of the anon list, to give -- * pages a chance to be referenced before reclaiming. All -- * pages are rotated regardless of classzone as this is -- * about consistent aging. -+ * Do some background aging, to give pages a chance to be -+ * referenced before reclaiming. All pages are rotated -+ * regardless of classzone as this is about consistent aging. - */ -- age_active_anon(pgdat, &sc); -+ kswapd_age_node(pgdat, &sc); - - /* - * If we're getting trouble reclaiming, start doing writepage ---- a/mm/workingset.c -+++ b/mm/workingset.c -@@ -187,7 +187,6 @@ static unsigned int bucket_order __read_ - static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction, - bool workingset) - { -- eviction >>= bucket_order; - eviction &= EVICTION_MASK; - eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; - eviction = (eviction << NODES_SHIFT) | pgdat->node_id; -@@ -212,10 +211,107 @@ static void unpack_shadow(void *shadow, - - *memcgidp = memcgid; - *pgdat = NODE_DATA(nid); -- *evictionp = entry << bucket_order; -+ *evictionp = entry; - *workingsetp = workingset; - } - -+#ifdef CONFIG_LRU_GEN -+ -+static void *lru_gen_eviction(struct page *page) -+{ -+ int hist; -+ unsigned long token; -+ unsigned long min_seq; -+ struct lruvec *lruvec; -+ struct lru_gen_struct *lrugen; -+ int type = page_is_file_lru(page); -+ int delta = thp_nr_pages(page); -+ int refs = page_lru_refs(page); -+ int tier = lru_tier_from_refs(refs); -+ struct mem_cgroup *memcg = page_memcg(page); -+ struct pglist_data *pgdat = page_pgdat(page); -+ -+ BUILD_BUG_ON(LRU_GEN_WIDTH + LRU_REFS_WIDTH > BITS_PER_LONG - EVICTION_SHIFT); -+ -+ lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ lrugen = &lruvec->lrugen; -+ min_seq = READ_ONCE(lrugen->min_seq[type]); -+ token = (min_seq << LRU_REFS_WIDTH) | max(refs - 1, 0); -+ -+ hist = lru_hist_from_seq(min_seq); -+ atomic_long_add(delta, &lrugen->evicted[hist][type][tier]); -+ -+ return pack_shadow(mem_cgroup_id(memcg), pgdat, token, refs); -+} -+ -+static void lru_gen_refault(struct page *page, void *shadow) -+{ -+ int hist, tier, refs; -+ int memcg_id; -+ bool workingset; -+ unsigned long token; -+ unsigned long min_seq; -+ struct lruvec *lruvec; -+ struct lru_gen_struct *lrugen; -+ struct mem_cgroup *memcg; -+ struct pglist_data *pgdat; -+ int type = page_is_file_lru(page); -+ int delta = thp_nr_pages(page); -+ -+ unpack_shadow(shadow, &memcg_id, &pgdat, &token, &workingset); -+ -+ if (pgdat != page_pgdat(page)) -+ return; -+ -+ rcu_read_lock(); -+ -+ memcg = page_memcg_rcu(page); -+ if (memcg_id != mem_cgroup_id(memcg)) -+ goto unlock; -+ -+ lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ lrugen = &lruvec->lrugen; -+ -+ min_seq = READ_ONCE(lrugen->min_seq[type]); -+ if ((token >> LRU_REFS_WIDTH) != (min_seq & (EVICTION_MASK >> LRU_REFS_WIDTH))) -+ goto unlock; -+ -+ hist = lru_hist_from_seq(min_seq); -+ /* see the comment in page_lru_refs() */ -+ refs = (token & (BIT(LRU_REFS_WIDTH) - 1)) + workingset; -+ tier = lru_tier_from_refs(refs); -+ -+ atomic_long_add(delta, &lrugen->refaulted[hist][type][tier]); -+ mod_lruvec_state(lruvec, WORKINGSET_REFAULT_BASE + type, delta); -+ -+ /* -+ * Count the following two cases as stalls: -+ * 1. For pages accessed through page tables, hotter pages pushed out -+ * hot pages which refaulted immediately. -+ * 2. For pages accessed multiple times through file descriptors, -+ * numbers of accesses might have been out of the range. -+ */ -+ if (lru_gen_in_fault() || refs == BIT(LRU_REFS_WIDTH)) { -+ SetPageWorkingset(page); -+ mod_lruvec_state(lruvec, WORKINGSET_RESTORE_BASE + type, delta); -+ } -+unlock: -+ rcu_read_unlock(); -+} -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static void *lru_gen_eviction(struct page *page) -+{ -+ return NULL; -+} -+ -+static void lru_gen_refault(struct page *page, void *shadow) -+{ -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - /** - * workingset_age_nonresident - age non-resident entries as LRU ages - * @lruvec: the lruvec that was aged -@@ -264,10 +360,14 @@ void *workingset_eviction(struct page *p - VM_BUG_ON_PAGE(page_count(page), page); - VM_BUG_ON_PAGE(!PageLocked(page), page); - -+ if (lru_gen_enabled()) -+ return lru_gen_eviction(page); -+ - lruvec = mem_cgroup_lruvec(target_memcg, pgdat); - /* XXX: target_memcg can be NULL, go through lruvec */ - memcgid = mem_cgroup_id(lruvec_memcg(lruvec)); - eviction = atomic_long_read(&lruvec->nonresident_age); -+ eviction >>= bucket_order; - workingset_age_nonresident(lruvec, thp_nr_pages(page)); - return pack_shadow(memcgid, pgdat, eviction, PageWorkingset(page)); - } -@@ -296,7 +396,13 @@ void workingset_refault(struct page *pag - bool workingset; - int memcgid; - -+ if (lru_gen_enabled()) { -+ lru_gen_refault(page, shadow); -+ return; -+ } -+ - unpack_shadow(shadow, &memcgid, &pgdat, &eviction, &workingset); -+ eviction <<= bucket_order; - - rcu_read_lock(); - /* diff --git a/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch b/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch deleted file mode 100644 index 5cd6e03dc60..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-07-mm-multi-gen-LRU-exploit-locality-in-rmap.patch +++ /dev/null @@ -1,491 +0,0 @@ -From e4277535f6d6708bb19b88c4bad155832671d69b Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:04 -0600 -Subject: [PATCH 07/29] mm: multi-gen LRU: exploit locality in rmap -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Searching the rmap for PTEs mapping each page on an LRU list (to test and -clear the accessed bit) can be expensive because pages from different VMAs -(PA space) are not cache friendly to the rmap (VA space). For workloads -mostly using mapped pages, searching the rmap can incur the highest CPU -cost in the reclaim path. - -This patch exploits spatial locality to reduce the trips into the rmap. -When shrink_page_list() walks the rmap and finds a young PTE, a new -function lru_gen_look_around() scans at most BITS_PER_LONG-1 adjacent -PTEs. On finding another young PTE, it clears the accessed bit and -updates the gen counter of the page mapped by this PTE to -(max_seq%MAX_NR_GENS)+1. - -Server benchmark results: - Single workload: - fio (buffered I/O): no change - - Single workload: - memcached (anon): +[3, 5]% - Ops/sec KB/sec - patch1-6: 1106168.46 43025.04 - patch1-7: 1147696.57 44640.29 - - Configurations: - no change - -Client benchmark results: - kswapd profiles: - patch1-6 - 39.03% lzo1x_1_do_compress (real work) - 18.47% page_vma_mapped_walk (overhead) - 6.74% _raw_spin_unlock_irq - 3.97% do_raw_spin_lock - 2.49% ptep_clear_flush - 2.48% anon_vma_interval_tree_iter_first - 1.92% page_referenced_one - 1.88% __zram_bvec_write - 1.48% memmove - 1.31% vma_interval_tree_iter_next - - patch1-7 - 48.16% lzo1x_1_do_compress (real work) - 8.20% page_vma_mapped_walk (overhead) - 7.06% _raw_spin_unlock_irq - 2.92% ptep_clear_flush - 2.53% __zram_bvec_write - 2.11% do_raw_spin_lock - 2.02% memmove - 1.93% lru_gen_look_around - 1.56% free_unref_page_list - 1.40% memset - - Configurations: - no change - -Link: https://lkml.kernel.org/r/20220918080010.2920238-8-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Barry Song -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/memcontrol.h | 31 +++++++ - include/linux/mmzone.h | 6 ++ - mm/internal.h | 1 + - mm/memcontrol.c | 1 + - mm/rmap.c | 7 ++ - mm/swap.c | 4 +- - mm/vmscan.c | 184 +++++++++++++++++++++++++++++++++++++ - 7 files changed, 232 insertions(+), 2 deletions(-) - ---- a/include/linux/memcontrol.h -+++ b/include/linux/memcontrol.h -@@ -442,6 +442,7 @@ static inline struct obj_cgroup *__page_ - * - LRU isolation - * - lock_page_memcg() - * - exclusive reference -+ * - mem_cgroup_trylock_pages() - * - * For a kmem page a caller should hold an rcu read lock to protect memcg - * associated with a kmem page from being released. -@@ -497,6 +498,7 @@ static inline struct mem_cgroup *page_me - * - LRU isolation - * - lock_page_memcg() - * - exclusive reference -+ * - mem_cgroup_trylock_pages() - * - * For a kmem page a caller should hold an rcu read lock to protect memcg - * associated with a kmem page from being released. -@@ -953,6 +955,23 @@ void unlock_page_memcg(struct page *page - - void __mod_memcg_state(struct mem_cgroup *memcg, int idx, int val); - -+/* try to stablize page_memcg() for all the pages in a memcg */ -+static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) -+{ -+ rcu_read_lock(); -+ -+ if (mem_cgroup_disabled() || !atomic_read(&memcg->moving_account)) -+ return true; -+ -+ rcu_read_unlock(); -+ return false; -+} -+ -+static inline void mem_cgroup_unlock_pages(void) -+{ -+ rcu_read_unlock(); -+} -+ - /* idx can be of type enum memcg_stat_item or node_stat_item */ - static inline void mod_memcg_state(struct mem_cgroup *memcg, - int idx, int val) -@@ -1369,6 +1388,18 @@ static inline void unlock_page_memcg(str - { - } - -+static inline bool mem_cgroup_trylock_pages(struct mem_cgroup *memcg) -+{ -+ /* to match page_memcg_rcu() */ -+ rcu_read_lock(); -+ return true; -+} -+ -+static inline void mem_cgroup_unlock_pages(void) -+{ -+ rcu_read_unlock(); -+} -+ - static inline void mem_cgroup_handle_over_high(void) - { - } ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -352,6 +352,7 @@ enum lruvec_flags { - #ifndef __GENERATING_BOUNDS_H - - struct lruvec; -+struct page_vma_mapped_walk; - - #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) - #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) -@@ -407,6 +408,7 @@ struct lru_gen_struct { - }; - - void lru_gen_init_lruvec(struct lruvec *lruvec); -+void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); - - #ifdef CONFIG_MEMCG - void lru_gen_init_memcg(struct mem_cgroup *memcg); -@@ -419,6 +421,10 @@ static inline void lru_gen_init_lruvec(s - { - } - -+static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) -+{ -+} -+ - #ifdef CONFIG_MEMCG - static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) - { ---- a/mm/internal.h -+++ b/mm/internal.h -@@ -35,6 +35,7 @@ - void page_writeback_init(void); - - vm_fault_t do_swap_page(struct vm_fault *vmf); -+void activate_page(struct page *page); - - void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, - unsigned long floor, unsigned long ceiling); ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -2798,6 +2798,7 @@ static void commit_charge(struct page *p - * - LRU isolation - * - lock_page_memcg() - * - exclusive reference -+ * - mem_cgroup_trylock_pages() - */ - page->memcg_data = (unsigned long)memcg; - } ---- a/mm/rmap.c -+++ b/mm/rmap.c -@@ -73,6 +73,7 @@ - #include - #include - #include -+#include - - #include - -@@ -793,6 +794,12 @@ static bool page_referenced_one(struct p - } - - if (pvmw.pte) { -+ if (lru_gen_enabled() && pte_young(*pvmw.pte) && -+ !(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) { -+ lru_gen_look_around(&pvmw); -+ referenced++; -+ } -+ - if (ptep_clear_flush_young_notify(vma, address, - pvmw.pte)) { - /* ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -325,7 +325,7 @@ static bool need_activate_page_drain(int - return pagevec_count(&per_cpu(lru_pvecs.activate_page, cpu)) != 0; - } - --static void activate_page(struct page *page) -+void activate_page(struct page *page) - { - page = compound_head(page); - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { -@@ -345,7 +345,7 @@ static inline void activate_page_drain(i - { - } - --static void activate_page(struct page *page) -+void activate_page(struct page *page) - { - struct lruvec *lruvec; - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -1409,6 +1409,11 @@ retry: - if (!sc->may_unmap && page_mapped(page)) - goto keep_locked; - -+ /* page_update_gen() tried to promote this page? */ -+ if (lru_gen_enabled() && !ignore_references && -+ page_mapped(page) && PageReferenced(page)) -+ goto keep_locked; -+ - may_enter_fs = (sc->gfp_mask & __GFP_FS) || - (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); - -@@ -2990,6 +2995,29 @@ static bool positive_ctrl_err(struct ctr - * the aging - ******************************************************************************/ - -+/* promote pages accessed through page tables */ -+static int page_update_gen(struct page *page, int gen) -+{ -+ unsigned long new_flags, old_flags = READ_ONCE(page->flags); -+ -+ VM_WARN_ON_ONCE(gen >= MAX_NR_GENS); -+ VM_WARN_ON_ONCE(!rcu_read_lock_held()); -+ -+ do { -+ /* lru_gen_del_page() has isolated this page? */ -+ if (!(old_flags & LRU_GEN_MASK)) { -+ /* for shrink_page_list() */ -+ new_flags = old_flags | BIT(PG_referenced); -+ continue; -+ } -+ -+ new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); -+ new_flags |= (gen + 1UL) << LRU_GEN_PGOFF; -+ } while (!try_cmpxchg(&page->flags, &old_flags, new_flags)); -+ -+ return ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+} -+ - /* protect pages accessed multiple times through file descriptors */ - static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) - { -@@ -3001,6 +3029,11 @@ static int page_inc_gen(struct lruvec *l - VM_WARN_ON_ONCE_PAGE(!(old_flags & LRU_GEN_MASK), page); - - do { -+ new_gen = ((old_flags & LRU_GEN_MASK) >> LRU_GEN_PGOFF) - 1; -+ /* page_update_gen() has promoted this page? */ -+ if (new_gen >= 0 && new_gen != old_gen) -+ return new_gen; -+ - new_gen = (old_gen + 1) % MAX_NR_GENS; - - new_flags = old_flags & ~(LRU_GEN_MASK | LRU_REFS_MASK | LRU_REFS_FLAGS); -@@ -3015,6 +3048,43 @@ static int page_inc_gen(struct lruvec *l - return new_gen; - } - -+static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) -+{ -+ unsigned long pfn = pte_pfn(pte); -+ -+ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); -+ -+ if (!pte_present(pte) || is_zero_pfn(pfn)) -+ return -1; -+ -+ if (WARN_ON_ONCE(pte_devmap(pte) || pte_special(pte))) -+ return -1; -+ -+ if (WARN_ON_ONCE(!pfn_valid(pfn))) -+ return -1; -+ -+ return pfn; -+} -+ -+static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, -+ struct pglist_data *pgdat) -+{ -+ struct page *page; -+ -+ /* try to avoid unnecessary memory loads */ -+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) -+ return NULL; -+ -+ page = compound_head(pfn_to_page(pfn)); -+ if (page_to_nid(page) != pgdat->node_id) -+ return NULL; -+ -+ if (page_memcg_rcu(page) != memcg) -+ return NULL; -+ -+ return page; -+} -+ - static void inc_min_seq(struct lruvec *lruvec, int type) - { - struct lru_gen_struct *lrugen = &lruvec->lrugen; -@@ -3214,6 +3284,114 @@ static void lru_gen_age_node(struct pgli - } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); - } - -+/* -+ * This function exploits spatial locality when shrink_page_list() walks the -+ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. -+ */ -+void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) -+{ -+ int i; -+ pte_t *pte; -+ unsigned long start; -+ unsigned long end; -+ unsigned long addr; -+ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; -+ struct page *page = pvmw->page; -+ struct mem_cgroup *memcg = page_memcg(page); -+ struct pglist_data *pgdat = page_pgdat(page); -+ struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -+ DEFINE_MAX_SEQ(lruvec); -+ int old_gen, new_gen = lru_gen_from_seq(max_seq); -+ -+ lockdep_assert_held(pvmw->ptl); -+ VM_WARN_ON_ONCE_PAGE(PageLRU(page), page); -+ -+ if (spin_is_contended(pvmw->ptl)) -+ return; -+ -+ start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); -+ end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; -+ -+ if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { -+ if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) -+ end = start + MIN_LRU_BATCH * PAGE_SIZE; -+ else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) -+ start = end - MIN_LRU_BATCH * PAGE_SIZE; -+ else { -+ start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; -+ end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; -+ } -+ } -+ -+ pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; -+ -+ rcu_read_lock(); -+ arch_enter_lazy_mmu_mode(); -+ -+ for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { -+ unsigned long pfn; -+ -+ pfn = get_pte_pfn(pte[i], pvmw->vma, addr); -+ if (pfn == -1) -+ continue; -+ -+ if (!pte_young(pte[i])) -+ continue; -+ -+ page = get_pfn_page(pfn, memcg, pgdat); -+ if (!page) -+ continue; -+ -+ if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) -+ VM_WARN_ON_ONCE(true); -+ -+ if (pte_dirty(pte[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && -+ !PageSwapCache(page))) -+ set_page_dirty(page); -+ -+ old_gen = page_lru_gen(page); -+ if (old_gen < 0) -+ SetPageReferenced(page); -+ else if (old_gen != new_gen) -+ __set_bit(i, bitmap); -+ } -+ -+ arch_leave_lazy_mmu_mode(); -+ rcu_read_unlock(); -+ -+ if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { -+ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { -+ page = pte_page(pte[i]); -+ activate_page(page); -+ } -+ return; -+ } -+ -+ /* page_update_gen() requires stable page_memcg() */ -+ if (!mem_cgroup_trylock_pages(memcg)) -+ return; -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); -+ -+ for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { -+ page = compound_head(pte_page(pte[i])); -+ if (page_memcg_rcu(page) != memcg) -+ continue; -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen < 0 || old_gen == new_gen) -+ continue; -+ -+ lru_gen_update_size(lruvec, page, old_gen, new_gen); -+ } -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ -+ mem_cgroup_unlock_pages(); -+} -+ - /****************************************************************************** - * the eviction - ******************************************************************************/ -@@ -3250,6 +3428,12 @@ static bool sort_page(struct lruvec *lru - return true; - } - -+ /* promoted */ -+ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { -+ list_move(&page->lru, &lrugen->lists[gen][type][zone]); -+ return true; -+ } -+ - /* protected */ - if (tier > tier_idx) { - int hist = lru_hist_from_seq(lrugen->min_seq[type]); diff --git a/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch b/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch deleted file mode 100644 index dad21dccb58..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-08-mm-multi-gen-LRU-support-page-table-walks.patch +++ /dev/null @@ -1,1687 +0,0 @@ -From 05223c4e80b34e29f2255c04ffebc2c4475e7593 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:05 -0600 -Subject: [PATCH 08/29] mm: multi-gen LRU: support page table walks -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To further exploit spatial locality, the aging prefers to walk page tables -to search for young PTEs and promote hot pages. A kill switch will be -added in the next patch to disable this behavior. When disabled, the -aging relies on the rmap only. - -NB: this behavior has nothing similar with the page table scanning in the -2.4 kernel [1], which searches page tables for old PTEs, adds cold pages -to swapcache and unmaps them. - -To avoid confusion, the term "iteration" specifically means the traversal -of an entire mm_struct list; the term "walk" will be applied to page -tables and the rmap, as usual. - -An mm_struct list is maintained for each memcg, and an mm_struct follows -its owner task to the new memcg when this task is migrated. Given an -lruvec, the aging iterates lruvec_memcg()->mm_list and calls -walk_page_range() with each mm_struct on this list to promote hot pages -before it increments max_seq. - -When multiple page table walkers iterate the same list, each of them gets -a unique mm_struct; therefore they can run concurrently. Page table -walkers ignore any misplaced pages, e.g., if an mm_struct was migrated, -pages it left in the previous memcg will not be promoted when its current -memcg is under reclaim. Similarly, page table walkers will not promote -pages from nodes other than the one under reclaim. - -This patch uses the following optimizations when walking page tables: -1. It tracks the usage of mm_struct's between context switches so that - page table walkers can skip processes that have been sleeping since - the last iteration. -2. It uses generational Bloom filters to record populated branches so - that page table walkers can reduce their search space based on the - query results, e.g., to skip page tables containing mostly holes or - misplaced pages. -3. It takes advantage of the accessed bit in non-leaf PMD entries when - CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y. -4. It does not zigzag between a PGD table and the same PMD table - spanning multiple VMAs. IOW, it finishes all the VMAs within the - range of the same PMD table before it returns to a PGD table. This - improves the cache performance for workloads that have large - numbers of tiny VMAs [2], especially when CONFIG_PGTABLE_LEVELS=5. - -Server benchmark results: - Single workload: - fio (buffered I/O): no change - - Single workload: - memcached (anon): +[8, 10]% - Ops/sec KB/sec - patch1-7: 1147696.57 44640.29 - patch1-8: 1245274.91 48435.66 - - Configurations: - no change - -Client benchmark results: - kswapd profiles: - patch1-7 - 48.16% lzo1x_1_do_compress (real work) - 8.20% page_vma_mapped_walk (overhead) - 7.06% _raw_spin_unlock_irq - 2.92% ptep_clear_flush - 2.53% __zram_bvec_write - 2.11% do_raw_spin_lock - 2.02% memmove - 1.93% lru_gen_look_around - 1.56% free_unref_page_list - 1.40% memset - - patch1-8 - 49.44% lzo1x_1_do_compress (real work) - 6.19% page_vma_mapped_walk (overhead) - 5.97% _raw_spin_unlock_irq - 3.13% get_pfn_page - 2.85% ptep_clear_flush - 2.42% __zram_bvec_write - 2.08% do_raw_spin_lock - 1.92% memmove - 1.44% alloc_zspage - 1.36% memset - - Configurations: - no change - -Thanks to the following developers for their efforts [3]. - kernel test robot - -[1] https://lwn.net/Articles/23732/ -[2] https://llvm.org/docs/ScudoHardenedAllocator.html -[3] https://lore.kernel.org/r/202204160827.ekEARWQo-lkp@intel.com/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-9-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - fs/exec.c | 2 + - include/linux/memcontrol.h | 5 + - include/linux/mm_types.h | 76 +++ - include/linux/mmzone.h | 56 +- - include/linux/swap.h | 4 + - kernel/exit.c | 1 + - kernel/fork.c | 9 + - kernel/sched/core.c | 1 + - mm/memcontrol.c | 25 + - mm/vmscan.c | 1010 +++++++++++++++++++++++++++++++++++- - 10 files changed, 1172 insertions(+), 17 deletions(-) - ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -1013,6 +1013,7 @@ static int exec_mmap(struct mm_struct *m - active_mm = tsk->active_mm; - tsk->active_mm = mm; - tsk->mm = mm; -+ lru_gen_add_mm(mm); - /* - * This prevents preemption while active_mm is being loaded and - * it and mm are being updated, which could cause problems for -@@ -1028,6 +1029,7 @@ static int exec_mmap(struct mm_struct *m - tsk->mm->vmacache_seqnum = 0; - vmacache_flush(tsk); - task_unlock(tsk); -+ lru_gen_use_mm(mm); - if (old_mm) { - mmap_read_unlock(old_mm); - BUG_ON(active_mm != old_mm); ---- a/include/linux/memcontrol.h -+++ b/include/linux/memcontrol.h -@@ -348,6 +348,11 @@ struct mem_cgroup { - struct deferred_split deferred_split_queue; - #endif - -+#ifdef CONFIG_LRU_GEN -+ /* per-memcg mm_struct list */ -+ struct lru_gen_mm_list mm_list; -+#endif -+ - struct mem_cgroup_per_node *nodeinfo[]; - }; - ---- a/include/linux/mm_types.h -+++ b/include/linux/mm_types.h -@@ -580,6 +580,22 @@ struct mm_struct { - #ifdef CONFIG_IOMMU_SUPPORT - u32 pasid; - #endif -+#ifdef CONFIG_LRU_GEN -+ struct { -+ /* this mm_struct is on lru_gen_mm_list */ -+ struct list_head list; -+ /* -+ * Set when switching to this mm_struct, as a hint of -+ * whether it has been used since the last time per-node -+ * page table walkers cleared the corresponding bits. -+ */ -+ unsigned long bitmap; -+#ifdef CONFIG_MEMCG -+ /* points to the memcg of "owner" above */ -+ struct mem_cgroup *memcg; -+#endif -+ } lru_gen; -+#endif /* CONFIG_LRU_GEN */ - } __randomize_layout; - - /* -@@ -606,6 +622,66 @@ static inline cpumask_t *mm_cpumask(stru - return (struct cpumask *)&mm->cpu_bitmap; - } - -+#ifdef CONFIG_LRU_GEN -+ -+struct lru_gen_mm_list { -+ /* mm_struct list for page table walkers */ -+ struct list_head fifo; -+ /* protects the list above */ -+ spinlock_t lock; -+}; -+ -+void lru_gen_add_mm(struct mm_struct *mm); -+void lru_gen_del_mm(struct mm_struct *mm); -+#ifdef CONFIG_MEMCG -+void lru_gen_migrate_mm(struct mm_struct *mm); -+#endif -+ -+static inline void lru_gen_init_mm(struct mm_struct *mm) -+{ -+ INIT_LIST_HEAD(&mm->lru_gen.list); -+ mm->lru_gen.bitmap = 0; -+#ifdef CONFIG_MEMCG -+ mm->lru_gen.memcg = NULL; -+#endif -+} -+ -+static inline void lru_gen_use_mm(struct mm_struct *mm) -+{ -+ /* -+ * When the bitmap is set, page reclaim knows this mm_struct has been -+ * used since the last time it cleared the bitmap. So it might be worth -+ * walking the page tables of this mm_struct to clear the accessed bit. -+ */ -+ WRITE_ONCE(mm->lru_gen.bitmap, -1); -+} -+ -+#else /* !CONFIG_LRU_GEN */ -+ -+static inline void lru_gen_add_mm(struct mm_struct *mm) -+{ -+} -+ -+static inline void lru_gen_del_mm(struct mm_struct *mm) -+{ -+} -+ -+#ifdef CONFIG_MEMCG -+static inline void lru_gen_migrate_mm(struct mm_struct *mm) -+{ -+} -+#endif -+ -+static inline void lru_gen_init_mm(struct mm_struct *mm) -+{ -+} -+ -+static inline void lru_gen_use_mm(struct mm_struct *mm) -+{ -+} -+ -+#endif /* CONFIG_LRU_GEN */ -+ - struct mmu_gather; - extern void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm); - extern void tlb_gather_mmu_fullmm(struct mmu_gather *tlb, struct mm_struct *mm); ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -385,7 +385,7 @@ enum { - * min_seq behind. - * - * The number of pages in each generation is eventually consistent and therefore -- * can be transiently negative. -+ * can be transiently negative when reset_batch_size() is pending. - */ - struct lru_gen_struct { - /* the aging increments the youngest generation number */ -@@ -407,6 +407,53 @@ struct lru_gen_struct { - atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; - }; - -+enum { -+ MM_LEAF_TOTAL, /* total leaf entries */ -+ MM_LEAF_OLD, /* old leaf entries */ -+ MM_LEAF_YOUNG, /* young leaf entries */ -+ MM_NONLEAF_TOTAL, /* total non-leaf entries */ -+ MM_NONLEAF_FOUND, /* non-leaf entries found in Bloom filters */ -+ MM_NONLEAF_ADDED, /* non-leaf entries added to Bloom filters */ -+ NR_MM_STATS -+}; -+ -+/* double-buffering Bloom filters */ -+#define NR_BLOOM_FILTERS 2 -+ -+struct lru_gen_mm_state { -+ /* set to max_seq after each iteration */ -+ unsigned long seq; -+ /* where the current iteration continues (inclusive) */ -+ struct list_head *head; -+ /* where the last iteration ended (exclusive) */ -+ struct list_head *tail; -+ /* to wait for the last page table walker to finish */ -+ struct wait_queue_head wait; -+ /* Bloom filters flip after each iteration */ -+ unsigned long *filters[NR_BLOOM_FILTERS]; -+ /* the mm stats for debugging */ -+ unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; -+ /* the number of concurrent page table walkers */ -+ int nr_walkers; -+}; -+ -+struct lru_gen_mm_walk { -+ /* the lruvec under reclaim */ -+ struct lruvec *lruvec; -+ /* unstable max_seq from lru_gen_struct */ -+ unsigned long max_seq; -+ /* the next address within an mm to scan */ -+ unsigned long next_addr; -+ /* to batch promoted pages */ -+ int nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ /* to batch the mm stats */ -+ int mm_stats[NR_MM_STATS]; -+ /* total batched items */ -+ int batched; -+ bool can_swap; -+ bool force_scan; -+}; -+ - void lru_gen_init_lruvec(struct lruvec *lruvec); - void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); - -@@ -457,6 +504,8 @@ struct lruvec { - #ifdef CONFIG_LRU_GEN - /* evictable pages divided into generations */ - struct lru_gen_struct lrugen; -+ /* to concurrently iterate lru_gen_mm_list */ -+ struct lru_gen_mm_state mm_state; - #endif - #ifdef CONFIG_MEMCG - struct pglist_data *pgdat; -@@ -1042,6 +1091,11 @@ typedef struct pglist_data { - - unsigned long flags; - -+#ifdef CONFIG_LRU_GEN -+ /* kswap mm walk data */ -+ struct lru_gen_mm_walk mm_walk; -+#endif -+ - ZONE_PADDING(_pad2_) - - /* Per-node vmstats */ ---- a/include/linux/swap.h -+++ b/include/linux/swap.h -@@ -137,6 +137,10 @@ union swap_header { - */ - struct reclaim_state { - unsigned long reclaimed_slab; -+#ifdef CONFIG_LRU_GEN -+ /* per-thread mm walk data */ -+ struct lru_gen_mm_walk *mm_walk; -+#endif - }; - - #ifdef __KERNEL__ ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -469,6 +469,7 @@ assign_new_owner: - goto retry; - } - WRITE_ONCE(mm->owner, c); -+ lru_gen_migrate_mm(mm); - task_unlock(c); - put_task_struct(c); - } ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1083,6 +1083,7 @@ static struct mm_struct *mm_init(struct - goto fail_nocontext; - - mm->user_ns = get_user_ns(user_ns); -+ lru_gen_init_mm(mm); - return mm; - - fail_nocontext: -@@ -1125,6 +1126,7 @@ static inline void __mmput(struct mm_str - } - if (mm->binfmt) - module_put(mm->binfmt->module); -+ lru_gen_del_mm(mm); - mmdrop(mm); - } - -@@ -2622,6 +2624,13 @@ pid_t kernel_clone(struct kernel_clone_a - get_task_struct(p); - } - -+ if (IS_ENABLED(CONFIG_LRU_GEN) && !(clone_flags & CLONE_VM)) { -+ /* lock the task to synchronize with memcg migration */ -+ task_lock(p); -+ lru_gen_add_mm(p->mm); -+ task_unlock(p); -+ } -+ - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -5010,6 +5010,7 @@ context_switch(struct rq *rq, struct tas - * finish_task_switch()'s mmdrop(). - */ - switch_mm_irqs_off(prev->active_mm, next->mm, next); -+ lru_gen_use_mm(next->mm); - - if (!prev->mm) { // from kernel - /* will mmdrop() in finish_task_switch(). */ ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -6212,6 +6212,30 @@ static void mem_cgroup_move_task(void) - } - #endif - -+#ifdef CONFIG_LRU_GEN -+static void mem_cgroup_attach(struct cgroup_taskset *tset) -+{ -+ struct task_struct *task; -+ struct cgroup_subsys_state *css; -+ -+ /* find the first leader if there is any */ -+ cgroup_taskset_for_each_leader(task, css, tset) -+ break; -+ -+ if (!task) -+ return; -+ -+ task_lock(task); -+ if (task->mm && READ_ONCE(task->mm->owner) == task) -+ lru_gen_migrate_mm(task->mm); -+ task_unlock(task); -+} -+#else -+static void mem_cgroup_attach(struct cgroup_taskset *tset) -+{ -+} -+#endif /* CONFIG_LRU_GEN */ -+ - static int seq_puts_memcg_tunable(struct seq_file *m, unsigned long value) - { - if (value == PAGE_COUNTER_MAX) -@@ -6555,6 +6579,7 @@ struct cgroup_subsys memory_cgrp_subsys - .css_reset = mem_cgroup_css_reset, - .css_rstat_flush = mem_cgroup_css_rstat_flush, - .can_attach = mem_cgroup_can_attach, -+ .attach = mem_cgroup_attach, - .cancel_attach = mem_cgroup_cancel_attach, - .post_attach = mem_cgroup_move_task, - .dfl_cftypes = memory_files, ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -50,6 +50,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -2853,7 +2855,7 @@ static bool can_age_anon_pages(struct pg - for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ - for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) - --static struct lruvec __maybe_unused *get_lruvec(struct mem_cgroup *memcg, int nid) -+static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) - { - struct pglist_data *pgdat = NODE_DATA(nid); - -@@ -2899,6 +2901,371 @@ static bool __maybe_unused seq_is_valid( - } - - /****************************************************************************** -+ * mm_struct list -+ ******************************************************************************/ -+ -+static struct lru_gen_mm_list *get_mm_list(struct mem_cgroup *memcg) -+{ -+ static struct lru_gen_mm_list mm_list = { -+ .fifo = LIST_HEAD_INIT(mm_list.fifo), -+ .lock = __SPIN_LOCK_UNLOCKED(mm_list.lock), -+ }; -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) -+ return &memcg->mm_list; -+#endif -+ VM_WARN_ON_ONCE(!mem_cgroup_disabled()); -+ -+ return &mm_list; -+} -+ -+void lru_gen_add_mm(struct mm_struct *mm) -+{ -+ int nid; -+ struct mem_cgroup *memcg = get_mem_cgroup_from_mm(mm); -+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); -+ -+ VM_WARN_ON_ONCE(!list_empty(&mm->lru_gen.list)); -+#ifdef CONFIG_MEMCG -+ VM_WARN_ON_ONCE(mm->lru_gen.memcg); -+ mm->lru_gen.memcg = memcg; -+#endif -+ spin_lock(&mm_list->lock); -+ -+ for_each_node_state(nid, N_MEMORY) { -+ struct lruvec *lruvec = get_lruvec(memcg, nid); -+ -+ if (!lruvec) -+ continue; -+ -+ /* the first addition since the last iteration */ -+ if (lruvec->mm_state.tail == &mm_list->fifo) -+ lruvec->mm_state.tail = &mm->lru_gen.list; -+ } -+ -+ list_add_tail(&mm->lru_gen.list, &mm_list->fifo); -+ -+ spin_unlock(&mm_list->lock); -+} -+ -+void lru_gen_del_mm(struct mm_struct *mm) -+{ -+ int nid; -+ struct lru_gen_mm_list *mm_list; -+ struct mem_cgroup *memcg = NULL; -+ -+ if (list_empty(&mm->lru_gen.list)) -+ return; -+ -+#ifdef CONFIG_MEMCG -+ memcg = mm->lru_gen.memcg; -+#endif -+ mm_list = get_mm_list(memcg); -+ -+ spin_lock(&mm_list->lock); -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(memcg, nid); -+ -+ if (!lruvec) -+ continue; -+ -+ /* where the last iteration ended (exclusive) */ -+ if (lruvec->mm_state.tail == &mm->lru_gen.list) -+ lruvec->mm_state.tail = lruvec->mm_state.tail->next; -+ -+ /* where the current iteration continues (inclusive) */ -+ if (lruvec->mm_state.head != &mm->lru_gen.list) -+ continue; -+ -+ lruvec->mm_state.head = lruvec->mm_state.head->next; -+ /* the deletion ends the current iteration */ -+ if (lruvec->mm_state.head == &mm_list->fifo) -+ WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); -+ } -+ -+ list_del_init(&mm->lru_gen.list); -+ -+ spin_unlock(&mm_list->lock); -+ -+#ifdef CONFIG_MEMCG -+ mem_cgroup_put(mm->lru_gen.memcg); -+ mm->lru_gen.memcg = NULL; -+#endif -+} -+ -+#ifdef CONFIG_MEMCG -+void lru_gen_migrate_mm(struct mm_struct *mm) -+{ -+ struct mem_cgroup *memcg; -+ struct task_struct *task = rcu_dereference_protected(mm->owner, true); -+ -+ VM_WARN_ON_ONCE(task->mm != mm); -+ lockdep_assert_held(&task->alloc_lock); -+ -+ /* for mm_update_next_owner() */ -+ if (mem_cgroup_disabled()) -+ return; -+ -+ rcu_read_lock(); -+ memcg = mem_cgroup_from_task(task); -+ rcu_read_unlock(); -+ if (memcg == mm->lru_gen.memcg) -+ return; -+ -+ VM_WARN_ON_ONCE(!mm->lru_gen.memcg); -+ VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); -+ -+ lru_gen_del_mm(mm); -+ lru_gen_add_mm(mm); -+} -+#endif -+ -+/* -+ * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when -+ * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of -+ * bits in a bitmap, k is the number of hash functions and n is the number of -+ * inserted items. -+ * -+ * Page table walkers use one of the two filters to reduce their search space. -+ * To get rid of non-leaf entries that no longer have enough leaf entries, the -+ * aging uses the double-buffering technique to flip to the other filter each -+ * time it produces a new generation. For non-leaf entries that have enough -+ * leaf entries, the aging carries them over to the next generation in -+ * walk_pmd_range(); the eviction also report them when walking the rmap -+ * in lru_gen_look_around(). -+ * -+ * For future optimizations: -+ * 1. It's not necessary to keep both filters all the time. The spare one can be -+ * freed after the RCU grace period and reallocated if needed again. -+ * 2. And when reallocating, it's worth scaling its size according to the number -+ * of inserted entries in the other filter, to reduce the memory overhead on -+ * small systems and false positives on large systems. -+ * 3. Jenkins' hash function is an alternative to Knuth's. -+ */ -+#define BLOOM_FILTER_SHIFT 15 -+ -+static inline int filter_gen_from_seq(unsigned long seq) -+{ -+ return seq % NR_BLOOM_FILTERS; -+} -+ -+static void get_item_key(void *item, int *key) -+{ -+ u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); -+ -+ BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); -+ -+ key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); -+ key[1] = hash >> BLOOM_FILTER_SHIFT; -+} -+ -+static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) -+{ -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ filter = lruvec->mm_state.filters[gen]; -+ if (filter) { -+ bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); -+ return; -+ } -+ -+ filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), -+ __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); -+ WRITE_ONCE(lruvec->mm_state.filters[gen], filter); -+} -+ -+static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) -+{ -+ int key[2]; -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ filter = READ_ONCE(lruvec->mm_state.filters[gen]); -+ if (!filter) -+ return; -+ -+ get_item_key(item, key); -+ -+ if (!test_bit(key[0], filter)) -+ set_bit(key[0], filter); -+ if (!test_bit(key[1], filter)) -+ set_bit(key[1], filter); -+} -+ -+static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) -+{ -+ int key[2]; -+ unsigned long *filter; -+ int gen = filter_gen_from_seq(seq); -+ -+ filter = READ_ONCE(lruvec->mm_state.filters[gen]); -+ if (!filter) -+ return true; -+ -+ get_item_key(item, key); -+ -+ return test_bit(key[0], filter) && test_bit(key[1], filter); -+} -+ -+static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) -+{ -+ int i; -+ int hist; -+ -+ lockdep_assert_held(&get_mm_list(lruvec_memcg(lruvec))->lock); -+ -+ if (walk) { -+ hist = lru_hist_from_seq(walk->max_seq); -+ -+ for (i = 0; i < NR_MM_STATS; i++) { -+ WRITE_ONCE(lruvec->mm_state.stats[hist][i], -+ lruvec->mm_state.stats[hist][i] + walk->mm_stats[i]); -+ walk->mm_stats[i] = 0; -+ } -+ } -+ -+ if (NR_HIST_GENS > 1 && last) { -+ hist = lru_hist_from_seq(lruvec->mm_state.seq + 1); -+ -+ for (i = 0; i < NR_MM_STATS; i++) -+ WRITE_ONCE(lruvec->mm_state.stats[hist][i], 0); -+ } -+} -+ -+static bool should_skip_mm(struct mm_struct *mm, struct lru_gen_mm_walk *walk) -+{ -+ int type; -+ unsigned long size = 0; -+ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); -+ int key = pgdat->node_id % BITS_PER_TYPE(mm->lru_gen.bitmap); -+ -+ if (!walk->force_scan && !test_bit(key, &mm->lru_gen.bitmap)) -+ return true; -+ -+ clear_bit(key, &mm->lru_gen.bitmap); -+ -+ for (type = !walk->can_swap; type < ANON_AND_FILE; type++) { -+ size += type ? get_mm_counter(mm, MM_FILEPAGES) : -+ get_mm_counter(mm, MM_ANONPAGES) + -+ get_mm_counter(mm, MM_SHMEMPAGES); -+ } -+ -+ if (size < MIN_LRU_BATCH) -+ return true; -+ -+ return !mmget_not_zero(mm); -+} -+ -+static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, -+ struct mm_struct **iter) -+{ -+ bool first = false; -+ bool last = true; -+ struct mm_struct *mm = NULL; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); -+ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; -+ -+ /* -+ * There are four interesting cases for this page table walker: -+ * 1. It tries to start a new iteration of mm_list with a stale max_seq; -+ * there is nothing left to do. -+ * 2. It's the first of the current generation, and it needs to reset -+ * the Bloom filter for the next generation. -+ * 3. It reaches the end of mm_list, and it needs to increment -+ * mm_state->seq; the iteration is done. -+ * 4. It's the last of the current generation, and it needs to reset the -+ * mm stats counters for the next generation. -+ */ -+ spin_lock(&mm_list->lock); -+ -+ VM_WARN_ON_ONCE(mm_state->seq + 1 < walk->max_seq); -+ VM_WARN_ON_ONCE(*iter && mm_state->seq > walk->max_seq); -+ VM_WARN_ON_ONCE(*iter && !mm_state->nr_walkers); -+ -+ if (walk->max_seq <= mm_state->seq) { -+ if (!*iter) -+ last = false; -+ goto done; -+ } -+ -+ if (!mm_state->nr_walkers) { -+ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); -+ -+ mm_state->head = mm_list->fifo.next; -+ first = true; -+ } -+ -+ while (!mm && mm_state->head != &mm_list->fifo) { -+ mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); -+ -+ mm_state->head = mm_state->head->next; -+ -+ /* force scan for those added after the last iteration */ -+ if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { -+ mm_state->tail = mm_state->head; -+ walk->force_scan = true; -+ } -+ -+ if (should_skip_mm(mm, walk)) -+ mm = NULL; -+ } -+ -+ if (mm_state->head == &mm_list->fifo) -+ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); -+done: -+ if (*iter && !mm) -+ mm_state->nr_walkers--; -+ if (!*iter && mm) -+ mm_state->nr_walkers++; -+ -+ if (mm_state->nr_walkers) -+ last = false; -+ -+ if (*iter || last) -+ reset_mm_stats(lruvec, walk, last); -+ -+ spin_unlock(&mm_list->lock); -+ -+ if (mm && first) -+ reset_bloom_filter(lruvec, walk->max_seq + 1); -+ -+ if (*iter) -+ mmput_async(*iter); -+ -+ *iter = mm; -+ -+ return last; -+} -+ -+static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) -+{ -+ bool success = false; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ struct lru_gen_mm_list *mm_list = get_mm_list(memcg); -+ struct lru_gen_mm_state *mm_state = &lruvec->mm_state; -+ -+ spin_lock(&mm_list->lock); -+ -+ VM_WARN_ON_ONCE(mm_state->seq + 1 < max_seq); -+ -+ if (max_seq > mm_state->seq && !mm_state->nr_walkers) { -+ VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); -+ -+ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); -+ reset_mm_stats(lruvec, NULL, true); -+ success = true; -+ } -+ -+ spin_unlock(&mm_list->lock); -+ -+ return success; -+} -+ -+/****************************************************************************** - * refault feedback loop - ******************************************************************************/ - -@@ -3048,6 +3415,118 @@ static int page_inc_gen(struct lruvec *l - return new_gen; - } - -+static void update_batch_size(struct lru_gen_mm_walk *walk, struct page *page, -+ int old_gen, int new_gen) -+{ -+ int type = page_is_file_lru(page); -+ int zone = page_zonenum(page); -+ int delta = thp_nr_pages(page); -+ -+ VM_WARN_ON_ONCE(old_gen >= MAX_NR_GENS); -+ VM_WARN_ON_ONCE(new_gen >= MAX_NR_GENS); -+ -+ walk->batched++; -+ -+ walk->nr_pages[old_gen][type][zone] -= delta; -+ walk->nr_pages[new_gen][type][zone] += delta; -+} -+ -+static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) -+{ -+ int gen, type, zone; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ walk->batched = 0; -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ enum lru_list lru = type * LRU_INACTIVE_FILE; -+ int delta = walk->nr_pages[gen][type][zone]; -+ -+ if (!delta) -+ continue; -+ -+ walk->nr_pages[gen][type][zone] = 0; -+ WRITE_ONCE(lrugen->nr_pages[gen][type][zone], -+ lrugen->nr_pages[gen][type][zone] + delta); -+ -+ if (lru_gen_is_active(lruvec, gen)) -+ lru += LRU_ACTIVE; -+ __update_lru_size(lruvec, lru, zone, delta); -+ } -+} -+ -+static int should_skip_vma(unsigned long start, unsigned long end, struct mm_walk *args) -+{ -+ struct address_space *mapping; -+ struct vm_area_struct *vma = args->vma; -+ struct lru_gen_mm_walk *walk = args->private; -+ -+ if (!vma_is_accessible(vma)) -+ return true; -+ -+ if (is_vm_hugetlb_page(vma)) -+ return true; -+ -+ if (vma->vm_flags & (VM_LOCKED | VM_SPECIAL | VM_SEQ_READ | VM_RAND_READ)) -+ return true; -+ -+ if (vma == get_gate_vma(vma->vm_mm)) -+ return true; -+ -+ if (vma_is_anonymous(vma)) -+ return !walk->can_swap; -+ -+ if (WARN_ON_ONCE(!vma->vm_file || !vma->vm_file->f_mapping)) -+ return true; -+ -+ mapping = vma->vm_file->f_mapping; -+ if (mapping_unevictable(mapping)) -+ return true; -+ -+ if (shmem_mapping(mapping)) -+ return !walk->can_swap; -+ -+ /* to exclude special mappings like dax, etc. */ -+ return !mapping->a_ops->readpage; -+} -+ -+/* -+ * Some userspace memory allocators map many single-page VMAs. Instead of -+ * returning back to the PGD table for each of such VMAs, finish an entire PMD -+ * table to reduce zigzags and improve cache performance. -+ */ -+static bool get_next_vma(unsigned long mask, unsigned long size, struct mm_walk *args, -+ unsigned long *vm_start, unsigned long *vm_end) -+{ -+ unsigned long start = round_up(*vm_end, size); -+ unsigned long end = (start | ~mask) + 1; -+ -+ VM_WARN_ON_ONCE(mask & size); -+ VM_WARN_ON_ONCE((start & mask) != (*vm_start & mask)); -+ -+ while (args->vma) { -+ if (start >= args->vma->vm_end) { -+ args->vma = args->vma->vm_next; -+ continue; -+ } -+ -+ if (end && end <= args->vma->vm_start) -+ return false; -+ -+ if (should_skip_vma(args->vma->vm_start, args->vma->vm_end, args)) { -+ args->vma = args->vma->vm_next; -+ continue; -+ } -+ -+ *vm_start = max(start, args->vma->vm_start); -+ *vm_end = min(end - 1, args->vma->vm_end - 1) + 1; -+ -+ return true; -+ } -+ -+ return false; -+} -+ - static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr) - { - unsigned long pfn = pte_pfn(pte); -@@ -3066,8 +3545,28 @@ static unsigned long get_pte_pfn(pte_t p - return pfn; - } - -+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) -+static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr) -+{ -+ unsigned long pfn = pmd_pfn(pmd); -+ -+ VM_WARN_ON_ONCE(addr < vma->vm_start || addr >= vma->vm_end); -+ -+ if (!pmd_present(pmd) || is_huge_zero_pmd(pmd)) -+ return -1; -+ -+ if (WARN_ON_ONCE(pmd_devmap(pmd))) -+ return -1; -+ -+ if (WARN_ON_ONCE(!pfn_valid(pfn))) -+ return -1; -+ -+ return pfn; -+} -+#endif -+ - static struct page *get_pfn_page(unsigned long pfn, struct mem_cgroup *memcg, -- struct pglist_data *pgdat) -+ struct pglist_data *pgdat, bool can_swap) - { - struct page *page; - -@@ -3082,9 +3581,375 @@ static struct page *get_pfn_page(unsigne - if (page_memcg_rcu(page) != memcg) - return NULL; - -+ /* file VMAs can contain anon pages from COW */ -+ if (!page_is_file_lru(page) && !can_swap) -+ return NULL; -+ - return page; - } - -+static bool suitable_to_scan(int total, int young) -+{ -+ int n = clamp_t(int, cache_line_size() / sizeof(pte_t), 2, 8); -+ -+ /* suitable if the average number of young PTEs per cacheline is >=1 */ -+ return young * n >= total; -+} -+ -+static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, -+ struct mm_walk *args) -+{ -+ int i; -+ pte_t *pte; -+ spinlock_t *ptl; -+ unsigned long addr; -+ int total = 0; -+ int young = 0; -+ struct lru_gen_mm_walk *walk = args->private; -+ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); -+ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); -+ -+ VM_WARN_ON_ONCE(pmd_leaf(*pmd)); -+ -+ ptl = pte_lockptr(args->mm, pmd); -+ if (!spin_trylock(ptl)) -+ return false; -+ -+ arch_enter_lazy_mmu_mode(); -+ -+ pte = pte_offset_map(pmd, start & PMD_MASK); -+restart: -+ for (i = pte_index(start), addr = start; addr != end; i++, addr += PAGE_SIZE) { -+ unsigned long pfn; -+ struct page *page; -+ -+ total++; -+ walk->mm_stats[MM_LEAF_TOTAL]++; -+ -+ pfn = get_pte_pfn(pte[i], args->vma, addr); -+ if (pfn == -1) -+ continue; -+ -+ if (!pte_young(pte[i])) { -+ walk->mm_stats[MM_LEAF_OLD]++; -+ continue; -+ } -+ -+ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); -+ if (!page) -+ continue; -+ -+ if (!ptep_test_and_clear_young(args->vma, addr, pte + i)) -+ VM_WARN_ON_ONCE(true); -+ -+ young++; -+ walk->mm_stats[MM_LEAF_YOUNG]++; -+ -+ if (pte_dirty(pte[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && -+ !PageSwapCache(page))) -+ set_page_dirty(page); -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen >= 0 && old_gen != new_gen) -+ update_batch_size(walk, page, old_gen, new_gen); -+ } -+ -+ if (i < PTRS_PER_PTE && get_next_vma(PMD_MASK, PAGE_SIZE, args, &start, &end)) -+ goto restart; -+ -+ pte_unmap(pte); -+ -+ arch_leave_lazy_mmu_mode(); -+ spin_unlock(ptl); -+ -+ return suitable_to_scan(total, young); -+} -+ -+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) -+static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, -+ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) -+{ -+ int i; -+ pmd_t *pmd; -+ spinlock_t *ptl; -+ struct lru_gen_mm_walk *walk = args->private; -+ struct mem_cgroup *memcg = lruvec_memcg(walk->lruvec); -+ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); -+ int old_gen, new_gen = lru_gen_from_seq(walk->max_seq); -+ -+ VM_WARN_ON_ONCE(pud_leaf(*pud)); -+ -+ /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ -+ if (*start == -1) { -+ *start = next; -+ return; -+ } -+ -+ i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); -+ if (i && i <= MIN_LRU_BATCH) { -+ __set_bit(i - 1, bitmap); -+ return; -+ } -+ -+ pmd = pmd_offset(pud, *start); -+ -+ ptl = pmd_lockptr(args->mm, pmd); -+ if (!spin_trylock(ptl)) -+ goto done; -+ -+ arch_enter_lazy_mmu_mode(); -+ -+ do { -+ unsigned long pfn; -+ struct page *page; -+ unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; -+ -+ pfn = get_pmd_pfn(pmd[i], vma, addr); -+ if (pfn == -1) -+ goto next; -+ -+ if (!pmd_trans_huge(pmd[i])) { -+ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) -+ pmdp_test_and_clear_young(vma, addr, pmd + i); -+ goto next; -+ } -+ -+ page = get_pfn_page(pfn, memcg, pgdat, walk->can_swap); -+ if (!page) -+ goto next; -+ -+ if (!pmdp_test_and_clear_young(vma, addr, pmd + i)) -+ goto next; -+ -+ walk->mm_stats[MM_LEAF_YOUNG]++; -+ -+ if (pmd_dirty(pmd[i]) && !PageDirty(page) && -+ !(PageAnon(page) && PageSwapBacked(page) && -+ !PageSwapCache(page))) -+ set_page_dirty(page); -+ -+ old_gen = page_update_gen(page, new_gen); -+ if (old_gen >= 0 && old_gen != new_gen) -+ update_batch_size(walk, page, old_gen, new_gen); -+next: -+ i = i > MIN_LRU_BATCH ? 0 : find_next_bit(bitmap, MIN_LRU_BATCH, i) + 1; -+ } while (i <= MIN_LRU_BATCH); -+ -+ arch_leave_lazy_mmu_mode(); -+ spin_unlock(ptl); -+done: -+ *start = -1; -+ bitmap_zero(bitmap, MIN_LRU_BATCH); -+} -+#else -+static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, -+ struct mm_walk *args, unsigned long *bitmap, unsigned long *start) -+{ -+} -+#endif -+ -+static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, -+ struct mm_walk *args) -+{ -+ int i; -+ pmd_t *pmd; -+ unsigned long next; -+ unsigned long addr; -+ struct vm_area_struct *vma; -+ unsigned long pos = -1; -+ struct lru_gen_mm_walk *walk = args->private; -+ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; -+ -+ VM_WARN_ON_ONCE(pud_leaf(*pud)); -+ -+ /* -+ * Finish an entire PMD in two passes: the first only reaches to PTE -+ * tables to avoid taking the PMD lock; the second, if necessary, takes -+ * the PMD lock to clear the accessed bit in PMD entries. -+ */ -+ pmd = pmd_offset(pud, start & PUD_MASK); -+restart: -+ /* walk_pte_range() may call get_next_vma() */ -+ vma = args->vma; -+ for (i = pmd_index(start), addr = start; addr != end; i++, addr = next) { -+ pmd_t val = pmd_read_atomic(pmd + i); -+ -+ /* for pmd_read_atomic() */ -+ barrier(); -+ -+ next = pmd_addr_end(addr, end); -+ -+ if (!pmd_present(val) || is_huge_zero_pmd(val)) { -+ walk->mm_stats[MM_LEAF_TOTAL]++; -+ continue; -+ } -+ -+#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+ if (pmd_trans_huge(val)) { -+ unsigned long pfn = pmd_pfn(val); -+ struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec); -+ -+ walk->mm_stats[MM_LEAF_TOTAL]++; -+ -+ if (!pmd_young(val)) { -+ walk->mm_stats[MM_LEAF_OLD]++; -+ continue; -+ } -+ -+ /* try to avoid unnecessary memory loads */ -+ if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) -+ continue; -+ -+ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); -+ continue; -+ } -+#endif -+ walk->mm_stats[MM_NONLEAF_TOTAL]++; -+ -+#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -+ if (!pmd_young(val)) -+ continue; -+ -+ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); -+#endif -+ if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) -+ continue; -+ -+ walk->mm_stats[MM_NONLEAF_FOUND]++; -+ -+ if (!walk_pte_range(&val, addr, next, args)) -+ continue; -+ -+ walk->mm_stats[MM_NONLEAF_ADDED]++; -+ -+ /* carry over to the next generation */ -+ update_bloom_filter(walk->lruvec, walk->max_seq + 1, pmd + i); -+ } -+ -+ walk_pmd_range_locked(pud, -1, vma, args, bitmap, &pos); -+ -+ if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end)) -+ goto restart; -+} -+ -+static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, -+ struct mm_walk *args) -+{ -+ int i; -+ pud_t *pud; -+ unsigned long addr; -+ unsigned long next; -+ struct lru_gen_mm_walk *walk = args->private; -+ -+ VM_WARN_ON_ONCE(p4d_leaf(*p4d)); -+ -+ pud = pud_offset(p4d, start & P4D_MASK); -+restart: -+ for (i = pud_index(start), addr = start; addr != end; i++, addr = next) { -+ pud_t val = READ_ONCE(pud[i]); -+ -+ next = pud_addr_end(addr, end); -+ -+ if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val))) -+ continue; -+ -+ walk_pmd_range(&val, addr, next, args); -+ -+ /* a racy check to curtail the waiting time */ -+ if (wq_has_sleeper(&walk->lruvec->mm_state.wait)) -+ return 1; -+ -+ if (need_resched() || walk->batched >= MAX_LRU_BATCH) { -+ end = (addr | ~PUD_MASK) + 1; -+ goto done; -+ } -+ } -+ -+ if (i < PTRS_PER_PUD && get_next_vma(P4D_MASK, PUD_SIZE, args, &start, &end)) -+ goto restart; -+ -+ end = round_up(end, P4D_SIZE); -+done: -+ if (!end || !args->vma) -+ return 1; -+ -+ walk->next_addr = max(end, args->vma->vm_start); -+ -+ return -EAGAIN; -+} -+ -+static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_mm_walk *walk) -+{ -+ static const struct mm_walk_ops mm_walk_ops = { -+ .test_walk = should_skip_vma, -+ .p4d_entry = walk_pud_range, -+ }; -+ -+ int err; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ -+ walk->next_addr = FIRST_USER_ADDRESS; -+ -+ do { -+ err = -EBUSY; -+ -+ /* page_update_gen() requires stable page_memcg() */ -+ if (!mem_cgroup_trylock_pages(memcg)) -+ break; -+ -+ /* the caller might be holding the lock for write */ -+ if (mmap_read_trylock(mm)) { -+ err = walk_page_range(mm, walk->next_addr, ULONG_MAX, &mm_walk_ops, walk); -+ -+ mmap_read_unlock(mm); -+ } -+ -+ mem_cgroup_unlock_pages(); -+ -+ if (walk->batched) { -+ spin_lock_irq(&lruvec->lru_lock); -+ reset_batch_size(lruvec, walk); -+ spin_unlock_irq(&lruvec->lru_lock); -+ } -+ -+ cond_resched(); -+ } while (err == -EAGAIN); -+} -+ -+static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) -+{ -+ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; -+ -+ if (pgdat && current_is_kswapd()) { -+ VM_WARN_ON_ONCE(walk); -+ -+ walk = &pgdat->mm_walk; -+ } else if (!pgdat && !walk) { -+ VM_WARN_ON_ONCE(current_is_kswapd()); -+ -+ walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); -+ } -+ -+ current->reclaim_state->mm_walk = walk; -+ -+ return walk; -+} -+ -+static void clear_mm_walk(void) -+{ -+ struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; -+ -+ VM_WARN_ON_ONCE(walk && memchr_inv(walk->nr_pages, 0, sizeof(walk->nr_pages))); -+ VM_WARN_ON_ONCE(walk && memchr_inv(walk->mm_stats, 0, sizeof(walk->mm_stats))); -+ -+ current->reclaim_state->mm_walk = NULL; -+ -+ if (!current_is_kswapd()) -+ kfree(walk); -+} -+ - static void inc_min_seq(struct lruvec *lruvec, int type) - { - struct lru_gen_struct *lrugen = &lruvec->lrugen; -@@ -3136,7 +4001,7 @@ next: - return success; - } - --static void inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool can_swap) -+static void inc_max_seq(struct lruvec *lruvec, bool can_swap) - { - int prev, next; - int type, zone; -@@ -3146,9 +4011,6 @@ static void inc_max_seq(struct lruvec *l - - VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); - -- if (max_seq != lrugen->max_seq) -- goto unlock; -- - for (type = ANON_AND_FILE - 1; type >= 0; type--) { - if (get_nr_gens(lruvec, type) != MAX_NR_GENS) - continue; -@@ -3186,10 +4048,76 @@ static void inc_max_seq(struct lruvec *l - - /* make sure preceding modifications appear */ - smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); --unlock: -+ - spin_unlock_irq(&lruvec->lru_lock); - } - -+static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, -+ struct scan_control *sc, bool can_swap) -+{ -+ bool success; -+ struct lru_gen_mm_walk *walk; -+ struct mm_struct *mm = NULL; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); -+ -+ /* see the comment in iterate_mm_list() */ -+ if (max_seq <= READ_ONCE(lruvec->mm_state.seq)) { -+ success = false; -+ goto done; -+ } -+ -+ /* -+ * If the hardware doesn't automatically set the accessed bit, fallback -+ * to lru_gen_look_around(), which only clears the accessed bit in a -+ * handful of PTEs. Spreading the work out over a period of time usually -+ * is less efficient, but it avoids bursty page faults. -+ */ -+ if (!arch_has_hw_pte_young()) { -+ success = iterate_mm_list_nowalk(lruvec, max_seq); -+ goto done; -+ } -+ -+ walk = set_mm_walk(NULL); -+ if (!walk) { -+ success = iterate_mm_list_nowalk(lruvec, max_seq); -+ goto done; -+ } -+ -+ walk->lruvec = lruvec; -+ walk->max_seq = max_seq; -+ walk->can_swap = can_swap; -+ walk->force_scan = false; -+ -+ do { -+ success = iterate_mm_list(lruvec, walk, &mm); -+ if (mm) -+ walk_mm(lruvec, mm, walk); -+ -+ cond_resched(); -+ } while (mm); -+done: -+ if (!success) { -+ if (sc->priority <= DEF_PRIORITY - 2) -+ wait_event_killable(lruvec->mm_state.wait, -+ max_seq < READ_ONCE(lrugen->max_seq)); -+ -+ return max_seq < READ_ONCE(lrugen->max_seq); -+ } -+ -+ VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); -+ -+ inc_max_seq(lruvec, can_swap); -+ /* either this sees any waiters or they will see updated max_seq */ -+ if (wq_has_sleeper(&lruvec->mm_state.wait)) -+ wake_up_all(&lruvec->mm_state.wait); -+ -+ wakeup_flusher_threads(WB_REASON_VMSCAN); -+ -+ return true; -+} -+ - static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsigned long *min_seq, - struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) - { -@@ -3265,7 +4193,7 @@ static void age_lruvec(struct lruvec *lr - - need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); - if (need_aging) -- inc_max_seq(lruvec, max_seq, swappiness); -+ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); - } - - static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) -@@ -3274,6 +4202,8 @@ static void lru_gen_age_node(struct pgli - - VM_WARN_ON_ONCE(!current_is_kswapd()); - -+ set_mm_walk(pgdat); -+ - memcg = mem_cgroup_iter(NULL, NULL, NULL); - do { - struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); -@@ -3282,11 +4212,16 @@ static void lru_gen_age_node(struct pgli - - cond_resched(); - } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+ -+ clear_mm_walk(); - } - - /* - * This function exploits spatial locality when shrink_page_list() walks the -- * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. -+ * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. If -+ * the scan was done cacheline efficiently, it adds the PMD entry pointing to -+ * the PTE table to the Bloom filter. This forms a feedback loop between the -+ * eviction and the aging. - */ - void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) - { -@@ -3295,6 +4230,8 @@ void lru_gen_look_around(struct page_vma - unsigned long start; - unsigned long end; - unsigned long addr; -+ struct lru_gen_mm_walk *walk; -+ int young = 0; - unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; - struct page *page = pvmw->page; - struct mem_cgroup *memcg = page_memcg(page); -@@ -3309,6 +4246,9 @@ void lru_gen_look_around(struct page_vma - if (spin_is_contended(pvmw->ptl)) - return; - -+ /* avoid taking the LRU lock under the PTL when possible */ -+ walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; -+ - start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); - end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; - -@@ -3338,13 +4278,15 @@ void lru_gen_look_around(struct page_vma - if (!pte_young(pte[i])) - continue; - -- page = get_pfn_page(pfn, memcg, pgdat); -+ page = get_pfn_page(pfn, memcg, pgdat, !walk || walk->can_swap); - if (!page) - continue; - - if (!ptep_test_and_clear_young(pvmw->vma, addr, pte + i)) - VM_WARN_ON_ONCE(true); - -+ young++; -+ - if (pte_dirty(pte[i]) && !PageDirty(page) && - !(PageAnon(page) && PageSwapBacked(page) && - !PageSwapCache(page))) -@@ -3360,7 +4302,11 @@ void lru_gen_look_around(struct page_vma - arch_leave_lazy_mmu_mode(); - rcu_read_unlock(); - -- if (bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { -+ /* feedback from rmap walkers to page table walkers */ -+ if (suitable_to_scan(i, young)) -+ update_bloom_filter(lruvec, max_seq, pvmw->pmd); -+ -+ if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { - for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { - page = pte_page(pte[i]); - activate_page(page); -@@ -3372,8 +4318,10 @@ void lru_gen_look_around(struct page_vma - if (!mem_cgroup_trylock_pages(memcg)) - return; - -- spin_lock_irq(&lruvec->lru_lock); -- new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); -+ if (!walk) { -+ spin_lock_irq(&lruvec->lru_lock); -+ new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); -+ } - - for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { - page = compound_head(pte_page(pte[i])); -@@ -3384,10 +4332,14 @@ void lru_gen_look_around(struct page_vma - if (old_gen < 0 || old_gen == new_gen) - continue; - -- lru_gen_update_size(lruvec, page, old_gen, new_gen); -+ if (walk) -+ update_batch_size(walk, page, old_gen, new_gen); -+ else -+ lru_gen_update_size(lruvec, page, old_gen, new_gen); - } - -- spin_unlock_irq(&lruvec->lru_lock); -+ if (!walk) -+ spin_unlock_irq(&lruvec->lru_lock); - - mem_cgroup_unlock_pages(); - } -@@ -3670,6 +4622,7 @@ static int evict_pages(struct lruvec *lr - struct page *page; - enum vm_event_item item; - struct reclaim_stat stat; -+ struct lru_gen_mm_walk *walk; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - -@@ -3706,6 +4659,10 @@ static int evict_pages(struct lruvec *lr - - move_pages_to_lru(lruvec, &list); - -+ walk = current->reclaim_state->mm_walk; -+ if (walk && walk->batched) -+ reset_batch_size(lruvec, walk); -+ - item = current_is_kswapd() ? PGSTEAL_KSWAPD : PGSTEAL_DIRECT; - if (!cgroup_reclaim(sc)) - __count_vm_events(item, reclaimed); -@@ -3722,6 +4679,11 @@ static int evict_pages(struct lruvec *lr - return scanned; - } - -+/* -+ * For future optimizations: -+ * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg -+ * reclaim. -+ */ - static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, - bool can_swap) - { -@@ -3747,7 +4709,8 @@ static unsigned long get_nr_to_scan(stru - if (current_is_kswapd()) - return 0; - -- inc_max_seq(lruvec, max_seq, can_swap); -+ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) -+ return nr_to_scan; - done: - return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; - } -@@ -3761,6 +4724,8 @@ static void lru_gen_shrink_lruvec(struct - - blk_start_plug(&plug); - -+ set_mm_walk(lruvec_pgdat(lruvec)); -+ - while (true) { - int delta; - int swappiness; -@@ -3788,6 +4753,8 @@ static void lru_gen_shrink_lruvec(struct - cond_resched(); - } - -+ clear_mm_walk(); -+ - blk_finish_plug(&plug); - } - -@@ -3804,15 +4771,21 @@ void lru_gen_init_lruvec(struct lruvec * - - for_each_gen_type_zone(gen, type, zone) - INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -+ -+ lruvec->mm_state.seq = MIN_NR_GENS; -+ init_waitqueue_head(&lruvec->mm_state.wait); - } - - #ifdef CONFIG_MEMCG - void lru_gen_init_memcg(struct mem_cgroup *memcg) - { -+ INIT_LIST_HEAD(&memcg->mm_list.fifo); -+ spin_lock_init(&memcg->mm_list.lock); - } - - void lru_gen_exit_memcg(struct mem_cgroup *memcg) - { -+ int i; - int nid; - - for_each_node(nid) { -@@ -3820,6 +4793,11 @@ void lru_gen_exit_memcg(struct mem_cgrou - - VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, - sizeof(lruvec->lrugen.nr_pages))); -+ -+ for (i = 0; i < NR_BLOOM_FILTERS; i++) { -+ bitmap_free(lruvec->mm_state.filters[i]); -+ lruvec->mm_state.filters[i] = NULL; -+ } - } - } - #endif diff --git a/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch b/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch deleted file mode 100644 index b5fb1951514..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-09-mm-multi-gen-LRU-optimize-multiple-memcgs.patch +++ /dev/null @@ -1,315 +0,0 @@ -From 36a18a68ea458e8f4db2ca86b00091daf32c6c74 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:06 -0600 -Subject: [PATCH 09/29] mm: multi-gen LRU: optimize multiple memcgs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When multiple memcgs are available, it is possible to use generations as a -frame of reference to make better choices and improve overall performance -under global memory pressure. This patch adds a basic optimization to -select memcgs that can drop single-use unmapped clean pages first. Doing -so reduces the chance of going into the aging path or swapping, which can -be costly. - -A typical example that benefits from this optimization is a server running -mixed types of workloads, e.g., heavy anon workload in one memcg and heavy -buffered I/O workload in the other. - -Though this optimization can be applied to both kswapd and direct reclaim, -it is only added to kswapd to keep the patchset manageable. Later -improvements may cover the direct reclaim path. - -While ensuring certain fairness to all eligible memcgs, proportional scans -of individual memcgs also require proper backoff to avoid overshooting -their aggregate reclaim target by too much. Otherwise it can cause high -direct reclaim latency. The conditions for backoff are: - -1. At low priorities, for direct reclaim, if aging fairness or direct - reclaim latency is at risk, i.e., aging one memcg multiple times or - swapping after the target is met. -2. At high priorities, for global reclaim, if per-zone free pages are - above respective watermarks. - -Server benchmark results: - Mixed workloads: - fio (buffered I/O): +[19, 21]% - IOPS BW - patch1-8: 1880k 7343MiB/s - patch1-9: 2252k 8796MiB/s - - memcached (anon): +[119, 123]% - Ops/sec KB/sec - patch1-8: 862768.65 33514.68 - patch1-9: 1911022.12 74234.54 - - Mixed workloads: - fio (buffered I/O): +[75, 77]% - IOPS BW - 5.19-rc1: 1279k 4996MiB/s - patch1-9: 2252k 8796MiB/s - - memcached (anon): +[13, 15]% - Ops/sec KB/sec - 5.19-rc1: 1673524.04 65008.87 - patch1-9: 1911022.12 74234.54 - - Configurations: - (changes since patch 6) - - cat mixed.sh - modprobe brd rd_nr=2 rd_size=56623104 - - swapoff -a - mkswap /dev/ram0 - swapon /dev/ram0 - - mkfs.ext4 /dev/ram1 - mount -t ext4 /dev/ram1 /mnt - - memtier_benchmark -S /var/run/memcached/memcached.sock \ - -P memcache_binary -n allkeys --key-minimum=1 \ - --key-maximum=50000000 --key-pattern=P:P -c 1 -t 36 \ - --ratio 1:0 --pipeline 8 -d 2000 - - fio -name=mglru --numjobs=36 --directory=/mnt --size=1408m \ - --buffered=1 --ioengine=io_uring --iodepth=128 \ - --iodepth_batch_submit=32 --iodepth_batch_complete=32 \ - --rw=randread --random_distribution=random --norandommap \ - --time_based --ramp_time=10m --runtime=90m --group_reporting & - pid=$! - - sleep 200 - - memtier_benchmark -S /var/run/memcached/memcached.sock \ - -P memcache_binary -n allkeys --key-minimum=1 \ - --key-maximum=50000000 --key-pattern=R:R -c 1 -t 36 \ - --ratio 0:1 --pipeline 8 --randomize --distinct-client-seed - - kill -INT $pid - wait - -Client benchmark results: - no change (CONFIG_MEMCG=n) - -Link: https://lkml.kernel.org/r/20220918080010.2920238-10-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - mm/vmscan.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 96 insertions(+), 9 deletions(-) - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -127,6 +127,12 @@ struct scan_control { - /* Always discard instead of demoting to lower tier memory */ - unsigned int no_demotion:1; - -+#ifdef CONFIG_LRU_GEN -+ /* help kswapd make better choices among multiple memcgs */ -+ unsigned int memcgs_need_aging:1; -+ unsigned long last_reclaimed; -+#endif -+ - /* Allocation order */ - s8 order; - -@@ -4202,6 +4208,19 @@ static void lru_gen_age_node(struct pgli - - VM_WARN_ON_ONCE(!current_is_kswapd()); - -+ sc->last_reclaimed = sc->nr_reclaimed; -+ -+ /* -+ * To reduce the chance of going into the aging path, which can be -+ * costly, optimistically skip it if the flag below was cleared in the -+ * eviction path. This improves the overall performance when multiple -+ * memcgs are available. -+ */ -+ if (!sc->memcgs_need_aging) { -+ sc->memcgs_need_aging = true; -+ return; -+ } -+ - set_mm_walk(pgdat); - - memcg = mem_cgroup_iter(NULL, NULL, NULL); -@@ -4613,7 +4632,8 @@ static int isolate_pages(struct lruvec * - return scanned; - } - --static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) -+static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -+ bool *need_swapping) - { - int type; - int scanned; -@@ -4676,6 +4696,9 @@ static int evict_pages(struct lruvec *lr - - sc->nr_reclaimed += reclaimed; - -+ if (need_swapping && type == LRU_GEN_ANON) -+ *need_swapping = true; -+ - return scanned; - } - -@@ -4685,9 +4708,8 @@ static int evict_pages(struct lruvec *lr - * reclaim. - */ - static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, -- bool can_swap) -+ bool can_swap, bool *need_aging) - { -- bool need_aging; - unsigned long nr_to_scan; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - DEFINE_MAX_SEQ(lruvec); -@@ -4697,8 +4719,8 @@ static unsigned long get_nr_to_scan(stru - (mem_cgroup_below_low(memcg) && !sc->memcg_low_reclaim)) - return 0; - -- need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); -- if (!need_aging) -+ *need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, can_swap, &nr_to_scan); -+ if (!*need_aging) - return nr_to_scan; - - /* skip the aging path at the default priority */ -@@ -4715,10 +4737,68 @@ done: - return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; - } - -+static bool should_abort_scan(struct lruvec *lruvec, unsigned long seq, -+ struct scan_control *sc, bool need_swapping) -+{ -+ int i; -+ DEFINE_MAX_SEQ(lruvec); -+ -+ if (!current_is_kswapd()) { -+ /* age each memcg once to ensure fairness */ -+ if (max_seq - seq > 1) -+ return true; -+ -+ /* over-swapping can increase allocation latency */ -+ if (sc->nr_reclaimed >= sc->nr_to_reclaim && need_swapping) -+ return true; -+ -+ /* give this thread a chance to exit and free its memory */ -+ if (fatal_signal_pending(current)) { -+ sc->nr_reclaimed += MIN_LRU_BATCH; -+ return true; -+ } -+ -+ if (cgroup_reclaim(sc)) -+ return false; -+ } else if (sc->nr_reclaimed - sc->last_reclaimed < sc->nr_to_reclaim) -+ return false; -+ -+ /* keep scanning at low priorities to ensure fairness */ -+ if (sc->priority > DEF_PRIORITY - 2) -+ return false; -+ -+ /* -+ * A minimum amount of work was done under global memory pressure. For -+ * kswapd, it may be overshooting. For direct reclaim, the target isn't -+ * met, and yet the allocation may still succeed, since kswapd may have -+ * caught up. In either case, it's better to stop now, and restart if -+ * necessary. -+ */ -+ for (i = 0; i <= sc->reclaim_idx; i++) { -+ unsigned long wmark; -+ struct zone *zone = lruvec_pgdat(lruvec)->node_zones + i; -+ -+ if (!managed_zone(zone)) -+ continue; -+ -+ wmark = current_is_kswapd() ? high_wmark_pages(zone) : low_wmark_pages(zone); -+ if (wmark > zone_page_state(zone, NR_FREE_PAGES)) -+ return false; -+ } -+ -+ sc->nr_reclaimed += MIN_LRU_BATCH; -+ -+ return true; -+} -+ - static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) - { - struct blk_plug plug; -+ bool need_aging = false; -+ bool need_swapping = false; - unsigned long scanned = 0; -+ unsigned long reclaimed = sc->nr_reclaimed; -+ DEFINE_MAX_SEQ(lruvec); - - lru_add_drain(); - -@@ -4738,21 +4818,28 @@ static void lru_gen_shrink_lruvec(struct - else - swappiness = 0; - -- nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); -+ nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness, &need_aging); - if (!nr_to_scan) -- break; -+ goto done; - -- delta = evict_pages(lruvec, sc, swappiness); -+ delta = evict_pages(lruvec, sc, swappiness, &need_swapping); - if (!delta) -- break; -+ goto done; - - scanned += delta; - if (scanned >= nr_to_scan) - break; - -+ if (should_abort_scan(lruvec, max_seq, sc, need_swapping)) -+ break; -+ - cond_resched(); - } - -+ /* see the comment in lru_gen_age_node() */ -+ if (sc->nr_reclaimed - reclaimed >= MIN_LRU_BATCH && !need_aging) -+ sc->memcgs_need_aging = false; -+done: - clear_mm_walk(); - - blk_finish_plug(&plug); diff --git a/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch b/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch deleted file mode 100644 index cf5b8f0e9f7..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-10-mm-multi-gen-LRU-kill-switch.patch +++ /dev/null @@ -1,498 +0,0 @@ -From 640db3a029dca909af47157ca18f52b29d34a1b9 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:07 -0600 -Subject: [PATCH 10/29] mm: multi-gen LRU: kill switch -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add /sys/kernel/mm/lru_gen/enabled as a kill switch. Components that -can be disabled include: - 0x0001: the multi-gen LRU core - 0x0002: walking page table, when arch_has_hw_pte_young() returns - true - 0x0004: clearing the accessed bit in non-leaf PMD entries, when - CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y - [yYnN]: apply to all the components above -E.g., - echo y >/sys/kernel/mm/lru_gen/enabled - cat /sys/kernel/mm/lru_gen/enabled - 0x0007 - echo 5 >/sys/kernel/mm/lru_gen/enabled - cat /sys/kernel/mm/lru_gen/enabled - 0x0005 - -NB: the page table walks happen on the scale of seconds under heavy memory -pressure, in which case the mmap_lock contention is a lesser concern, -compared with the LRU lock contention and the I/O congestion. So far the -only well-known case of the mmap_lock contention happens on Android, due -to Scudo [1] which allocates several thousand VMAs for merely a few -hundred MBs. The SPF and the Maple Tree also have provided their own -assessments [2][3]. However, if walking page tables does worsen the -mmap_lock contention, the kill switch can be used to disable it. In this -case the multi-gen LRU will suffer a minor performance degradation, as -shown previously. - -Clearing the accessed bit in non-leaf PMD entries can also be disabled, -since this behavior was not tested on x86 varieties other than Intel and -AMD. - -[1] https://source.android.com/devices/tech/debug/scudo -[2] https://lore.kernel.org/r/20220128131006.67712-1-michel@lespinasse.org/ -[3] https://lore.kernel.org/r/20220426150616.3937571-1-Liam.Howlett@oracle.com/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-11-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/cgroup.h | 15 ++- - include/linux/mm_inline.h | 15 ++- - include/linux/mmzone.h | 9 ++ - kernel/cgroup/cgroup-internal.h | 1 - - mm/Kconfig | 6 + - mm/vmscan.c | 228 +++++++++++++++++++++++++++++++- - 6 files changed, 265 insertions(+), 9 deletions(-) - ---- a/include/linux/cgroup.h -+++ b/include/linux/cgroup.h -@@ -433,6 +433,18 @@ static inline void cgroup_put(struct cgr - css_put(&cgrp->self); - } - -+extern struct mutex cgroup_mutex; -+ -+static inline void cgroup_lock(void) -+{ -+ mutex_lock(&cgroup_mutex); -+} -+ -+static inline void cgroup_unlock(void) -+{ -+ mutex_unlock(&cgroup_mutex); -+} -+ - /** - * task_css_set_check - obtain a task's css_set with extra access conditions - * @task: the task to obtain css_set for -@@ -447,7 +459,6 @@ static inline void cgroup_put(struct cgr - * as locks used during the cgroup_subsys::attach() methods. - */ - #ifdef CONFIG_PROVE_RCU --extern struct mutex cgroup_mutex; - extern spinlock_t css_set_lock; - #define task_css_set_check(task, __c) \ - rcu_dereference_check((task)->cgroups, \ -@@ -708,6 +719,8 @@ struct cgroup; - static inline u64 cgroup_id(const struct cgroup *cgrp) { return 1; } - static inline void css_get(struct cgroup_subsys_state *css) {} - static inline void css_put(struct cgroup_subsys_state *css) {} -+static inline void cgroup_lock(void) {} -+static inline void cgroup_unlock(void) {} - static inline int cgroup_attach_task_all(struct task_struct *from, - struct task_struct *t) { return 0; } - static inline int cgroupstats_build(struct cgroupstats *stats, ---- a/include/linux/mm_inline.h -+++ b/include/linux/mm_inline.h -@@ -91,10 +91,21 @@ static __always_inline enum lru_list pag - - #ifdef CONFIG_LRU_GEN - -+#ifdef CONFIG_LRU_GEN_ENABLED - static inline bool lru_gen_enabled(void) - { -- return true; -+ DECLARE_STATIC_KEY_TRUE(lru_gen_caps[NR_LRU_GEN_CAPS]); -+ -+ return static_branch_likely(&lru_gen_caps[LRU_GEN_CORE]); -+} -+#else -+static inline bool lru_gen_enabled(void) -+{ -+ DECLARE_STATIC_KEY_FALSE(lru_gen_caps[NR_LRU_GEN_CAPS]); -+ -+ return static_branch_unlikely(&lru_gen_caps[LRU_GEN_CORE]); - } -+#endif - - static inline bool lru_gen_in_fault(void) - { -@@ -207,7 +218,7 @@ static inline bool lru_gen_add_page(stru - - VM_WARN_ON_ONCE_PAGE(gen != -1, page); - -- if (PageUnevictable(page)) -+ if (PageUnevictable(page) || !lrugen->enabled) - return false; - /* - * There are three common cases for this page: ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -364,6 +364,13 @@ enum { - LRU_GEN_FILE, - }; - -+enum { -+ LRU_GEN_CORE, -+ LRU_GEN_MM_WALK, -+ LRU_GEN_NONLEAF_YOUNG, -+ NR_LRU_GEN_CAPS -+}; -+ - #define MIN_LRU_BATCH BITS_PER_LONG - #define MAX_LRU_BATCH (MIN_LRU_BATCH * 64) - -@@ -405,6 +412,8 @@ struct lru_gen_struct { - /* can be modified without holding the LRU lock */ - atomic_long_t evicted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; - atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; -+ /* whether the multi-gen LRU is enabled */ -+ bool enabled; - }; - - enum { ---- a/kernel/cgroup/cgroup-internal.h -+++ b/kernel/cgroup/cgroup-internal.h -@@ -165,7 +165,6 @@ struct cgroup_mgctx { - #define DEFINE_CGROUP_MGCTX(name) \ - struct cgroup_mgctx name = CGROUP_MGCTX_INIT(name) - --extern struct mutex cgroup_mutex; - extern spinlock_t css_set_lock; - extern struct cgroup_subsys *cgroup_subsys[]; - extern struct list_head cgroup_roots; ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -906,6 +906,12 @@ config LRU_GEN - help - A high performance LRU implementation to overcommit memory. - -+config LRU_GEN_ENABLED -+ bool "Enable by default" -+ depends on LRU_GEN -+ help -+ This option enables the multi-gen LRU by default. -+ - config LRU_GEN_STATS - bool "Full stats for debugging" - depends on LRU_GEN ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -52,6 +52,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -2841,6 +2842,14 @@ static bool can_age_anon_pages(struct pg - - #ifdef CONFIG_LRU_GEN - -+#ifdef CONFIG_LRU_GEN_ENABLED -+DEFINE_STATIC_KEY_ARRAY_TRUE(lru_gen_caps, NR_LRU_GEN_CAPS); -+#define get_cap(cap) static_branch_likely(&lru_gen_caps[cap]) -+#else -+DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); -+#define get_cap(cap) static_branch_unlikely(&lru_gen_caps[cap]) -+#endif -+ - /****************************************************************************** - * shorthand helpers - ******************************************************************************/ -@@ -3717,7 +3726,8 @@ static void walk_pmd_range_locked(pud_t - goto next; - - if (!pmd_trans_huge(pmd[i])) { -- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)) -+ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && -+ get_cap(LRU_GEN_NONLEAF_YOUNG)) - pmdp_test_and_clear_young(vma, addr, pmd + i); - goto next; - } -@@ -3815,10 +3825,12 @@ restart: - walk->mm_stats[MM_NONLEAF_TOTAL]++; - - #ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -- if (!pmd_young(val)) -- continue; -+ if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { -+ if (!pmd_young(val)) -+ continue; - -- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); -+ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); -+ } - #endif - if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) - continue; -@@ -4080,7 +4092,7 @@ static bool try_to_inc_max_seq(struct lr - * handful of PTEs. Spreading the work out over a period of time usually - * is less efficient, but it avoids bursty page faults. - */ -- if (!arch_has_hw_pte_young()) { -+ if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { - success = iterate_mm_list_nowalk(lruvec, max_seq); - goto done; - } -@@ -4846,6 +4858,208 @@ done: - } - - /****************************************************************************** -+ * state change -+ ******************************************************************************/ -+ -+static bool __maybe_unused state_is_valid(struct lruvec *lruvec) -+{ -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ if (lrugen->enabled) { -+ enum lru_list lru; -+ -+ for_each_evictable_lru(lru) { -+ if (!list_empty(&lruvec->lists[lru])) -+ return false; -+ } -+ } else { -+ int gen, type, zone; -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ if (!list_empty(&lrugen->lists[gen][type][zone])) -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static bool fill_evictable(struct lruvec *lruvec) -+{ -+ enum lru_list lru; -+ int remaining = MAX_LRU_BATCH; -+ -+ for_each_evictable_lru(lru) { -+ int type = is_file_lru(lru); -+ bool active = is_active_lru(lru); -+ struct list_head *head = &lruvec->lists[lru]; -+ -+ while (!list_empty(head)) { -+ bool success; -+ struct page *page = lru_to_page(head); -+ -+ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); -+ VM_WARN_ON_ONCE_PAGE(PageActive(page) != active, page); -+ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); -+ VM_WARN_ON_ONCE_PAGE(page_lru_gen(page) != -1, page); -+ -+ del_page_from_lru_list(page, lruvec); -+ success = lru_gen_add_page(lruvec, page, false); -+ VM_WARN_ON_ONCE(!success); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static bool drain_evictable(struct lruvec *lruvec) -+{ -+ int gen, type, zone; -+ int remaining = MAX_LRU_BATCH; -+ -+ for_each_gen_type_zone(gen, type, zone) { -+ struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; -+ -+ while (!list_empty(head)) { -+ bool success; -+ struct page *page = lru_to_page(head); -+ -+ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); -+ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); -+ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); -+ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); -+ -+ success = lru_gen_del_page(lruvec, page, false); -+ VM_WARN_ON_ONCE(!success); -+ add_page_to_lru_list(page, lruvec); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+static void lru_gen_change_state(bool enabled) -+{ -+ static DEFINE_MUTEX(state_mutex); -+ -+ struct mem_cgroup *memcg; -+ -+ cgroup_lock(); -+ cpus_read_lock(); -+ get_online_mems(); -+ mutex_lock(&state_mutex); -+ -+ if (enabled == lru_gen_enabled()) -+ goto unlock; -+ -+ if (enabled) -+ static_branch_enable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); -+ else -+ static_branch_disable_cpuslocked(&lru_gen_caps[LRU_GEN_CORE]); -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ int nid; -+ -+ for_each_node(nid) { -+ struct lruvec *lruvec = get_lruvec(memcg, nid); -+ -+ if (!lruvec) -+ continue; -+ -+ spin_lock_irq(&lruvec->lru_lock); -+ -+ VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -+ VM_WARN_ON_ONCE(!state_is_valid(lruvec)); -+ -+ lruvec->lrugen.enabled = enabled; -+ -+ while (!(enabled ? fill_evictable(lruvec) : drain_evictable(lruvec))) { -+ spin_unlock_irq(&lruvec->lru_lock); -+ cond_resched(); -+ spin_lock_irq(&lruvec->lru_lock); -+ } -+ -+ spin_unlock_irq(&lruvec->lru_lock); -+ } -+ -+ cond_resched(); -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+unlock: -+ mutex_unlock(&state_mutex); -+ put_online_mems(); -+ cpus_read_unlock(); -+ cgroup_unlock(); -+} -+ -+/****************************************************************************** -+ * sysfs interface -+ ******************************************************************************/ -+ -+static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ unsigned int caps = 0; -+ -+ if (get_cap(LRU_GEN_CORE)) -+ caps |= BIT(LRU_GEN_CORE); -+ -+ if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) -+ caps |= BIT(LRU_GEN_MM_WALK); -+ -+ if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) -+ caps |= BIT(LRU_GEN_NONLEAF_YOUNG); -+ -+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); -+} -+ -+static ssize_t store_enabled(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t len) -+{ -+ int i; -+ unsigned int caps; -+ -+ if (tolower(*buf) == 'n') -+ caps = 0; -+ else if (tolower(*buf) == 'y') -+ caps = -1; -+ else if (kstrtouint(buf, 0, &caps)) -+ return -EINVAL; -+ -+ for (i = 0; i < NR_LRU_GEN_CAPS; i++) { -+ bool enabled = caps & BIT(i); -+ -+ if (i == LRU_GEN_CORE) -+ lru_gen_change_state(enabled); -+ else if (enabled) -+ static_branch_enable(&lru_gen_caps[i]); -+ else -+ static_branch_disable(&lru_gen_caps[i]); -+ } -+ -+ return len; -+} -+ -+static struct kobj_attribute lru_gen_enabled_attr = __ATTR( -+ enabled, 0644, show_enabled, store_enabled -+); -+ -+static struct attribute *lru_gen_attrs[] = { -+ &lru_gen_enabled_attr.attr, -+ NULL -+}; -+ -+static struct attribute_group lru_gen_attr_group = { -+ .name = "lru_gen", -+ .attrs = lru_gen_attrs, -+}; -+ -+/****************************************************************************** - * initialization - ******************************************************************************/ - -@@ -4855,6 +5069,7 @@ void lru_gen_init_lruvec(struct lruvec * - struct lru_gen_struct *lrugen = &lruvec->lrugen; - - lrugen->max_seq = MIN_NR_GENS + 1; -+ lrugen->enabled = lru_gen_enabled(); - - for_each_gen_type_zone(gen, type, zone) - INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -@@ -4894,6 +5109,9 @@ static int __init init_lru_gen(void) - BUILD_BUG_ON(MIN_NR_GENS + 1 >= MAX_NR_GENS); - BUILD_BUG_ON(BIT(LRU_GEN_WIDTH) <= MAX_NR_GENS); - -+ if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) -+ pr_err("lru_gen: failed to create sysfs group\n"); -+ - return 0; - }; - late_initcall(init_lru_gen); diff --git a/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch b/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch deleted file mode 100644 index 30e20aff6ed..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-11-mm-multi-gen-LRU-thrashing-prevention.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 73d1ff551760f0c79c47ab70faa4c2ca91413f5c Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:08 -0600 -Subject: [PATCH 11/29] mm: multi-gen LRU: thrashing prevention -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add /sys/kernel/mm/lru_gen/min_ttl_ms for thrashing prevention, as -requested by many desktop users [1]. - -When set to value N, it prevents the working set of N milliseconds from -getting evicted. The OOM killer is triggered if this working set cannot -be kept in memory. Based on the average human detectable lag (~100ms), -N=1000 usually eliminates intolerable lags due to thrashing. Larger -values like N=3000 make lags less noticeable at the risk of premature OOM -kills. - -Compared with the size-based approach [2], this time-based approach -has the following advantages: - -1. It is easier to configure because it is agnostic to applications - and memory sizes. -2. It is more reliable because it is directly wired to the OOM killer. - -[1] https://lore.kernel.org/r/Ydza%2FzXKY9ATRoh6@google.com/ -[2] https://lore.kernel.org/r/20101028191523.GA14972@google.com/ - -Link: https://lkml.kernel.org/r/20220918080010.2920238-12-yuzhao@google.com -Signed-off-by: Yu Zhao -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Qi Zheng -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/mmzone.h | 2 ++ - mm/vmscan.c | 74 ++++++++++++++++++++++++++++++++++++++++-- - 2 files changed, 73 insertions(+), 3 deletions(-) - ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -399,6 +399,8 @@ struct lru_gen_struct { - unsigned long max_seq; - /* the eviction increments the oldest generation numbers */ - unsigned long min_seq[ANON_AND_FILE]; -+ /* the birth time of each generation in jiffies */ -+ unsigned long timestamps[MAX_NR_GENS]; - /* the multi-gen LRU lists, lazily sorted on eviction */ - struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; - /* the multi-gen LRU sizes, eventually consistent */ ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -4064,6 +4064,7 @@ static void inc_max_seq(struct lruvec *l - for (type = 0; type < ANON_AND_FILE; type++) - reset_ctrl_pos(lruvec, type, false); - -+ WRITE_ONCE(lrugen->timestamps[next], jiffies); - /* make sure preceding modifications appear */ - smp_store_release(&lrugen->max_seq, lrugen->max_seq + 1); - -@@ -4193,7 +4194,7 @@ static bool should_run_aging(struct lruv - return false; - } - --static void age_lruvec(struct lruvec *lruvec, struct scan_control *sc) -+static bool age_lruvec(struct lruvec *lruvec, struct scan_control *sc, unsigned long min_ttl) - { - bool need_aging; - unsigned long nr_to_scan; -@@ -4207,16 +4208,36 @@ static void age_lruvec(struct lruvec *lr - mem_cgroup_calculate_protection(NULL, memcg); - - if (mem_cgroup_below_min(memcg)) -- return; -+ return false; - - need_aging = should_run_aging(lruvec, max_seq, min_seq, sc, swappiness, &nr_to_scan); -+ -+ if (min_ttl) { -+ int gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); -+ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -+ -+ if (time_is_after_jiffies(birth + min_ttl)) -+ return false; -+ -+ /* the size is likely too small to be helpful */ -+ if (!nr_to_scan && sc->priority != DEF_PRIORITY) -+ return false; -+ } -+ - if (need_aging) - try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); -+ -+ return true; - } - -+/* to protect the working set of the last N jiffies */ -+static unsigned long lru_gen_min_ttl __read_mostly; -+ - static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) - { - struct mem_cgroup *memcg; -+ bool success = false; -+ unsigned long min_ttl = READ_ONCE(lru_gen_min_ttl); - - VM_WARN_ON_ONCE(!current_is_kswapd()); - -@@ -4239,12 +4260,32 @@ static void lru_gen_age_node(struct pgli - do { - struct lruvec *lruvec = mem_cgroup_lruvec(memcg, pgdat); - -- age_lruvec(lruvec, sc); -+ if (age_lruvec(lruvec, sc, min_ttl)) -+ success = true; - - cond_resched(); - } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); - - clear_mm_walk(); -+ -+ /* check the order to exclude compaction-induced reclaim */ -+ if (success || !min_ttl || sc->order) -+ return; -+ -+ /* -+ * The main goal is to OOM kill if every generation from all memcgs is -+ * younger than min_ttl. However, another possibility is all memcgs are -+ * either below min or empty. -+ */ -+ if (mutex_trylock(&oom_lock)) { -+ struct oom_control oc = { -+ .gfp_mask = sc->gfp_mask, -+ }; -+ -+ out_of_memory(&oc); -+ -+ mutex_unlock(&oom_lock); -+ } - } - - /* -@@ -5002,6 +5043,28 @@ unlock: - * sysfs interface - ******************************************************************************/ - -+static ssize_t show_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, char *buf) -+{ -+ return sprintf(buf, "%u\n", jiffies_to_msecs(READ_ONCE(lru_gen_min_ttl))); -+} -+ -+static ssize_t store_min_ttl(struct kobject *kobj, struct kobj_attribute *attr, -+ const char *buf, size_t len) -+{ -+ unsigned int msecs; -+ -+ if (kstrtouint(buf, 0, &msecs)) -+ return -EINVAL; -+ -+ WRITE_ONCE(lru_gen_min_ttl, msecs_to_jiffies(msecs)); -+ -+ return len; -+} -+ -+static struct kobj_attribute lru_gen_min_ttl_attr = __ATTR( -+ min_ttl_ms, 0644, show_min_ttl, store_min_ttl -+); -+ - static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, char *buf) - { - unsigned int caps = 0; -@@ -5050,6 +5113,7 @@ static struct kobj_attribute lru_gen_ena - ); - - static struct attribute *lru_gen_attrs[] = { -+ &lru_gen_min_ttl_attr.attr, - &lru_gen_enabled_attr.attr, - NULL - }; -@@ -5065,12 +5129,16 @@ static struct attribute_group lru_gen_at - - void lru_gen_init_lruvec(struct lruvec *lruvec) - { -+ int i; - int gen, type, zone; - struct lru_gen_struct *lrugen = &lruvec->lrugen; - - lrugen->max_seq = MIN_NR_GENS + 1; - lrugen->enabled = lru_gen_enabled(); - -+ for (i = 0; i <= MIN_NR_GENS + 1; i++) -+ lrugen->timestamps[i] = jiffies; -+ - for_each_gen_type_zone(gen, type, zone) - INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); - diff --git a/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch b/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch deleted file mode 100644 index 482e714bb6a..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-12-mm-multi-gen-LRU-debugfs-interface.patch +++ /dev/null @@ -1,579 +0,0 @@ -From 530716d008ca26315f246cd70dc1cefc636beaa4 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 18 Sep 2022 02:00:09 -0600 -Subject: [PATCH 12/29] mm: multi-gen LRU: debugfs interface -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add /sys/kernel/debug/lru_gen for working set estimation and proactive -reclaim. These techniques are commonly used to optimize job scheduling -(bin packing) in data centers [1][2]. - -Compared with the page table-based approach and the PFN-based -approach, this lruvec-based approach has the following advantages: -1. It offers better choices because it is aware of memcgs, NUMA nodes, - shared mappings and unmapped page cache. -2. It is more scalable because it is O(nr_hot_pages), whereas the - PFN-based approach is O(nr_total_pages). - -Add /sys/kernel/debug/lru_gen_full for debugging. - -[1] https://dl.acm.org/doi/10.1145/3297858.3304053 -[2] https://dl.acm.org/doi/10.1145/3503222.3507731 - -Link: https://lkml.kernel.org/r/20220918080010.2920238-13-yuzhao@google.com -Signed-off-by: Yu Zhao -Reviewed-by: Qi Zheng -Acked-by: Brian Geffon -Acked-by: Jan Alexander Steffens (heftig) -Acked-by: Oleksandr Natalenko -Acked-by: Steven Barrett -Acked-by: Suleiman Souhlal -Tested-by: Daniel Byrne -Tested-by: Donald Carr -Tested-by: Holger Hoffstätte -Tested-by: Konstantin Kharlamov -Tested-by: Shuang Zhai -Tested-by: Sofia Trinh -Tested-by: Vaibhav Jain -Cc: Andi Kleen -Cc: Aneesh Kumar K.V -Cc: Barry Song -Cc: Catalin Marinas -Cc: Dave Hansen -Cc: Hillf Danton -Cc: Jens Axboe -Cc: Johannes Weiner -Cc: Jonathan Corbet -Cc: Linus Torvalds -Cc: Matthew Wilcox -Cc: Mel Gorman -Cc: Miaohe Lin -Cc: Michael Larabel -Cc: Michal Hocko -Cc: Mike Rapoport -Cc: Mike Rapoport -Cc: Peter Zijlstra -Cc: Tejun Heo -Cc: Vlastimil Babka -Cc: Will Deacon -Signed-off-by: Andrew Morton ---- - include/linux/nodemask.h | 1 + - mm/vmscan.c | 411 ++++++++++++++++++++++++++++++++++++++- - 2 files changed, 402 insertions(+), 10 deletions(-) - ---- a/include/linux/nodemask.h -+++ b/include/linux/nodemask.h -@@ -485,6 +485,7 @@ static inline int num_node_state(enum no - #define first_online_node 0 - #define first_memory_node 0 - #define next_online_node(nid) (MAX_NUMNODES) -+#define next_memory_node(nid) (MAX_NUMNODES) - #define nr_node_ids 1U - #define nr_online_nodes 1U - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -53,6 +53,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -3968,12 +3969,40 @@ static void clear_mm_walk(void) - kfree(walk); - } - --static void inc_min_seq(struct lruvec *lruvec, int type) -+static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) - { -+ int zone; -+ int remaining = MAX_LRU_BATCH; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); -+ -+ if (type == LRU_GEN_ANON && !can_swap) -+ goto done; -+ -+ /* prevent cold/hot inversion if force_scan is true */ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) { -+ struct list_head *head = &lrugen->lists[old_gen][type][zone]; -+ -+ while (!list_empty(head)) { -+ struct page *page = lru_to_page(head); -+ -+ VM_WARN_ON_ONCE_PAGE(PageUnevictable(page), page); -+ VM_WARN_ON_ONCE_PAGE(PageActive(page), page); -+ VM_WARN_ON_ONCE_PAGE(page_is_file_lru(page) != type, page); -+ VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); - -+ new_gen = page_inc_gen(lruvec, page, false); -+ list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); -+ -+ if (!--remaining) -+ return false; -+ } -+ } -+done: - reset_ctrl_pos(lruvec, type, true); - WRITE_ONCE(lrugen->min_seq[type], lrugen->min_seq[type] + 1); -+ -+ return true; - } - - static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) -@@ -4019,7 +4048,7 @@ next: - return success; - } - --static void inc_max_seq(struct lruvec *lruvec, bool can_swap) -+static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) - { - int prev, next; - int type, zone; -@@ -4033,9 +4062,13 @@ static void inc_max_seq(struct lruvec *l - if (get_nr_gens(lruvec, type) != MAX_NR_GENS) - continue; - -- VM_WARN_ON_ONCE(type == LRU_GEN_FILE || can_swap); -+ VM_WARN_ON_ONCE(!force_scan && (type == LRU_GEN_FILE || can_swap)); - -- inc_min_seq(lruvec, type); -+ while (!inc_min_seq(lruvec, type, can_swap)) { -+ spin_unlock_irq(&lruvec->lru_lock); -+ cond_resched(); -+ spin_lock_irq(&lruvec->lru_lock); -+ } - } - - /* -@@ -4072,7 +4105,7 @@ static void inc_max_seq(struct lruvec *l - } - - static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, -- struct scan_control *sc, bool can_swap) -+ struct scan_control *sc, bool can_swap, bool force_scan) - { - bool success; - struct lru_gen_mm_walk *walk; -@@ -4093,7 +4126,7 @@ static bool try_to_inc_max_seq(struct lr - * handful of PTEs. Spreading the work out over a period of time usually - * is less efficient, but it avoids bursty page faults. - */ -- if (!(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { -+ if (!force_scan && !(arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))) { - success = iterate_mm_list_nowalk(lruvec, max_seq); - goto done; - } -@@ -4107,7 +4140,7 @@ static bool try_to_inc_max_seq(struct lr - walk->lruvec = lruvec; - walk->max_seq = max_seq; - walk->can_swap = can_swap; -- walk->force_scan = false; -+ walk->force_scan = force_scan; - - do { - success = iterate_mm_list(lruvec, walk, &mm); -@@ -4127,7 +4160,7 @@ done: - - VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); - -- inc_max_seq(lruvec, can_swap); -+ inc_max_seq(lruvec, can_swap, force_scan); - /* either this sees any waiters or they will see updated max_seq */ - if (wq_has_sleeper(&lruvec->mm_state.wait)) - wake_up_all(&lruvec->mm_state.wait); -@@ -4225,7 +4258,7 @@ static bool age_lruvec(struct lruvec *lr - } - - if (need_aging) -- try_to_inc_max_seq(lruvec, max_seq, sc, swappiness); -+ try_to_inc_max_seq(lruvec, max_seq, sc, swappiness, false); - - return true; - } -@@ -4784,7 +4817,7 @@ static unsigned long get_nr_to_scan(stru - if (current_is_kswapd()) - return 0; - -- if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap)) -+ if (try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false)) - return nr_to_scan; - done: - return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; -@@ -5124,6 +5157,361 @@ static struct attribute_group lru_gen_at - }; - - /****************************************************************************** -+ * debugfs interface -+ ******************************************************************************/ -+ -+static void *lru_gen_seq_start(struct seq_file *m, loff_t *pos) -+{ -+ struct mem_cgroup *memcg; -+ loff_t nr_to_skip = *pos; -+ -+ m->private = kvmalloc(PATH_MAX, GFP_KERNEL); -+ if (!m->private) -+ return ERR_PTR(-ENOMEM); -+ -+ memcg = mem_cgroup_iter(NULL, NULL, NULL); -+ do { -+ int nid; -+ -+ for_each_node_state(nid, N_MEMORY) { -+ if (!nr_to_skip--) -+ return get_lruvec(memcg, nid); -+ } -+ } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL))); -+ -+ return NULL; -+} -+ -+static void lru_gen_seq_stop(struct seq_file *m, void *v) -+{ -+ if (!IS_ERR_OR_NULL(v)) -+ mem_cgroup_iter_break(NULL, lruvec_memcg(v)); -+ -+ kvfree(m->private); -+ m->private = NULL; -+} -+ -+static void *lru_gen_seq_next(struct seq_file *m, void *v, loff_t *pos) -+{ -+ int nid = lruvec_pgdat(v)->node_id; -+ struct mem_cgroup *memcg = lruvec_memcg(v); -+ -+ ++*pos; -+ -+ nid = next_memory_node(nid); -+ if (nid == MAX_NUMNODES) { -+ memcg = mem_cgroup_iter(NULL, memcg, NULL); -+ if (!memcg) -+ return NULL; -+ -+ nid = first_memory_node; -+ } -+ -+ return get_lruvec(memcg, nid); -+} -+ -+static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, -+ unsigned long max_seq, unsigned long *min_seq, -+ unsigned long seq) -+{ -+ int i; -+ int type, tier; -+ int hist = lru_hist_from_seq(seq); -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ -+ for (tier = 0; tier < MAX_NR_TIERS; tier++) { -+ seq_printf(m, " %10d", tier); -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ const char *s = " "; -+ unsigned long n[3] = {}; -+ -+ if (seq == max_seq) { -+ s = "RT "; -+ n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]); -+ n[1] = READ_ONCE(lrugen->avg_total[type][tier]); -+ } else if (seq == min_seq[type] || NR_HIST_GENS > 1) { -+ s = "rep"; -+ n[0] = atomic_long_read(&lrugen->refaulted[hist][type][tier]); -+ n[1] = atomic_long_read(&lrugen->evicted[hist][type][tier]); -+ if (tier) -+ n[2] = READ_ONCE(lrugen->protected[hist][type][tier - 1]); -+ } -+ -+ for (i = 0; i < 3; i++) -+ seq_printf(m, " %10lu%c", n[i], s[i]); -+ } -+ seq_putc(m, '\n'); -+ } -+ -+ seq_puts(m, " "); -+ for (i = 0; i < NR_MM_STATS; i++) { -+ const char *s = " "; -+ unsigned long n = 0; -+ -+ if (seq == max_seq && NR_HIST_GENS == 1) { -+ s = "LOYNFA"; -+ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); -+ } else if (seq != max_seq && NR_HIST_GENS > 1) { -+ s = "loynfa"; -+ n = READ_ONCE(lruvec->mm_state.stats[hist][i]); -+ } -+ -+ seq_printf(m, " %10lu%c", n, s[i]); -+ } -+ seq_putc(m, '\n'); -+} -+ -+static int lru_gen_seq_show(struct seq_file *m, void *v) -+{ -+ unsigned long seq; -+ bool full = !debugfs_real_fops(m->file)->write; -+ struct lruvec *lruvec = v; -+ struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ int nid = lruvec_pgdat(lruvec)->node_id; -+ struct mem_cgroup *memcg = lruvec_memcg(lruvec); -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (nid == first_memory_node) { -+ const char *path = memcg ? m->private : ""; -+ -+#ifdef CONFIG_MEMCG -+ if (memcg) -+ cgroup_path(memcg->css.cgroup, m->private, PATH_MAX); -+#endif -+ seq_printf(m, "memcg %5hu %s\n", mem_cgroup_id(memcg), path); -+ } -+ -+ seq_printf(m, " node %5d\n", nid); -+ -+ if (!full) -+ seq = min_seq[LRU_GEN_ANON]; -+ else if (max_seq >= MAX_NR_GENS) -+ seq = max_seq - MAX_NR_GENS + 1; -+ else -+ seq = 0; -+ -+ for (; seq <= max_seq; seq++) { -+ int type, zone; -+ int gen = lru_gen_from_seq(seq); -+ unsigned long birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -+ -+ seq_printf(m, " %10lu %10u", seq, jiffies_to_msecs(jiffies - birth)); -+ -+ for (type = 0; type < ANON_AND_FILE; type++) { -+ unsigned long size = 0; -+ char mark = full && seq < min_seq[type] ? 'x' : ' '; -+ -+ for (zone = 0; zone < MAX_NR_ZONES; zone++) -+ size += max(READ_ONCE(lrugen->nr_pages[gen][type][zone]), 0L); -+ -+ seq_printf(m, " %10lu%c", size, mark); -+ } -+ -+ seq_putc(m, '\n'); -+ -+ if (full) -+ lru_gen_seq_show_full(m, lruvec, max_seq, min_seq, seq); -+ } -+ -+ return 0; -+} -+ -+static const struct seq_operations lru_gen_seq_ops = { -+ .start = lru_gen_seq_start, -+ .stop = lru_gen_seq_stop, -+ .next = lru_gen_seq_next, -+ .show = lru_gen_seq_show, -+}; -+ -+static int run_aging(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, -+ bool can_swap, bool force_scan) -+{ -+ DEFINE_MAX_SEQ(lruvec); -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (seq < max_seq) -+ return 0; -+ -+ if (seq > max_seq) -+ return -EINVAL; -+ -+ if (!force_scan && min_seq[!can_swap] + MAX_NR_GENS - 1 <= max_seq) -+ return -ERANGE; -+ -+ try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, force_scan); -+ -+ return 0; -+} -+ -+static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_control *sc, -+ int swappiness, unsigned long nr_to_reclaim) -+{ -+ DEFINE_MAX_SEQ(lruvec); -+ -+ if (seq + MIN_NR_GENS > max_seq) -+ return -EINVAL; -+ -+ sc->nr_reclaimed = 0; -+ -+ while (!signal_pending(current)) { -+ DEFINE_MIN_SEQ(lruvec); -+ -+ if (seq < min_seq[!swappiness]) -+ return 0; -+ -+ if (sc->nr_reclaimed >= nr_to_reclaim) -+ return 0; -+ -+ if (!evict_pages(lruvec, sc, swappiness, NULL)) -+ return 0; -+ -+ cond_resched(); -+ } -+ -+ return -EINTR; -+} -+ -+static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, -+ struct scan_control *sc, int swappiness, unsigned long opt) -+{ -+ struct lruvec *lruvec; -+ int err = -EINVAL; -+ struct mem_cgroup *memcg = NULL; -+ -+ if (nid < 0 || nid >= MAX_NUMNODES || !node_state(nid, N_MEMORY)) -+ return -EINVAL; -+ -+ if (!mem_cgroup_disabled()) { -+ rcu_read_lock(); -+ memcg = mem_cgroup_from_id(memcg_id); -+#ifdef CONFIG_MEMCG -+ if (memcg && !css_tryget(&memcg->css)) -+ memcg = NULL; -+#endif -+ rcu_read_unlock(); -+ -+ if (!memcg) -+ return -EINVAL; -+ } -+ -+ if (memcg_id != mem_cgroup_id(memcg)) -+ goto done; -+ -+ lruvec = get_lruvec(memcg, nid); -+ -+ if (swappiness < 0) -+ swappiness = get_swappiness(lruvec, sc); -+ else if (swappiness > 200) -+ goto done; -+ -+ switch (cmd) { -+ case '+': -+ err = run_aging(lruvec, seq, sc, swappiness, opt); -+ break; -+ case '-': -+ err = run_eviction(lruvec, seq, sc, swappiness, opt); -+ break; -+ } -+done: -+ mem_cgroup_put(memcg); -+ -+ return err; -+} -+ -+static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, -+ size_t len, loff_t *pos) -+{ -+ void *buf; -+ char *cur, *next; -+ unsigned int flags; -+ struct blk_plug plug; -+ int err = -EINVAL; -+ struct scan_control sc = { -+ .may_writepage = true, -+ .may_unmap = true, -+ .may_swap = true, -+ .reclaim_idx = MAX_NR_ZONES - 1, -+ .gfp_mask = GFP_KERNEL, -+ }; -+ -+ buf = kvmalloc(len + 1, GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ -+ if (copy_from_user(buf, src, len)) { -+ kvfree(buf); -+ return -EFAULT; -+ } -+ -+ set_task_reclaim_state(current, &sc.reclaim_state); -+ flags = memalloc_noreclaim_save(); -+ blk_start_plug(&plug); -+ if (!set_mm_walk(NULL)) { -+ err = -ENOMEM; -+ goto done; -+ } -+ -+ next = buf; -+ next[len] = '\0'; -+ -+ while ((cur = strsep(&next, ",;\n"))) { -+ int n; -+ int end; -+ char cmd; -+ unsigned int memcg_id; -+ unsigned int nid; -+ unsigned long seq; -+ unsigned int swappiness = -1; -+ unsigned long opt = -1; -+ -+ cur = skip_spaces(cur); -+ if (!*cur) -+ continue; -+ -+ n = sscanf(cur, "%c %u %u %lu %n %u %n %lu %n", &cmd, &memcg_id, &nid, -+ &seq, &end, &swappiness, &end, &opt, &end); -+ if (n < 4 || cur[end]) { -+ err = -EINVAL; -+ break; -+ } -+ -+ err = run_cmd(cmd, memcg_id, nid, seq, &sc, swappiness, opt); -+ if (err) -+ break; -+ } -+done: -+ clear_mm_walk(); -+ blk_finish_plug(&plug); -+ memalloc_noreclaim_restore(flags); -+ set_task_reclaim_state(current, NULL); -+ -+ kvfree(buf); -+ -+ return err ? : len; -+} -+ -+static int lru_gen_seq_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &lru_gen_seq_ops); -+} -+ -+static const struct file_operations lru_gen_rw_fops = { -+ .open = lru_gen_seq_open, -+ .read = seq_read, -+ .write = lru_gen_seq_write, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+static const struct file_operations lru_gen_ro_fops = { -+ .open = lru_gen_seq_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = seq_release, -+}; -+ -+/****************************************************************************** - * initialization - ******************************************************************************/ - -@@ -5180,6 +5568,9 @@ static int __init init_lru_gen(void) - if (sysfs_create_group(mm_kobj, &lru_gen_attr_group)) - pr_err("lru_gen: failed to create sysfs group\n"); - -+ debugfs_create_file("lru_gen", 0644, NULL, NULL, &lru_gen_rw_fops); -+ debugfs_create_file("lru_gen_full", 0444, NULL, NULL, &lru_gen_ro_fops); -+ - return 0; - }; - late_initcall(init_lru_gen); diff --git a/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch b/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch deleted file mode 100644 index fd4aa727473..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-13-mm-mglru-don-t-sync-disk-for-each-aging-cycle.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 92d430e8955c976eacb7cc91d7ff849c0dd009af Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Wed, 28 Sep 2022 13:36:58 -0600 -Subject: [PATCH 13/29] mm/mglru: don't sync disk for each aging cycle - -wakeup_flusher_threads() was added under the assumption that if a system -runs out of clean cold pages, it might want to write back dirty pages more -aggressively so that they can become clean and be dropped. - -However, doing so can breach the rate limit a system wants to impose on -writeback, resulting in early SSD wearout. - -Link: https://lkml.kernel.org/r/YzSiWq9UEER5LKup@google.com -Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") -Signed-off-by: Yu Zhao -Reported-by: Axel Rasmussen -Signed-off-by: Andrew Morton ---- - mm/vmscan.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -4165,8 +4165,6 @@ done: - if (wq_has_sleeper(&lruvec->mm_state.wait)) - wake_up_all(&lruvec->mm_state.wait); - -- wakeup_flusher_threads(WB_REASON_VMSCAN); -- - return true; - } - diff --git a/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch b/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch deleted file mode 100644 index 31b35cbc4b6..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-14-mm-multi-gen-LRU-retry-pages-written-back-while-isol.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 6f315879ad750391a0b1fab8c9170bc054a5f5d7 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Tue, 15 Nov 2022 18:38:07 -0700 -Subject: [PATCH 14/29] mm: multi-gen LRU: retry pages written back while - isolated - -The page reclaim isolates a batch of pages from the tail of one of the -LRU lists and works on those pages one by one. For a suitable -swap-backed page, if the swap device is async, it queues that page for -writeback. After the page reclaim finishes an entire batch, it puts back -the pages it queued for writeback to the head of the original LRU list. - -In the meantime, the page writeback flushes the queued pages also by -batches. Its batching logic is independent from that of the page reclaim. -For each of the pages it writes back, the page writeback calls -rotate_reclaimable_page() which tries to rotate a page to the tail. - -rotate_reclaimable_page() only works for a page after the page reclaim -has put it back. If an async swap device is fast enough, the page -writeback can finish with that page while the page reclaim is still -working on the rest of the batch containing it. In this case, that page -will remain at the head and the page reclaim will not retry it before -reaching there. - -This patch adds a retry to evict_pages(). After evict_pages() has -finished an entire batch and before it puts back pages it cannot free -immediately, it retries those that may have missed the rotation. - -Before this patch, ~60% of pages swapped to an Intel Optane missed -rotate_reclaimable_page(). After this patch, ~99% of missed pages were -reclaimed upon retry. - -This problem affects relatively slow async swap devices like Samsung 980 -Pro much less and does not affect sync swap devices like zram or zswap at -all. - -Link: https://lkml.kernel.org/r/20221116013808.3995280-1-yuzhao@google.com -Fixes: ac35a4902374 ("mm: multi-gen LRU: minimal implementation") -Signed-off-by: Yu Zhao -Cc: "Yin, Fengwei" -Signed-off-by: Andrew Morton ---- - mm/vmscan.c | 48 +++++++++++++++++++++++++++++++++++++----------- - 1 file changed, 37 insertions(+), 11 deletions(-) - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -4723,10 +4723,13 @@ static int evict_pages(struct lruvec *lr - int scanned; - int reclaimed; - LIST_HEAD(list); -+ LIST_HEAD(clean); - struct page *page; -+ struct page *next; - enum vm_event_item item; - struct reclaim_stat stat; - struct lru_gen_mm_walk *walk; -+ bool skip_retry = false; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - -@@ -4743,20 +4746,37 @@ static int evict_pages(struct lruvec *lr - - if (list_empty(&list)) - return scanned; -- -+retry: - reclaimed = shrink_page_list(&list, pgdat, sc, &stat, false); -+ sc->nr_reclaimed += reclaimed; - -- list_for_each_entry(page, &list, lru) { -- /* restore LRU_REFS_FLAGS cleared by isolate_page() */ -- if (PageWorkingset(page)) -- SetPageReferenced(page); -+ list_for_each_entry_safe_reverse(page, next, &list, lru) { -+ if (!page_evictable(page)) { -+ list_del(&page->lru); -+ putback_lru_page(page); -+ continue; -+ } - -- /* don't add rejected pages to the oldest generation */ - if (PageReclaim(page) && -- (PageDirty(page) || PageWriteback(page))) -- ClearPageActive(page); -- else -- SetPageActive(page); -+ (PageDirty(page) || PageWriteback(page))) { -+ /* restore LRU_REFS_FLAGS cleared by isolate_page() */ -+ if (PageWorkingset(page)) -+ SetPageReferenced(page); -+ continue; -+ } -+ -+ if (skip_retry || PageActive(page) || PageReferenced(page) || -+ page_mapped(page) || PageLocked(page) || -+ PageDirty(page) || PageWriteback(page)) { -+ /* don't add rejected pages to the oldest generation */ -+ set_mask_bits(&page->flags, LRU_REFS_MASK | LRU_REFS_FLAGS, -+ BIT(PG_active)); -+ continue; -+ } -+ -+ /* retry pages that may have missed rotate_reclaimable_page() */ -+ list_move(&page->lru, &clean); -+ sc->nr_scanned -= thp_nr_pages(page); - } - - spin_lock_irq(&lruvec->lru_lock); -@@ -4778,7 +4798,13 @@ static int evict_pages(struct lruvec *lr - mem_cgroup_uncharge_list(&list); - free_unref_page_list(&list); - -- sc->nr_reclaimed += reclaimed; -+ INIT_LIST_HEAD(&list); -+ list_splice_init(&clean, &list); -+ -+ if (!list_empty(&list)) { -+ skip_retry = true; -+ goto retry; -+ } - - if (need_swapping && type == LRU_GEN_ANON) - *need_swapping = true; diff --git a/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch b/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch deleted file mode 100644 index 5b1d378504a..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-15-mm-multi-gen-LRU-move-lru_gen_add_mm-out-of-IRQ-off-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 255bb0ac393f1c2818cd75af45a9226300ab3daf Mon Sep 17 00:00:00 2001 -From: Sebastian Andrzej Siewior -Date: Wed, 26 Oct 2022 15:48:30 +0200 -Subject: [PATCH 15/29] mm: multi-gen LRU: move lru_gen_add_mm() out of IRQ-off - region - -lru_gen_add_mm() has been added within an IRQ-off region in the commit -mentioned below. The other invocations of lru_gen_add_mm() are not within -an IRQ-off region. - -The invocation within IRQ-off region is problematic on PREEMPT_RT because -the function is using a spin_lock_t which must not be used within -IRQ-disabled regions. - -The other invocations of lru_gen_add_mm() occur while -task_struct::alloc_lock is acquired. Move lru_gen_add_mm() after -interrupts are enabled and before task_unlock(). - -Link: https://lkml.kernel.org/r/20221026134830.711887-1-bigeasy@linutronix.de -Fixes: bd74fdaea1460 ("mm: multi-gen LRU: support page table walks") -Signed-off-by: Sebastian Andrzej Siewior -Acked-by: Yu Zhao -Cc: Al Viro -Cc: "Eric W . Biederman" -Cc: Kees Cook -Cc: Thomas Gleixner -Signed-off-by: Andrew Morton ---- - fs/exec.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -1013,7 +1013,6 @@ static int exec_mmap(struct mm_struct *m - active_mm = tsk->active_mm; - tsk->active_mm = mm; - tsk->mm = mm; -- lru_gen_add_mm(mm); - /* - * This prevents preemption while active_mm is being loaded and - * it and mm are being updated, which could cause problems for -@@ -1028,6 +1027,7 @@ static int exec_mmap(struct mm_struct *m - local_irq_enable(); - tsk->mm->vmacache_seqnum = 0; - vmacache_flush(tsk); -+ lru_gen_add_mm(mm); - task_unlock(tsk); - lru_gen_use_mm(mm); - if (old_mm) { diff --git a/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch b/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch deleted file mode 100644 index 1c10c168a50..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-17-mm-add-dummy-pmd_young-for-architectures-not-having-.patch +++ /dev/null @@ -1,96 +0,0 @@ -From c5ec455ebd2b488d91de9d8915a0c8036a2a04dd Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Wed, 30 Nov 2022 14:49:41 -0800 -Subject: [PATCH 17/29] mm: add dummy pmd_young() for architectures not having - it - -In order to avoid #ifdeffery add a dummy pmd_young() implementation as a -fallback. This is required for the later patch "mm: introduce -arch_has_hw_nonleaf_pmd_young()". - -Link: https://lkml.kernel.org/r/fd3ac3cd-7349-6bbd-890a-71a9454ca0b3@suse.com -Signed-off-by: Juergen Gross -Acked-by: Yu Zhao -Cc: Borislav Petkov -Cc: Dave Hansen -Cc: Geert Uytterhoeven -Cc: "H. Peter Anvin" -Cc: Ingo Molnar -Cc: Sander Eikelenboom -Cc: Thomas Gleixner -Signed-off-by: Andrew Morton ---- - arch/mips/include/asm/pgtable.h | 1 + - arch/riscv/include/asm/pgtable.h | 1 + - arch/s390/include/asm/pgtable.h | 1 + - arch/sparc/include/asm/pgtable_64.h | 1 + - arch/x86/include/asm/pgtable.h | 1 + - include/linux/pgtable.h | 7 +++++++ - 6 files changed, 12 insertions(+) - ---- a/arch/mips/include/asm/pgtable.h -+++ b/arch/mips/include/asm/pgtable.h -@@ -632,6 +632,7 @@ static inline pmd_t pmd_mkdirty(pmd_t pm - return pmd; - } - -+#define pmd_young pmd_young - static inline int pmd_young(pmd_t pmd) - { - return !!(pmd_val(pmd) & _PAGE_ACCESSED); ---- a/arch/riscv/include/asm/pgtable.h -+++ b/arch/riscv/include/asm/pgtable.h -@@ -535,6 +535,7 @@ static inline int pmd_dirty(pmd_t pmd) - return pte_dirty(pmd_pte(pmd)); - } - -+#define pmd_young pmd_young - static inline int pmd_young(pmd_t pmd) - { - return pte_young(pmd_pte(pmd)); ---- a/arch/s390/include/asm/pgtable.h -+++ b/arch/s390/include/asm/pgtable.h -@@ -748,6 +748,7 @@ static inline int pmd_dirty(pmd_t pmd) - return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0; - } - -+#define pmd_young pmd_young - static inline int pmd_young(pmd_t pmd) - { - return (pmd_val(pmd) & _SEGMENT_ENTRY_YOUNG) != 0; ---- a/arch/sparc/include/asm/pgtable_64.h -+++ b/arch/sparc/include/asm/pgtable_64.h -@@ -712,6 +712,7 @@ static inline unsigned long pmd_dirty(pm - return pte_dirty(pte); - } - -+#define pmd_young pmd_young - static inline unsigned long pmd_young(pmd_t pmd) - { - pte_t pte = __pte(pmd_val(pmd)); ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -136,6 +136,7 @@ static inline int pmd_dirty(pmd_t pmd) - return pmd_flags(pmd) & _PAGE_DIRTY; - } - -+#define pmd_young pmd_young - static inline int pmd_young(pmd_t pmd) - { - return pmd_flags(pmd) & _PAGE_ACCESSED; ---- a/include/linux/pgtable.h -+++ b/include/linux/pgtable.h -@@ -164,6 +164,13 @@ static inline pte_t *virt_to_kpte(unsign - return pmd_none(*pmd) ? NULL : pte_offset_kernel(pmd, vaddr); - } - -+#ifndef pmd_young -+static inline int pmd_young(pmd_t pmd) -+{ -+ return 0; -+} -+#endif -+ - #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS - extern int ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, diff --git a/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch b/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch deleted file mode 100644 index 9a1f9bead6c..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 46cbda7b65998a5af4493f745d94417af697bd68 Mon Sep 17 00:00:00 2001 -From: Juergen Gross -Date: Wed, 23 Nov 2022 07:45:10 +0100 -Subject: [PATCH 18/29] mm: introduce arch_has_hw_nonleaf_pmd_young() - -When running as a Xen PV guests commit eed9a328aa1a ("mm: x86: add -CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") can cause a protection violation in -pmdp_test_and_clear_young(): - - BUG: unable to handle page fault for address: ffff8880083374d0 - #PF: supervisor write access in kernel mode - #PF: error_code(0x0003) - permissions violation - PGD 3026067 P4D 3026067 PUD 3027067 PMD 7fee5067 PTE 8010000008337065 - Oops: 0003 [#1] PREEMPT SMP NOPTI - CPU: 7 PID: 158 Comm: kswapd0 Not tainted 6.1.0-rc5-20221118-doflr+ #1 - RIP: e030:pmdp_test_and_clear_young+0x25/0x40 - -This happens because the Xen hypervisor can't emulate direct writes to -page table entries other than PTEs. - -This can easily be fixed by introducing arch_has_hw_nonleaf_pmd_young() -similar to arch_has_hw_pte_young() and test that instead of -CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG. - -Link: https://lkml.kernel.org/r/20221123064510.16225-1-jgross@suse.com -Fixes: eed9a328aa1a ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") -Signed-off-by: Juergen Gross -Reported-by: Sander Eikelenboom -Acked-by: Yu Zhao -Tested-by: Sander Eikelenboom -Acked-by: David Hildenbrand [core changes] -Signed-off-by: Andrew Morton ---- - arch/x86/include/asm/pgtable.h | 8 ++++++++ - include/linux/pgtable.h | 11 +++++++++++ - mm/vmscan.c | 10 +++++----- - 3 files changed, 24 insertions(+), 5 deletions(-) - ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young - return true; - } - -+#ifdef CONFIG_XEN_PV -+#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young -+static inline bool arch_has_hw_nonleaf_pmd_young(void) -+{ -+ return !cpu_feature_enabled(X86_FEATURE_XENPV); -+} -+#endif -+ - #endif /* __ASSEMBLY__ */ - - #endif /* _ASM_X86_PGTABLE_H */ ---- a/include/linux/pgtable.h -+++ b/include/linux/pgtable.h -@@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young - #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - #endif - -+#ifndef arch_has_hw_nonleaf_pmd_young -+/* -+ * Return whether the accessed bit in non-leaf PMD entries is supported on the -+ * local CPU. -+ */ -+static inline bool arch_has_hw_nonleaf_pmd_young(void) -+{ -+ return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG); -+} -+#endif -+ - #ifndef arch_has_hw_pte_young - /* - * Return whether the accessed bit is supported on the local CPU. ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -3727,7 +3727,7 @@ static void walk_pmd_range_locked(pud_t - goto next; - - if (!pmd_trans_huge(pmd[i])) { -- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && -+ if (arch_has_hw_nonleaf_pmd_young() && - get_cap(LRU_GEN_NONLEAF_YOUNG)) - pmdp_test_and_clear_young(vma, addr, pmd + i); - goto next; -@@ -3825,14 +3825,14 @@ restart: - #endif - walk->mm_stats[MM_NONLEAF_TOTAL]++; - --#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG -- if (get_cap(LRU_GEN_NONLEAF_YOUNG)) { -+ if (arch_has_hw_nonleaf_pmd_young() && -+ get_cap(LRU_GEN_NONLEAF_YOUNG)) { - if (!pmd_young(val)) - continue; - - walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); - } --#endif -+ - if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) - continue; - -@@ -5132,7 +5132,7 @@ static ssize_t show_enabled(struct kobje - if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK)) - caps |= BIT(LRU_GEN_MM_WALK); - -- if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG)) -+ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG)) - caps |= BIT(LRU_GEN_NONLEAF_YOUNG); - - return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps); diff --git a/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch b/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch deleted file mode 100644 index e37386abdf1..00000000000 --- a/target/linux/generic/backport-6.1/020-v6.2-16-mm-multi-gen-LRU-fix-crash-during-cgroup-migration.patch +++ /dev/null @@ -1,56 +0,0 @@ -From c7dfefd4bdfba3d5171038d1cc2d4160288e6ee4 Mon Sep 17 00:00:00 2001 -From: Yu Zhao -Date: Sun, 15 Jan 2023 20:44:05 -0700 -Subject: [PATCH 16/29] mm: multi-gen LRU: fix crash during cgroup migration - -lru_gen_migrate_mm() assumes lru_gen_add_mm() runs prior to itself. This -isn't true for the following scenario: - - CPU 1 CPU 2 - - clone() - cgroup_can_fork() - cgroup_procs_write() - cgroup_post_fork() - task_lock() - lru_gen_migrate_mm() - task_unlock() - task_lock() - lru_gen_add_mm() - task_unlock() - -And when the above happens, kernel crashes because of linked list -corruption (mm_struct->lru_gen.list). - -Link: https://lore.kernel.org/r/20230115134651.30028-1-msizanoen@qtmlabs.xyz/ -Link: https://lkml.kernel.org/r/20230116034405.2960276-1-yuzhao@google.com -Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") -Signed-off-by: Yu Zhao -Reported-by: msizanoen -Tested-by: msizanoen -Cc: [6.1+] -Signed-off-by: Andrew Morton ---- - mm/vmscan.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/mm/vmscan.c -+++ b/mm/vmscan.c -@@ -3024,13 +3024,16 @@ void lru_gen_migrate_mm(struct mm_struct - if (mem_cgroup_disabled()) - return; - -+ /* migration can happen before addition */ -+ if (!mm->lru_gen.memcg) -+ return; -+ - rcu_read_lock(); - memcg = mem_cgroup_from_task(task); - rcu_read_unlock(); - if (memcg == mm->lru_gen.memcg) - return; - -- VM_WARN_ON_ONCE(!mm->lru_gen.memcg); - VM_WARN_ON_ONCE(list_empty(&mm->lru_gen.list)); - - lru_gen_del_mm(mm); diff --git a/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch b/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch deleted file mode 100644 index 82feb7421d5..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-00-MIPS-uasm-Enable-muhu-opcode-for-MIPS-R6.patch +++ /dev/null @@ -1,65 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:02 +0200 -Subject: [PATCH] MIPS: uasm: Enable muhu opcode for MIPS R6 - -Enable the 'muhu' instruction, complementing the existing 'mulu', needed -to implement a MIPS32 BPF JIT. - -Also fix a typo in the existing definition of 'dmulu'. - -Signed-off-by: Tony Ambardar - -This patch is a dependency for my 32-bit MIPS eBPF JIT. - -Signed-off-by: Johan Almbladh ---- - ---- a/arch/mips/include/asm/uasm.h -+++ b/arch/mips/include/asm/uasm.h -@@ -145,6 +145,7 @@ Ip_u1(_mtlo); - Ip_u3u1u2(_mul); - Ip_u1u2(_multu); - Ip_u3u1u2(_mulu); -+Ip_u3u1u2(_muhu); - Ip_u3u1u2(_nor); - Ip_u3u1u2(_or); - Ip_u2u1u3(_ori); ---- a/arch/mips/mm/uasm-mips.c -+++ b/arch/mips/mm/uasm-mips.c -@@ -90,7 +90,7 @@ static const struct insn insn_table[insn - RS | RT | RD}, - [insn_dmtc0] = {M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET}, - [insn_dmultu] = {M(spec_op, 0, 0, 0, 0, dmultu_op), RS | RT}, -- [insn_dmulu] = {M(spec_op, 0, 0, 0, dmult_dmul_op, dmultu_op), -+ [insn_dmulu] = {M(spec_op, 0, 0, 0, dmultu_dmulu_op, dmultu_op), - RS | RT | RD}, - [insn_drotr] = {M(spec_op, 1, 0, 0, 0, dsrl_op), RT | RD | RE}, - [insn_drotr32] = {M(spec_op, 1, 0, 0, 0, dsrl32_op), RT | RD | RE}, -@@ -150,6 +150,8 @@ static const struct insn insn_table[insn - [insn_mtlo] = {M(spec_op, 0, 0, 0, 0, mtlo_op), RS}, - [insn_mulu] = {M(spec_op, 0, 0, 0, multu_mulu_op, multu_op), - RS | RT | RD}, -+ [insn_muhu] = {M(spec_op, 0, 0, 0, multu_muhu_op, multu_op), -+ RS | RT | RD}, - #ifndef CONFIG_CPU_MIPSR6 - [insn_mul] = {M(spec2_op, 0, 0, 0, 0, mul_op), RS | RT | RD}, - #else ---- a/arch/mips/mm/uasm.c -+++ b/arch/mips/mm/uasm.c -@@ -59,7 +59,7 @@ enum opcode { - insn_lddir, insn_ldpte, insn_ldx, insn_lh, insn_lhu, insn_ll, insn_lld, - insn_lui, insn_lw, insn_lwu, insn_lwx, insn_mfc0, insn_mfhc0, insn_mfhi, - insn_mflo, insn_modu, insn_movn, insn_movz, insn_mtc0, insn_mthc0, -- insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_nor, -+ insn_mthi, insn_mtlo, insn_mul, insn_multu, insn_mulu, insn_muhu, insn_nor, - insn_or, insn_ori, insn_pref, insn_rfe, insn_rotr, insn_sb, insn_sc, - insn_scd, insn_seleqz, insn_selnez, insn_sd, insn_sh, insn_sll, - insn_sllv, insn_slt, insn_slti, insn_sltiu, insn_sltu, insn_sra, -@@ -344,6 +344,7 @@ I_u1(_mtlo) - I_u3u1u2(_mul) - I_u1u2(_multu) - I_u3u1u2(_mulu) -+I_u3u1u2(_muhu) - I_u3u1u2(_nor) - I_u3u1u2(_or) - I_u2u1u3(_ori) diff --git a/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch b/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch deleted file mode 100644 index 3a4d573f80a..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-01-mips-uasm-Add-workaround-for-Loongson-2F-nop-CPU-err.patch +++ /dev/null @@ -1,31 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:03 +0200 -Subject: [PATCH] mips: uasm: Add workaround for Loongson-2F nop CPU errata - -This patch implements a workaround for the Loongson-2F nop in generated, -code, if the existing option CONFIG_CPU_NOP_WORKAROUND is set. Before, -the binutils option -mfix-loongson2f-nop was enabled, but no workaround -was done when emitting MIPS code. Now, the nop pseudo instruction is -emitted as "or ax,ax,zero" instead of the default "sll zero,zero,0". This -is consistent with the workaround implemented by binutils. - -Link: https://sourceware.org/legacy-ml/binutils/2009-11/msg00387.html - -Signed-off-by: Johan Almbladh -Reviewed-by: Jiaxun Yang ---- - ---- a/arch/mips/include/asm/uasm.h -+++ b/arch/mips/include/asm/uasm.h -@@ -249,7 +249,11 @@ static inline void uasm_l##lb(struct uas - #define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off) - #define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3) - #define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b) -+#ifdef CONFIG_CPU_NOP_WORKAROUNDS -+#define uasm_i_nop(buf) uasm_i_or(buf, 1, 1, 0) -+#else - #define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0) -+#endif - #define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1) - - static inline void uasm_i_drotr_safe(u32 **p, unsigned int a1, diff --git a/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch b/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch deleted file mode 100644 index 79806599612..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-02-mips-bpf-Add-eBPF-JIT-for-32-bit-MIPS.patch +++ /dev/null @@ -1,3078 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:04 +0200 -Subject: [PATCH] mips: bpf: Add eBPF JIT for 32-bit MIPS - -This is an implementation of an eBPF JIT for 32-bit MIPS I-V and MIPS32. -The implementation supports all 32-bit and 64-bit ALU and JMP operations, -including the recently-added atomics. 64-bit div/mod and 64-bit atomics -are implemented using function calls to math64 and atomic64 functions, -respectively. All 32-bit operations are implemented natively by the JIT, -except if the CPU lacks ll/sc instructions. - -Register mapping -================ -All 64-bit eBPF registers are mapped to native 32-bit MIPS register pairs, -and does not use any stack scratch space for register swapping. This means -that all eBPF register data is kept in CPU registers all the time, and -this simplifies the register management a lot. It also reduces the JIT's -pressure on temporary registers since we do not have to move data around. - -Native register pairs are ordered according to CPU endiannes, following -the O32 calling convention for passing 64-bit arguments and return values. -The eBPF return value, arguments and callee-saved registers are mapped to -their native MIPS equivalents. - -Since the 32 highest bits in the eBPF FP (frame pointer) register are -always zero, only one general-purpose register is actually needed for the -mapping. The MIPS fp register is used for this purpose. The high bits are -mapped to MIPS register r0. This saves us one CPU register, which is much -needed for temporaries, while still allowing us to treat the R10 (FP) -register just like any other eBPF register in the JIT. - -The MIPS gp (global pointer) and at (assembler temporary) registers are -used as internal temporary registers for constant blinding. CPU registers -t6-t9 are used internally by the JIT when constructing more complex 64-bit -operations. This is precisely what is needed - two registers to store an -operand value, and two more as scratch registers when performing the -operation. - -The register mapping is shown below. - - R0 - $v1, $v0 return value - R1 - $a1, $a0 argument 1, passed in registers - R2 - $a3, $a2 argument 2, passed in registers - R3 - $t1, $t0 argument 3, passed on stack - R4 - $t3, $t2 argument 4, passed on stack - R5 - $t4, $t3 argument 5, passed on stack - R6 - $s1, $s0 callee-saved - R7 - $s3, $s2 callee-saved - R8 - $s5, $s4 callee-saved - R9 - $s7, $s6 callee-saved - FP - $r0, $fp 32-bit frame pointer - AX - $gp, $at constant-blinding - $t6 - $t9 unallocated, JIT temporaries - -Jump offsets -============ -The JIT tries to map all conditional JMP operations to MIPS conditional -PC-relative branches. The MIPS branch offset field is 18 bits, in bytes, -which is equivalent to the eBPF 16-bit instruction offset. However, since -the JIT may emit more than one CPU instruction per eBPF instruction, the -field width may overflow. If that happens, the JIT converts the long -conditional jump to a short PC-relative branch with the condition -inverted, jumping over a long unconditional absolute jmp (j). - -This conversion will change the instruction offset mapping used for jumps, -and may in turn result in more branch offset overflows. The JIT therefore -dry-runs the translation until no more branches are converted and the -offsets do not change anymore. There is an upper bound on this of course, -and if the JIT hits that limit, the last two iterations are run with all -branches being converted. - -Tail call count -=============== -The current tail call count is stored in the 16-byte area of the caller's -stack frame that is reserved for the callee in the o32 ABI. The value is -initialized in the prologue, and propagated to the tail-callee by skipping -the initialization instructions when emitting the tail call. - -Signed-off-by: Johan Almbladh ---- - create mode 100644 arch/mips/net/bpf_jit_comp.c - create mode 100644 arch/mips/net/bpf_jit_comp.h - create mode 100644 arch/mips/net/bpf_jit_comp32.c - ---- a/arch/mips/net/Makefile -+++ b/arch/mips/net/Makefile -@@ -2,4 +2,9 @@ - # MIPS networking code - - obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o --obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o -+ -+ifeq ($(CONFIG_32BIT),y) -+ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o bpf_jit_comp32.o -+else -+ obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o -+endif ---- /dev/null -+++ b/arch/mips/net/bpf_jit_comp.c -@@ -0,0 +1,1020 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Just-In-Time compiler for eBPF bytecode on MIPS. -+ * Implementation of JIT functions common to 32-bit and 64-bit CPUs. -+ * -+ * Copyright (c) 2021 Anyfi Networks AB. -+ * Author: Johan Almbladh -+ * -+ * Based on code and ideas from -+ * Copyright (c) 2017 Cavium, Inc. -+ * Copyright (c) 2017 Shubham Bansal -+ * Copyright (c) 2011 Mircea Gherzan -+ */ -+ -+/* -+ * Code overview -+ * ============= -+ * -+ * - bpf_jit_comp.h -+ * Common definitions and utilities. -+ * -+ * - bpf_jit_comp.c -+ * Implementation of JIT top-level logic and exported JIT API functions. -+ * Implementation of internal operations shared by 32-bit and 64-bit code. -+ * JMP and ALU JIT control code, register control code, shared ALU and -+ * JMP/JMP32 JIT operations. -+ * -+ * - bpf_jit_comp32.c -+ * Implementation of functions to JIT prologue, epilogue and a single eBPF -+ * instruction for 32-bit MIPS CPUs. The functions use shared operations -+ * where possible, and implement the rest for 32-bit MIPS such as ALU64 -+ * operations. -+ * -+ * - bpf_jit_comp64.c -+ * Ditto, for 64-bit MIPS CPUs. -+ * -+ * Zero and sign extension -+ * ======================== -+ * 32-bit MIPS instructions on 64-bit MIPS registers use sign extension, -+ * but the eBPF instruction set mandates zero extension. We let the verifier -+ * insert explicit zero-extensions after 32-bit ALU operations, both for -+ * 32-bit and 64-bit MIPS JITs. Conditional JMP32 operations on 64-bit MIPs -+ * are JITed with sign extensions inserted when so expected. -+ * -+ * ALU operations -+ * ============== -+ * ALU operations on 32/64-bit MIPS and ALU64 operations on 64-bit MIPS are -+ * JITed in the following steps. ALU64 operations on 32-bit MIPS are more -+ * complicated and therefore only processed by special implementations in -+ * step (3). -+ * -+ * 1) valid_alu_i: -+ * Determine if an immediate operation can be emitted as such, or if -+ * we must fall back to the register version. -+ * -+ * 2) rewrite_alu_i: -+ * Convert BPF operation and immediate value to a canonical form for -+ * JITing. In some degenerate cases this form may be a no-op. -+ * -+ * 3) emit_alu_{i,i64,r,64}: -+ * Emit instructions for an ALU or ALU64 immediate or register operation. -+ * -+ * JMP operations -+ * ============== -+ * JMP and JMP32 operations require an JIT instruction offset table for -+ * translating the jump offset. This table is computed by dry-running the -+ * JIT without actually emitting anything. However, the computed PC-relative -+ * offset may overflow the 18-bit offset field width of the native MIPS -+ * branch instruction. In such cases, the long jump is converted into the -+ * following sequence. -+ * -+ * ! +2 Inverted PC-relative branch -+ * nop Delay slot -+ * j Unconditional absolute long jump -+ * nop Delay slot -+ * -+ * Since this converted sequence alters the offset table, all offsets must -+ * be re-calculated. This may in turn trigger new branch conversions, so -+ * the process is repeated until no further changes are made. Normally it -+ * completes in 1-2 iterations. If JIT_MAX_ITERATIONS should reached, we -+ * fall back to converting every remaining jump operation. The branch -+ * conversion is independent of how the JMP or JMP32 condition is JITed. -+ * -+ * JMP32 and JMP operations are JITed as follows. -+ * -+ * 1) setup_jmp_{i,r}: -+ * Convert jump conditional and offset into a form that can be JITed. -+ * This form may be a no-op, a canonical form, or an inverted PC-relative -+ * jump if branch conversion is necessary. -+ * -+ * 2) valid_jmp_i: -+ * Determine if an immediate operations can be emitted as such, or if -+ * we must fall back to the register version. Applies to JMP32 for 32-bit -+ * MIPS, and both JMP and JMP32 for 64-bit MIPS. -+ * -+ * 3) emit_jmp_{i,i64,r,r64}: -+ * Emit instructions for an JMP or JMP32 immediate or register operation. -+ * -+ * 4) finish_jmp_{i,r}: -+ * Emit any instructions needed to finish the jump. This includes a nop -+ * for the delay slot if a branch was emitted, and a long absolute jump -+ * if the branch was converted. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "bpf_jit_comp.h" -+ -+/* Convenience macros for descriptor access */ -+#define CONVERTED(desc) ((desc) & JIT_DESC_CONVERT) -+#define INDEX(desc) ((desc) & ~JIT_DESC_CONVERT) -+ -+/* -+ * Push registers on the stack, starting at a given depth from the stack -+ * pointer and increasing. The next depth to be written is returned. -+ */ -+int push_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth) -+{ -+ int reg; -+ -+ for (reg = 0; reg < BITS_PER_BYTE * sizeof(mask); reg++) -+ if (mask & BIT(reg)) { -+ if ((excl & BIT(reg)) == 0) { -+ if (sizeof(long) == 4) -+ emit(ctx, sw, reg, depth, MIPS_R_SP); -+ else /* sizeof(long) == 8 */ -+ emit(ctx, sd, reg, depth, MIPS_R_SP); -+ } -+ depth += sizeof(long); -+ } -+ -+ ctx->stack_used = max((int)ctx->stack_used, depth); -+ return depth; -+} -+ -+/* -+ * Pop registers from the stack, starting at a given depth from the stack -+ * pointer and increasing. The next depth to be read is returned. -+ */ -+int pop_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth) -+{ -+ int reg; -+ -+ for (reg = 0; reg < BITS_PER_BYTE * sizeof(mask); reg++) -+ if (mask & BIT(reg)) { -+ if ((excl & BIT(reg)) == 0) { -+ if (sizeof(long) == 4) -+ emit(ctx, lw, reg, depth, MIPS_R_SP); -+ else /* sizeof(long) == 8 */ -+ emit(ctx, ld, reg, depth, MIPS_R_SP); -+ } -+ depth += sizeof(long); -+ } -+ -+ return depth; -+} -+ -+/* Compute the 28-bit jump target address from a BPF program location */ -+int get_target(struct jit_context *ctx, u32 loc) -+{ -+ u32 index = INDEX(ctx->descriptors[loc]); -+ unsigned long pc = (unsigned long)&ctx->target[ctx->jit_index]; -+ unsigned long addr = (unsigned long)&ctx->target[index]; -+ -+ if (!ctx->target) -+ return 0; -+ -+ if ((addr ^ pc) & ~MIPS_JMP_MASK) -+ return -1; -+ -+ return addr & MIPS_JMP_MASK; -+} -+ -+/* Compute the PC-relative offset to relative BPF program offset */ -+int get_offset(const struct jit_context *ctx, int off) -+{ -+ return (INDEX(ctx->descriptors[ctx->bpf_index + off]) - -+ ctx->jit_index - 1) * sizeof(u32); -+} -+ -+/* dst = imm (register width) */ -+void emit_mov_i(struct jit_context *ctx, u8 dst, s32 imm) -+{ -+ if (imm >= -0x8000 && imm <= 0x7fff) { -+ emit(ctx, addiu, dst, MIPS_R_ZERO, imm); -+ } else { -+ emit(ctx, lui, dst, (s16)((u32)imm >> 16)); -+ emit(ctx, ori, dst, dst, (u16)(imm & 0xffff)); -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* dst = src (register width) */ -+void emit_mov_r(struct jit_context *ctx, u8 dst, u8 src) -+{ -+ emit(ctx, ori, dst, src, 0); -+ clobber_reg(ctx, dst); -+} -+ -+/* Validate ALU immediate range */ -+bool valid_alu_i(u8 op, s32 imm) -+{ -+ switch (BPF_OP(op)) { -+ case BPF_NEG: -+ case BPF_LSH: -+ case BPF_RSH: -+ case BPF_ARSH: -+ /* All legal eBPF values are valid */ -+ return true; -+ case BPF_ADD: -+ /* imm must be 16 bits */ -+ return imm >= -0x8000 && imm <= 0x7fff; -+ case BPF_SUB: -+ /* -imm must be 16 bits */ -+ return imm >= -0x7fff && imm <= 0x8000; -+ case BPF_AND: -+ case BPF_OR: -+ case BPF_XOR: -+ /* imm must be 16 bits unsigned */ -+ return imm >= 0 && imm <= 0xffff; -+ case BPF_MUL: -+ /* imm must be zero or a positive power of two */ -+ return imm == 0 || (imm > 0 && is_power_of_2(imm)); -+ case BPF_DIV: -+ case BPF_MOD: -+ /* imm must be an 17-bit power of two */ -+ return (u32)imm <= 0x10000 && is_power_of_2((u32)imm); -+ } -+ return false; -+} -+ -+/* Rewrite ALU immediate operation */ -+bool rewrite_alu_i(u8 op, s32 imm, u8 *alu, s32 *val) -+{ -+ bool act = true; -+ -+ switch (BPF_OP(op)) { -+ case BPF_LSH: -+ case BPF_RSH: -+ case BPF_ARSH: -+ case BPF_ADD: -+ case BPF_SUB: -+ case BPF_OR: -+ case BPF_XOR: -+ /* imm == 0 is a no-op */ -+ act = imm != 0; -+ break; -+ case BPF_MUL: -+ if (imm == 1) { -+ /* dst * 1 is a no-op */ -+ act = false; -+ } else if (imm == 0) { -+ /* dst * 0 is dst & 0 */ -+ op = BPF_AND; -+ } else { -+ /* dst * (1 << n) is dst << n */ -+ op = BPF_LSH; -+ imm = ilog2(abs(imm)); -+ } -+ break; -+ case BPF_DIV: -+ if (imm == 1) { -+ /* dst / 1 is a no-op */ -+ act = false; -+ } else { -+ /* dst / (1 << n) is dst >> n */ -+ op = BPF_RSH; -+ imm = ilog2(imm); -+ } -+ break; -+ case BPF_MOD: -+ /* dst % (1 << n) is dst & ((1 << n) - 1) */ -+ op = BPF_AND; -+ imm--; -+ break; -+ } -+ -+ *alu = op; -+ *val = imm; -+ return act; -+} -+ -+/* ALU immediate operation (32-bit) */ -+void emit_alu_i(struct jit_context *ctx, u8 dst, s32 imm, u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = -dst */ -+ case BPF_NEG: -+ emit(ctx, subu, dst, MIPS_R_ZERO, dst); -+ break; -+ /* dst = dst & imm */ -+ case BPF_AND: -+ emit(ctx, andi, dst, dst, (u16)imm); -+ break; -+ /* dst = dst | imm */ -+ case BPF_OR: -+ emit(ctx, ori, dst, dst, (u16)imm); -+ break; -+ /* dst = dst ^ imm */ -+ case BPF_XOR: -+ emit(ctx, xori, dst, dst, (u16)imm); -+ break; -+ /* dst = dst << imm */ -+ case BPF_LSH: -+ emit(ctx, sll, dst, dst, imm); -+ break; -+ /* dst = dst >> imm */ -+ case BPF_RSH: -+ emit(ctx, srl, dst, dst, imm); -+ break; -+ /* dst = dst >> imm (arithmetic) */ -+ case BPF_ARSH: -+ emit(ctx, sra, dst, dst, imm); -+ break; -+ /* dst = dst + imm */ -+ case BPF_ADD: -+ emit(ctx, addiu, dst, dst, imm); -+ break; -+ /* dst = dst - imm */ -+ case BPF_SUB: -+ emit(ctx, addiu, dst, dst, -imm); -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* ALU register operation (32-bit) */ -+void emit_alu_r(struct jit_context *ctx, u8 dst, u8 src, u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = dst & src */ -+ case BPF_AND: -+ emit(ctx, and, dst, dst, src); -+ break; -+ /* dst = dst | src */ -+ case BPF_OR: -+ emit(ctx, or, dst, dst, src); -+ break; -+ /* dst = dst ^ src */ -+ case BPF_XOR: -+ emit(ctx, xor, dst, dst, src); -+ break; -+ /* dst = dst << src */ -+ case BPF_LSH: -+ emit(ctx, sllv, dst, dst, src); -+ break; -+ /* dst = dst >> src */ -+ case BPF_RSH: -+ emit(ctx, srlv, dst, dst, src); -+ break; -+ /* dst = dst >> src (arithmetic) */ -+ case BPF_ARSH: -+ emit(ctx, srav, dst, dst, src); -+ break; -+ /* dst = dst + src */ -+ case BPF_ADD: -+ emit(ctx, addu, dst, dst, src); -+ break; -+ /* dst = dst - src */ -+ case BPF_SUB: -+ emit(ctx, subu, dst, dst, src); -+ break; -+ /* dst = dst * src */ -+ case BPF_MUL: -+ if (cpu_has_mips32r1 || cpu_has_mips32r6) { -+ emit(ctx, mul, dst, dst, src); -+ } else { -+ emit(ctx, multu, dst, src); -+ emit(ctx, mflo, dst); -+ } -+ break; -+ /* dst = dst / src */ -+ case BPF_DIV: -+ if (cpu_has_mips32r6) { -+ emit(ctx, divu_r6, dst, dst, src); -+ } else { -+ emit(ctx, divu, dst, src); -+ emit(ctx, mflo, dst); -+ } -+ break; -+ /* dst = dst % src */ -+ case BPF_MOD: -+ if (cpu_has_mips32r6) { -+ emit(ctx, modu, dst, dst, src); -+ } else { -+ emit(ctx, divu, dst, src); -+ emit(ctx, mfhi, dst); -+ } -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Atomic read-modify-write (32-bit) */ -+void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code) -+{ -+ emit(ctx, ll, MIPS_R_T9, off, dst); -+ switch (code) { -+ case BPF_ADD: -+ emit(ctx, addu, MIPS_R_T8, MIPS_R_T9, src); -+ break; -+ case BPF_AND: -+ emit(ctx, and, MIPS_R_T8, MIPS_R_T9, src); -+ break; -+ case BPF_OR: -+ emit(ctx, or, MIPS_R_T8, MIPS_R_T9, src); -+ break; -+ case BPF_XOR: -+ emit(ctx, xor, MIPS_R_T8, MIPS_R_T9, src); -+ break; -+ } -+ emit(ctx, sc, MIPS_R_T8, off, dst); -+ emit(ctx, beqz, MIPS_R_T8, -16); -+ emit(ctx, nop); /* Delay slot */ -+} -+ -+/* Atomic compare-and-exchange (32-bit) */ -+void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off) -+{ -+ emit(ctx, ll, MIPS_R_T9, off, dst); -+ emit(ctx, bne, MIPS_R_T9, res, 12); -+ emit(ctx, move, MIPS_R_T8, src); /* Delay slot */ -+ emit(ctx, sc, MIPS_R_T8, off, dst); -+ emit(ctx, beqz, MIPS_R_T8, -20); -+ emit(ctx, move, res, MIPS_R_T9); /* Delay slot */ -+ clobber_reg(ctx, res); -+} -+ -+/* Swap bytes and truncate a register word or half word */ -+void emit_bswap_r(struct jit_context *ctx, u8 dst, u32 width) -+{ -+ u8 tmp = MIPS_R_T8; -+ u8 msk = MIPS_R_T9; -+ -+ switch (width) { -+ /* Swap bytes in a word */ -+ case 32: -+ if (cpu_has_mips32r2 || cpu_has_mips32r6) { -+ emit(ctx, wsbh, dst, dst); -+ emit(ctx, rotr, dst, dst, 16); -+ } else { -+ emit(ctx, sll, tmp, dst, 16); /* tmp = dst << 16 */ -+ emit(ctx, srl, dst, dst, 16); /* dst = dst >> 16 */ -+ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ -+ -+ emit(ctx, lui, msk, 0xff); /* msk = 0x00ff0000 */ -+ emit(ctx, ori, msk, msk, 0xff); /* msk = msk | 0xff */ -+ -+ emit(ctx, and, tmp, dst, msk); /* tmp = dst & msk */ -+ emit(ctx, sll, tmp, tmp, 8); /* tmp = tmp << 8 */ -+ emit(ctx, srl, dst, dst, 8); /* dst = dst >> 8 */ -+ emit(ctx, and, dst, dst, msk); /* dst = dst & msk */ -+ emit(ctx, or, dst, dst, tmp); /* reg = dst | tmp */ -+ } -+ break; -+ /* Swap bytes in a half word */ -+ case 16: -+ if (cpu_has_mips32r2 || cpu_has_mips32r6) { -+ emit(ctx, wsbh, dst, dst); -+ emit(ctx, andi, dst, dst, 0xffff); -+ } else { -+ emit(ctx, andi, tmp, dst, 0xff00); /* t = d & 0xff00 */ -+ emit(ctx, srl, tmp, tmp, 8); /* t = t >> 8 */ -+ emit(ctx, andi, dst, dst, 0x00ff); /* d = d & 0x00ff */ -+ emit(ctx, sll, dst, dst, 8); /* d = d << 8 */ -+ emit(ctx, or, dst, dst, tmp); /* d = d | t */ -+ } -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Validate jump immediate range */ -+bool valid_jmp_i(u8 op, s32 imm) -+{ -+ switch (op) { -+ case JIT_JNOP: -+ /* Immediate value not used */ -+ return true; -+ case BPF_JEQ: -+ case BPF_JNE: -+ /* No immediate operation */ -+ return false; -+ case BPF_JSET: -+ case JIT_JNSET: -+ /* imm must be 16 bits unsigned */ -+ return imm >= 0 && imm <= 0xffff; -+ case BPF_JGE: -+ case BPF_JLT: -+ case BPF_JSGE: -+ case BPF_JSLT: -+ /* imm must be 16 bits */ -+ return imm >= -0x8000 && imm <= 0x7fff; -+ case BPF_JGT: -+ case BPF_JLE: -+ case BPF_JSGT: -+ case BPF_JSLE: -+ /* imm + 1 must be 16 bits */ -+ return imm >= -0x8001 && imm <= 0x7ffe; -+ } -+ return false; -+} -+ -+/* Invert a conditional jump operation */ -+static u8 invert_jmp(u8 op) -+{ -+ switch (op) { -+ case BPF_JA: return JIT_JNOP; -+ case BPF_JEQ: return BPF_JNE; -+ case BPF_JNE: return BPF_JEQ; -+ case BPF_JSET: return JIT_JNSET; -+ case BPF_JGT: return BPF_JLE; -+ case BPF_JGE: return BPF_JLT; -+ case BPF_JLT: return BPF_JGE; -+ case BPF_JLE: return BPF_JGT; -+ case BPF_JSGT: return BPF_JSLE; -+ case BPF_JSGE: return BPF_JSLT; -+ case BPF_JSLT: return BPF_JSGE; -+ case BPF_JSLE: return BPF_JSGT; -+ } -+ return 0; -+} -+ -+/* Prepare a PC-relative jump operation */ -+static void setup_jmp(struct jit_context *ctx, u8 bpf_op, -+ s16 bpf_off, u8 *jit_op, s32 *jit_off) -+{ -+ u32 *descp = &ctx->descriptors[ctx->bpf_index]; -+ int op = bpf_op; -+ int offset = 0; -+ -+ /* Do not compute offsets on the first pass */ -+ if (INDEX(*descp) == 0) -+ goto done; -+ -+ /* Skip jumps never taken */ -+ if (bpf_op == JIT_JNOP) -+ goto done; -+ -+ /* Convert jumps always taken */ -+ if (bpf_op == BPF_JA) -+ *descp |= JIT_DESC_CONVERT; -+ -+ /* -+ * Current ctx->jit_index points to the start of the branch preamble. -+ * Since the preamble differs among different branch conditionals, -+ * the current index cannot be used to compute the branch offset. -+ * Instead, we use the offset table value for the next instruction, -+ * which gives the index immediately after the branch delay slot. -+ */ -+ if (!CONVERTED(*descp)) { -+ int target = ctx->bpf_index + bpf_off + 1; -+ int origin = ctx->bpf_index + 1; -+ -+ offset = (INDEX(ctx->descriptors[target]) - -+ INDEX(ctx->descriptors[origin]) + 1) * sizeof(u32); -+ } -+ -+ /* -+ * The PC-relative branch offset field on MIPS is 18 bits signed, -+ * so if the computed offset is larger than this we generate a an -+ * absolute jump that we skip with an inverted conditional branch. -+ */ -+ if (CONVERTED(*descp) || offset < -0x20000 || offset > 0x1ffff) { -+ offset = 3 * sizeof(u32); -+ op = invert_jmp(bpf_op); -+ ctx->changes += !CONVERTED(*descp); -+ *descp |= JIT_DESC_CONVERT; -+ } -+ -+done: -+ *jit_off = offset; -+ *jit_op = op; -+} -+ -+/* Prepare a PC-relative jump operation with immediate conditional */ -+void setup_jmp_i(struct jit_context *ctx, s32 imm, u8 width, -+ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off) -+{ -+ bool always = false; -+ bool never = false; -+ -+ switch (bpf_op) { -+ case BPF_JEQ: -+ case BPF_JNE: -+ break; -+ case BPF_JSET: -+ case BPF_JLT: -+ never = imm == 0; -+ break; -+ case BPF_JGE: -+ always = imm == 0; -+ break; -+ case BPF_JGT: -+ never = (u32)imm == U32_MAX; -+ break; -+ case BPF_JLE: -+ always = (u32)imm == U32_MAX; -+ break; -+ case BPF_JSGT: -+ never = imm == S32_MAX && width == 32; -+ break; -+ case BPF_JSGE: -+ always = imm == S32_MIN && width == 32; -+ break; -+ case BPF_JSLT: -+ never = imm == S32_MIN && width == 32; -+ break; -+ case BPF_JSLE: -+ always = imm == S32_MAX && width == 32; -+ break; -+ } -+ -+ if (never) -+ bpf_op = JIT_JNOP; -+ if (always) -+ bpf_op = BPF_JA; -+ setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off); -+} -+ -+/* Prepare a PC-relative jump operation with register conditional */ -+void setup_jmp_r(struct jit_context *ctx, bool same_reg, -+ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off) -+{ -+ switch (bpf_op) { -+ case BPF_JSET: -+ break; -+ case BPF_JEQ: -+ case BPF_JGE: -+ case BPF_JLE: -+ case BPF_JSGE: -+ case BPF_JSLE: -+ if (same_reg) -+ bpf_op = BPF_JA; -+ break; -+ case BPF_JNE: -+ case BPF_JLT: -+ case BPF_JGT: -+ case BPF_JSGT: -+ case BPF_JSLT: -+ if (same_reg) -+ bpf_op = JIT_JNOP; -+ break; -+ } -+ setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off); -+} -+ -+/* Finish a PC-relative jump operation */ -+int finish_jmp(struct jit_context *ctx, u8 jit_op, s16 bpf_off) -+{ -+ /* Emit conditional branch delay slot */ -+ if (jit_op != JIT_JNOP) -+ emit(ctx, nop); -+ /* -+ * Emit an absolute long jump with delay slot, -+ * if the PC-relative branch was converted. -+ */ -+ if (CONVERTED(ctx->descriptors[ctx->bpf_index])) { -+ int target = get_target(ctx, ctx->bpf_index + bpf_off + 1); -+ -+ if (target < 0) -+ return -1; -+ emit(ctx, j, target); -+ emit(ctx, nop); -+ } -+ return 0; -+} -+ -+/* Jump immediate (32-bit) */ -+void emit_jmp_i(struct jit_context *ctx, u8 dst, s32 imm, s32 off, u8 op) -+{ -+ switch (op) { -+ /* No-op, used internally for branch optimization */ -+ case JIT_JNOP: -+ break; -+ /* PC += off if dst & imm */ -+ case BPF_JSET: -+ emit(ctx, andi, MIPS_R_T9, dst, (u16)imm); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ -+ case JIT_JNSET: -+ emit(ctx, andi, MIPS_R_T9, dst, (u16)imm); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst > imm */ -+ case BPF_JGT: -+ emit(ctx, sltiu, MIPS_R_T9, dst, imm + 1); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst >= imm */ -+ case BPF_JGE: -+ emit(ctx, sltiu, MIPS_R_T9, dst, imm); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst < imm */ -+ case BPF_JLT: -+ emit(ctx, sltiu, MIPS_R_T9, dst, imm); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst <= imm */ -+ case BPF_JLE: -+ emit(ctx, sltiu, MIPS_R_T9, dst, imm + 1); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst > imm (signed) */ -+ case BPF_JSGT: -+ emit(ctx, slti, MIPS_R_T9, dst, imm + 1); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst >= imm (signed) */ -+ case BPF_JSGE: -+ emit(ctx, slti, MIPS_R_T9, dst, imm); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst < imm (signed) */ -+ case BPF_JSLT: -+ emit(ctx, slti, MIPS_R_T9, dst, imm); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JSLE: -+ emit(ctx, slti, MIPS_R_T9, dst, imm + 1); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ } -+} -+ -+/* Jump register (32-bit) */ -+void emit_jmp_r(struct jit_context *ctx, u8 dst, u8 src, s32 off, u8 op) -+{ -+ switch (op) { -+ /* No-op, used internally for branch optimization */ -+ case JIT_JNOP: -+ break; -+ /* PC += off if dst == src */ -+ case BPF_JEQ: -+ emit(ctx, beq, dst, src, off); -+ break; -+ /* PC += off if dst != src */ -+ case BPF_JNE: -+ emit(ctx, bne, dst, src, off); -+ break; -+ /* PC += off if dst & src */ -+ case BPF_JSET: -+ emit(ctx, and, MIPS_R_T9, dst, src); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ -+ case JIT_JNSET: -+ emit(ctx, and, MIPS_R_T9, dst, src); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst > src */ -+ case BPF_JGT: -+ emit(ctx, sltu, MIPS_R_T9, src, dst); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst >= src */ -+ case BPF_JGE: -+ emit(ctx, sltu, MIPS_R_T9, dst, src); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst < src */ -+ case BPF_JLT: -+ emit(ctx, sltu, MIPS_R_T9, dst, src); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst <= src */ -+ case BPF_JLE: -+ emit(ctx, sltu, MIPS_R_T9, src, dst); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst > src (signed) */ -+ case BPF_JSGT: -+ emit(ctx, slt, MIPS_R_T9, src, dst); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst >= src (signed) */ -+ case BPF_JSGE: -+ emit(ctx, slt, MIPS_R_T9, dst, src); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst < src (signed) */ -+ case BPF_JSLT: -+ emit(ctx, slt, MIPS_R_T9, dst, src); -+ emit(ctx, bnez, MIPS_R_T9, off); -+ break; -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JSLE: -+ emit(ctx, slt, MIPS_R_T9, src, dst); -+ emit(ctx, beqz, MIPS_R_T9, off); -+ break; -+ } -+} -+ -+/* Jump always */ -+int emit_ja(struct jit_context *ctx, s16 off) -+{ -+ int target = get_target(ctx, ctx->bpf_index + off + 1); -+ -+ if (target < 0) -+ return -1; -+ emit(ctx, j, target); -+ emit(ctx, nop); -+ return 0; -+} -+ -+/* Jump to epilogue */ -+int emit_exit(struct jit_context *ctx) -+{ -+ int target = get_target(ctx, ctx->program->len); -+ -+ if (target < 0) -+ return -1; -+ emit(ctx, j, target); -+ emit(ctx, nop); -+ return 0; -+} -+ -+/* Build the program body from eBPF bytecode */ -+static int build_body(struct jit_context *ctx) -+{ -+ const struct bpf_prog *prog = ctx->program; -+ unsigned int i; -+ -+ ctx->stack_used = 0; -+ for (i = 0; i < prog->len; i++) { -+ const struct bpf_insn *insn = &prog->insnsi[i]; -+ u32 *descp = &ctx->descriptors[i]; -+ int ret; -+ -+ access_reg(ctx, insn->src_reg); -+ access_reg(ctx, insn->dst_reg); -+ -+ ctx->bpf_index = i; -+ if (ctx->target == NULL) { -+ ctx->changes += INDEX(*descp) != ctx->jit_index; -+ *descp &= JIT_DESC_CONVERT; -+ *descp |= ctx->jit_index; -+ } -+ -+ ret = build_insn(insn, ctx); -+ if (ret < 0) -+ return ret; -+ -+ if (ret > 0) { -+ i++; -+ if (ctx->target == NULL) -+ descp[1] = ctx->jit_index; -+ } -+ } -+ -+ /* Store the end offset, where the epilogue begins */ -+ ctx->descriptors[prog->len] = ctx->jit_index; -+ return 0; -+} -+ -+/* Set the branch conversion flag on all instructions */ -+static void set_convert_flag(struct jit_context *ctx, bool enable) -+{ -+ const struct bpf_prog *prog = ctx->program; -+ u32 flag = enable ? JIT_DESC_CONVERT : 0; -+ unsigned int i; -+ -+ for (i = 0; i <= prog->len; i++) -+ ctx->descriptors[i] = INDEX(ctx->descriptors[i]) | flag; -+} -+ -+static void jit_fill_hole(void *area, unsigned int size) -+{ -+ u32 *p; -+ -+ /* We are guaranteed to have aligned memory. */ -+ for (p = area; size >= sizeof(u32); size -= sizeof(u32)) -+ uasm_i_break(&p, BRK_BUG); /* Increments p */ -+} -+ -+bool bpf_jit_needs_zext(void) -+{ -+ return true; -+} -+ -+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) -+{ -+ struct bpf_prog *tmp, *orig_prog = prog; -+ struct bpf_binary_header *header = NULL; -+ struct jit_context ctx; -+ bool tmp_blinded = false; -+ unsigned int tmp_idx; -+ unsigned int image_size; -+ u8 *image_ptr; -+ int tries; -+ -+ /* -+ * If BPF JIT was not enabled then we must fall back to -+ * the interpreter. -+ */ -+ if (!prog->jit_requested) -+ return orig_prog; -+ /* -+ * If constant blinding was enabled and we failed during blinding -+ * then we must fall back to the interpreter. Otherwise, we save -+ * the new JITed code. -+ */ -+ tmp = bpf_jit_blind_constants(prog); -+ if (IS_ERR(tmp)) -+ return orig_prog; -+ if (tmp != prog) { -+ tmp_blinded = true; -+ prog = tmp; -+ } -+ -+ memset(&ctx, 0, sizeof(ctx)); -+ ctx.program = prog; -+ -+ /* -+ * Not able to allocate memory for descriptors[], then -+ * we must fall back to the interpreter -+ */ -+ ctx.descriptors = kcalloc(prog->len + 1, sizeof(*ctx.descriptors), -+ GFP_KERNEL); -+ if (ctx.descriptors == NULL) -+ goto out_err; -+ -+ /* First pass discovers used resources */ -+ if (build_body(&ctx) < 0) -+ goto out_err; -+ /* -+ * Second pass computes instruction offsets. -+ * If any PC-relative branches are out of range, a sequence of -+ * a PC-relative branch + a jump is generated, and we have to -+ * try again from the beginning to generate the new offsets. -+ * This is done until no additional conversions are necessary. -+ * The last two iterations are done with all branches being -+ * converted, to guarantee offset table convergence within a -+ * fixed number of iterations. -+ */ -+ ctx.jit_index = 0; -+ build_prologue(&ctx); -+ tmp_idx = ctx.jit_index; -+ -+ tries = JIT_MAX_ITERATIONS; -+ do { -+ ctx.jit_index = tmp_idx; -+ ctx.changes = 0; -+ if (tries == 2) -+ set_convert_flag(&ctx, true); -+ if (build_body(&ctx) < 0) -+ goto out_err; -+ } while (ctx.changes > 0 && --tries > 0); -+ -+ if (WARN_ONCE(ctx.changes > 0, "JIT offsets failed to converge")) -+ goto out_err; -+ -+ build_epilogue(&ctx, MIPS_R_RA); -+ -+ /* Now we know the size of the structure to make */ -+ image_size = sizeof(u32) * ctx.jit_index; -+ header = bpf_jit_binary_alloc(image_size, &image_ptr, -+ sizeof(u32), jit_fill_hole); -+ /* -+ * Not able to allocate memory for the structure then -+ * we must fall back to the interpretation -+ */ -+ if (header == NULL) -+ goto out_err; -+ -+ /* Actual pass to generate final JIT code */ -+ ctx.target = (u32 *)image_ptr; -+ ctx.jit_index = 0; -+ -+ /* -+ * If building the JITed code fails somehow, -+ * we fall back to the interpretation. -+ */ -+ build_prologue(&ctx); -+ if (build_body(&ctx) < 0) -+ goto out_err; -+ build_epilogue(&ctx, MIPS_R_RA); -+ -+ /* Populate line info meta data */ -+ set_convert_flag(&ctx, false); -+ bpf_prog_fill_jited_linfo(prog, &ctx.descriptors[1]); -+ -+ /* Set as read-only exec and flush instruction cache */ -+ bpf_jit_binary_lock_ro(header); -+ flush_icache_range((unsigned long)header, -+ (unsigned long)&ctx.target[ctx.jit_index]); -+ -+ if (bpf_jit_enable > 1) -+ bpf_jit_dump(prog->len, image_size, 2, ctx.target); -+ -+ prog->bpf_func = (void *)ctx.target; -+ prog->jited = 1; -+ prog->jited_len = image_size; -+ -+out: -+ if (tmp_blinded) -+ bpf_jit_prog_release_other(prog, prog == orig_prog ? -+ tmp : orig_prog); -+ kfree(ctx.descriptors); -+ return prog; -+ -+out_err: -+ prog = orig_prog; -+ if (header) -+ bpf_jit_binary_free(header); -+ goto out; -+} ---- /dev/null -+++ b/arch/mips/net/bpf_jit_comp.h -@@ -0,0 +1,211 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Just-In-Time compiler for eBPF bytecode on 32-bit and 64-bit MIPS. -+ * -+ * Copyright (c) 2021 Anyfi Networks AB. -+ * Author: Johan Almbladh -+ * -+ * Based on code and ideas from -+ * Copyright (c) 2017 Cavium, Inc. -+ * Copyright (c) 2017 Shubham Bansal -+ * Copyright (c) 2011 Mircea Gherzan -+ */ -+ -+#ifndef _BPF_JIT_COMP_H -+#define _BPF_JIT_COMP_H -+ -+/* MIPS registers */ -+#define MIPS_R_ZERO 0 /* Const zero */ -+#define MIPS_R_AT 1 /* Asm temp */ -+#define MIPS_R_V0 2 /* Result */ -+#define MIPS_R_V1 3 /* Result */ -+#define MIPS_R_A0 4 /* Argument */ -+#define MIPS_R_A1 5 /* Argument */ -+#define MIPS_R_A2 6 /* Argument */ -+#define MIPS_R_A3 7 /* Argument */ -+#define MIPS_R_A4 8 /* Arg (n64) */ -+#define MIPS_R_A5 9 /* Arg (n64) */ -+#define MIPS_R_A6 10 /* Arg (n64) */ -+#define MIPS_R_A7 11 /* Arg (n64) */ -+#define MIPS_R_T0 8 /* Temp (o32) */ -+#define MIPS_R_T1 9 /* Temp (o32) */ -+#define MIPS_R_T2 10 /* Temp (o32) */ -+#define MIPS_R_T3 11 /* Temp (o32) */ -+#define MIPS_R_T4 12 /* Temporary */ -+#define MIPS_R_T5 13 /* Temporary */ -+#define MIPS_R_T6 14 /* Temporary */ -+#define MIPS_R_T7 15 /* Temporary */ -+#define MIPS_R_S0 16 /* Saved */ -+#define MIPS_R_S1 17 /* Saved */ -+#define MIPS_R_S2 18 /* Saved */ -+#define MIPS_R_S3 19 /* Saved */ -+#define MIPS_R_S4 20 /* Saved */ -+#define MIPS_R_S5 21 /* Saved */ -+#define MIPS_R_S6 22 /* Saved */ -+#define MIPS_R_S7 23 /* Saved */ -+#define MIPS_R_T8 24 /* Temporary */ -+#define MIPS_R_T9 25 /* Temporary */ -+/* MIPS_R_K0 26 Reserved */ -+/* MIPS_R_K1 27 Reserved */ -+#define MIPS_R_GP 28 /* Global ptr */ -+#define MIPS_R_SP 29 /* Stack ptr */ -+#define MIPS_R_FP 30 /* Frame ptr */ -+#define MIPS_R_RA 31 /* Return */ -+ -+/* -+ * Jump address mask for immediate jumps. The four most significant bits -+ * must be equal to PC. -+ */ -+#define MIPS_JMP_MASK 0x0fffffffUL -+ -+/* Maximum number of iterations in offset table computation */ -+#define JIT_MAX_ITERATIONS 8 -+ -+/* -+ * Jump pseudo-instructions used internally -+ * for branch conversion and branch optimization. -+ */ -+#define JIT_JNSET 0xe0 -+#define JIT_JNOP 0xf0 -+ -+/* Descriptor flag for PC-relative branch conversion */ -+#define JIT_DESC_CONVERT BIT(31) -+ -+/* JIT context for an eBPF program */ -+struct jit_context { -+ struct bpf_prog *program; /* The eBPF program being JITed */ -+ u32 *descriptors; /* eBPF to JITed CPU insn descriptors */ -+ u32 *target; /* JITed code buffer */ -+ u32 bpf_index; /* Index of current BPF program insn */ -+ u32 jit_index; /* Index of current JIT target insn */ -+ u32 changes; /* Number of PC-relative branch conv */ -+ u32 accessed; /* Bit mask of read eBPF registers */ -+ u32 clobbered; /* Bit mask of modified CPU registers */ -+ u32 stack_size; /* Total allocated stack size in bytes */ -+ u32 saved_size; /* Size of callee-saved registers */ -+ u32 stack_used; /* Stack size used for function calls */ -+}; -+ -+/* Emit the instruction if the JIT memory space has been allocated */ -+#define emit(ctx, func, ...) \ -+do { \ -+ if ((ctx)->target != NULL) { \ -+ u32 *p = &(ctx)->target[ctx->jit_index]; \ -+ uasm_i_##func(&p, ##__VA_ARGS__); \ -+ } \ -+ (ctx)->jit_index++; \ -+} while (0) -+ -+/* -+ * Mark a BPF register as accessed, it needs to be -+ * initialized by the program if expected, e.g. FP. -+ */ -+static inline void access_reg(struct jit_context *ctx, u8 reg) -+{ -+ ctx->accessed |= BIT(reg); -+} -+ -+/* -+ * Mark a CPU register as clobbered, it needs to be -+ * saved/restored by the program if callee-saved. -+ */ -+static inline void clobber_reg(struct jit_context *ctx, u8 reg) -+{ -+ ctx->clobbered |= BIT(reg); -+} -+ -+/* -+ * Push registers on the stack, starting at a given depth from the stack -+ * pointer and increasing. The next depth to be written is returned. -+ */ -+int push_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth); -+ -+/* -+ * Pop registers from the stack, starting at a given depth from the stack -+ * pointer and increasing. The next depth to be read is returned. -+ */ -+int pop_regs(struct jit_context *ctx, u32 mask, u32 excl, int depth); -+ -+/* Compute the 28-bit jump target address from a BPF program location */ -+int get_target(struct jit_context *ctx, u32 loc); -+ -+/* Compute the PC-relative offset to relative BPF program offset */ -+int get_offset(const struct jit_context *ctx, int off); -+ -+/* dst = imm (32-bit) */ -+void emit_mov_i(struct jit_context *ctx, u8 dst, s32 imm); -+ -+/* dst = src (32-bit) */ -+void emit_mov_r(struct jit_context *ctx, u8 dst, u8 src); -+ -+/* Validate ALU/ALU64 immediate range */ -+bool valid_alu_i(u8 op, s32 imm); -+ -+/* Rewrite ALU/ALU64 immediate operation */ -+bool rewrite_alu_i(u8 op, s32 imm, u8 *alu, s32 *val); -+ -+/* ALU immediate operation (32-bit) */ -+void emit_alu_i(struct jit_context *ctx, u8 dst, s32 imm, u8 op); -+ -+/* ALU register operation (32-bit) */ -+void emit_alu_r(struct jit_context *ctx, u8 dst, u8 src, u8 op); -+ -+/* Atomic read-modify-write (32-bit) */ -+void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code); -+ -+/* Atomic compare-and-exchange (32-bit) */ -+void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off); -+ -+/* Swap bytes and truncate a register word or half word */ -+void emit_bswap_r(struct jit_context *ctx, u8 dst, u32 width); -+ -+/* Validate JMP/JMP32 immediate range */ -+bool valid_jmp_i(u8 op, s32 imm); -+ -+/* Prepare a PC-relative jump operation with immediate conditional */ -+void setup_jmp_i(struct jit_context *ctx, s32 imm, u8 width, -+ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off); -+ -+/* Prepare a PC-relative jump operation with register conditional */ -+void setup_jmp_r(struct jit_context *ctx, bool same_reg, -+ u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off); -+ -+/* Finish a PC-relative jump operation */ -+int finish_jmp(struct jit_context *ctx, u8 jit_op, s16 bpf_off); -+ -+/* Conditional JMP/JMP32 immediate */ -+void emit_jmp_i(struct jit_context *ctx, u8 dst, s32 imm, s32 off, u8 op); -+ -+/* Conditional JMP/JMP32 register */ -+void emit_jmp_r(struct jit_context *ctx, u8 dst, u8 src, s32 off, u8 op); -+ -+/* Jump always */ -+int emit_ja(struct jit_context *ctx, s16 off); -+ -+/* Jump to epilogue */ -+int emit_exit(struct jit_context *ctx); -+ -+/* -+ * Build program prologue to set up the stack and registers. -+ * This function is implemented separately for 32-bit and 64-bit JITs. -+ */ -+void build_prologue(struct jit_context *ctx); -+ -+/* -+ * Build the program epilogue to restore the stack and registers. -+ * This function is implemented separately for 32-bit and 64-bit JITs. -+ */ -+void build_epilogue(struct jit_context *ctx, int dest_reg); -+ -+/* -+ * Convert an eBPF instruction to native instruction, i.e -+ * JITs an eBPF instruction. -+ * Returns : -+ * 0 - Successfully JITed an 8-byte eBPF instruction -+ * >0 - Successfully JITed a 16-byte eBPF instruction -+ * <0 - Failed to JIT. -+ * This function is implemented separately for 32-bit and 64-bit JITs. -+ */ -+int build_insn(const struct bpf_insn *insn, struct jit_context *ctx); -+ -+#endif /* _BPF_JIT_COMP_H */ ---- /dev/null -+++ b/arch/mips/net/bpf_jit_comp32.c -@@ -0,0 +1,1741 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Just-In-Time compiler for eBPF bytecode on MIPS. -+ * Implementation of JIT functions for 32-bit CPUs. -+ * -+ * Copyright (c) 2021 Anyfi Networks AB. -+ * Author: Johan Almbladh -+ * -+ * Based on code and ideas from -+ * Copyright (c) 2017 Cavium, Inc. -+ * Copyright (c) 2017 Shubham Bansal -+ * Copyright (c) 2011 Mircea Gherzan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "bpf_jit_comp.h" -+ -+/* MIPS a4-a7 are not available in the o32 ABI */ -+#undef MIPS_R_A4 -+#undef MIPS_R_A5 -+#undef MIPS_R_A6 -+#undef MIPS_R_A7 -+ -+/* Stack is 8-byte aligned in o32 ABI */ -+#define MIPS_STACK_ALIGNMENT 8 -+ -+/* -+ * The top 16 bytes of a stack frame is reserved for the callee in O32 ABI. -+ * This corresponds to stack space for register arguments a0-a3. -+ */ -+#define JIT_RESERVED_STACK 16 -+ -+/* Temporary 64-bit register used by JIT */ -+#define JIT_REG_TMP MAX_BPF_JIT_REG -+ -+/* -+ * Number of prologue bytes to skip when doing a tail call. -+ * Tail call count (TCC) initialization (8 bytes) always, plus -+ * R0-to-v0 assignment (4 bytes) if big endian. -+ */ -+#ifdef __BIG_ENDIAN -+#define JIT_TCALL_SKIP 12 -+#else -+#define JIT_TCALL_SKIP 8 -+#endif -+ -+/* CPU registers holding the callee return value */ -+#define JIT_RETURN_REGS \ -+ (BIT(MIPS_R_V0) | \ -+ BIT(MIPS_R_V1)) -+ -+/* CPU registers arguments passed to callee directly */ -+#define JIT_ARG_REGS \ -+ (BIT(MIPS_R_A0) | \ -+ BIT(MIPS_R_A1) | \ -+ BIT(MIPS_R_A2) | \ -+ BIT(MIPS_R_A3)) -+ -+/* CPU register arguments passed to callee on stack */ -+#define JIT_STACK_REGS \ -+ (BIT(MIPS_R_T0) | \ -+ BIT(MIPS_R_T1) | \ -+ BIT(MIPS_R_T2) | \ -+ BIT(MIPS_R_T3) | \ -+ BIT(MIPS_R_T4) | \ -+ BIT(MIPS_R_T5)) -+ -+/* Caller-saved CPU registers */ -+#define JIT_CALLER_REGS \ -+ (JIT_RETURN_REGS | \ -+ JIT_ARG_REGS | \ -+ JIT_STACK_REGS) -+ -+/* Callee-saved CPU registers */ -+#define JIT_CALLEE_REGS \ -+ (BIT(MIPS_R_S0) | \ -+ BIT(MIPS_R_S1) | \ -+ BIT(MIPS_R_S2) | \ -+ BIT(MIPS_R_S3) | \ -+ BIT(MIPS_R_S4) | \ -+ BIT(MIPS_R_S5) | \ -+ BIT(MIPS_R_S6) | \ -+ BIT(MIPS_R_S7) | \ -+ BIT(MIPS_R_GP) | \ -+ BIT(MIPS_R_FP) | \ -+ BIT(MIPS_R_RA)) -+ -+/* -+ * Mapping of 64-bit eBPF registers to 32-bit native MIPS registers. -+ * -+ * 1) Native register pairs are ordered according to CPU endiannes, following -+ * the MIPS convention for passing 64-bit arguments and return values. -+ * 2) The eBPF return value, arguments and callee-saved registers are mapped -+ * to their native MIPS equivalents. -+ * 3) Since the 32 highest bits in the eBPF FP register are always zero, -+ * only one general-purpose register is actually needed for the mapping. -+ * We use the fp register for this purpose, and map the highest bits to -+ * the MIPS register r0 (zero). -+ * 4) We use the MIPS gp and at registers as internal temporary registers -+ * for constant blinding. The gp register is callee-saved. -+ * 5) One 64-bit temporary register is mapped for use when sign-extending -+ * immediate operands. MIPS registers t6-t9 are available to the JIT -+ * for as temporaries when implementing complex 64-bit operations. -+ * -+ * With this scheme all eBPF registers are being mapped to native MIPS -+ * registers without having to use any stack scratch space. The direct -+ * register mapping (2) simplifies the handling of function calls. -+ */ -+static const u8 bpf2mips32[][2] = { -+ /* Return value from in-kernel function, and exit value from eBPF */ -+ [BPF_REG_0] = {MIPS_R_V1, MIPS_R_V0}, -+ /* Arguments from eBPF program to in-kernel function */ -+ [BPF_REG_1] = {MIPS_R_A1, MIPS_R_A0}, -+ [BPF_REG_2] = {MIPS_R_A3, MIPS_R_A2}, -+ /* Remaining arguments, to be passed on the stack per O32 ABI */ -+ [BPF_REG_3] = {MIPS_R_T1, MIPS_R_T0}, -+ [BPF_REG_4] = {MIPS_R_T3, MIPS_R_T2}, -+ [BPF_REG_5] = {MIPS_R_T5, MIPS_R_T4}, -+ /* Callee-saved registers that in-kernel function will preserve */ -+ [BPF_REG_6] = {MIPS_R_S1, MIPS_R_S0}, -+ [BPF_REG_7] = {MIPS_R_S3, MIPS_R_S2}, -+ [BPF_REG_8] = {MIPS_R_S5, MIPS_R_S4}, -+ [BPF_REG_9] = {MIPS_R_S7, MIPS_R_S6}, -+ /* Read-only frame pointer to access the eBPF stack */ -+#ifdef __BIG_ENDIAN -+ [BPF_REG_FP] = {MIPS_R_FP, MIPS_R_ZERO}, -+#else -+ [BPF_REG_FP] = {MIPS_R_ZERO, MIPS_R_FP}, -+#endif -+ /* Temporary register for blinding constants */ -+ [BPF_REG_AX] = {MIPS_R_GP, MIPS_R_AT}, -+ /* Temporary register for internal JIT use */ -+ [JIT_REG_TMP] = {MIPS_R_T7, MIPS_R_T6}, -+}; -+ -+/* Get low CPU register for a 64-bit eBPF register mapping */ -+static inline u8 lo(const u8 reg[]) -+{ -+#ifdef __BIG_ENDIAN -+ return reg[0]; -+#else -+ return reg[1]; -+#endif -+} -+ -+/* Get high CPU register for a 64-bit eBPF register mapping */ -+static inline u8 hi(const u8 reg[]) -+{ -+#ifdef __BIG_ENDIAN -+ return reg[1]; -+#else -+ return reg[0]; -+#endif -+} -+ -+/* -+ * Mark a 64-bit CPU register pair as clobbered, it needs to be -+ * saved/restored by the program if callee-saved. -+ */ -+static void clobber_reg64(struct jit_context *ctx, const u8 reg[]) -+{ -+ clobber_reg(ctx, reg[0]); -+ clobber_reg(ctx, reg[1]); -+} -+ -+/* dst = imm (sign-extended) */ -+static void emit_mov_se_i64(struct jit_context *ctx, const u8 dst[], s32 imm) -+{ -+ emit_mov_i(ctx, lo(dst), imm); -+ if (imm < 0) -+ emit(ctx, addiu, hi(dst), MIPS_R_ZERO, -1); -+ else -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ clobber_reg64(ctx, dst); -+} -+ -+/* Zero extension, if verifier does not do it for us */ -+static void emit_zext_ver(struct jit_context *ctx, const u8 dst[]) -+{ -+ if (!ctx->program->aux->verifier_zext) { -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ clobber_reg(ctx, hi(dst)); -+ } -+} -+ -+/* Load delay slot, if ISA mandates it */ -+static void emit_load_delay(struct jit_context *ctx) -+{ -+ if (!cpu_has_mips_2_3_4_5_r) -+ emit(ctx, nop); -+} -+ -+/* ALU immediate operation (64-bit) */ -+static void emit_alu_i64(struct jit_context *ctx, -+ const u8 dst[], s32 imm, u8 op) -+{ -+ u8 src = MIPS_R_T6; -+ -+ /* -+ * ADD/SUB with all but the max negative imm can be handled by -+ * inverting the operation and the imm value, saving one insn. -+ */ -+ if (imm > S32_MIN && imm < 0) -+ switch (op) { -+ case BPF_ADD: -+ op = BPF_SUB; -+ imm = -imm; -+ break; -+ case BPF_SUB: -+ op = BPF_ADD; -+ imm = -imm; -+ break; -+ } -+ -+ /* Move immediate to temporary register */ -+ emit_mov_i(ctx, src, imm); -+ -+ switch (op) { -+ /* dst = dst + imm */ -+ case BPF_ADD: -+ emit(ctx, addu, lo(dst), lo(dst), src); -+ emit(ctx, sltu, MIPS_R_T9, lo(dst), src); -+ emit(ctx, addu, hi(dst), hi(dst), MIPS_R_T9); -+ if (imm < 0) -+ emit(ctx, addiu, hi(dst), hi(dst), -1); -+ break; -+ /* dst = dst - imm */ -+ case BPF_SUB: -+ emit(ctx, sltu, MIPS_R_T9, lo(dst), src); -+ emit(ctx, subu, lo(dst), lo(dst), src); -+ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); -+ if (imm < 0) -+ emit(ctx, addiu, hi(dst), hi(dst), 1); -+ break; -+ /* dst = dst | imm */ -+ case BPF_OR: -+ emit(ctx, or, lo(dst), lo(dst), src); -+ if (imm < 0) -+ emit(ctx, addiu, hi(dst), MIPS_R_ZERO, -1); -+ break; -+ /* dst = dst & imm */ -+ case BPF_AND: -+ emit(ctx, and, lo(dst), lo(dst), src); -+ if (imm >= 0) -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ break; -+ /* dst = dst ^ imm */ -+ case BPF_XOR: -+ emit(ctx, xor, lo(dst), lo(dst), src); -+ if (imm < 0) { -+ emit(ctx, subu, hi(dst), MIPS_R_ZERO, hi(dst)); -+ emit(ctx, addiu, hi(dst), hi(dst), -1); -+ } -+ break; -+ } -+ clobber_reg64(ctx, dst); -+} -+ -+/* ALU register operation (64-bit) */ -+static void emit_alu_r64(struct jit_context *ctx, -+ const u8 dst[], const u8 src[], u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = dst + src */ -+ case BPF_ADD: -+ if (src == dst) { -+ emit(ctx, srl, MIPS_R_T9, lo(dst), 31); -+ emit(ctx, addu, lo(dst), lo(dst), lo(dst)); -+ } else { -+ emit(ctx, addu, lo(dst), lo(dst), lo(src)); -+ emit(ctx, sltu, MIPS_R_T9, lo(dst), lo(src)); -+ } -+ emit(ctx, addu, hi(dst), hi(dst), hi(src)); -+ emit(ctx, addu, hi(dst), hi(dst), MIPS_R_T9); -+ break; -+ /* dst = dst - src */ -+ case BPF_SUB: -+ emit(ctx, sltu, MIPS_R_T9, lo(dst), lo(src)); -+ emit(ctx, subu, lo(dst), lo(dst), lo(src)); -+ emit(ctx, subu, hi(dst), hi(dst), hi(src)); -+ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); -+ break; -+ /* dst = dst | src */ -+ case BPF_OR: -+ emit(ctx, or, lo(dst), lo(dst), lo(src)); -+ emit(ctx, or, hi(dst), hi(dst), hi(src)); -+ break; -+ /* dst = dst & src */ -+ case BPF_AND: -+ emit(ctx, and, lo(dst), lo(dst), lo(src)); -+ emit(ctx, and, hi(dst), hi(dst), hi(src)); -+ break; -+ /* dst = dst ^ src */ -+ case BPF_XOR: -+ emit(ctx, xor, lo(dst), lo(dst), lo(src)); -+ emit(ctx, xor, hi(dst), hi(dst), hi(src)); -+ break; -+ } -+ clobber_reg64(ctx, dst); -+} -+ -+/* ALU invert (64-bit) */ -+static void emit_neg_i64(struct jit_context *ctx, const u8 dst[]) -+{ -+ emit(ctx, sltu, MIPS_R_T9, MIPS_R_ZERO, lo(dst)); -+ emit(ctx, subu, lo(dst), MIPS_R_ZERO, lo(dst)); -+ emit(ctx, subu, hi(dst), MIPS_R_ZERO, hi(dst)); -+ emit(ctx, subu, hi(dst), hi(dst), MIPS_R_T9); -+ -+ clobber_reg64(ctx, dst); -+} -+ -+/* ALU shift immediate (64-bit) */ -+static void emit_shift_i64(struct jit_context *ctx, -+ const u8 dst[], u32 imm, u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = dst << imm */ -+ case BPF_LSH: -+ if (imm < 32) { -+ emit(ctx, srl, MIPS_R_T9, lo(dst), 32 - imm); -+ emit(ctx, sll, lo(dst), lo(dst), imm); -+ emit(ctx, sll, hi(dst), hi(dst), imm); -+ emit(ctx, or, hi(dst), hi(dst), MIPS_R_T9); -+ } else { -+ emit(ctx, sll, hi(dst), lo(dst), imm - 32); -+ emit(ctx, move, lo(dst), MIPS_R_ZERO); -+ } -+ break; -+ /* dst = dst >> imm */ -+ case BPF_RSH: -+ if (imm < 32) { -+ emit(ctx, sll, MIPS_R_T9, hi(dst), 32 - imm); -+ emit(ctx, srl, lo(dst), lo(dst), imm); -+ emit(ctx, srl, hi(dst), hi(dst), imm); -+ emit(ctx, or, lo(dst), lo(dst), MIPS_R_T9); -+ } else { -+ emit(ctx, srl, lo(dst), hi(dst), imm - 32); -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ } -+ break; -+ /* dst = dst >> imm (arithmetic) */ -+ case BPF_ARSH: -+ if (imm < 32) { -+ emit(ctx, sll, MIPS_R_T9, hi(dst), 32 - imm); -+ emit(ctx, srl, lo(dst), lo(dst), imm); -+ emit(ctx, sra, hi(dst), hi(dst), imm); -+ emit(ctx, or, lo(dst), lo(dst), MIPS_R_T9); -+ } else { -+ emit(ctx, sra, lo(dst), hi(dst), imm - 32); -+ emit(ctx, sra, hi(dst), hi(dst), 31); -+ } -+ break; -+ } -+ clobber_reg64(ctx, dst); -+} -+ -+/* ALU shift register (64-bit) */ -+static void emit_shift_r64(struct jit_context *ctx, -+ const u8 dst[], u8 src, u8 op) -+{ -+ u8 t1 = MIPS_R_T8; -+ u8 t2 = MIPS_R_T9; -+ -+ emit(ctx, andi, t1, src, 32); /* t1 = src & 32 */ -+ emit(ctx, beqz, t1, 16); /* PC += 16 if t1 == 0 */ -+ emit(ctx, nor, t2, src, MIPS_R_ZERO); /* t2 = ~src (delay slot) */ -+ -+ switch (BPF_OP(op)) { -+ /* dst = dst << src */ -+ case BPF_LSH: -+ /* Next: shift >= 32 */ -+ emit(ctx, sllv, hi(dst), lo(dst), src); /* dh = dl << src */ -+ emit(ctx, move, lo(dst), MIPS_R_ZERO); /* dl = 0 */ -+ emit(ctx, b, 20); /* PC += 20 */ -+ /* +16: shift < 32 */ -+ emit(ctx, srl, t1, lo(dst), 1); /* t1 = dl >> 1 */ -+ emit(ctx, srlv, t1, t1, t2); /* t1 = t1 >> t2 */ -+ emit(ctx, sllv, lo(dst), lo(dst), src); /* dl = dl << src */ -+ emit(ctx, sllv, hi(dst), hi(dst), src); /* dh = dh << src */ -+ emit(ctx, or, hi(dst), hi(dst), t1); /* dh = dh | t1 */ -+ break; -+ /* dst = dst >> src */ -+ case BPF_RSH: -+ /* Next: shift >= 32 */ -+ emit(ctx, srlv, lo(dst), hi(dst), src); /* dl = dh >> src */ -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); /* dh = 0 */ -+ emit(ctx, b, 20); /* PC += 20 */ -+ /* +16: shift < 32 */ -+ emit(ctx, sll, t1, hi(dst), 1); /* t1 = dl << 1 */ -+ emit(ctx, sllv, t1, t1, t2); /* t1 = t1 << t2 */ -+ emit(ctx, srlv, lo(dst), lo(dst), src); /* dl = dl >> src */ -+ emit(ctx, srlv, hi(dst), hi(dst), src); /* dh = dh >> src */ -+ emit(ctx, or, lo(dst), lo(dst), t1); /* dl = dl | t1 */ -+ break; -+ /* dst = dst >> src (arithmetic) */ -+ case BPF_ARSH: -+ /* Next: shift >= 32 */ -+ emit(ctx, srav, lo(dst), hi(dst), src); /* dl = dh >>a src */ -+ emit(ctx, sra, hi(dst), hi(dst), 31); /* dh = dh >>a 31 */ -+ emit(ctx, b, 20); /* PC += 20 */ -+ /* +16: shift < 32 */ -+ emit(ctx, sll, t1, hi(dst), 1); /* t1 = dl << 1 */ -+ emit(ctx, sllv, t1, t1, t2); /* t1 = t1 << t2 */ -+ emit(ctx, srlv, lo(dst), lo(dst), src); /* dl = dl >>a src */ -+ emit(ctx, srav, hi(dst), hi(dst), src); /* dh = dh >> src */ -+ emit(ctx, or, lo(dst), lo(dst), t1); /* dl = dl | t1 */ -+ break; -+ } -+ -+ /* +20: Done */ -+ clobber_reg64(ctx, dst); -+} -+ -+/* ALU mul immediate (64x32-bit) */ -+static void emit_mul_i64(struct jit_context *ctx, const u8 dst[], s32 imm) -+{ -+ u8 src = MIPS_R_T6; -+ u8 tmp = MIPS_R_T9; -+ -+ switch (imm) { -+ /* dst = dst * 1 is a no-op */ -+ case 1: -+ break; -+ /* dst = dst * -1 */ -+ case -1: -+ emit_neg_i64(ctx, dst); -+ break; -+ case 0: -+ emit_mov_r(ctx, lo(dst), MIPS_R_ZERO); -+ emit_mov_r(ctx, hi(dst), MIPS_R_ZERO); -+ break; -+ /* Full 64x32 multiply */ -+ default: -+ /* hi(dst) = hi(dst) * src(imm) */ -+ emit_mov_i(ctx, src, imm); -+ if (cpu_has_mips32r1 || cpu_has_mips32r6) { -+ emit(ctx, mul, hi(dst), hi(dst), src); -+ } else { -+ emit(ctx, multu, hi(dst), src); -+ emit(ctx, mflo, hi(dst)); -+ } -+ -+ /* hi(dst) = hi(dst) - lo(dst) */ -+ if (imm < 0) -+ emit(ctx, subu, hi(dst), hi(dst), lo(dst)); -+ -+ /* tmp = lo(dst) * src(imm) >> 32 */ -+ /* lo(dst) = lo(dst) * src(imm) */ -+ if (cpu_has_mips32r6) { -+ emit(ctx, muhu, tmp, lo(dst), src); -+ emit(ctx, mulu, lo(dst), lo(dst), src); -+ } else { -+ emit(ctx, multu, lo(dst), src); -+ emit(ctx, mflo, lo(dst)); -+ emit(ctx, mfhi, tmp); -+ } -+ -+ /* hi(dst) += tmp */ -+ emit(ctx, addu, hi(dst), hi(dst), tmp); -+ clobber_reg64(ctx, dst); -+ break; -+ } -+} -+ -+/* ALU mul register (64x64-bit) */ -+static void emit_mul_r64(struct jit_context *ctx, -+ const u8 dst[], const u8 src[]) -+{ -+ u8 acc = MIPS_R_T8; -+ u8 tmp = MIPS_R_T9; -+ -+ /* acc = hi(dst) * lo(src) */ -+ if (cpu_has_mips32r1 || cpu_has_mips32r6) { -+ emit(ctx, mul, acc, hi(dst), lo(src)); -+ } else { -+ emit(ctx, multu, hi(dst), lo(src)); -+ emit(ctx, mflo, acc); -+ } -+ -+ /* tmp = lo(dst) * hi(src) */ -+ if (cpu_has_mips32r1 || cpu_has_mips32r6) { -+ emit(ctx, mul, tmp, lo(dst), hi(src)); -+ } else { -+ emit(ctx, multu, lo(dst), hi(src)); -+ emit(ctx, mflo, tmp); -+ } -+ -+ /* acc += tmp */ -+ emit(ctx, addu, acc, acc, tmp); -+ -+ /* tmp = lo(dst) * lo(src) >> 32 */ -+ /* lo(dst) = lo(dst) * lo(src) */ -+ if (cpu_has_mips32r6) { -+ emit(ctx, muhu, tmp, lo(dst), lo(src)); -+ emit(ctx, mulu, lo(dst), lo(dst), lo(src)); -+ } else { -+ emit(ctx, multu, lo(dst), lo(src)); -+ emit(ctx, mflo, lo(dst)); -+ emit(ctx, mfhi, tmp); -+ } -+ -+ /* hi(dst) = acc + tmp */ -+ emit(ctx, addu, hi(dst), acc, tmp); -+ clobber_reg64(ctx, dst); -+} -+ -+/* Helper function for 64-bit modulo */ -+static u64 jit_mod64(u64 a, u64 b) -+{ -+ u64 rem; -+ -+ div64_u64_rem(a, b, &rem); -+ return rem; -+} -+ -+/* ALU div/mod register (64-bit) */ -+static void emit_divmod_r64(struct jit_context *ctx, -+ const u8 dst[], const u8 src[], u8 op) -+{ -+ const u8 *r0 = bpf2mips32[BPF_REG_0]; /* Mapped to v0-v1 */ -+ const u8 *r1 = bpf2mips32[BPF_REG_1]; /* Mapped to a0-a1 */ -+ const u8 *r2 = bpf2mips32[BPF_REG_2]; /* Mapped to a2-a3 */ -+ int exclude, k; -+ u32 addr = 0; -+ -+ /* Push caller-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ 0, JIT_RESERVED_STACK); -+ -+ /* Put 64-bit arguments 1 and 2 in registers a0-a3 */ -+ for (k = 0; k < 2; k++) { -+ emit(ctx, move, MIPS_R_T9, src[k]); -+ emit(ctx, move, r1[k], dst[k]); -+ emit(ctx, move, r2[k], MIPS_R_T9); -+ } -+ -+ /* Emit function call */ -+ switch (BPF_OP(op)) { -+ /* dst = dst / src */ -+ case BPF_DIV: -+ addr = (u32)&div64_u64; -+ break; -+ /* dst = dst % src */ -+ case BPF_MOD: -+ addr = (u32)&jit_mod64; -+ break; -+ } -+ emit_mov_i(ctx, MIPS_R_T9, addr); -+ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* Store the 64-bit result in dst */ -+ emit(ctx, move, dst[0], r0[0]); -+ emit(ctx, move, dst[1], r0[1]); -+ -+ /* Restore caller-saved registers, excluding the computed result */ -+ exclude = BIT(lo(dst)) | BIT(hi(dst)); -+ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ exclude, JIT_RESERVED_STACK); -+ emit_load_delay(ctx); -+ -+ clobber_reg64(ctx, dst); -+ clobber_reg(ctx, MIPS_R_V0); -+ clobber_reg(ctx, MIPS_R_V1); -+ clobber_reg(ctx, MIPS_R_RA); -+} -+ -+/* Swap bytes in a register word */ -+static void emit_swap8_r(struct jit_context *ctx, u8 dst, u8 src, u8 mask) -+{ -+ u8 tmp = MIPS_R_T9; -+ -+ emit(ctx, and, tmp, src, mask); /* tmp = src & 0x00ff00ff */ -+ emit(ctx, sll, tmp, tmp, 8); /* tmp = tmp << 8 */ -+ emit(ctx, srl, dst, src, 8); /* dst = src >> 8 */ -+ emit(ctx, and, dst, dst, mask); /* dst = dst & 0x00ff00ff */ -+ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ -+} -+ -+/* Swap half words in a register word */ -+static void emit_swap16_r(struct jit_context *ctx, u8 dst, u8 src) -+{ -+ u8 tmp = MIPS_R_T9; -+ -+ emit(ctx, sll, tmp, src, 16); /* tmp = src << 16 */ -+ emit(ctx, srl, dst, src, 16); /* dst = src >> 16 */ -+ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ -+} -+ -+/* Swap bytes and truncate a register double word, word or half word */ -+static void emit_bswap_r64(struct jit_context *ctx, const u8 dst[], u32 width) -+{ -+ u8 tmp = MIPS_R_T8; -+ -+ switch (width) { -+ /* Swap bytes in a double word */ -+ case 64: -+ if (cpu_has_mips32r2 || cpu_has_mips32r6) { -+ emit(ctx, rotr, tmp, hi(dst), 16); -+ emit(ctx, rotr, hi(dst), lo(dst), 16); -+ emit(ctx, wsbh, lo(dst), tmp); -+ emit(ctx, wsbh, hi(dst), hi(dst)); -+ } else { -+ emit_swap16_r(ctx, tmp, lo(dst)); -+ emit_swap16_r(ctx, lo(dst), hi(dst)); -+ emit(ctx, move, hi(dst), tmp); -+ -+ emit(ctx, lui, tmp, 0xff); /* tmp = 0x00ff0000 */ -+ emit(ctx, ori, tmp, tmp, 0xff); /* tmp = 0x00ff00ff */ -+ emit_swap8_r(ctx, lo(dst), lo(dst), tmp); -+ emit_swap8_r(ctx, hi(dst), hi(dst), tmp); -+ } -+ break; -+ /* Swap bytes in a word */ -+ /* Swap bytes in a half word */ -+ case 32: -+ case 16: -+ emit_bswap_r(ctx, lo(dst), width); -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ break; -+ } -+ clobber_reg64(ctx, dst); -+} -+ -+/* Truncate a register double word, word or half word */ -+static void emit_trunc_r64(struct jit_context *ctx, const u8 dst[], u32 width) -+{ -+ switch (width) { -+ case 64: -+ break; -+ /* Zero-extend a word */ -+ case 32: -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ clobber_reg(ctx, hi(dst)); -+ break; -+ /* Zero-extend a half word */ -+ case 16: -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ emit(ctx, andi, lo(dst), lo(dst), 0xffff); -+ clobber_reg64(ctx, dst); -+ break; -+ } -+} -+ -+/* Load operation: dst = *(size*)(src + off) */ -+static void emit_ldx(struct jit_context *ctx, -+ const u8 dst[], u8 src, s16 off, u8 size) -+{ -+ switch (size) { -+ /* Load a byte */ -+ case BPF_B: -+ emit(ctx, lbu, lo(dst), off, src); -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ break; -+ /* Load a half word */ -+ case BPF_H: -+ emit(ctx, lhu, lo(dst), off, src); -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ break; -+ /* Load a word */ -+ case BPF_W: -+ emit(ctx, lw, lo(dst), off, src); -+ emit(ctx, move, hi(dst), MIPS_R_ZERO); -+ break; -+ /* Load a double word */ -+ case BPF_DW: -+ if (dst[1] == src) { -+ emit(ctx, lw, dst[0], off + 4, src); -+ emit(ctx, lw, dst[1], off, src); -+ } else { -+ emit(ctx, lw, dst[1], off, src); -+ emit(ctx, lw, dst[0], off + 4, src); -+ } -+ emit_load_delay(ctx); -+ break; -+ } -+ clobber_reg64(ctx, dst); -+} -+ -+/* Store operation: *(size *)(dst + off) = src */ -+static void emit_stx(struct jit_context *ctx, -+ const u8 dst, const u8 src[], s16 off, u8 size) -+{ -+ switch (size) { -+ /* Store a byte */ -+ case BPF_B: -+ emit(ctx, sb, lo(src), off, dst); -+ break; -+ /* Store a half word */ -+ case BPF_H: -+ emit(ctx, sh, lo(src), off, dst); -+ break; -+ /* Store a word */ -+ case BPF_W: -+ emit(ctx, sw, lo(src), off, dst); -+ break; -+ /* Store a double word */ -+ case BPF_DW: -+ emit(ctx, sw, src[1], off, dst); -+ emit(ctx, sw, src[0], off + 4, dst); -+ break; -+ } -+} -+ -+/* Atomic read-modify-write (32-bit, non-ll/sc fallback) */ -+static void emit_atomic_r32(struct jit_context *ctx, -+ u8 dst, u8 src, s16 off, u8 code) -+{ -+ u32 exclude = 0; -+ u32 addr = 0; -+ -+ /* Push caller-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ 0, JIT_RESERVED_STACK); -+ /* -+ * Argument 1: dst+off if xchg, otherwise src, passed in register a0 -+ * Argument 2: src if xchg, othersize dst+off, passed in register a1 -+ */ -+ emit(ctx, move, MIPS_R_T9, dst); -+ emit(ctx, move, MIPS_R_A0, src); -+ emit(ctx, addiu, MIPS_R_A1, MIPS_R_T9, off); -+ -+ /* Emit function call */ -+ switch (code) { -+ case BPF_ADD: -+ addr = (u32)&atomic_add; -+ break; -+ case BPF_SUB: -+ addr = (u32)&atomic_sub; -+ break; -+ case BPF_OR: -+ addr = (u32)&atomic_or; -+ break; -+ case BPF_AND: -+ addr = (u32)&atomic_and; -+ break; -+ case BPF_XOR: -+ addr = (u32)&atomic_xor; -+ break; -+ } -+ emit_mov_i(ctx, MIPS_R_T9, addr); -+ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* Restore caller-saved registers, except any fetched value */ -+ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ exclude, JIT_RESERVED_STACK); -+ emit_load_delay(ctx); -+ clobber_reg(ctx, MIPS_R_RA); -+} -+ -+/* Atomic read-modify-write (64-bit) */ -+static void emit_atomic_r64(struct jit_context *ctx, -+ u8 dst, const u8 src[], s16 off, u8 code) -+{ -+ const u8 *r1 = bpf2mips32[BPF_REG_1]; /* Mapped to a0-a1 */ -+ u32 exclude = 0; -+ u32 addr = 0; -+ -+ /* Push caller-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ 0, JIT_RESERVED_STACK); -+ /* -+ * Argument 1: 64-bit src, passed in registers a0-a1 -+ * Argument 2: 32-bit dst+off, passed in register a2 -+ */ -+ emit(ctx, move, MIPS_R_T9, dst); -+ emit(ctx, move, r1[0], src[0]); -+ emit(ctx, move, r1[1], src[1]); -+ emit(ctx, addiu, MIPS_R_A2, MIPS_R_T9, off); -+ -+ /* Emit function call */ -+ switch (code) { -+ case BPF_ADD: -+ addr = (u32)&atomic64_add; -+ break; -+ case BPF_SUB: -+ addr = (u32)&atomic64_sub; -+ break; -+ case BPF_OR: -+ addr = (u32)&atomic64_or; -+ break; -+ case BPF_AND: -+ addr = (u32)&atomic64_and; -+ break; -+ case BPF_XOR: -+ addr = (u32)&atomic64_xor; -+ break; -+ } -+ emit_mov_i(ctx, MIPS_R_T9, addr); -+ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* Restore caller-saved registers, except any fetched value */ -+ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, -+ exclude, JIT_RESERVED_STACK); -+ emit_load_delay(ctx); -+ clobber_reg(ctx, MIPS_R_RA); -+} -+ -+/* -+ * Conditional movz or an emulated equivalent. -+ * Note that the rs register may be modified. -+ */ -+static void emit_movz_r(struct jit_context *ctx, u8 rd, u8 rs, u8 rt) -+{ -+ if (cpu_has_mips_2) { -+ emit(ctx, movz, rd, rs, rt); /* rd = rt ? rd : rs */ -+ } else if (cpu_has_mips32r6) { -+ if (rs != MIPS_R_ZERO) -+ emit(ctx, seleqz, rs, rs, rt); /* rs = 0 if rt == 0 */ -+ emit(ctx, selnez, rd, rd, rt); /* rd = 0 if rt != 0 */ -+ if (rs != MIPS_R_ZERO) -+ emit(ctx, or, rd, rd, rs); /* rd = rd | rs */ -+ } else { -+ emit(ctx, bnez, rt, 8); /* PC += 8 if rd != 0 */ -+ emit(ctx, nop); /* +0: delay slot */ -+ emit(ctx, or, rd, rs, MIPS_R_ZERO); /* +4: rd = rs */ -+ } -+ clobber_reg(ctx, rd); -+ clobber_reg(ctx, rs); -+} -+ -+/* -+ * Conditional movn or an emulated equivalent. -+ * Note that the rs register may be modified. -+ */ -+static void emit_movn_r(struct jit_context *ctx, u8 rd, u8 rs, u8 rt) -+{ -+ if (cpu_has_mips_2) { -+ emit(ctx, movn, rd, rs, rt); /* rd = rt ? rs : rd */ -+ } else if (cpu_has_mips32r6) { -+ if (rs != MIPS_R_ZERO) -+ emit(ctx, selnez, rs, rs, rt); /* rs = 0 if rt == 0 */ -+ emit(ctx, seleqz, rd, rd, rt); /* rd = 0 if rt != 0 */ -+ if (rs != MIPS_R_ZERO) -+ emit(ctx, or, rd, rd, rs); /* rd = rd | rs */ -+ } else { -+ emit(ctx, beqz, rt, 8); /* PC += 8 if rd == 0 */ -+ emit(ctx, nop); /* +0: delay slot */ -+ emit(ctx, or, rd, rs, MIPS_R_ZERO); /* +4: rd = rs */ -+ } -+ clobber_reg(ctx, rd); -+ clobber_reg(ctx, rs); -+} -+ -+/* Emulation of 64-bit sltiu rd, rs, imm, where imm may be S32_MAX + 1 */ -+static void emit_sltiu_r64(struct jit_context *ctx, u8 rd, -+ const u8 rs[], s64 imm) -+{ -+ u8 tmp = MIPS_R_T9; -+ -+ if (imm < 0) { -+ emit_mov_i(ctx, rd, imm); /* rd = imm */ -+ emit(ctx, sltu, rd, lo(rs), rd); /* rd = rsl < rd */ -+ emit(ctx, sltiu, tmp, hi(rs), -1); /* tmp = rsh < ~0U */ -+ emit(ctx, or, rd, rd, tmp); /* rd = rd | tmp */ -+ } else { /* imm >= 0 */ -+ if (imm > 0x7fff) { -+ emit_mov_i(ctx, rd, (s32)imm); /* rd = imm */ -+ emit(ctx, sltu, rd, lo(rs), rd); /* rd = rsl < rd */ -+ } else { -+ emit(ctx, sltiu, rd, lo(rs), imm); /* rd = rsl < imm */ -+ } -+ emit_movn_r(ctx, rd, MIPS_R_ZERO, hi(rs)); /* rd = 0 if rsh */ -+ } -+} -+ -+/* Emulation of 64-bit sltu rd, rs, rt */ -+static void emit_sltu_r64(struct jit_context *ctx, u8 rd, -+ const u8 rs[], const u8 rt[]) -+{ -+ u8 tmp = MIPS_R_T9; -+ -+ emit(ctx, sltu, rd, lo(rs), lo(rt)); /* rd = rsl < rtl */ -+ emit(ctx, subu, tmp, hi(rs), hi(rt)); /* tmp = rsh - rth */ -+ emit_movn_r(ctx, rd, MIPS_R_ZERO, tmp); /* rd = 0 if tmp != 0 */ -+ emit(ctx, sltu, tmp, hi(rs), hi(rt)); /* tmp = rsh < rth */ -+ emit(ctx, or, rd, rd, tmp); /* rd = rd | tmp */ -+} -+ -+/* Emulation of 64-bit slti rd, rs, imm, where imm may be S32_MAX + 1 */ -+static void emit_slti_r64(struct jit_context *ctx, u8 rd, -+ const u8 rs[], s64 imm) -+{ -+ u8 t1 = MIPS_R_T8; -+ u8 t2 = MIPS_R_T9; -+ u8 cmp; -+ -+ /* -+ * if ((rs < 0) ^ (imm < 0)) t1 = imm >u rsl -+ * else t1 = rsl > 31 */ -+ if (imm < 0) -+ emit_movz_r(ctx, t1, t2, rd); /* t1 = rd ? t1 : t2 */ -+ else -+ emit_movn_r(ctx, t1, t2, rd); /* t1 = rd ? t2 : t1 */ -+ /* -+ * if ((imm < 0 && rsh != 0xffffffff) || -+ * (imm >= 0 && rsh != 0)) -+ * t1 = 0 -+ */ -+ if (imm < 0) { -+ emit(ctx, addiu, rd, hi(rs), 1); /* rd = rsh + 1 */ -+ cmp = rd; -+ } else { /* imm >= 0 */ -+ cmp = hi(rs); -+ } -+ emit_movn_r(ctx, t1, MIPS_R_ZERO, cmp); /* t1 = 0 if cmp != 0 */ -+ -+ /* -+ * if (imm < 0) rd = rsh < -1 -+ * else rd = rsh != 0 -+ * rd = rd | t1 -+ */ -+ emit(ctx, slti, rd, hi(rs), imm < 0 ? -1 : 0); /* rd = rsh < hi(imm) */ -+ emit(ctx, or, rd, rd, t1); /* rd = rd | t1 */ -+} -+ -+/* Emulation of 64-bit(slt rd, rs, rt) */ -+static void emit_slt_r64(struct jit_context *ctx, u8 rd, -+ const u8 rs[], const u8 rt[]) -+{ -+ u8 t1 = MIPS_R_T7; -+ u8 t2 = MIPS_R_T8; -+ u8 t3 = MIPS_R_T9; -+ -+ /* -+ * if ((rs < 0) ^ (rt < 0)) t1 = rtl > 31 */ -+ emit_movn_r(ctx, t1, t2, rd); /* t1 = rd ? t2 : t1 */ -+ emit_movn_r(ctx, t1, MIPS_R_ZERO, t3); /* t1 = 0 if t3 != 0 */ -+ -+ /* rd = (rsh < rth) | t1 */ -+ emit(ctx, slt, rd, hi(rs), hi(rt)); /* rd = rsh = -0x7fff && imm <= 0x8000) { -+ emit(ctx, addiu, tmp, lo(dst), -imm); -+ } else if ((u32)imm <= 0xffff) { -+ emit(ctx, xori, tmp, lo(dst), imm); -+ } else { /* Register fallback */ -+ emit_mov_i(ctx, tmp, imm); -+ emit(ctx, xor, tmp, lo(dst), tmp); -+ } -+ if (imm < 0) { /* Compare sign extension */ -+ emit(ctx, addu, MIPS_R_T9, hi(dst), 1); -+ emit(ctx, or, tmp, tmp, MIPS_R_T9); -+ } else { /* Compare zero extension */ -+ emit(ctx, or, tmp, tmp, hi(dst)); -+ } -+ if (op == BPF_JEQ) -+ emit(ctx, beqz, tmp, off); -+ else /* BPF_JNE */ -+ emit(ctx, bnez, tmp, off); -+ break; -+ /* PC += off if dst & imm */ -+ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ -+ case BPF_JSET: -+ case JIT_JNSET: -+ if ((u32)imm <= 0xffff) { -+ emit(ctx, andi, tmp, lo(dst), imm); -+ } else { /* Register fallback */ -+ emit_mov_i(ctx, tmp, imm); -+ emit(ctx, and, tmp, lo(dst), tmp); -+ } -+ if (imm < 0) /* Sign-extension pulls in high word */ -+ emit(ctx, or, tmp, tmp, hi(dst)); -+ if (op == BPF_JSET) -+ emit(ctx, bnez, tmp, off); -+ else /* JIT_JNSET */ -+ emit(ctx, beqz, tmp, off); -+ break; -+ /* PC += off if dst > imm */ -+ case BPF_JGT: -+ emit_sltiu_r64(ctx, tmp, dst, (s64)imm + 1); -+ emit(ctx, beqz, tmp, off); -+ break; -+ /* PC += off if dst >= imm */ -+ case BPF_JGE: -+ emit_sltiu_r64(ctx, tmp, dst, imm); -+ emit(ctx, beqz, tmp, off); -+ break; -+ /* PC += off if dst < imm */ -+ case BPF_JLT: -+ emit_sltiu_r64(ctx, tmp, dst, imm); -+ emit(ctx, bnez, tmp, off); -+ break; -+ /* PC += off if dst <= imm */ -+ case BPF_JLE: -+ emit_sltiu_r64(ctx, tmp, dst, (s64)imm + 1); -+ emit(ctx, bnez, tmp, off); -+ break; -+ /* PC += off if dst > imm (signed) */ -+ case BPF_JSGT: -+ emit_slti_r64(ctx, tmp, dst, (s64)imm + 1); -+ emit(ctx, beqz, tmp, off); -+ break; -+ /* PC += off if dst >= imm (signed) */ -+ case BPF_JSGE: -+ emit_slti_r64(ctx, tmp, dst, imm); -+ emit(ctx, beqz, tmp, off); -+ break; -+ /* PC += off if dst < imm (signed) */ -+ case BPF_JSLT: -+ emit_slti_r64(ctx, tmp, dst, imm); -+ emit(ctx, bnez, tmp, off); -+ break; -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JSLE: -+ emit_slti_r64(ctx, tmp, dst, (s64)imm + 1); -+ emit(ctx, bnez, tmp, off); -+ break; -+ } -+} -+ -+/* Jump register (64-bit) */ -+static void emit_jmp_r64(struct jit_context *ctx, -+ const u8 dst[], const u8 src[], s32 off, u8 op) -+{ -+ u8 t1 = MIPS_R_T6; -+ u8 t2 = MIPS_R_T7; -+ -+ switch (op) { -+ /* No-op, used internally for branch optimization */ -+ case JIT_JNOP: -+ break; -+ /* PC += off if dst == src */ -+ /* PC += off if dst != src */ -+ case BPF_JEQ: -+ case BPF_JNE: -+ emit(ctx, subu, t1, lo(dst), lo(src)); -+ emit(ctx, subu, t2, hi(dst), hi(src)); -+ emit(ctx, or, t1, t1, t2); -+ if (op == BPF_JEQ) -+ emit(ctx, beqz, t1, off); -+ else /* BPF_JNE */ -+ emit(ctx, bnez, t1, off); -+ break; -+ /* PC += off if dst & src */ -+ /* PC += off if (dst & imm) == 0 (not in BPF, used for long jumps) */ -+ case BPF_JSET: -+ case JIT_JNSET: -+ emit(ctx, and, t1, lo(dst), lo(src)); -+ emit(ctx, and, t2, hi(dst), hi(src)); -+ emit(ctx, or, t1, t1, t2); -+ if (op == BPF_JSET) -+ emit(ctx, bnez, t1, off); -+ else /* JIT_JNSET */ -+ emit(ctx, beqz, t1, off); -+ break; -+ /* PC += off if dst > src */ -+ case BPF_JGT: -+ emit_sltu_r64(ctx, t1, src, dst); -+ emit(ctx, bnez, t1, off); -+ break; -+ /* PC += off if dst >= src */ -+ case BPF_JGE: -+ emit_sltu_r64(ctx, t1, dst, src); -+ emit(ctx, beqz, t1, off); -+ break; -+ /* PC += off if dst < src */ -+ case BPF_JLT: -+ emit_sltu_r64(ctx, t1, dst, src); -+ emit(ctx, bnez, t1, off); -+ break; -+ /* PC += off if dst <= src */ -+ case BPF_JLE: -+ emit_sltu_r64(ctx, t1, src, dst); -+ emit(ctx, beqz, t1, off); -+ break; -+ /* PC += off if dst > src (signed) */ -+ case BPF_JSGT: -+ emit_slt_r64(ctx, t1, src, dst); -+ emit(ctx, bnez, t1, off); -+ break; -+ /* PC += off if dst >= src (signed) */ -+ case BPF_JSGE: -+ emit_slt_r64(ctx, t1, dst, src); -+ emit(ctx, beqz, t1, off); -+ break; -+ /* PC += off if dst < src (signed) */ -+ case BPF_JSLT: -+ emit_slt_r64(ctx, t1, dst, src); -+ emit(ctx, bnez, t1, off); -+ break; -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JSLE: -+ emit_slt_r64(ctx, t1, src, dst); -+ emit(ctx, beqz, t1, off); -+ break; -+ } -+} -+ -+/* Function call */ -+static int emit_call(struct jit_context *ctx, const struct bpf_insn *insn) -+{ -+ bool fixed; -+ u64 addr; -+ -+ /* Decode the call address */ -+ if (bpf_jit_get_func_addr(ctx->program, insn, false, -+ &addr, &fixed) < 0) -+ return -1; -+ if (!fixed) -+ return -1; -+ -+ /* Push stack arguments */ -+ push_regs(ctx, JIT_STACK_REGS, 0, JIT_RESERVED_STACK); -+ -+ /* Emit function call */ -+ emit_mov_i(ctx, MIPS_R_T9, addr); -+ emit(ctx, jalr, MIPS_R_RA, MIPS_R_T9); -+ emit(ctx, nop); /* Delay slot */ -+ -+ clobber_reg(ctx, MIPS_R_RA); -+ clobber_reg(ctx, MIPS_R_V0); -+ clobber_reg(ctx, MIPS_R_V1); -+ return 0; -+} -+ -+/* Function tail call */ -+static int emit_tail_call(struct jit_context *ctx) -+{ -+ u8 ary = lo(bpf2mips32[BPF_REG_2]); -+ u8 ind = lo(bpf2mips32[BPF_REG_3]); -+ u8 t1 = MIPS_R_T8; -+ u8 t2 = MIPS_R_T9; -+ int off; -+ -+ /* -+ * Tail call: -+ * eBPF R1 - function argument (context ptr), passed in a0-a1 -+ * eBPF R2 - ptr to object with array of function entry points -+ * eBPF R3 - array index of function to be called -+ * stack[sz] - remaining tail call count, initialized in prologue -+ */ -+ -+ /* if (ind >= ary->map.max_entries) goto out */ -+ off = offsetof(struct bpf_array, map.max_entries); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, lw, t1, off, ary); /* t1 = ary->map.max_entries*/ -+ emit_load_delay(ctx); /* Load delay slot */ -+ emit(ctx, sltu, t1, ind, t1); /* t1 = ind < t1 */ -+ emit(ctx, beqz, t1, get_offset(ctx, 1)); /* PC += off(1) if t1 == 0 */ -+ /* (next insn delay slot) */ -+ /* if (TCC-- <= 0) goto out */ -+ emit(ctx, lw, t2, ctx->stack_size, MIPS_R_SP); /* t2 = *(SP + size) */ -+ emit_load_delay(ctx); /* Load delay slot */ -+ emit(ctx, blez, t2, get_offset(ctx, 1)); /* PC += off(1) if t2 < 0 */ -+ emit(ctx, addiu, t2, t2, -1); /* t2-- (delay slot) */ -+ emit(ctx, sw, t2, ctx->stack_size, MIPS_R_SP); /* *(SP + size) = t2 */ -+ -+ /* prog = ary->ptrs[ind] */ -+ off = offsetof(struct bpf_array, ptrs); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, sll, t1, ind, 2); /* t1 = ind << 2 */ -+ emit(ctx, addu, t1, t1, ary); /* t1 += ary */ -+ emit(ctx, lw, t2, off, t1); /* t2 = *(t1 + off) */ -+ emit_load_delay(ctx); /* Load delay slot */ -+ -+ /* if (prog == 0) goto out */ -+ emit(ctx, beqz, t2, get_offset(ctx, 1)); /* PC += off(1) if t2 == 0 */ -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* func = prog->bpf_func + 8 (prologue skip offset) */ -+ off = offsetof(struct bpf_prog, bpf_func); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, lw, t1, off, t2); /* t1 = *(t2 + off) */ -+ emit_load_delay(ctx); /* Load delay slot */ -+ emit(ctx, addiu, t1, t1, JIT_TCALL_SKIP); /* t1 += skip (8 or 12) */ -+ -+ /* goto func */ -+ build_epilogue(ctx, t1); -+ return 0; -+} -+ -+/* -+ * Stack frame layout for a JITed program (stack grows down). -+ * -+ * Higher address : Caller's stack frame : -+ * :----------------------------: -+ * : 64-bit eBPF args r3-r5 : -+ * :----------------------------: -+ * : Reserved / tail call count : -+ * +============================+ <--- MIPS sp before call -+ * | Callee-saved registers, | -+ * | including RA and FP | -+ * +----------------------------+ <--- eBPF FP (MIPS zero,fp) -+ * | Local eBPF variables | -+ * | allocated by program | -+ * +----------------------------+ -+ * | Reserved for caller-saved | -+ * | registers | -+ * +----------------------------+ -+ * | Reserved for 64-bit eBPF | -+ * | args r3-r5 & args passed | -+ * | on stack in kernel calls | -+ * Lower address +============================+ <--- MIPS sp -+ */ -+ -+/* Build program prologue to set up the stack and registers */ -+void build_prologue(struct jit_context *ctx) -+{ -+ const u8 *r1 = bpf2mips32[BPF_REG_1]; -+ const u8 *fp = bpf2mips32[BPF_REG_FP]; -+ int stack, saved, locals, reserved; -+ -+ /* -+ * The first two instructions initialize TCC in the reserved (for us) -+ * 16-byte area in the parent's stack frame. On a tail call, the -+ * calling function jumps into the prologue after these instructions. -+ */ -+ emit(ctx, ori, MIPS_R_T9, MIPS_R_ZERO, -+ min(MAX_TAIL_CALL_CNT + 1, 0xffff)); -+ emit(ctx, sw, MIPS_R_T9, 0, MIPS_R_SP); -+ -+ /* -+ * Register eBPF R1 contains the 32-bit context pointer argument. -+ * A 32-bit argument is always passed in MIPS register a0, regardless -+ * of CPU endianness. Initialize R1 accordingly and zero-extend. -+ */ -+#ifdef __BIG_ENDIAN -+ emit(ctx, move, lo(r1), MIPS_R_A0); -+#endif -+ -+ /* === Entry-point for tail calls === */ -+ -+ /* Zero-extend the 32-bit argument */ -+ emit(ctx, move, hi(r1), MIPS_R_ZERO); -+ -+ /* If the eBPF frame pointer was accessed it must be saved */ -+ if (ctx->accessed & BIT(BPF_REG_FP)) -+ clobber_reg64(ctx, fp); -+ -+ /* Compute the stack space needed for callee-saved registers */ -+ saved = hweight32(ctx->clobbered & JIT_CALLEE_REGS) * sizeof(u32); -+ saved = ALIGN(saved, MIPS_STACK_ALIGNMENT); -+ -+ /* Stack space used by eBPF program local data */ -+ locals = ALIGN(ctx->program->aux->stack_depth, MIPS_STACK_ALIGNMENT); -+ -+ /* -+ * If we are emitting function calls, reserve extra stack space for -+ * caller-saved registers and function arguments passed on the stack. -+ * The required space is computed automatically during resource -+ * usage discovery (pass 1). -+ */ -+ reserved = ctx->stack_used; -+ -+ /* Allocate the stack frame */ -+ stack = ALIGN(saved + locals + reserved, MIPS_STACK_ALIGNMENT); -+ emit(ctx, addiu, MIPS_R_SP, MIPS_R_SP, -stack); -+ -+ /* Store callee-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, stack - saved); -+ -+ /* Initialize the eBPF frame pointer if accessed */ -+ if (ctx->accessed & BIT(BPF_REG_FP)) -+ emit(ctx, addiu, lo(fp), MIPS_R_SP, stack - saved); -+ -+ ctx->saved_size = saved; -+ ctx->stack_size = stack; -+} -+ -+/* Build the program epilogue to restore the stack and registers */ -+void build_epilogue(struct jit_context *ctx, int dest_reg) -+{ -+ /* Restore callee-saved registers from stack */ -+ pop_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, -+ ctx->stack_size - ctx->saved_size); -+ /* -+ * A 32-bit return value is always passed in MIPS register v0, -+ * but on big-endian targets the low part of R0 is mapped to v1. -+ */ -+#ifdef __BIG_ENDIAN -+ emit(ctx, move, MIPS_R_V0, MIPS_R_V1); -+#endif -+ -+ /* Jump to the return address and adjust the stack pointer */ -+ emit(ctx, jr, dest_reg); -+ emit(ctx, addiu, MIPS_R_SP, MIPS_R_SP, ctx->stack_size); -+} -+ -+/* Build one eBPF instruction */ -+int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) -+{ -+ const u8 *dst = bpf2mips32[insn->dst_reg]; -+ const u8 *src = bpf2mips32[insn->src_reg]; -+ const u8 *tmp = bpf2mips32[JIT_REG_TMP]; -+ u8 code = insn->code; -+ s16 off = insn->off; -+ s32 imm = insn->imm; -+ s32 val, rel; -+ u8 alu, jmp; -+ -+ switch (code) { -+ /* ALU operations */ -+ /* dst = imm */ -+ case BPF_ALU | BPF_MOV | BPF_K: -+ emit_mov_i(ctx, lo(dst), imm); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = src */ -+ case BPF_ALU | BPF_MOV | BPF_X: -+ if (imm == 1) { -+ /* Special mov32 for zext */ -+ emit_mov_i(ctx, hi(dst), 0); -+ } else { -+ emit_mov_r(ctx, lo(dst), lo(src)); -+ emit_zext_ver(ctx, dst); -+ } -+ break; -+ /* dst = -dst */ -+ case BPF_ALU | BPF_NEG: -+ emit_alu_i(ctx, lo(dst), 0, BPF_NEG); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst & imm */ -+ /* dst = dst | imm */ -+ /* dst = dst ^ imm */ -+ /* dst = dst << imm */ -+ /* dst = dst >> imm */ -+ /* dst = dst >> imm (arithmetic) */ -+ /* dst = dst + imm */ -+ /* dst = dst - imm */ -+ /* dst = dst * imm */ -+ /* dst = dst / imm */ -+ /* dst = dst % imm */ -+ case BPF_ALU | BPF_OR | BPF_K: -+ case BPF_ALU | BPF_AND | BPF_K: -+ case BPF_ALU | BPF_XOR | BPF_K: -+ case BPF_ALU | BPF_LSH | BPF_K: -+ case BPF_ALU | BPF_RSH | BPF_K: -+ case BPF_ALU | BPF_ARSH | BPF_K: -+ case BPF_ALU | BPF_ADD | BPF_K: -+ case BPF_ALU | BPF_SUB | BPF_K: -+ case BPF_ALU | BPF_MUL | BPF_K: -+ case BPF_ALU | BPF_DIV | BPF_K: -+ case BPF_ALU | BPF_MOD | BPF_K: -+ if (!valid_alu_i(BPF_OP(code), imm)) { -+ emit_mov_i(ctx, MIPS_R_T6, imm); -+ emit_alu_r(ctx, lo(dst), MIPS_R_T6, BPF_OP(code)); -+ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { -+ emit_alu_i(ctx, lo(dst), val, alu); -+ } -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst & src */ -+ /* dst = dst | src */ -+ /* dst = dst ^ src */ -+ /* dst = dst << src */ -+ /* dst = dst >> src */ -+ /* dst = dst >> src (arithmetic) */ -+ /* dst = dst + src */ -+ /* dst = dst - src */ -+ /* dst = dst * src */ -+ /* dst = dst / src */ -+ /* dst = dst % src */ -+ case BPF_ALU | BPF_AND | BPF_X: -+ case BPF_ALU | BPF_OR | BPF_X: -+ case BPF_ALU | BPF_XOR | BPF_X: -+ case BPF_ALU | BPF_LSH | BPF_X: -+ case BPF_ALU | BPF_RSH | BPF_X: -+ case BPF_ALU | BPF_ARSH | BPF_X: -+ case BPF_ALU | BPF_ADD | BPF_X: -+ case BPF_ALU | BPF_SUB | BPF_X: -+ case BPF_ALU | BPF_MUL | BPF_X: -+ case BPF_ALU | BPF_DIV | BPF_X: -+ case BPF_ALU | BPF_MOD | BPF_X: -+ emit_alu_r(ctx, lo(dst), lo(src), BPF_OP(code)); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = imm (64-bit) */ -+ case BPF_ALU64 | BPF_MOV | BPF_K: -+ emit_mov_se_i64(ctx, dst, imm); -+ break; -+ /* dst = src (64-bit) */ -+ case BPF_ALU64 | BPF_MOV | BPF_X: -+ emit_mov_r(ctx, lo(dst), lo(src)); -+ emit_mov_r(ctx, hi(dst), hi(src)); -+ break; -+ /* dst = -dst (64-bit) */ -+ case BPF_ALU64 | BPF_NEG: -+ emit_neg_i64(ctx, dst); -+ break; -+ /* dst = dst & imm (64-bit) */ -+ case BPF_ALU64 | BPF_AND | BPF_K: -+ emit_alu_i64(ctx, dst, imm, BPF_OP(code)); -+ break; -+ /* dst = dst | imm (64-bit) */ -+ /* dst = dst ^ imm (64-bit) */ -+ /* dst = dst + imm (64-bit) */ -+ /* dst = dst - imm (64-bit) */ -+ case BPF_ALU64 | BPF_OR | BPF_K: -+ case BPF_ALU64 | BPF_XOR | BPF_K: -+ case BPF_ALU64 | BPF_ADD | BPF_K: -+ case BPF_ALU64 | BPF_SUB | BPF_K: -+ if (imm) -+ emit_alu_i64(ctx, dst, imm, BPF_OP(code)); -+ break; -+ /* dst = dst << imm (64-bit) */ -+ /* dst = dst >> imm (64-bit) */ -+ /* dst = dst >> imm (64-bit, arithmetic) */ -+ case BPF_ALU64 | BPF_LSH | BPF_K: -+ case BPF_ALU64 | BPF_RSH | BPF_K: -+ case BPF_ALU64 | BPF_ARSH | BPF_K: -+ if (imm) -+ emit_shift_i64(ctx, dst, imm, BPF_OP(code)); -+ break; -+ /* dst = dst * imm (64-bit) */ -+ case BPF_ALU64 | BPF_MUL | BPF_K: -+ emit_mul_i64(ctx, dst, imm); -+ break; -+ /* dst = dst / imm (64-bit) */ -+ /* dst = dst % imm (64-bit) */ -+ case BPF_ALU64 | BPF_DIV | BPF_K: -+ case BPF_ALU64 | BPF_MOD | BPF_K: -+ /* -+ * Sign-extend the immediate value into a temporary register, -+ * and then do the operation on this register. -+ */ -+ emit_mov_se_i64(ctx, tmp, imm); -+ emit_divmod_r64(ctx, dst, tmp, BPF_OP(code)); -+ break; -+ /* dst = dst & src (64-bit) */ -+ /* dst = dst | src (64-bit) */ -+ /* dst = dst ^ src (64-bit) */ -+ /* dst = dst + src (64-bit) */ -+ /* dst = dst - src (64-bit) */ -+ case BPF_ALU64 | BPF_AND | BPF_X: -+ case BPF_ALU64 | BPF_OR | BPF_X: -+ case BPF_ALU64 | BPF_XOR | BPF_X: -+ case BPF_ALU64 | BPF_ADD | BPF_X: -+ case BPF_ALU64 | BPF_SUB | BPF_X: -+ emit_alu_r64(ctx, dst, src, BPF_OP(code)); -+ break; -+ /* dst = dst << src (64-bit) */ -+ /* dst = dst >> src (64-bit) */ -+ /* dst = dst >> src (64-bit, arithmetic) */ -+ case BPF_ALU64 | BPF_LSH | BPF_X: -+ case BPF_ALU64 | BPF_RSH | BPF_X: -+ case BPF_ALU64 | BPF_ARSH | BPF_X: -+ emit_shift_r64(ctx, dst, lo(src), BPF_OP(code)); -+ break; -+ /* dst = dst * src (64-bit) */ -+ case BPF_ALU64 | BPF_MUL | BPF_X: -+ emit_mul_r64(ctx, dst, src); -+ break; -+ /* dst = dst / src (64-bit) */ -+ /* dst = dst % src (64-bit) */ -+ case BPF_ALU64 | BPF_DIV | BPF_X: -+ case BPF_ALU64 | BPF_MOD | BPF_X: -+ emit_divmod_r64(ctx, dst, src, BPF_OP(code)); -+ break; -+ /* dst = htole(dst) */ -+ /* dst = htobe(dst) */ -+ case BPF_ALU | BPF_END | BPF_FROM_LE: -+ case BPF_ALU | BPF_END | BPF_FROM_BE: -+ if (BPF_SRC(code) == -+#ifdef __BIG_ENDIAN -+ BPF_FROM_LE -+#else -+ BPF_FROM_BE -+#endif -+ ) -+ emit_bswap_r64(ctx, dst, imm); -+ else -+ emit_trunc_r64(ctx, dst, imm); -+ break; -+ /* dst = imm64 */ -+ case BPF_LD | BPF_IMM | BPF_DW: -+ emit_mov_i(ctx, lo(dst), imm); -+ emit_mov_i(ctx, hi(dst), insn[1].imm); -+ return 1; -+ /* LDX: dst = *(size *)(src + off) */ -+ case BPF_LDX | BPF_MEM | BPF_W: -+ case BPF_LDX | BPF_MEM | BPF_H: -+ case BPF_LDX | BPF_MEM | BPF_B: -+ case BPF_LDX | BPF_MEM | BPF_DW: -+ emit_ldx(ctx, dst, lo(src), off, BPF_SIZE(code)); -+ break; -+ /* ST: *(size *)(dst + off) = imm */ -+ case BPF_ST | BPF_MEM | BPF_W: -+ case BPF_ST | BPF_MEM | BPF_H: -+ case BPF_ST | BPF_MEM | BPF_B: -+ case BPF_ST | BPF_MEM | BPF_DW: -+ switch (BPF_SIZE(code)) { -+ case BPF_DW: -+ /* Sign-extend immediate value into temporary reg */ -+ emit_mov_se_i64(ctx, tmp, imm); -+ break; -+ case BPF_W: -+ case BPF_H: -+ case BPF_B: -+ emit_mov_i(ctx, lo(tmp), imm); -+ break; -+ } -+ emit_stx(ctx, lo(dst), tmp, off, BPF_SIZE(code)); -+ break; -+ /* STX: *(size *)(dst + off) = src */ -+ case BPF_STX | BPF_MEM | BPF_W: -+ case BPF_STX | BPF_MEM | BPF_H: -+ case BPF_STX | BPF_MEM | BPF_B: -+ case BPF_STX | BPF_MEM | BPF_DW: -+ emit_stx(ctx, lo(dst), src, off, BPF_SIZE(code)); -+ break; -+ /* Speculation barrier */ -+ case BPF_ST | BPF_NOSPEC: -+ break; -+ /* Atomics */ -+ case BPF_STX | BPF_XADD | BPF_W: -+ switch (imm) { -+ case BPF_ADD: -+ case BPF_AND: -+ case BPF_OR: -+ case BPF_XOR: -+ if (cpu_has_llsc) -+ emit_atomic_r(ctx, lo(dst), lo(src), off, imm); -+ else /* Non-ll/sc fallback */ -+ emit_atomic_r32(ctx, lo(dst), lo(src), -+ off, imm); -+ break; -+ default: -+ goto notyet; -+ } -+ break; -+ /* Atomics (64-bit) */ -+ case BPF_STX | BPF_XADD | BPF_DW: -+ switch (imm) { -+ case BPF_ADD: -+ case BPF_AND: -+ case BPF_OR: -+ case BPF_XOR: -+ emit_atomic_r64(ctx, lo(dst), src, off, imm); -+ break; -+ default: -+ goto notyet; -+ } -+ break; -+ /* PC += off if dst == src */ -+ /* PC += off if dst != src */ -+ /* PC += off if dst & src */ -+ /* PC += off if dst > src */ -+ /* PC += off if dst >= src */ -+ /* PC += off if dst < src */ -+ /* PC += off if dst <= src */ -+ /* PC += off if dst > src (signed) */ -+ /* PC += off if dst >= src (signed) */ -+ /* PC += off if dst < src (signed) */ -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JMP32 | BPF_JEQ | BPF_X: -+ case BPF_JMP32 | BPF_JNE | BPF_X: -+ case BPF_JMP32 | BPF_JSET | BPF_X: -+ case BPF_JMP32 | BPF_JGT | BPF_X: -+ case BPF_JMP32 | BPF_JGE | BPF_X: -+ case BPF_JMP32 | BPF_JLT | BPF_X: -+ case BPF_JMP32 | BPF_JLE | BPF_X: -+ case BPF_JMP32 | BPF_JSGT | BPF_X: -+ case BPF_JMP32 | BPF_JSGE | BPF_X: -+ case BPF_JMP32 | BPF_JSLT | BPF_X: -+ case BPF_JMP32 | BPF_JSLE | BPF_X: -+ if (off == 0) -+ break; -+ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); -+ emit_jmp_r(ctx, lo(dst), lo(src), rel, jmp); -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == imm */ -+ /* PC += off if dst != imm */ -+ /* PC += off if dst & imm */ -+ /* PC += off if dst > imm */ -+ /* PC += off if dst >= imm */ -+ /* PC += off if dst < imm */ -+ /* PC += off if dst <= imm */ -+ /* PC += off if dst > imm (signed) */ -+ /* PC += off if dst >= imm (signed) */ -+ /* PC += off if dst < imm (signed) */ -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JMP32 | BPF_JEQ | BPF_K: -+ case BPF_JMP32 | BPF_JNE | BPF_K: -+ case BPF_JMP32 | BPF_JSET | BPF_K: -+ case BPF_JMP32 | BPF_JGT | BPF_K: -+ case BPF_JMP32 | BPF_JGE | BPF_K: -+ case BPF_JMP32 | BPF_JLT | BPF_K: -+ case BPF_JMP32 | BPF_JLE | BPF_K: -+ case BPF_JMP32 | BPF_JSGT | BPF_K: -+ case BPF_JMP32 | BPF_JSGE | BPF_K: -+ case BPF_JMP32 | BPF_JSLT | BPF_K: -+ case BPF_JMP32 | BPF_JSLE | BPF_K: -+ if (off == 0) -+ break; -+ setup_jmp_i(ctx, imm, 32, BPF_OP(code), off, &jmp, &rel); -+ if (valid_jmp_i(jmp, imm)) { -+ emit_jmp_i(ctx, lo(dst), imm, rel, jmp); -+ } else { -+ /* Move large immediate to register */ -+ emit_mov_i(ctx, MIPS_R_T6, imm); -+ emit_jmp_r(ctx, lo(dst), MIPS_R_T6, rel, jmp); -+ } -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == src */ -+ /* PC += off if dst != src */ -+ /* PC += off if dst & src */ -+ /* PC += off if dst > src */ -+ /* PC += off if dst >= src */ -+ /* PC += off if dst < src */ -+ /* PC += off if dst <= src */ -+ /* PC += off if dst > src (signed) */ -+ /* PC += off if dst >= src (signed) */ -+ /* PC += off if dst < src (signed) */ -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JMP | BPF_JEQ | BPF_X: -+ case BPF_JMP | BPF_JNE | BPF_X: -+ case BPF_JMP | BPF_JSET | BPF_X: -+ case BPF_JMP | BPF_JGT | BPF_X: -+ case BPF_JMP | BPF_JGE | BPF_X: -+ case BPF_JMP | BPF_JLT | BPF_X: -+ case BPF_JMP | BPF_JLE | BPF_X: -+ case BPF_JMP | BPF_JSGT | BPF_X: -+ case BPF_JMP | BPF_JSGE | BPF_X: -+ case BPF_JMP | BPF_JSLT | BPF_X: -+ case BPF_JMP | BPF_JSLE | BPF_X: -+ if (off == 0) -+ break; -+ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); -+ emit_jmp_r64(ctx, dst, src, rel, jmp); -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == imm */ -+ /* PC += off if dst != imm */ -+ /* PC += off if dst & imm */ -+ /* PC += off if dst > imm */ -+ /* PC += off if dst >= imm */ -+ /* PC += off if dst < imm */ -+ /* PC += off if dst <= imm */ -+ /* PC += off if dst > imm (signed) */ -+ /* PC += off if dst >= imm (signed) */ -+ /* PC += off if dst < imm (signed) */ -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JMP | BPF_JEQ | BPF_K: -+ case BPF_JMP | BPF_JNE | BPF_K: -+ case BPF_JMP | BPF_JSET | BPF_K: -+ case BPF_JMP | BPF_JGT | BPF_K: -+ case BPF_JMP | BPF_JGE | BPF_K: -+ case BPF_JMP | BPF_JLT | BPF_K: -+ case BPF_JMP | BPF_JLE | BPF_K: -+ case BPF_JMP | BPF_JSGT | BPF_K: -+ case BPF_JMP | BPF_JSGE | BPF_K: -+ case BPF_JMP | BPF_JSLT | BPF_K: -+ case BPF_JMP | BPF_JSLE | BPF_K: -+ if (off == 0) -+ break; -+ setup_jmp_i(ctx, imm, 64, BPF_OP(code), off, &jmp, &rel); -+ emit_jmp_i64(ctx, dst, imm, rel, jmp); -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off */ -+ case BPF_JMP | BPF_JA: -+ if (off == 0) -+ break; -+ if (emit_ja(ctx, off) < 0) -+ goto toofar; -+ break; -+ /* Tail call */ -+ case BPF_JMP | BPF_TAIL_CALL: -+ if (emit_tail_call(ctx) < 0) -+ goto invalid; -+ break; -+ /* Function call */ -+ case BPF_JMP | BPF_CALL: -+ if (emit_call(ctx, insn) < 0) -+ goto invalid; -+ break; -+ /* Function return */ -+ case BPF_JMP | BPF_EXIT: -+ /* -+ * Optimization: when last instruction is EXIT -+ * simply continue to epilogue. -+ */ -+ if (ctx->bpf_index == ctx->program->len - 1) -+ break; -+ if (emit_exit(ctx) < 0) -+ goto toofar; -+ break; -+ -+ default: -+invalid: -+ pr_err_once("unknown opcode %02x\n", code); -+ return -EINVAL; -+notyet: -+ pr_info_once("*** NOT YET: opcode %02x ***\n", code); -+ return -EFAULT; -+toofar: -+ pr_info_once("*** TOO FAR: jump at %u opcode %02x ***\n", -+ ctx->bpf_index, code); -+ return -E2BIG; -+ } -+ return 0; -+} diff --git a/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch b/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch deleted file mode 100644 index 38b46c0b765..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-03-mips-bpf-Add-new-eBPF-JIT-for-64-bit-MIPS.patch +++ /dev/null @@ -1,1005 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:05 +0200 -Subject: [PATCH] mips: bpf: Add new eBPF JIT for 64-bit MIPS - -This is an implementation on of an eBPF JIT for 64-bit MIPS III-V and -MIPS64r1-r6. It uses the same framework introduced by the 32-bit JIT. - -Signed-off-by: Johan Almbladh ---- - create mode 100644 arch/mips/net/bpf_jit_comp64.c - ---- /dev/null -+++ b/arch/mips/net/bpf_jit_comp64.c -@@ -0,0 +1,991 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Just-In-Time compiler for eBPF bytecode on MIPS. -+ * Implementation of JIT functions for 64-bit CPUs. -+ * -+ * Copyright (c) 2021 Anyfi Networks AB. -+ * Author: Johan Almbladh -+ * -+ * Based on code and ideas from -+ * Copyright (c) 2017 Cavium, Inc. -+ * Copyright (c) 2017 Shubham Bansal -+ * Copyright (c) 2011 Mircea Gherzan -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "bpf_jit_comp.h" -+ -+/* MIPS t0-t3 are not available in the n64 ABI */ -+#undef MIPS_R_T0 -+#undef MIPS_R_T1 -+#undef MIPS_R_T2 -+#undef MIPS_R_T3 -+ -+/* Stack is 16-byte aligned in n64 ABI */ -+#define MIPS_STACK_ALIGNMENT 16 -+ -+/* Extra 64-bit eBPF registers used by JIT */ -+#define JIT_REG_TC (MAX_BPF_JIT_REG + 0) -+#define JIT_REG_ZX (MAX_BPF_JIT_REG + 1) -+ -+/* Number of prologue bytes to skip when doing a tail call */ -+#define JIT_TCALL_SKIP 4 -+ -+/* Callee-saved CPU registers that the JIT must preserve */ -+#define JIT_CALLEE_REGS \ -+ (BIT(MIPS_R_S0) | \ -+ BIT(MIPS_R_S1) | \ -+ BIT(MIPS_R_S2) | \ -+ BIT(MIPS_R_S3) | \ -+ BIT(MIPS_R_S4) | \ -+ BIT(MIPS_R_S5) | \ -+ BIT(MIPS_R_S6) | \ -+ BIT(MIPS_R_S7) | \ -+ BIT(MIPS_R_GP) | \ -+ BIT(MIPS_R_FP) | \ -+ BIT(MIPS_R_RA)) -+ -+/* Caller-saved CPU registers available for JIT use */ -+#define JIT_CALLER_REGS \ -+ (BIT(MIPS_R_A5) | \ -+ BIT(MIPS_R_A6) | \ -+ BIT(MIPS_R_A7)) -+/* -+ * Mapping of 64-bit eBPF registers to 64-bit native MIPS registers. -+ * MIPS registers t4 - t7 may be used by the JIT as temporary registers. -+ * MIPS registers t8 - t9 are reserved for single-register common functions. -+ */ -+static const u8 bpf2mips64[] = { -+ /* Return value from in-kernel function, and exit value from eBPF */ -+ [BPF_REG_0] = MIPS_R_V0, -+ /* Arguments from eBPF program to in-kernel function */ -+ [BPF_REG_1] = MIPS_R_A0, -+ [BPF_REG_2] = MIPS_R_A1, -+ [BPF_REG_3] = MIPS_R_A2, -+ [BPF_REG_4] = MIPS_R_A3, -+ [BPF_REG_5] = MIPS_R_A4, -+ /* Callee-saved registers that in-kernel function will preserve */ -+ [BPF_REG_6] = MIPS_R_S0, -+ [BPF_REG_7] = MIPS_R_S1, -+ [BPF_REG_8] = MIPS_R_S2, -+ [BPF_REG_9] = MIPS_R_S3, -+ /* Read-only frame pointer to access the eBPF stack */ -+ [BPF_REG_FP] = MIPS_R_FP, -+ /* Temporary register for blinding constants */ -+ [BPF_REG_AX] = MIPS_R_AT, -+ /* Tail call count register, caller-saved */ -+ [JIT_REG_TC] = MIPS_R_A5, -+ /* Constant for register zero-extension */ -+ [JIT_REG_ZX] = MIPS_R_V1, -+}; -+ -+/* -+ * MIPS 32-bit operations on 64-bit registers generate a sign-extended -+ * result. However, the eBPF ISA mandates zero-extension, so we rely on the -+ * verifier to add that for us (emit_zext_ver). In addition, ALU arithmetic -+ * operations, right shift and byte swap require properly sign-extended -+ * operands or the result is unpredictable. We emit explicit sign-extensions -+ * in those cases. -+ */ -+ -+/* Sign extension */ -+static void emit_sext(struct jit_context *ctx, u8 dst, u8 src) -+{ -+ emit(ctx, sll, dst, src, 0); -+ clobber_reg(ctx, dst); -+} -+ -+/* Zero extension */ -+static void emit_zext(struct jit_context *ctx, u8 dst) -+{ -+ if (cpu_has_mips64r2 || cpu_has_mips64r6) { -+ emit(ctx, dinsu, dst, MIPS_R_ZERO, 32, 32); -+ } else { -+ emit(ctx, and, dst, dst, bpf2mips64[JIT_REG_ZX]); -+ access_reg(ctx, JIT_REG_ZX); /* We need the ZX register */ -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Zero extension, if verifier does not do it for us */ -+static void emit_zext_ver(struct jit_context *ctx, u8 dst) -+{ -+ if (!ctx->program->aux->verifier_zext) -+ emit_zext(ctx, dst); -+} -+ -+/* dst = imm (64-bit) */ -+static void emit_mov_i64(struct jit_context *ctx, u8 dst, u64 imm64) -+{ -+ if (imm64 >= 0xffffffffffff8000ULL || imm64 < 0x8000ULL) { -+ emit(ctx, daddiu, dst, MIPS_R_ZERO, (s16)imm64); -+ } else if (imm64 >= 0xffffffff80000000ULL || -+ (imm64 < 0x80000000 && imm64 > 0xffff)) { -+ emit(ctx, lui, dst, (s16)(imm64 >> 16)); -+ emit(ctx, ori, dst, dst, (u16)imm64 & 0xffff); -+ } else { -+ u8 acc = MIPS_R_ZERO; -+ int k; -+ -+ for (k = 0; k < 4; k++) { -+ u16 half = imm64 >> (48 - 16 * k); -+ -+ if (acc == dst) -+ emit(ctx, dsll, dst, dst, 16); -+ -+ if (half) { -+ emit(ctx, ori, dst, acc, half); -+ acc = dst; -+ } -+ } -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* ALU immediate operation (64-bit) */ -+static void emit_alu_i64(struct jit_context *ctx, u8 dst, s32 imm, u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = dst | imm */ -+ case BPF_OR: -+ emit(ctx, ori, dst, dst, (u16)imm); -+ break; -+ /* dst = dst ^ imm */ -+ case BPF_XOR: -+ emit(ctx, xori, dst, dst, (u16)imm); -+ break; -+ /* dst = -dst */ -+ case BPF_NEG: -+ emit(ctx, dsubu, dst, MIPS_R_ZERO, dst); -+ break; -+ /* dst = dst << imm */ -+ case BPF_LSH: -+ emit(ctx, dsll_safe, dst, dst, imm); -+ break; -+ /* dst = dst >> imm */ -+ case BPF_RSH: -+ emit(ctx, dsrl_safe, dst, dst, imm); -+ break; -+ /* dst = dst >> imm (arithmetic) */ -+ case BPF_ARSH: -+ emit(ctx, dsra_safe, dst, dst, imm); -+ break; -+ /* dst = dst + imm */ -+ case BPF_ADD: -+ emit(ctx, daddiu, dst, dst, imm); -+ break; -+ /* dst = dst - imm */ -+ case BPF_SUB: -+ emit(ctx, daddiu, dst, dst, -imm); -+ break; -+ default: -+ /* Width-generic operations */ -+ emit_alu_i(ctx, dst, imm, op); -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* ALU register operation (64-bit) */ -+static void emit_alu_r64(struct jit_context *ctx, u8 dst, u8 src, u8 op) -+{ -+ switch (BPF_OP(op)) { -+ /* dst = dst << src */ -+ case BPF_LSH: -+ emit(ctx, dsllv, dst, dst, src); -+ break; -+ /* dst = dst >> src */ -+ case BPF_RSH: -+ emit(ctx, dsrlv, dst, dst, src); -+ break; -+ /* dst = dst >> src (arithmetic) */ -+ case BPF_ARSH: -+ emit(ctx, dsrav, dst, dst, src); -+ break; -+ /* dst = dst + src */ -+ case BPF_ADD: -+ emit(ctx, daddu, dst, dst, src); -+ break; -+ /* dst = dst - src */ -+ case BPF_SUB: -+ emit(ctx, dsubu, dst, dst, src); -+ break; -+ /* dst = dst * src */ -+ case BPF_MUL: -+ if (cpu_has_mips64r6) { -+ emit(ctx, dmulu, dst, dst, src); -+ } else { -+ emit(ctx, dmultu, dst, src); -+ emit(ctx, mflo, dst); -+ } -+ break; -+ /* dst = dst / src */ -+ case BPF_DIV: -+ if (cpu_has_mips64r6) { -+ emit(ctx, ddivu_r6, dst, dst, src); -+ } else { -+ emit(ctx, ddivu, dst, src); -+ emit(ctx, mflo, dst); -+ } -+ break; -+ /* dst = dst % src */ -+ case BPF_MOD: -+ if (cpu_has_mips64r6) { -+ emit(ctx, dmodu, dst, dst, src); -+ } else { -+ emit(ctx, ddivu, dst, src); -+ emit(ctx, mfhi, dst); -+ } -+ break; -+ default: -+ /* Width-generic operations */ -+ emit_alu_r(ctx, dst, src, op); -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Swap sub words in a register double word */ -+static void emit_swap_r64(struct jit_context *ctx, u8 dst, u8 mask, u32 bits) -+{ -+ u8 tmp = MIPS_R_T9; -+ -+ emit(ctx, and, tmp, dst, mask); /* tmp = dst & mask */ -+ emit(ctx, dsll, tmp, tmp, bits); /* tmp = tmp << bits */ -+ emit(ctx, dsrl, dst, dst, bits); /* dst = dst >> bits */ -+ emit(ctx, and, dst, dst, mask); /* dst = dst & mask */ -+ emit(ctx, or, dst, dst, tmp); /* dst = dst | tmp */ -+} -+ -+/* Swap bytes and truncate a register double word, word or half word */ -+static void emit_bswap_r64(struct jit_context *ctx, u8 dst, u32 width) -+{ -+ switch (width) { -+ /* Swap bytes in a double word */ -+ case 64: -+ if (cpu_has_mips64r2 || cpu_has_mips64r6) { -+ emit(ctx, dsbh, dst, dst); -+ emit(ctx, dshd, dst, dst); -+ } else { -+ u8 t1 = MIPS_R_T6; -+ u8 t2 = MIPS_R_T7; -+ -+ emit(ctx, dsll32, t2, dst, 0); /* t2 = dst << 32 */ -+ emit(ctx, dsrl32, dst, dst, 0); /* dst = dst >> 32 */ -+ emit(ctx, or, dst, dst, t2); /* dst = dst | t2 */ -+ -+ emit(ctx, ori, t2, MIPS_R_ZERO, 0xffff); -+ emit(ctx, dsll32, t1, t2, 0); /* t1 = t2 << 32 */ -+ emit(ctx, or, t1, t1, t2); /* t1 = t1 | t2 */ -+ emit_swap_r64(ctx, dst, t1, 16);/* dst = swap16(dst) */ -+ -+ emit(ctx, lui, t2, 0xff); /* t2 = 0x00ff0000 */ -+ emit(ctx, ori, t2, t2, 0xff); /* t2 = t2 | 0x00ff */ -+ emit(ctx, dsll32, t1, t2, 0); /* t1 = t2 << 32 */ -+ emit(ctx, or, t1, t1, t2); /* t1 = t1 | t2 */ -+ emit_swap_r64(ctx, dst, t1, 8); /* dst = swap8(dst) */ -+ } -+ break; -+ /* Swap bytes in a half word */ -+ /* Swap bytes in a word */ -+ case 32: -+ case 16: -+ emit_sext(ctx, dst, dst); -+ emit_bswap_r(ctx, dst, width); -+ if (cpu_has_mips64r2 || cpu_has_mips64r6) -+ emit_zext(ctx, dst); -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Truncate a register double word, word or half word */ -+static void emit_trunc_r64(struct jit_context *ctx, u8 dst, u32 width) -+{ -+ switch (width) { -+ case 64: -+ break; -+ /* Zero-extend a word */ -+ case 32: -+ emit_zext(ctx, dst); -+ break; -+ /* Zero-extend a half word */ -+ case 16: -+ emit(ctx, andi, dst, dst, 0xffff); -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Load operation: dst = *(size*)(src + off) */ -+static void emit_ldx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) -+{ -+ switch (size) { -+ /* Load a byte */ -+ case BPF_B: -+ emit(ctx, lbu, dst, off, src); -+ break; -+ /* Load a half word */ -+ case BPF_H: -+ emit(ctx, lhu, dst, off, src); -+ break; -+ /* Load a word */ -+ case BPF_W: -+ emit(ctx, lwu, dst, off, src); -+ break; -+ /* Load a double word */ -+ case BPF_DW: -+ emit(ctx, ld, dst, off, src); -+ break; -+ } -+ clobber_reg(ctx, dst); -+} -+ -+/* Store operation: *(size *)(dst + off) = src */ -+static void emit_stx(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 size) -+{ -+ switch (size) { -+ /* Store a byte */ -+ case BPF_B: -+ emit(ctx, sb, src, off, dst); -+ break; -+ /* Store a half word */ -+ case BPF_H: -+ emit(ctx, sh, src, off, dst); -+ break; -+ /* Store a word */ -+ case BPF_W: -+ emit(ctx, sw, src, off, dst); -+ break; -+ /* Store a double word */ -+ case BPF_DW: -+ emit(ctx, sd, src, off, dst); -+ break; -+ } -+} -+ -+/* Atomic read-modify-write */ -+static void emit_atomic_r64(struct jit_context *ctx, -+ u8 dst, u8 src, s16 off, u8 code) -+{ -+ u8 t1 = MIPS_R_T6; -+ u8 t2 = MIPS_R_T7; -+ -+ emit(ctx, lld, t1, off, dst); -+ switch (code) { -+ case BPF_ADD: -+ emit(ctx, daddu, t2, t1, src); -+ break; -+ case BPF_AND: -+ emit(ctx, and, t2, t1, src); -+ break; -+ case BPF_OR: -+ emit(ctx, or, t2, t1, src); -+ break; -+ case BPF_XOR: -+ emit(ctx, xor, t2, t1, src); -+ break; -+ } -+ emit(ctx, scd, t2, off, dst); -+ emit(ctx, beqz, t2, -16); -+ emit(ctx, nop); /* Delay slot */ -+} -+ -+/* Function call */ -+static int emit_call(struct jit_context *ctx, const struct bpf_insn *insn) -+{ -+ u8 zx = bpf2mips64[JIT_REG_ZX]; -+ u8 tmp = MIPS_R_T6; -+ bool fixed; -+ u64 addr; -+ -+ /* Decode the call address */ -+ if (bpf_jit_get_func_addr(ctx->program, insn, false, -+ &addr, &fixed) < 0) -+ return -1; -+ if (!fixed) -+ return -1; -+ -+ /* Push caller-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); -+ -+ /* Emit function call */ -+ emit_mov_i64(ctx, tmp, addr); -+ emit(ctx, jalr, MIPS_R_RA, tmp); -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* Restore caller-saved registers */ -+ pop_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); -+ -+ /* Re-initialize the JIT zero-extension register if accessed */ -+ if (ctx->accessed & BIT(JIT_REG_ZX)) { -+ emit(ctx, daddiu, zx, MIPS_R_ZERO, -1); -+ emit(ctx, dsrl32, zx, zx, 0); -+ } -+ -+ clobber_reg(ctx, MIPS_R_RA); -+ clobber_reg(ctx, MIPS_R_V0); -+ clobber_reg(ctx, MIPS_R_V1); -+ return 0; -+} -+ -+/* Function tail call */ -+static int emit_tail_call(struct jit_context *ctx) -+{ -+ u8 ary = bpf2mips64[BPF_REG_2]; -+ u8 ind = bpf2mips64[BPF_REG_3]; -+ u8 tcc = bpf2mips64[JIT_REG_TC]; -+ u8 tmp = MIPS_R_T6; -+ int off; -+ -+ /* -+ * Tail call: -+ * eBPF R1 - function argument (context ptr), passed in a0-a1 -+ * eBPF R2 - ptr to object with array of function entry points -+ * eBPF R3 - array index of function to be called -+ */ -+ -+ /* if (ind >= ary->map.max_entries) goto out */ -+ off = offsetof(struct bpf_array, map.max_entries); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, lwu, tmp, off, ary); /* tmp = ary->map.max_entrs*/ -+ emit(ctx, sltu, tmp, ind, tmp); /* tmp = ind < t1 */ -+ emit(ctx, beqz, tmp, get_offset(ctx, 1)); /* PC += off(1) if tmp == 0*/ -+ -+ /* if (--TCC < 0) goto out */ -+ emit(ctx, daddiu, tcc, tcc, -1); /* tcc-- (delay slot) */ -+ emit(ctx, bltz, tcc, get_offset(ctx, 1)); /* PC += off(1) if tcc < 0 */ -+ /* (next insn delay slot) */ -+ /* prog = ary->ptrs[ind] */ -+ off = offsetof(struct bpf_array, ptrs); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, dsll, tmp, ind, 3); /* tmp = ind << 3 */ -+ emit(ctx, daddu, tmp, tmp, ary); /* tmp += ary */ -+ emit(ctx, ld, tmp, off, tmp); /* tmp = *(tmp + off) */ -+ -+ /* if (prog == 0) goto out */ -+ emit(ctx, beqz, tmp, get_offset(ctx, 1)); /* PC += off(1) if tmp == 0*/ -+ emit(ctx, nop); /* Delay slot */ -+ -+ /* func = prog->bpf_func + 8 (prologue skip offset) */ -+ off = offsetof(struct bpf_prog, bpf_func); -+ if (off > 0x7fff) -+ return -1; -+ emit(ctx, ld, tmp, off, tmp); /* tmp = *(tmp + off) */ -+ emit(ctx, daddiu, tmp, tmp, JIT_TCALL_SKIP); /* tmp += skip (4) */ -+ -+ /* goto func */ -+ build_epilogue(ctx, tmp); -+ access_reg(ctx, JIT_REG_TC); -+ return 0; -+} -+ -+/* -+ * Stack frame layout for a JITed program (stack grows down). -+ * -+ * Higher address : Previous stack frame : -+ * +===========================+ <--- MIPS sp before call -+ * | Callee-saved registers, | -+ * | including RA and FP | -+ * +---------------------------+ <--- eBPF FP (MIPS fp) -+ * | Local eBPF variables | -+ * | allocated by program | -+ * +---------------------------+ -+ * | Reserved for caller-saved | -+ * | registers | -+ * Lower address +===========================+ <--- MIPS sp -+ */ -+ -+/* Build program prologue to set up the stack and registers */ -+void build_prologue(struct jit_context *ctx) -+{ -+ u8 fp = bpf2mips64[BPF_REG_FP]; -+ u8 tc = bpf2mips64[JIT_REG_TC]; -+ u8 zx = bpf2mips64[JIT_REG_ZX]; -+ int stack, saved, locals, reserved; -+ -+ /* -+ * The first instruction initializes the tail call count register. -+ * On a tail call, the calling function jumps into the prologue -+ * after this instruction. -+ */ -+ emit(ctx, addiu, tc, MIPS_R_ZERO, min(MAX_TAIL_CALL_CNT + 1, 0xffff)); -+ -+ /* === Entry-point for tail calls === */ -+ -+ /* -+ * If the eBPF frame pointer and tail call count registers were -+ * accessed they must be preserved. Mark them as clobbered here -+ * to save and restore them on the stack as needed. -+ */ -+ if (ctx->accessed & BIT(BPF_REG_FP)) -+ clobber_reg(ctx, fp); -+ if (ctx->accessed & BIT(JIT_REG_TC)) -+ clobber_reg(ctx, tc); -+ if (ctx->accessed & BIT(JIT_REG_ZX)) -+ clobber_reg(ctx, zx); -+ -+ /* Compute the stack space needed for callee-saved registers */ -+ saved = hweight32(ctx->clobbered & JIT_CALLEE_REGS) * sizeof(u64); -+ saved = ALIGN(saved, MIPS_STACK_ALIGNMENT); -+ -+ /* Stack space used by eBPF program local data */ -+ locals = ALIGN(ctx->program->aux->stack_depth, MIPS_STACK_ALIGNMENT); -+ -+ /* -+ * If we are emitting function calls, reserve extra stack space for -+ * caller-saved registers needed by the JIT. The required space is -+ * computed automatically during resource usage discovery (pass 1). -+ */ -+ reserved = ctx->stack_used; -+ -+ /* Allocate the stack frame */ -+ stack = ALIGN(saved + locals + reserved, MIPS_STACK_ALIGNMENT); -+ if (stack) -+ emit(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, -stack); -+ -+ /* Store callee-saved registers on stack */ -+ push_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, stack - saved); -+ -+ /* Initialize the eBPF frame pointer if accessed */ -+ if (ctx->accessed & BIT(BPF_REG_FP)) -+ emit(ctx, daddiu, fp, MIPS_R_SP, stack - saved); -+ -+ /* Initialize the ePF JIT zero-extension register if accessed */ -+ if (ctx->accessed & BIT(JIT_REG_ZX)) { -+ emit(ctx, daddiu, zx, MIPS_R_ZERO, -1); -+ emit(ctx, dsrl32, zx, zx, 0); -+ } -+ -+ ctx->saved_size = saved; -+ ctx->stack_size = stack; -+} -+ -+/* Build the program epilogue to restore the stack and registers */ -+void build_epilogue(struct jit_context *ctx, int dest_reg) -+{ -+ /* Restore callee-saved registers from stack */ -+ pop_regs(ctx, ctx->clobbered & JIT_CALLEE_REGS, 0, -+ ctx->stack_size - ctx->saved_size); -+ -+ /* Release the stack frame */ -+ if (ctx->stack_size) -+ emit(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, ctx->stack_size); -+ -+ /* Jump to return address and sign-extend the 32-bit return value */ -+ emit(ctx, jr, dest_reg); -+ emit(ctx, sll, MIPS_R_V0, MIPS_R_V0, 0); /* Delay slot */ -+} -+ -+/* Build one eBPF instruction */ -+int build_insn(const struct bpf_insn *insn, struct jit_context *ctx) -+{ -+ u8 dst = bpf2mips64[insn->dst_reg]; -+ u8 src = bpf2mips64[insn->src_reg]; -+ u8 code = insn->code; -+ s16 off = insn->off; -+ s32 imm = insn->imm; -+ s32 val, rel; -+ u8 alu, jmp; -+ -+ switch (code) { -+ /* ALU operations */ -+ /* dst = imm */ -+ case BPF_ALU | BPF_MOV | BPF_K: -+ emit_mov_i(ctx, dst, imm); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = src */ -+ case BPF_ALU | BPF_MOV | BPF_X: -+ if (imm == 1) { -+ /* Special mov32 for zext */ -+ emit_zext(ctx, dst); -+ } else { -+ emit_mov_r(ctx, dst, src); -+ emit_zext_ver(ctx, dst); -+ } -+ break; -+ /* dst = -dst */ -+ case BPF_ALU | BPF_NEG: -+ emit_sext(ctx, dst, dst); -+ emit_alu_i(ctx, dst, 0, BPF_NEG); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst & imm */ -+ /* dst = dst | imm */ -+ /* dst = dst ^ imm */ -+ /* dst = dst << imm */ -+ case BPF_ALU | BPF_OR | BPF_K: -+ case BPF_ALU | BPF_AND | BPF_K: -+ case BPF_ALU | BPF_XOR | BPF_K: -+ case BPF_ALU | BPF_LSH | BPF_K: -+ if (!valid_alu_i(BPF_OP(code), imm)) { -+ emit_mov_i(ctx, MIPS_R_T4, imm); -+ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); -+ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { -+ emit_alu_i(ctx, dst, val, alu); -+ } -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst >> imm */ -+ /* dst = dst >> imm (arithmetic) */ -+ /* dst = dst + imm */ -+ /* dst = dst - imm */ -+ /* dst = dst * imm */ -+ /* dst = dst / imm */ -+ /* dst = dst % imm */ -+ case BPF_ALU | BPF_RSH | BPF_K: -+ case BPF_ALU | BPF_ARSH | BPF_K: -+ case BPF_ALU | BPF_ADD | BPF_K: -+ case BPF_ALU | BPF_SUB | BPF_K: -+ case BPF_ALU | BPF_MUL | BPF_K: -+ case BPF_ALU | BPF_DIV | BPF_K: -+ case BPF_ALU | BPF_MOD | BPF_K: -+ if (!valid_alu_i(BPF_OP(code), imm)) { -+ emit_sext(ctx, dst, dst); -+ emit_mov_i(ctx, MIPS_R_T4, imm); -+ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); -+ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { -+ emit_sext(ctx, dst, dst); -+ emit_alu_i(ctx, dst, val, alu); -+ } -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst & src */ -+ /* dst = dst | src */ -+ /* dst = dst ^ src */ -+ /* dst = dst << src */ -+ case BPF_ALU | BPF_AND | BPF_X: -+ case BPF_ALU | BPF_OR | BPF_X: -+ case BPF_ALU | BPF_XOR | BPF_X: -+ case BPF_ALU | BPF_LSH | BPF_X: -+ emit_alu_r(ctx, dst, src, BPF_OP(code)); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = dst >> src */ -+ /* dst = dst >> src (arithmetic) */ -+ /* dst = dst + src */ -+ /* dst = dst - src */ -+ /* dst = dst * src */ -+ /* dst = dst / src */ -+ /* dst = dst % src */ -+ case BPF_ALU | BPF_RSH | BPF_X: -+ case BPF_ALU | BPF_ARSH | BPF_X: -+ case BPF_ALU | BPF_ADD | BPF_X: -+ case BPF_ALU | BPF_SUB | BPF_X: -+ case BPF_ALU | BPF_MUL | BPF_X: -+ case BPF_ALU | BPF_DIV | BPF_X: -+ case BPF_ALU | BPF_MOD | BPF_X: -+ emit_sext(ctx, dst, dst); -+ emit_sext(ctx, MIPS_R_T4, src); -+ emit_alu_r(ctx, dst, MIPS_R_T4, BPF_OP(code)); -+ emit_zext_ver(ctx, dst); -+ break; -+ /* dst = imm (64-bit) */ -+ case BPF_ALU64 | BPF_MOV | BPF_K: -+ emit_mov_i(ctx, dst, imm); -+ break; -+ /* dst = src (64-bit) */ -+ case BPF_ALU64 | BPF_MOV | BPF_X: -+ emit_mov_r(ctx, dst, src); -+ break; -+ /* dst = -dst (64-bit) */ -+ case BPF_ALU64 | BPF_NEG: -+ emit_alu_i64(ctx, dst, 0, BPF_NEG); -+ break; -+ /* dst = dst & imm (64-bit) */ -+ /* dst = dst | imm (64-bit) */ -+ /* dst = dst ^ imm (64-bit) */ -+ /* dst = dst << imm (64-bit) */ -+ /* dst = dst >> imm (64-bit) */ -+ /* dst = dst >> imm ((64-bit, arithmetic) */ -+ /* dst = dst + imm (64-bit) */ -+ /* dst = dst - imm (64-bit) */ -+ /* dst = dst * imm (64-bit) */ -+ /* dst = dst / imm (64-bit) */ -+ /* dst = dst % imm (64-bit) */ -+ case BPF_ALU64 | BPF_AND | BPF_K: -+ case BPF_ALU64 | BPF_OR | BPF_K: -+ case BPF_ALU64 | BPF_XOR | BPF_K: -+ case BPF_ALU64 | BPF_LSH | BPF_K: -+ case BPF_ALU64 | BPF_RSH | BPF_K: -+ case BPF_ALU64 | BPF_ARSH | BPF_K: -+ case BPF_ALU64 | BPF_ADD | BPF_K: -+ case BPF_ALU64 | BPF_SUB | BPF_K: -+ case BPF_ALU64 | BPF_MUL | BPF_K: -+ case BPF_ALU64 | BPF_DIV | BPF_K: -+ case BPF_ALU64 | BPF_MOD | BPF_K: -+ if (!valid_alu_i(BPF_OP(code), imm)) { -+ emit_mov_i(ctx, MIPS_R_T4, imm); -+ emit_alu_r64(ctx, dst, MIPS_R_T4, BPF_OP(code)); -+ } else if (rewrite_alu_i(BPF_OP(code), imm, &alu, &val)) { -+ emit_alu_i64(ctx, dst, val, alu); -+ } -+ break; -+ /* dst = dst & src (64-bit) */ -+ /* dst = dst | src (64-bit) */ -+ /* dst = dst ^ src (64-bit) */ -+ /* dst = dst << src (64-bit) */ -+ /* dst = dst >> src (64-bit) */ -+ /* dst = dst >> src (64-bit, arithmetic) */ -+ /* dst = dst + src (64-bit) */ -+ /* dst = dst - src (64-bit) */ -+ /* dst = dst * src (64-bit) */ -+ /* dst = dst / src (64-bit) */ -+ /* dst = dst % src (64-bit) */ -+ case BPF_ALU64 | BPF_AND | BPF_X: -+ case BPF_ALU64 | BPF_OR | BPF_X: -+ case BPF_ALU64 | BPF_XOR | BPF_X: -+ case BPF_ALU64 | BPF_LSH | BPF_X: -+ case BPF_ALU64 | BPF_RSH | BPF_X: -+ case BPF_ALU64 | BPF_ARSH | BPF_X: -+ case BPF_ALU64 | BPF_ADD | BPF_X: -+ case BPF_ALU64 | BPF_SUB | BPF_X: -+ case BPF_ALU64 | BPF_MUL | BPF_X: -+ case BPF_ALU64 | BPF_DIV | BPF_X: -+ case BPF_ALU64 | BPF_MOD | BPF_X: -+ emit_alu_r64(ctx, dst, src, BPF_OP(code)); -+ break; -+ /* dst = htole(dst) */ -+ /* dst = htobe(dst) */ -+ case BPF_ALU | BPF_END | BPF_FROM_LE: -+ case BPF_ALU | BPF_END | BPF_FROM_BE: -+ if (BPF_SRC(code) == -+#ifdef __BIG_ENDIAN -+ BPF_FROM_LE -+#else -+ BPF_FROM_BE -+#endif -+ ) -+ emit_bswap_r64(ctx, dst, imm); -+ else -+ emit_trunc_r64(ctx, dst, imm); -+ break; -+ /* dst = imm64 */ -+ case BPF_LD | BPF_IMM | BPF_DW: -+ emit_mov_i64(ctx, dst, (u32)imm | ((u64)insn[1].imm << 32)); -+ return 1; -+ /* LDX: dst = *(size *)(src + off) */ -+ case BPF_LDX | BPF_MEM | BPF_W: -+ case BPF_LDX | BPF_MEM | BPF_H: -+ case BPF_LDX | BPF_MEM | BPF_B: -+ case BPF_LDX | BPF_MEM | BPF_DW: -+ emit_ldx(ctx, dst, src, off, BPF_SIZE(code)); -+ break; -+ /* ST: *(size *)(dst + off) = imm */ -+ case BPF_ST | BPF_MEM | BPF_W: -+ case BPF_ST | BPF_MEM | BPF_H: -+ case BPF_ST | BPF_MEM | BPF_B: -+ case BPF_ST | BPF_MEM | BPF_DW: -+ emit_mov_i(ctx, MIPS_R_T4, imm); -+ emit_stx(ctx, dst, MIPS_R_T4, off, BPF_SIZE(code)); -+ break; -+ /* STX: *(size *)(dst + off) = src */ -+ case BPF_STX | BPF_MEM | BPF_W: -+ case BPF_STX | BPF_MEM | BPF_H: -+ case BPF_STX | BPF_MEM | BPF_B: -+ case BPF_STX | BPF_MEM | BPF_DW: -+ emit_stx(ctx, dst, src, off, BPF_SIZE(code)); -+ break; -+ /* Speculation barrier */ -+ case BPF_ST | BPF_NOSPEC: -+ break; -+ /* Atomics */ -+ case BPF_STX | BPF_XADD | BPF_W: -+ case BPF_STX | BPF_XADD | BPF_DW: -+ switch (imm) { -+ case BPF_ADD: -+ case BPF_AND: -+ case BPF_OR: -+ case BPF_XOR: -+ if (BPF_SIZE(code) == BPF_DW) { -+ emit_atomic_r64(ctx, dst, src, off, imm); -+ } else { /* 32-bit, no fetch */ -+ emit_sext(ctx, MIPS_R_T4, src); -+ emit_atomic_r(ctx, dst, MIPS_R_T4, off, imm); -+ } -+ break; -+ default: -+ goto notyet; -+ } -+ break; -+ /* PC += off if dst == src */ -+ /* PC += off if dst != src */ -+ /* PC += off if dst & src */ -+ /* PC += off if dst > src */ -+ /* PC += off if dst >= src */ -+ /* PC += off if dst < src */ -+ /* PC += off if dst <= src */ -+ /* PC += off if dst > src (signed) */ -+ /* PC += off if dst >= src (signed) */ -+ /* PC += off if dst < src (signed) */ -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JMP32 | BPF_JEQ | BPF_X: -+ case BPF_JMP32 | BPF_JNE | BPF_X: -+ case BPF_JMP32 | BPF_JSET | BPF_X: -+ case BPF_JMP32 | BPF_JGT | BPF_X: -+ case BPF_JMP32 | BPF_JGE | BPF_X: -+ case BPF_JMP32 | BPF_JLT | BPF_X: -+ case BPF_JMP32 | BPF_JLE | BPF_X: -+ case BPF_JMP32 | BPF_JSGT | BPF_X: -+ case BPF_JMP32 | BPF_JSGE | BPF_X: -+ case BPF_JMP32 | BPF_JSLT | BPF_X: -+ case BPF_JMP32 | BPF_JSLE | BPF_X: -+ if (off == 0) -+ break; -+ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); -+ emit_sext(ctx, MIPS_R_T4, dst); /* Sign-extended dst */ -+ emit_sext(ctx, MIPS_R_T5, src); /* Sign-extended src */ -+ emit_jmp_r(ctx, MIPS_R_T4, MIPS_R_T5, rel, jmp); -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == imm */ -+ /* PC += off if dst != imm */ -+ /* PC += off if dst & imm */ -+ /* PC += off if dst > imm */ -+ /* PC += off if dst >= imm */ -+ /* PC += off if dst < imm */ -+ /* PC += off if dst <= imm */ -+ /* PC += off if dst > imm (signed) */ -+ /* PC += off if dst >= imm (signed) */ -+ /* PC += off if dst < imm (signed) */ -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JMP32 | BPF_JEQ | BPF_K: -+ case BPF_JMP32 | BPF_JNE | BPF_K: -+ case BPF_JMP32 | BPF_JSET | BPF_K: -+ case BPF_JMP32 | BPF_JGT | BPF_K: -+ case BPF_JMP32 | BPF_JGE | BPF_K: -+ case BPF_JMP32 | BPF_JLT | BPF_K: -+ case BPF_JMP32 | BPF_JLE | BPF_K: -+ case BPF_JMP32 | BPF_JSGT | BPF_K: -+ case BPF_JMP32 | BPF_JSGE | BPF_K: -+ case BPF_JMP32 | BPF_JSLT | BPF_K: -+ case BPF_JMP32 | BPF_JSLE | BPF_K: -+ if (off == 0) -+ break; -+ setup_jmp_i(ctx, imm, 32, BPF_OP(code), off, &jmp, &rel); -+ emit_sext(ctx, MIPS_R_T4, dst); /* Sign-extended dst */ -+ if (valid_jmp_i(jmp, imm)) { -+ emit_jmp_i(ctx, MIPS_R_T4, imm, rel, jmp); -+ } else { -+ /* Move large immediate to register, sign-extended */ -+ emit_mov_i(ctx, MIPS_R_T5, imm); -+ emit_jmp_r(ctx, MIPS_R_T4, MIPS_R_T5, rel, jmp); -+ } -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == src */ -+ /* PC += off if dst != src */ -+ /* PC += off if dst & src */ -+ /* PC += off if dst > src */ -+ /* PC += off if dst >= src */ -+ /* PC += off if dst < src */ -+ /* PC += off if dst <= src */ -+ /* PC += off if dst > src (signed) */ -+ /* PC += off if dst >= src (signed) */ -+ /* PC += off if dst < src (signed) */ -+ /* PC += off if dst <= src (signed) */ -+ case BPF_JMP | BPF_JEQ | BPF_X: -+ case BPF_JMP | BPF_JNE | BPF_X: -+ case BPF_JMP | BPF_JSET | BPF_X: -+ case BPF_JMP | BPF_JGT | BPF_X: -+ case BPF_JMP | BPF_JGE | BPF_X: -+ case BPF_JMP | BPF_JLT | BPF_X: -+ case BPF_JMP | BPF_JLE | BPF_X: -+ case BPF_JMP | BPF_JSGT | BPF_X: -+ case BPF_JMP | BPF_JSGE | BPF_X: -+ case BPF_JMP | BPF_JSLT | BPF_X: -+ case BPF_JMP | BPF_JSLE | BPF_X: -+ if (off == 0) -+ break; -+ setup_jmp_r(ctx, dst == src, BPF_OP(code), off, &jmp, &rel); -+ emit_jmp_r(ctx, dst, src, rel, jmp); -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off if dst == imm */ -+ /* PC += off if dst != imm */ -+ /* PC += off if dst & imm */ -+ /* PC += off if dst > imm */ -+ /* PC += off if dst >= imm */ -+ /* PC += off if dst < imm */ -+ /* PC += off if dst <= imm */ -+ /* PC += off if dst > imm (signed) */ -+ /* PC += off if dst >= imm (signed) */ -+ /* PC += off if dst < imm (signed) */ -+ /* PC += off if dst <= imm (signed) */ -+ case BPF_JMP | BPF_JEQ | BPF_K: -+ case BPF_JMP | BPF_JNE | BPF_K: -+ case BPF_JMP | BPF_JSET | BPF_K: -+ case BPF_JMP | BPF_JGT | BPF_K: -+ case BPF_JMP | BPF_JGE | BPF_K: -+ case BPF_JMP | BPF_JLT | BPF_K: -+ case BPF_JMP | BPF_JLE | BPF_K: -+ case BPF_JMP | BPF_JSGT | BPF_K: -+ case BPF_JMP | BPF_JSGE | BPF_K: -+ case BPF_JMP | BPF_JSLT | BPF_K: -+ case BPF_JMP | BPF_JSLE | BPF_K: -+ if (off == 0) -+ break; -+ setup_jmp_i(ctx, imm, 64, BPF_OP(code), off, &jmp, &rel); -+ if (valid_jmp_i(jmp, imm)) { -+ emit_jmp_i(ctx, dst, imm, rel, jmp); -+ } else { -+ /* Move large immediate to register */ -+ emit_mov_i(ctx, MIPS_R_T4, imm); -+ emit_jmp_r(ctx, dst, MIPS_R_T4, rel, jmp); -+ } -+ if (finish_jmp(ctx, jmp, off) < 0) -+ goto toofar; -+ break; -+ /* PC += off */ -+ case BPF_JMP | BPF_JA: -+ if (off == 0) -+ break; -+ if (emit_ja(ctx, off) < 0) -+ goto toofar; -+ break; -+ /* Tail call */ -+ case BPF_JMP | BPF_TAIL_CALL: -+ if (emit_tail_call(ctx) < 0) -+ goto invalid; -+ break; -+ /* Function call */ -+ case BPF_JMP | BPF_CALL: -+ if (emit_call(ctx, insn) < 0) -+ goto invalid; -+ break; -+ /* Function return */ -+ case BPF_JMP | BPF_EXIT: -+ /* -+ * Optimization: when last instruction is EXIT -+ * simply continue to epilogue. -+ */ -+ if (ctx->bpf_index == ctx->program->len - 1) -+ break; -+ if (emit_exit(ctx) < 0) -+ goto toofar; -+ break; -+ -+ default: -+invalid: -+ pr_err_once("unknown opcode %02x\n", code); -+ return -EINVAL; -+notyet: -+ pr_info_once("*** NOT YET: opcode %02x ***\n", code); -+ return -EFAULT; -+toofar: -+ pr_info_once("*** TOO FAR: jump at %u opcode %02x ***\n", -+ ctx->bpf_index, code); -+ return -E2BIG; -+ } -+ return 0; -+} diff --git a/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch b/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch deleted file mode 100644 index 63553ebe584..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-04-mips-bpf-Add-JIT-workarounds-for-CPU-errata.patch +++ /dev/null @@ -1,120 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:06 +0200 -Subject: [PATCH] mips: bpf: Add JIT workarounds for CPU errata - -This patch adds workarounds for the following CPU errata to the MIPS -eBPF JIT, if enabled in the kernel configuration. - - - R10000 ll/sc weak ordering - - Loongson-3 ll/sc weak ordering - - Loongson-2F jump hang - -The Loongson-2F nop errata is implemented in uasm, which the JIT uses, -so no additional mitigations are needed for that. - -Signed-off-by: Johan Almbladh -Reviewed-by: Jiaxun Yang ---- - ---- a/arch/mips/net/bpf_jit_comp.c -+++ b/arch/mips/net/bpf_jit_comp.c -@@ -404,6 +404,7 @@ void emit_alu_r(struct jit_context *ctx, - /* Atomic read-modify-write (32-bit) */ - void emit_atomic_r(struct jit_context *ctx, u8 dst, u8 src, s16 off, u8 code) - { -+ LLSC_sync(ctx); - emit(ctx, ll, MIPS_R_T9, off, dst); - switch (code) { - case BPF_ADD: -@@ -420,18 +421,19 @@ void emit_atomic_r(struct jit_context *c - break; - } - emit(ctx, sc, MIPS_R_T8, off, dst); -- emit(ctx, beqz, MIPS_R_T8, -16); -+ emit(ctx, LLSC_beqz, MIPS_R_T8, -16 - LLSC_offset); - emit(ctx, nop); /* Delay slot */ - } - - /* Atomic compare-and-exchange (32-bit) */ - void emit_cmpxchg_r(struct jit_context *ctx, u8 dst, u8 src, u8 res, s16 off) - { -+ LLSC_sync(ctx); - emit(ctx, ll, MIPS_R_T9, off, dst); - emit(ctx, bne, MIPS_R_T9, res, 12); - emit(ctx, move, MIPS_R_T8, src); /* Delay slot */ - emit(ctx, sc, MIPS_R_T8, off, dst); -- emit(ctx, beqz, MIPS_R_T8, -20); -+ emit(ctx, LLSC_beqz, MIPS_R_T8, -20 - LLSC_offset); - emit(ctx, move, res, MIPS_R_T9); /* Delay slot */ - clobber_reg(ctx, res); - } ---- a/arch/mips/net/bpf_jit_comp.h -+++ b/arch/mips/net/bpf_jit_comp.h -@@ -87,7 +87,7 @@ struct jit_context { - }; - - /* Emit the instruction if the JIT memory space has been allocated */ --#define emit(ctx, func, ...) \ -+#define __emit(ctx, func, ...) \ - do { \ - if ((ctx)->target != NULL) { \ - u32 *p = &(ctx)->target[ctx->jit_index]; \ -@@ -95,6 +95,30 @@ do { \ - } \ - (ctx)->jit_index++; \ - } while (0) -+#define emit(...) __emit(__VA_ARGS__) -+ -+/* Workaround for R10000 ll/sc errata */ -+#ifdef CONFIG_WAR_R10000 -+#define LLSC_beqz beqzl -+#else -+#define LLSC_beqz beqz -+#endif -+ -+/* Workaround for Loongson-3 ll/sc errata */ -+#ifdef CONFIG_CPU_LOONGSON3_WORKAROUNDS -+#define LLSC_sync(ctx) emit(ctx, sync, 0) -+#define LLSC_offset 4 -+#else -+#define LLSC_sync(ctx) -+#define LLSC_offset 0 -+#endif -+ -+/* Workaround for Loongson-2F jump errata */ -+#ifdef CONFIG_CPU_JUMP_WORKAROUNDS -+#define JALR_MASK 0xffffffffcfffffffULL -+#else -+#define JALR_MASK (~0ULL) -+#endif - - /* - * Mark a BPF register as accessed, it needs to be ---- a/arch/mips/net/bpf_jit_comp64.c -+++ b/arch/mips/net/bpf_jit_comp64.c -@@ -375,6 +375,7 @@ static void emit_atomic_r64(struct jit_c - u8 t1 = MIPS_R_T6; - u8 t2 = MIPS_R_T7; - -+ LLSC_sync(ctx); - emit(ctx, lld, t1, off, dst); - switch (code) { - case BPF_ADD: -@@ -391,7 +392,7 @@ static void emit_atomic_r64(struct jit_c - break; - } - emit(ctx, scd, t2, off, dst); -- emit(ctx, beqz, t2, -16); -+ emit(ctx, LLSC_beqz, t2, -16 - LLSC_offset); - emit(ctx, nop); /* Delay slot */ - } - -@@ -414,7 +415,7 @@ static int emit_call(struct jit_context - push_regs(ctx, ctx->clobbered & JIT_CALLER_REGS, 0, 0); - - /* Emit function call */ -- emit_mov_i64(ctx, tmp, addr); -+ emit_mov_i64(ctx, tmp, addr & JALR_MASK); - emit(ctx, jalr, MIPS_R_RA, tmp); - emit(ctx, nop); /* Delay slot */ - diff --git a/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch b/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch deleted file mode 100644 index 14763c1211e..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-05-mips-bpf-Enable-eBPF-JITs.patch +++ /dev/null @@ -1,61 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:07 +0200 -Subject: [PATCH] mips: bpf: Enable eBPF JITs - -This patch enables the new eBPF JITs for 32-bit and 64-bit MIPS. It also -disables the old cBPF JIT to so cBPF programs are converted to use the -new JIT. - -Workarounds for R4000 CPU errata are not implemented by the JIT, so the -JIT is disabled if any of those workarounds are configured. - -Signed-off-by: Johan Almbladh ---- - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -3431,6 +3431,7 @@ S: Supported - F: arch/arm64/net/ - - BPF JIT for MIPS (32-BIT AND 64-BIT) -+M: Johan Almbladh - M: Paul Burton - L: netdev@vger.kernel.org - L: bpf@vger.kernel.org ---- a/arch/mips/Kconfig -+++ b/arch/mips/Kconfig -@@ -57,7 +57,6 @@ config MIPS - select HAVE_ARCH_TRACEHOOK - select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES - select HAVE_ASM_MODVERSIONS -- select HAVE_CBPF_JIT if !64BIT && !CPU_MICROMIPS - select HAVE_CONTEXT_TRACKING - select HAVE_TIF_NOHZ - select HAVE_C_RECORDMCOUNT -@@ -65,7 +64,10 @@ config MIPS - select HAVE_DEBUG_STACKOVERFLOW - select HAVE_DMA_CONTIGUOUS - select HAVE_DYNAMIC_FTRACE -- select HAVE_EBPF_JIT if 64BIT && !CPU_MICROMIPS && TARGET_ISA_REV >= 2 -+ select HAVE_EBPF_JIT if !CPU_MICROMIPS && \ -+ !CPU_DADDI_WORKAROUNDS && \ -+ !CPU_R4000_WORKAROUNDS && \ -+ !CPU_R4400_WORKAROUNDS - select HAVE_EXIT_THREAD - select HAVE_FAST_GUP - select HAVE_FTRACE_MCOUNT_RECORD ---- a/arch/mips/net/Makefile -+++ b/arch/mips/net/Makefile -@@ -2,9 +2,10 @@ - # MIPS networking code - - obj-$(CONFIG_MIPS_CBPF_JIT) += bpf_jit.o bpf_jit_asm.o -+obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o - - ifeq ($(CONFIG_32BIT),y) -- obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp.o bpf_jit_comp32.o -+ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp32.o - else -- obj-$(CONFIG_MIPS_EBPF_JIT) += ebpf_jit.o -+ obj-$(CONFIG_MIPS_EBPF_JIT) += bpf_jit_comp64.o - endif diff --git a/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch b/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch deleted file mode 100644 index e25c336831d..00000000000 --- a/target/linux/generic/backport-6.1/050-v5.16-06-mips-bpf-Remove-old-BPF-JIT-implementations.patch +++ /dev/null @@ -1,387 +0,0 @@ -From: Johan Almbladh -Date: Tue, 5 Oct 2021 18:54:08 +0200 -Subject: [PATCH] mips: bpf: Remove old BPF JIT implementations - -This patch removes the old 32-bit cBPF and 64-bit eBPF JIT implementations. -They are replaced by a new eBPF implementation that supports both 32-bit -and 64-bit MIPS CPUs. - -Signed-off-by: Johan Almbladh ---- - delete mode 100644 arch/mips/net/bpf_jit.c - delete mode 100644 arch/mips/net/bpf_jit.h - delete mode 100644 arch/mips/net/bpf_jit_asm.S - delete mode 100644 arch/mips/net/ebpf_jit.c - ---- a/arch/mips/net/bpf_jit.h -+++ /dev/null -@@ -1,81 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ --/* -- * Just-In-Time compiler for BPF filters on MIPS -- * -- * Copyright (c) 2014 Imagination Technologies Ltd. -- * Author: Markos Chandras -- */ -- --#ifndef BPF_JIT_MIPS_OP_H --#define BPF_JIT_MIPS_OP_H -- --/* Registers used by JIT */ --#define MIPS_R_ZERO 0 --#define MIPS_R_V0 2 --#define MIPS_R_A0 4 --#define MIPS_R_A1 5 --#define MIPS_R_T4 12 --#define MIPS_R_T5 13 --#define MIPS_R_T6 14 --#define MIPS_R_T7 15 --#define MIPS_R_S0 16 --#define MIPS_R_S1 17 --#define MIPS_R_S2 18 --#define MIPS_R_S3 19 --#define MIPS_R_S4 20 --#define MIPS_R_S5 21 --#define MIPS_R_S6 22 --#define MIPS_R_S7 23 --#define MIPS_R_SP 29 --#define MIPS_R_RA 31 -- --/* Conditional codes */ --#define MIPS_COND_EQ 0x1 --#define MIPS_COND_GE (0x1 << 1) --#define MIPS_COND_GT (0x1 << 2) --#define MIPS_COND_NE (0x1 << 3) --#define MIPS_COND_ALL (0x1 << 4) --/* Conditionals on X register or K immediate */ --#define MIPS_COND_X (0x1 << 5) --#define MIPS_COND_K (0x1 << 6) -- --#define r_ret MIPS_R_V0 -- --/* -- * Use 2 scratch registers to avoid pipeline interlocks. -- * There is no overhead during epilogue and prologue since -- * any of the $s0-$s6 registers will only be preserved if -- * they are going to actually be used. -- */ --#define r_skb_hl MIPS_R_S0 /* skb header length */ --#define r_skb_data MIPS_R_S1 /* skb actual data */ --#define r_off MIPS_R_S2 --#define r_A MIPS_R_S3 --#define r_X MIPS_R_S4 --#define r_skb MIPS_R_S5 --#define r_M MIPS_R_S6 --#define r_skb_len MIPS_R_S7 --#define r_s0 MIPS_R_T4 /* scratch reg 1 */ --#define r_s1 MIPS_R_T5 /* scratch reg 2 */ --#define r_tmp_imm MIPS_R_T6 /* No need to preserve this */ --#define r_tmp MIPS_R_T7 /* No need to preserve this */ --#define r_zero MIPS_R_ZERO --#define r_sp MIPS_R_SP --#define r_ra MIPS_R_RA -- --#ifndef __ASSEMBLY__ -- --/* Declare ASM helpers */ -- --#define DECLARE_LOAD_FUNC(func) \ -- extern u8 func(unsigned long *skb, int offset); \ -- extern u8 func##_negative(unsigned long *skb, int offset); \ -- extern u8 func##_positive(unsigned long *skb, int offset) -- --DECLARE_LOAD_FUNC(sk_load_word); --DECLARE_LOAD_FUNC(sk_load_half); --DECLARE_LOAD_FUNC(sk_load_byte); -- --#endif -- --#endif /* BPF_JIT_MIPS_OP_H */ ---- a/arch/mips/net/bpf_jit_asm.S -+++ /dev/null -@@ -1,285 +0,0 @@ --/* -- * bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF -- * compiler. -- * -- * Copyright (C) 2015 Imagination Technologies Ltd. -- * Author: Markos Chandras -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; version 2 of the License. -- */ -- --#include --#include --#include --#include "bpf_jit.h" -- --/* ABI -- * -- * r_skb_hl skb header length -- * r_skb_data skb data -- * r_off(a1) offset register -- * r_A BPF register A -- * r_X PF register X -- * r_skb(a0) *skb -- * r_M *scratch memory -- * r_skb_le skb length -- * r_s0 Scratch register 0 -- * r_s1 Scratch register 1 -- * -- * On entry: -- * a0: *skb -- * a1: offset (imm or imm + X) -- * -- * All non-BPF-ABI registers are free for use. On return, we only -- * care about r_ret. The BPF-ABI registers are assumed to remain -- * unmodified during the entire filter operation. -- */ -- --#define skb a0 --#define offset a1 --#define SKF_LL_OFF (-0x200000) /* Can't include linux/filter.h in assembly */ -- -- /* We know better :) so prevent assembler reordering etc */ -- .set noreorder -- --#define is_offset_negative(TYPE) \ -- /* If offset is negative we have more work to do */ \ -- slti t0, offset, 0; \ -- bgtz t0, bpf_slow_path_##TYPE##_neg; \ -- /* Be careful what follows in DS. */ -- --#define is_offset_in_header(SIZE, TYPE) \ -- /* Reading from header? */ \ -- addiu $r_s0, $r_skb_hl, -SIZE; \ -- slt t0, $r_s0, offset; \ -- bgtz t0, bpf_slow_path_##TYPE; \ -- --LEAF(sk_load_word) -- is_offset_negative(word) --FEXPORT(sk_load_word_positive) -- is_offset_in_header(4, word) -- /* Offset within header boundaries */ -- PTR_ADDU t1, $r_skb_data, offset -- .set reorder -- lw $r_A, 0(t1) -- .set noreorder --#ifdef CONFIG_CPU_LITTLE_ENDIAN --# if MIPS_ISA_REV >= 2 -- wsbh t0, $r_A -- rotr $r_A, t0, 16 --# else -- sll t0, $r_A, 24 -- srl t1, $r_A, 24 -- srl t2, $r_A, 8 -- or t0, t0, t1 -- andi t2, t2, 0xff00 -- andi t1, $r_A, 0xff00 -- or t0, t0, t2 -- sll t1, t1, 8 -- or $r_A, t0, t1 --# endif --#endif -- jr $r_ra -- move $r_ret, zero -- END(sk_load_word) -- --LEAF(sk_load_half) -- is_offset_negative(half) --FEXPORT(sk_load_half_positive) -- is_offset_in_header(2, half) -- /* Offset within header boundaries */ -- PTR_ADDU t1, $r_skb_data, offset -- lhu $r_A, 0(t1) --#ifdef CONFIG_CPU_LITTLE_ENDIAN --# if MIPS_ISA_REV >= 2 -- wsbh $r_A, $r_A --# else -- sll t0, $r_A, 8 -- srl t1, $r_A, 8 -- andi t0, t0, 0xff00 -- or $r_A, t0, t1 --# endif --#endif -- jr $r_ra -- move $r_ret, zero -- END(sk_load_half) -- --LEAF(sk_load_byte) -- is_offset_negative(byte) --FEXPORT(sk_load_byte_positive) -- is_offset_in_header(1, byte) -- /* Offset within header boundaries */ -- PTR_ADDU t1, $r_skb_data, offset -- lbu $r_A, 0(t1) -- jr $r_ra -- move $r_ret, zero -- END(sk_load_byte) -- --/* -- * call skb_copy_bits: -- * (prototype in linux/skbuff.h) -- * -- * int skb_copy_bits(sk_buff *skb, int offset, void *to, int len) -- * -- * o32 mandates we leave 4 spaces for argument registers in case -- * the callee needs to use them. Even though we don't care about -- * the argument registers ourselves, we need to allocate that space -- * to remain ABI compliant since the callee may want to use that space. -- * We also allocate 2 more spaces for $r_ra and our return register (*to). -- * -- * n64 is a bit different. The *caller* will allocate the space to preserve -- * the arguments. So in 64-bit kernels, we allocate the 4-arg space for no -- * good reason but it does not matter that much really. -- * -- * (void *to) is returned in r_s0 -- * -- */ --#ifdef CONFIG_CPU_LITTLE_ENDIAN --#define DS_OFFSET(SIZE) (4 * SZREG) --#else --#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE)) --#endif --#define bpf_slow_path_common(SIZE) \ -- /* Quick check. Are we within reasonable boundaries? */ \ -- LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \ -- sltu $r_s0, offset, $r_s1; \ -- beqz $r_s0, fault; \ -- /* Load 4th argument in DS */ \ -- LONG_ADDIU a3, zero, SIZE; \ -- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \ -- PTR_LA t0, skb_copy_bits; \ -- PTR_S $r_ra, (5 * SZREG)($r_sp); \ -- /* Assign low slot to a2 */ \ -- PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \ -- jalr t0; \ -- /* Reset our destination slot (DS but it's ok) */ \ -- INT_S zero, (4 * SZREG)($r_sp); \ -- /* \ -- * skb_copy_bits returns 0 on success and -EFAULT \ -- * on error. Our data live in a2. Do not bother with \ -- * our data if an error has been returned. \ -- */ \ -- /* Restore our frame */ \ -- PTR_L $r_ra, (5 * SZREG)($r_sp); \ -- INT_L $r_s0, (4 * SZREG)($r_sp); \ -- bltz v0, fault; \ -- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \ -- move $r_ret, zero; \ -- --NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp) -- bpf_slow_path_common(4) --#ifdef CONFIG_CPU_LITTLE_ENDIAN --# if MIPS_ISA_REV >= 2 -- wsbh t0, $r_s0 -- jr $r_ra -- rotr $r_A, t0, 16 --# else -- sll t0, $r_s0, 24 -- srl t1, $r_s0, 24 -- srl t2, $r_s0, 8 -- or t0, t0, t1 -- andi t2, t2, 0xff00 -- andi t1, $r_s0, 0xff00 -- or t0, t0, t2 -- sll t1, t1, 8 -- jr $r_ra -- or $r_A, t0, t1 --# endif --#else -- jr $r_ra -- move $r_A, $r_s0 --#endif -- -- END(bpf_slow_path_word) -- --NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp) -- bpf_slow_path_common(2) --#ifdef CONFIG_CPU_LITTLE_ENDIAN --# if MIPS_ISA_REV >= 2 -- jr $r_ra -- wsbh $r_A, $r_s0 --# else -- sll t0, $r_s0, 8 -- andi t1, $r_s0, 0xff00 -- andi t0, t0, 0xff00 -- srl t1, t1, 8 -- jr $r_ra -- or $r_A, t0, t1 --# endif --#else -- jr $r_ra -- move $r_A, $r_s0 --#endif -- -- END(bpf_slow_path_half) -- --NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp) -- bpf_slow_path_common(1) -- jr $r_ra -- move $r_A, $r_s0 -- -- END(bpf_slow_path_byte) -- --/* -- * Negative entry points -- */ -- .macro bpf_is_end_of_data -- li t0, SKF_LL_OFF -- /* Reading link layer data? */ -- slt t1, offset, t0 -- bgtz t1, fault -- /* Be careful what follows in DS. */ -- .endm --/* -- * call skb_copy_bits: -- * (prototype in linux/filter.h) -- * -- * void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, -- * int k, unsigned int size) -- * -- * see above (bpf_slow_path_common) for ABI restrictions -- */ --#define bpf_negative_common(SIZE) \ -- PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \ -- PTR_LA t0, bpf_internal_load_pointer_neg_helper; \ -- PTR_S $r_ra, (5 * SZREG)($r_sp); \ -- jalr t0; \ -- li a2, SIZE; \ -- PTR_L $r_ra, (5 * SZREG)($r_sp); \ -- /* Check return pointer */ \ -- beqz v0, fault; \ -- PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \ -- /* Preserve our pointer */ \ -- move $r_s0, v0; \ -- /* Set return value */ \ -- move $r_ret, zero; \ -- --bpf_slow_path_word_neg: -- bpf_is_end_of_data --NESTED(sk_load_word_negative, (6 * SZREG), $r_sp) -- bpf_negative_common(4) -- jr $r_ra -- lw $r_A, 0($r_s0) -- END(sk_load_word_negative) -- --bpf_slow_path_half_neg: -- bpf_is_end_of_data --NESTED(sk_load_half_negative, (6 * SZREG), $r_sp) -- bpf_negative_common(2) -- jr $r_ra -- lhu $r_A, 0($r_s0) -- END(sk_load_half_negative) -- --bpf_slow_path_byte_neg: -- bpf_is_end_of_data --NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp) -- bpf_negative_common(1) -- jr $r_ra -- lbu $r_A, 0($r_s0) -- END(sk_load_byte_negative) -- --fault: -- jr $r_ra -- addiu $r_ret, zero, 1 diff --git a/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch b/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch deleted file mode 100644 index 51c23b6e349..00000000000 --- a/target/linux/generic/backport-6.1/080-v5.17-clk-gate-Add-devm_clk_hw_register_gate.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 815f0e738a8d5663a02350e2580706829144a722 Mon Sep 17 00:00:00 2001 -From: Horatiu Vultur -Date: Wed, 3 Nov 2021 09:50:59 +0100 -Subject: [PATCH] clk: gate: Add devm_clk_hw_register_gate() - -Add devm_clk_hw_register_gate() - devres-managed version of -clk_hw_register_gate() - -Suggested-by: Stephen Boyd -Signed-off-by: Horatiu Vultur -Acked-by: Nicolas Ferre -Signed-off-by: Nicolas Ferre -Link: https://lore.kernel.org/r/20211103085102.1656081-2-horatiu.vultur@microchip.com ---- - drivers/clk/clk-gate.c | 35 +++++++++++++++++++++++++++++++++++ - include/linux/clk-provider.h | 23 +++++++++++++++++++++++ - 2 files changed, 58 insertions(+) - ---- a/drivers/clk/clk-gate.c -+++ b/drivers/clk/clk-gate.c -@@ -7,6 +7,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -222,3 +223,37 @@ void clk_hw_unregister_gate(struct clk_h - kfree(gate); - } - EXPORT_SYMBOL_GPL(clk_hw_unregister_gate); -+ -+static void devm_clk_hw_release_gate(struct device *dev, void *res) -+{ -+ clk_hw_unregister_gate(*(struct clk_hw **)res); -+} -+ -+struct clk_hw *__devm_clk_hw_register_gate(struct device *dev, -+ struct device_node *np, const char *name, -+ const char *parent_name, const struct clk_hw *parent_hw, -+ const struct clk_parent_data *parent_data, -+ unsigned long flags, -+ void __iomem *reg, u8 bit_idx, -+ u8 clk_gate_flags, spinlock_t *lock) -+{ -+ struct clk_hw **ptr, *hw; -+ -+ ptr = devres_alloc(devm_clk_hw_release_gate, sizeof(*ptr), GFP_KERNEL); -+ if (!ptr) -+ return ERR_PTR(-ENOMEM); -+ -+ hw = __clk_hw_register_gate(dev, np, name, parent_name, parent_hw, -+ parent_data, flags, reg, bit_idx, -+ clk_gate_flags, lock); -+ -+ if (!IS_ERR(hw)) { -+ *ptr = hw; -+ devres_add(dev, ptr); -+ } else { -+ devres_free(ptr); -+ } -+ -+ return hw; -+} -+EXPORT_SYMBOL_GPL(__devm_clk_hw_register_gate); ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -490,6 +490,13 @@ struct clk_hw *__clk_hw_register_gate(st - unsigned long flags, - void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); -+struct clk_hw *__devm_clk_hw_register_gate(struct device *dev, -+ struct device_node *np, const char *name, -+ const char *parent_name, const struct clk_hw *parent_hw, -+ const struct clk_parent_data *parent_data, -+ unsigned long flags, -+ void __iomem *reg, u8 bit_idx, -+ u8 clk_gate_flags, spinlock_t *lock); - struct clk *clk_register_gate(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, -@@ -544,6 +551,22 @@ struct clk *clk_register_gate(struct dev - __clk_hw_register_gate((dev), NULL, (name), NULL, NULL, (parent_data), \ - (flags), (reg), (bit_idx), \ - (clk_gate_flags), (lock)) -+/** -+ * devm_clk_hw_register_gate - register a gate clock with the clock framework -+ * @dev: device that is registering this clock -+ * @name: name of this clock -+ * @parent_name: name of this clock's parent -+ * @flags: framework-specific flags for this clock -+ * @reg: register address to control gating of this clock -+ * @bit_idx: which bit in the register controls gating of this clock -+ * @clk_gate_flags: gate-specific flags for this clock -+ * @lock: shared register lock for this clock -+ */ -+#define devm_clk_hw_register_gate(dev, name, parent_name, flags, reg, bit_idx,\ -+ clk_gate_flags, lock) \ -+ __devm_clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL, \ -+ NULL, (flags), (reg), (bit_idx), \ -+ (clk_gate_flags), (lock)) - void clk_unregister_gate(struct clk *clk); - void clk_hw_unregister_gate(struct clk_hw *hw); - int clk_gate_is_enabled(struct clk_hw *hw); diff --git a/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch b/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch deleted file mode 100644 index e4c0833ae75..00000000000 --- a/target/linux/generic/backport-6.1/081-v5.17-regmap-allow-to-define-reg_update_bits-for-no-bus.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 02d6fdecb9c38de19065f6bed8d5214556fd061d Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 4 Nov 2021 16:00:40 +0100 -Subject: regmap: allow to define reg_update_bits for no bus configuration - -Some device requires a special handling for reg_update_bits and can't use -the normal regmap read write logic. An example is when locking is -handled by the device and rmw operations requires to do atomic operations. -Allow to declare a dedicated function in regmap_config for -reg_update_bits in no bus configuration. - -Signed-off-by: Ansuel Smith -Link: https://lore.kernel.org/r/20211104150040.1260-1-ansuelsmth@gmail.com -Signed-off-by: Mark Brown ---- - drivers/base/regmap/regmap.c | 1 + - include/linux/regmap.h | 7 +++++++ - 2 files changed, 8 insertions(+) - ---- a/drivers/base/regmap/regmap.c -+++ b/drivers/base/regmap/regmap.c -@@ -877,6 +877,7 @@ struct regmap *__regmap_init(struct devi - if (!bus) { - map->reg_read = config->reg_read; - map->reg_write = config->reg_write; -+ map->reg_update_bits = config->reg_update_bits; - - map->defer_caching = false; - goto skip_format_initialization; ---- a/include/linux/regmap.h -+++ b/include/linux/regmap.h -@@ -290,6 +290,11 @@ typedef void (*regmap_unlock)(void *); - * read operation on a bus such as SPI, I2C, etc. Most of the - * devices do not need this. - * @reg_write: Same as above for writing. -+ * @reg_update_bits: Optional callback that if filled will be used to perform -+ * all the update_bits(rmw) operation. Should only be provided -+ * if the function require special handling with lock and reg -+ * handling and the operation cannot be represented as a simple -+ * update_bits operation on a bus such as SPI, I2C, etc. - * @fast_io: Register IO is fast. Use a spinlock instead of a mutex - * to perform locking. This field is ignored if custom lock/unlock - * functions are used (see fields lock/unlock of struct regmap_config). -@@ -372,6 +377,8 @@ struct regmap_config { - - int (*reg_read)(void *context, unsigned int reg, unsigned int *val); - int (*reg_write)(void *context, unsigned int reg, unsigned int val); -+ int (*reg_update_bits)(void *context, unsigned int reg, -+ unsigned int mask, unsigned int val); - - bool fast_io; - diff --git a/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch b/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch deleted file mode 100644 index 7de3cbbda07..00000000000 --- a/target/linux/generic/backport-6.1/100-v5.18-tty-serial-bcm63xx-use-more-precise-Kconfig-symbol.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 0dc0da881b4574d1e04a079ab2ea75da61f5ad2e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 11 Mar 2022 10:32:33 +0100 -Subject: [PATCH] tty: serial: bcm63xx: use more precise Kconfig symbol -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Patches lowering SERIAL_BCM63XX dependencies led to a discussion and -documentation change regarding "depends" usage. Adjust Kconfig entry to -match current guidelines. Make this symbol available for relevant -architectures only. - -Cc: Geert Uytterhoeven -Reviewed-by: Geert Uytterhoeven -Acked-by: Florian Fainelli -Signed-off-by: Rafał Miłecki -Ref: f35a07f92616 ("tty: serial: bcm63xx: lower driver dependencies") -Ref: 18084e435ff6 ("Documentation/kbuild: Document platform dependency practises") -Link: https://lore.kernel.org/r/20220311093233.10012-1-zajec5@gmail.com -Signed-off-by: Greg Kroah-Hartman ---- - drivers/tty/serial/Kconfig | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/tty/serial/Kconfig -+++ b/drivers/tty/serial/Kconfig -@@ -1098,7 +1098,8 @@ config SERIAL_TIMBERDALE - config SERIAL_BCM63XX - tristate "Broadcom BCM63xx/BCM33xx UART support" - select SERIAL_CORE -- depends on COMMON_CLK -+ depends on ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC || COMPILE_TEST -+ default ARCH_BCM4908 || ARCH_BCM_63XX || BCM63XX || BMIPS_GENERIC - help - This enables the driver for the onchip UART core found on - the following chipsets: diff --git a/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch b/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch deleted file mode 100644 index caec8db5d69..00000000000 --- a/target/linux/generic/backport-6.1/200-v5.18-tools-resolve_btfids-Build-with-host-flags.patch +++ /dev/null @@ -1,49 +0,0 @@ -From cdbc4e3399ed8cdcf234a85f7a2482b622379e82 Mon Sep 17 00:00:00 2001 -From: Connor O'Brien -Date: Wed, 12 Jan 2022 00:25:03 +0000 -Subject: [PATCH] tools/resolve_btfids: Build with host flags - -resolve_btfids is built using $(HOSTCC) and $(HOSTLD) but does not -pick up the corresponding flags. As a result, host-specific settings -(such as a sysroot specified via HOSTCFLAGS=--sysroot=..., or a linker -specified via HOSTLDFLAGS=-fuse-ld=...) will not be respected. - -Fix this by setting CFLAGS to KBUILD_HOSTCFLAGS and LDFLAGS to -KBUILD_HOSTLDFLAGS. - -Also pass the cflags through to libbpf via EXTRA_CFLAGS to ensure that -the host libbpf is built with flags consistent with resolve_btfids. - -Signed-off-by: Connor O'Brien -Signed-off-by: Andrii Nakryiko -Acked-by: Song Liu -Link: https://lore.kernel.org/bpf/20220112002503.115968-1-connoro@google.com -(cherry picked from commit 0e3a1c902ffb56e9fe4416f0cd382c97b09ecbf6) -Signed-off-by: Stijn Tintel ---- - tools/bpf/resolve_btfids/Makefile | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - ---- a/tools/bpf/resolve_btfids/Makefile -+++ b/tools/bpf/resolve_btfids/Makefile -@@ -23,6 +23,8 @@ CC = $(HOSTCC) - LD = $(HOSTLD) - ARCH = $(HOSTARCH) - RM ?= rm -+CFLAGS := $(KBUILD_HOSTCFLAGS) -+LDFLAGS := $(KBUILD_HOSTLDFLAGS) - - OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/ - -@@ -45,9 +47,9 @@ $(SUBCMDOBJ): fixdep FORCE | $(OUTPUT)/l - $(Q)$(MAKE) -C $(SUBCMD_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@) - - $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf -- $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(abspath $(dir $@))/ $(abspath $@) -+ $(Q)$(MAKE) $(submake_extras) -C $(LIBBPF_SRC) OUTPUT=$(abspath $(dir $@))/ EXTRA_CFLAGS="$(CFLAGS)" $(abspath $@) - --CFLAGS := -g \ -+CFLAGS += -g \ - -I$(srctree)/tools/include \ - -I$(srctree)/tools/include/uapi \ - -I$(LIBBPF_SRC) \ diff --git a/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch b/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch deleted file mode 100644 index d1bef74f327..00000000000 --- a/target/linux/generic/backport-6.1/201-v5.16-scripts-dtc-Update-to-upstream-version-v1.6.1-19-g0a.patch +++ /dev/null @@ -1,997 +0,0 @@ -From a77725a9a3c5924e2fd4cd5b3557dd92a8e46f87 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Mon, 25 Oct 2021 11:05:45 -0500 -Subject: [PATCH 1/1] scripts/dtc: Update to upstream version - v1.6.1-19-g0a3a9d3449c8 - -This adds the following commits from upstream: - -0a3a9d3449c8 checks: Add an interrupt-map check -8fd24744e361 checks: Ensure '#interrupt-cells' only exists in interrupt providers -d8d1a9a77863 checks: Drop interrupt provider '#address-cells' check -52a16fd72824 checks: Make interrupt_provider check dependent on interrupts_extended_is_cell -37fd700685da treesource: Maintain phandle label/path on output -e33ce1d6a8c7 flattree: Use '\n', not ';' to separate asm pseudo-ops -d24cc189dca6 asm: Use assembler macros instead of cpp macros -ff3a30c115ad asm: Use .asciz and .ascii instead of .string -5eb5927d81ee fdtdump: fix -Werror=int-to-pointer-cast -0869f8269161 libfdt: Add ALIGNMENT error string -69595a167f06 checks: Fix bus-range check -72d09e2682a4 Makefile: add -Wsign-compare to warning options -b587787ef388 checks: Fix signedness comparisons warnings -69bed6c2418f dtc: Wrap phandle validity check -910221185560 fdtget: Fix signedness comparisons warnings -d966f08fcd21 tests: Fix signedness comparisons warnings -ecfb438c07fa dtc: Fix signedness comparisons warnings: pointer diff -5bec74a6d135 dtc: Fix signedness comparisons warnings: reservednum -24e7f511fd4a fdtdump: Fix signedness comparisons warnings -b6910bec1161 Bump version to v1.6.1 -21d61d18f968 Fix CID 1461557 -4c2ef8f4d14c checks: Introduce is_multiple_of() -e59ca36fb70e Make handling of cpp line information more tolerant -0c3fd9b6aceb checks: Drop interrupt_cells_is_cell check -6b3081abc4ac checks: Add check_is_cell() for all phandle+arg properties -2dffc192a77f yamltree: Remove marker ordering dependency -61e513439e40 pylibfdt: Rework "avoid unused variable warning" lines -c8bddd106095 tests: add a positive gpio test case -ad4abfadb687 checks: replace strstr and strrchr with strends -09c6a6e88718 dtc.h: add strends for suffix matching -9bb9b8d0b4a0 checks: tigthen up nr-gpios prop exception -b07b62ee3342 libfdt: Add FDT alignment check to fdt_check_header() -a2def5479950 libfdt: Check that the root-node name is empty -4ca61f84dc21 libfdt: Check that there is only one root node -34d708249a91 dtc: Remove -O dtbo support -8e7ff260f755 libfdt: Fix a possible "unchecked return value" warning -88875268c05c checks: Warn on node-name and property name being the same -9d2279e7e6ee checks: Change node-name check to match devicetree spec -f527c867a8c6 util: limit gnu_printf format attribute to gcc >= 4.4.0 - -Reviewed-by: Frank Rowand -Tested-by: Frank Rowand -Signed-off-by: Rob Herring ---- - scripts/dtc/checks.c | 222 ++++++++++++++++++++++-------- - scripts/dtc/dtc-lexer.l | 2 +- - scripts/dtc/dtc.c | 6 +- - scripts/dtc/dtc.h | 40 +++++- - scripts/dtc/flattree.c | 11 +- - scripts/dtc/libfdt/fdt.c | 4 + - scripts/dtc/libfdt/fdt_rw.c | 18 ++- - scripts/dtc/libfdt/fdt_strerror.c | 1 + - scripts/dtc/libfdt/libfdt.h | 7 + - scripts/dtc/livetree.c | 6 +- - scripts/dtc/treesource.c | 48 +++---- - scripts/dtc/util.h | 6 +- - scripts/dtc/version_gen.h | 2 +- - scripts/dtc/yamltree.c | 16 ++- - 14 files changed, 275 insertions(+), 114 deletions(-) - ---- a/scripts/dtc/checks.c -+++ b/scripts/dtc/checks.c -@@ -143,6 +143,14 @@ static void check_nodes_props(struct che - check_nodes_props(c, dti, child); - } - -+static bool is_multiple_of(int multiple, int divisor) -+{ -+ if (divisor == 0) -+ return multiple == 0; -+ else -+ return (multiple % divisor) == 0; -+} -+ - static bool run_check(struct check *c, struct dt_info *dti) - { - struct node *dt = dti->dt; -@@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_du - #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" - #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - #define DIGITS "0123456789" --#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" -+#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@" -+#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" - #define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" - - static void check_node_name_chars(struct check *c, struct dt_info *dti, - struct node *node) - { -- int n = strspn(node->name, c->data); -+ size_t n = strspn(node->name, c->data); - - if (n < strlen(node->name)) - FAIL(c, dti, node, "Bad character '%c' in node name", - node->name[n]); - } --ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); -+ERROR(node_name_chars, check_node_name_chars, NODECHARS); - - static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, - struct node *node) -@@ -330,6 +339,20 @@ static void check_node_name_format(struc - } - ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); - -+static void check_node_name_vs_property_name(struct check *c, -+ struct dt_info *dti, -+ struct node *node) -+{ -+ if (!node->parent) -+ return; -+ -+ if (get_property(node->parent, node->name)) { -+ FAIL(c, dti, node, "node name and property name conflict"); -+ } -+} -+WARNING(node_name_vs_property_name, check_node_name_vs_property_name, -+ NULL, &node_name_chars); -+ - static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, - struct node *node) - { -@@ -363,14 +386,14 @@ static void check_property_name_chars(st - struct property *prop; - - for_each_property(node, prop) { -- int n = strspn(prop->name, c->data); -+ size_t n = strspn(prop->name, c->data); - - if (n < strlen(prop->name)) - FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", - prop->name[n]); - } - } --ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); -+ERROR(property_name_chars, check_property_name_chars, PROPCHARS); - - static void check_property_name_chars_strict(struct check *c, - struct dt_info *dti, -@@ -380,7 +403,7 @@ static void check_property_name_chars_st - - for_each_property(node, prop) { - const char *name = prop->name; -- int n = strspn(name, c->data); -+ size_t n = strspn(name, c->data); - - if (n == strlen(prop->name)) - continue; -@@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct - - phandle = propval_cell(prop); - -- if ((phandle == 0) || (phandle == -1)) { -+ if (!phandle_is_valid(phandle)) { - FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", - phandle, prop->name); - return 0; -@@ -556,7 +579,7 @@ static void check_name_properties(struct - if (!prop) - return; /* No name property, that's fine */ - -- if ((prop->val.len != node->basenamelen+1) -+ if ((prop->val.len != node->basenamelen + 1U) - || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { - FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" - " of base node name)", prop->val.val); -@@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unus - */ - WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); - WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); --WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); - - WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); - WARNING_IF_NOT_STRING(model_is_string, "model"); -@@ -672,8 +694,7 @@ static void check_names_is_string_list(s - struct property *prop; - - for_each_property(node, prop) { -- const char *s = strrchr(prop->name, '-'); -- if (!s || !streq(s, "-names")) -+ if (!strends(prop->name, "-names")) - continue; - - c->data = prop->name; -@@ -753,7 +774,7 @@ static void check_reg_format(struct chec - size_cells = node_size_cells(node->parent); - entrylen = (addr_cells + size_cells) * sizeof(cell_t); - -- if (!entrylen || (prop->val.len % entrylen) != 0) -+ if (!is_multiple_of(prop->val.len, entrylen)) - FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " - "(#address-cells == %d, #size-cells == %d)", - prop->val.len, addr_cells, size_cells); -@@ -794,7 +815,7 @@ static void check_ranges_format(struct c - "#size-cells (%d) differs from %s (%d)", - ranges, c_size_cells, node->parent->fullpath, - p_size_cells); -- } else if ((prop->val.len % entrylen) != 0) { -+ } else if (!is_multiple_of(prop->val.len, entrylen)) { - FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " - "(parent #address-cells == %d, child #address-cells == %d, " - "#size-cells == %d)", ranges, prop->val.len, -@@ -871,7 +892,7 @@ static void check_pci_device_bus_num(str - } else { - cells = (cell_t *)prop->val.val; - min_bus = fdt32_to_cpu(cells[0]); -- max_bus = fdt32_to_cpu(cells[0]); -+ max_bus = fdt32_to_cpu(cells[1]); - } - if ((bus_num < min_bus) || (bus_num > max_bus)) - FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", -@@ -1367,9 +1388,9 @@ static void check_property_phandle_args( - const struct provider *provider) - { - struct node *root = dti->dt; -- int cell, cellsize = 0; -+ unsigned int cell, cellsize = 0; - -- if (prop->val.len % sizeof(cell_t)) { -+ if (!is_multiple_of(prop->val.len, sizeof(cell_t))) { - FAIL_PROP(c, dti, node, prop, - "property size (%d) is invalid, expected multiple of %zu", - prop->val.len, sizeof(cell_t)); -@@ -1379,14 +1400,14 @@ static void check_property_phandle_args( - for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { - struct node *provider_node; - struct property *cellprop; -- int phandle; -+ cell_t phandle; - - phandle = propval_cell_n(prop, cell); - /* - * Some bindings use a cell value 0 or -1 to skip over optional - * entries when each index position has a specific definition. - */ -- if (phandle == 0 || phandle == -1) { -+ if (!phandle_is_valid(phandle)) { - /* Give up if this is an overlay with external references */ - if (dti->dtsflags & DTSF_PLUGIN) - break; -@@ -1452,7 +1473,8 @@ static void check_provider_cells_propert - } - #define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ - static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ -- WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); -+ WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \ -+ WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references); - - WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); - WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); -@@ -1473,24 +1495,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_s - - static bool prop_is_gpio(struct property *prop) - { -- char *str; -- - /* - * *-gpios and *-gpio can appear in property names, - * so skip over any false matches (only one known ATM) - */ -- if (strstr(prop->name, "nr-gpio")) -+ if (strends(prop->name, ",nr-gpios")) - return false; - -- str = strrchr(prop->name, '-'); -- if (str) -- str++; -- else -- str = prop->name; -- if (!(streq(str, "gpios") || streq(str, "gpio"))) -- return false; -- -- return true; -+ return strends(prop->name, "-gpios") || -+ streq(prop->name, "gpios") || -+ strends(prop->name, "-gpio") || -+ streq(prop->name, "gpio"); - } - - static void check_gpios_property(struct check *c, -@@ -1525,13 +1540,10 @@ static void check_deprecated_gpio_proper - struct property *prop; - - for_each_property(node, prop) { -- char *str; -- - if (!prop_is_gpio(prop)) - continue; - -- str = strstr(prop->name, "gpio"); -- if (!streq(str, "gpio")) -+ if (!strends(prop->name, "gpio")) - continue; - - FAIL_PROP(c, dti, node, prop, -@@ -1561,21 +1573,106 @@ static void check_interrupt_provider(str - struct node *node) - { - struct property *prop; -+ bool irq_provider = node_is_interrupt_provider(node); - -- if (!node_is_interrupt_provider(node)) -+ prop = get_property(node, "#interrupt-cells"); -+ if (irq_provider && !prop) { -+ FAIL(c, dti, node, -+ "Missing '#interrupt-cells' in interrupt provider"); - return; -+ } - -- prop = get_property(node, "#interrupt-cells"); -- if (!prop) -+ if (!irq_provider && prop) { - FAIL(c, dti, node, -- "Missing #interrupt-cells in interrupt provider"); -+ "'#interrupt-cells' found, but node is not an interrupt provider"); -+ return; -+ } -+} -+WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); - -- prop = get_property(node, "#address-cells"); -- if (!prop) -+static void check_interrupt_map(struct check *c, -+ struct dt_info *dti, -+ struct node *node) -+{ -+ struct node *root = dti->dt; -+ struct property *prop, *irq_map_prop; -+ size_t cellsize, cell, map_cells; -+ -+ irq_map_prop = get_property(node, "interrupt-map"); -+ if (!irq_map_prop) -+ return; -+ -+ if (node->addr_cells < 0) { - FAIL(c, dti, node, -- "Missing #address-cells in interrupt provider"); -+ "Missing '#address-cells' in interrupt-map provider"); -+ return; -+ } -+ cellsize = node_addr_cells(node); -+ cellsize += propval_cell(get_property(node, "#interrupt-cells")); -+ -+ prop = get_property(node, "interrupt-map-mask"); -+ if (prop && (prop->val.len != (cellsize * sizeof(cell_t)))) -+ FAIL_PROP(c, dti, node, prop, -+ "property size (%d) is invalid, expected %zu", -+ prop->val.len, cellsize * sizeof(cell_t)); -+ -+ if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) { -+ FAIL_PROP(c, dti, node, irq_map_prop, -+ "property size (%d) is invalid, expected multiple of %zu", -+ irq_map_prop->val.len, sizeof(cell_t)); -+ return; -+ } -+ -+ map_cells = irq_map_prop->val.len / sizeof(cell_t); -+ for (cell = 0; cell < map_cells; ) { -+ struct node *provider_node; -+ struct property *cellprop; -+ int phandle; -+ size_t parent_cellsize; -+ -+ if ((cell + cellsize) >= map_cells) { -+ FAIL_PROP(c, dti, node, irq_map_prop, -+ "property size (%d) too small, expected > %zu", -+ irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t)); -+ break; -+ } -+ cell += cellsize; -+ -+ phandle = propval_cell_n(irq_map_prop, cell); -+ if (!phandle_is_valid(phandle)) { -+ /* Give up if this is an overlay with external references */ -+ if (!(dti->dtsflags & DTSF_PLUGIN)) -+ FAIL_PROP(c, dti, node, irq_map_prop, -+ "Cell %zu is not a phandle(%d)", -+ cell, phandle); -+ break; -+ } -+ -+ provider_node = get_node_by_phandle(root, phandle); -+ if (!provider_node) { -+ FAIL_PROP(c, dti, node, irq_map_prop, -+ "Could not get phandle(%d) node for (cell %zu)", -+ phandle, cell); -+ break; -+ } -+ -+ cellprop = get_property(provider_node, "#interrupt-cells"); -+ if (cellprop) { -+ parent_cellsize = propval_cell(cellprop); -+ } else { -+ FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])", -+ provider_node->fullpath, cell); -+ break; -+ } -+ -+ cellprop = get_property(provider_node, "#address-cells"); -+ if (cellprop) -+ parent_cellsize += propval_cell(cellprop); -+ -+ cell += 1 + parent_cellsize; -+ } - } --WARNING(interrupt_provider, check_interrupt_provider, NULL); -+WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); - - static void check_interrupts_property(struct check *c, - struct dt_info *dti, -@@ -1584,13 +1681,13 @@ static void check_interrupts_property(st - struct node *root = dti->dt; - struct node *irq_node = NULL, *parent = node; - struct property *irq_prop, *prop = NULL; -- int irq_cells, phandle; -+ cell_t irq_cells, phandle; - - irq_prop = get_property(node, "interrupts"); - if (!irq_prop) - return; - -- if (irq_prop->val.len % sizeof(cell_t)) -+ if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t))) - FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", - irq_prop->val.len, sizeof(cell_t)); - -@@ -1603,7 +1700,7 @@ static void check_interrupts_property(st - prop = get_property(parent, "interrupt-parent"); - if (prop) { - phandle = propval_cell(prop); -- if ((phandle == 0) || (phandle == -1)) { -+ if (!phandle_is_valid(phandle)) { - /* Give up if this is an overlay with - * external references */ - if (dti->dtsflags & DTSF_PLUGIN) -@@ -1639,7 +1736,7 @@ static void check_interrupts_property(st - } - - irq_cells = propval_cell(prop); -- if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { -+ if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) { - FAIL_PROP(c, dti, node, prop, - "size is (%d), expected multiple of %d", - irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); -@@ -1750,7 +1847,7 @@ WARNING(graph_port, check_graph_port, NU - static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, - struct node *endpoint) - { -- int phandle; -+ cell_t phandle; - struct node *node; - struct property *prop; - -@@ -1760,7 +1857,7 @@ static struct node *get_remote_endpoint( - - phandle = propval_cell(prop); - /* Give up if this is an overlay with external references */ -- if (phandle == 0 || phandle == -1) -+ if (!phandle_is_valid(phandle)) - return NULL; - - node = get_node_by_phandle(dti->dt, phandle); -@@ -1796,7 +1893,7 @@ WARNING(graph_endpoint, check_graph_endp - static struct check *check_table[] = { - &duplicate_node_names, &duplicate_property_names, - &node_name_chars, &node_name_format, &property_name_chars, -- &name_is_string, &name_properties, -+ &name_is_string, &name_properties, &node_name_vs_property_name, - - &duplicate_label, - -@@ -1804,7 +1901,7 @@ static struct check *check_table[] = { - &phandle_references, &path_references, - &omit_unused_nodes, - -- &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, -+ &address_cells_is_cell, &size_cells_is_cell, - &device_type_is_string, &model_is_string, &status_is_string, - &label_is_string, - -@@ -1839,26 +1936,43 @@ static struct check *check_table[] = { - &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, - - &clocks_property, -+ &clocks_is_cell, - &cooling_device_property, -+ &cooling_device_is_cell, - &dmas_property, -+ &dmas_is_cell, - &hwlocks_property, -+ &hwlocks_is_cell, - &interrupts_extended_property, -+ &interrupts_extended_is_cell, - &io_channels_property, -+ &io_channels_is_cell, - &iommus_property, -+ &iommus_is_cell, - &mboxes_property, -+ &mboxes_is_cell, - &msi_parent_property, -+ &msi_parent_is_cell, - &mux_controls_property, -+ &mux_controls_is_cell, - &phys_property, -+ &phys_is_cell, - &power_domains_property, -+ &power_domains_is_cell, - &pwms_property, -+ &pwms_is_cell, - &resets_property, -+ &resets_is_cell, - &sound_dai_property, -+ &sound_dai_is_cell, - &thermal_sensors_property, -+ &thermal_sensors_is_cell, - - &deprecated_gpio_property, - &gpios_property, - &interrupts_property, - &interrupt_provider, -+ &interrupt_map, - - &alias_paths, - -@@ -1882,7 +1996,7 @@ static void enable_warning_error(struct - - static void disable_warning_error(struct check *c, bool warn, bool error) - { -- int i; -+ unsigned int i; - - /* Lowering level, also lower it for things this is the prereq - * for */ -@@ -1903,7 +2017,7 @@ static void disable_warning_error(struct - - void parse_checks_option(bool warn, bool error, const char *arg) - { -- int i; -+ unsigned int i; - const char *name = arg; - bool enable = true; - -@@ -1930,7 +2044,7 @@ void parse_checks_option(bool warn, bool - - void process_checks(bool force, struct dt_info *dti) - { -- int i; -+ unsigned int i; - int error = 0; - - for (i = 0; i < ARRAY_SIZE(check_table); i++) { ---- a/scripts/dtc/dtc-lexer.l -+++ b/scripts/dtc/dtc-lexer.l -@@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(c - push_input_file(name); - } - --<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { -+<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { - char *line, *fnstart, *fnend; - struct data fn; - /* skip text before line # */ ---- a/scripts/dtc/dtc.c -+++ b/scripts/dtc/dtc.c -@@ -12,7 +12,7 @@ - * Command line options - */ - int quiet; /* Level of quietness */ --int reservenum; /* Number of memory reservation slots */ -+unsigned int reservenum;/* Number of memory reservation slots */ - int minsize; /* Minimum blob size */ - int padsize; /* Additional padding to blob */ - int alignsize; /* Additional padding to blob accroding to the alignsize */ -@@ -197,7 +197,7 @@ int main(int argc, char *argv[]) - depname = optarg; - break; - case 'R': -- reservenum = strtol(optarg, NULL, 0); -+ reservenum = strtoul(optarg, NULL, 0); - break; - case 'S': - minsize = strtol(optarg, NULL, 0); -@@ -359,8 +359,6 @@ int main(int argc, char *argv[]) - #endif - } else if (streq(outform, "dtb")) { - dt_to_blob(outf, dti, outversion); -- } else if (streq(outform, "dtbo")) { -- dt_to_blob(outf, dti, outversion); - } else if (streq(outform, "asm")) { - dt_to_asm(outf, dti, outversion); - } else if (streq(outform, "null")) { ---- a/scripts/dtc/dtc.h -+++ b/scripts/dtc/dtc.h -@@ -35,7 +35,7 @@ - * Command line options - */ - extern int quiet; /* Level of quietness */ --extern int reservenum; /* Number of memory reservation slots */ -+extern unsigned int reservenum; /* Number of memory reservation slots */ - extern int minsize; /* Minimum blob size */ - extern int padsize; /* Additional padding to blob */ - extern int alignsize; /* Additional padding to blob accroding to the alignsize */ -@@ -51,6 +51,11 @@ extern int annotate; /* annotate .dts w - - typedef uint32_t cell_t; - -+static inline bool phandle_is_valid(cell_t phandle) -+{ -+ return phandle != 0 && phandle != ~0U; -+} -+ - static inline uint16_t dtb_ld16(const void *p) - { - const uint8_t *bp = (const uint8_t *)p; -@@ -86,6 +91,16 @@ static inline uint64_t dtb_ld64(const vo - #define streq(a, b) (strcmp((a), (b)) == 0) - #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) - #define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0)) -+static inline bool strends(const char *str, const char *suffix) -+{ -+ unsigned int len, suffix_len; -+ -+ len = strlen(str); -+ suffix_len = strlen(suffix); -+ if (len < suffix_len) -+ return false; -+ return streq(str + len - suffix_len, suffix); -+} - - #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) - -@@ -101,6 +116,12 @@ enum markertype { - TYPE_UINT64, - TYPE_STRING, - }; -+ -+static inline bool is_type_marker(enum markertype type) -+{ -+ return type >= TYPE_UINT8; -+} -+ - extern const char *markername(enum markertype markertype); - - struct marker { -@@ -125,7 +146,22 @@ struct data { - for_each_marker(m) \ - if ((m)->type == (t)) - --size_t type_marker_length(struct marker *m); -+static inline struct marker *next_type_marker(struct marker *m) -+{ -+ for_each_marker(m) -+ if (is_type_marker(m->type)) -+ break; -+ return m; -+} -+ -+static inline size_t type_marker_length(struct marker *m) -+{ -+ struct marker *next = next_type_marker(m->next); -+ -+ if (next) -+ return next->offset - m->offset; -+ return 0; -+} - - void data_free(struct data d); - ---- a/scripts/dtc/flattree.c -+++ b/scripts/dtc/flattree.c -@@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_ - { - FILE *f = e; - -- fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", -+ fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n" -+ "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n", - (val >> 24) & 0xff, (val >> 16) & 0xff, - (val >> 8) & 0xff, val & 0xff); - } -@@ -134,9 +135,9 @@ static void asm_emit_string(void *e, con - FILE *f = e; - - if (len != 0) -- fprintf(f, "\t.string\t\"%.*s\"\n", len, str); -+ fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str); - else -- fprintf(f, "\t.string\t\"%s\"\n", str); -+ fprintf(f, "\t.asciz\t\"%s\"\n", str); - } - - static void asm_emit_align(void *e, int a) -@@ -295,7 +296,7 @@ static struct data flatten_reserve_list( - { - struct reserve_info *re; - struct data d = empty_data; -- int j; -+ unsigned int j; - - for (re = reservelist; re; re = re->next) { - d = data_append_re(d, re->address, re->size); -@@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f - - while (p < (strbuf.val + strbuf.len)) { - len = strlen(p); -- fprintf(f, "\t.string \"%s\"\n", p); -+ fprintf(f, "\t.asciz \"%s\"\n", p); - p += len+1; - } - } ---- a/scripts/dtc/libfdt/fdt.c -+++ b/scripts/dtc/libfdt/fdt.c -@@ -90,6 +90,10 @@ int fdt_check_header(const void *fdt) - { - size_t hdrsize; - -+ /* The device tree must be at an 8-byte aligned address */ -+ if ((uintptr_t)fdt & 7) -+ return -FDT_ERR_ALIGNMENT; -+ - if (fdt_magic(fdt) != FDT_MAGIC) - return -FDT_ERR_BADMAGIC; - if (!can_assume(LATEST)) { ---- a/scripts/dtc/libfdt/fdt_rw.c -+++ b/scripts/dtc/libfdt/fdt_rw.c -@@ -349,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, i - return offset; - - /* Try to place the new node after the parent's properties */ -- fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ -+ tag = fdt_next_tag(fdt, parentoffset, &nextoffset); -+ /* the fdt_subnode_offset_namelen() should ensure this never hits */ -+ if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) -+ return -FDT_ERR_INTERNAL; - do { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); -@@ -391,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffs - } - - static void fdt_packblocks_(const char *old, char *new, -- int mem_rsv_size, int struct_size) -+ int mem_rsv_size, -+ int struct_size, -+ int strings_size) - { - int mem_rsv_off, struct_off, strings_off; - -@@ -406,8 +411,7 @@ static void fdt_packblocks_(const char * - fdt_set_off_dt_struct(new, struct_off); - fdt_set_size_dt_struct(new, struct_size); - -- memmove(new + strings_off, old + fdt_off_dt_strings(old), -- fdt_size_dt_strings(old)); -+ memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); - fdt_set_off_dt_strings(new, strings_off); - fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); - } -@@ -467,7 +471,8 @@ int fdt_open_into(const void *fdt, void - return -FDT_ERR_NOSPACE; - } - -- fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); -+ fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, -+ fdt_size_dt_strings(fdt)); - memmove(buf, tmp, newsize); - - fdt_set_magic(buf, FDT_MAGIC); -@@ -487,7 +492,8 @@ int fdt_pack(void *fdt) - - mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) - * sizeof(struct fdt_reserve_entry); -- fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); -+ fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), -+ fdt_size_dt_strings(fdt)); - fdt_set_totalsize(fdt, fdt_data_size_(fdt)); - - return 0; ---- a/scripts/dtc/libfdt/fdt_strerror.c -+++ b/scripts/dtc/libfdt/fdt_strerror.c -@@ -39,6 +39,7 @@ static struct fdt_errtabent fdt_errtable - FDT_ERRTABENT(FDT_ERR_BADOVERLAY), - FDT_ERRTABENT(FDT_ERR_NOPHANDLES), - FDT_ERRTABENT(FDT_ERR_BADFLAGS), -+ FDT_ERRTABENT(FDT_ERR_ALIGNMENT), - }; - #define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) - ---- a/scripts/dtc/libfdt/libfdt.h -+++ b/scripts/dtc/libfdt/libfdt.h -@@ -131,6 +131,13 @@ uint32_t fdt_next_tag(const void *fdt, i - * to work even with unaligned pointers on platforms (such as ARMv5) that don't - * like unaligned loads and stores. - */ -+static inline uint16_t fdt16_ld(const fdt16_t *p) -+{ -+ const uint8_t *bp = (const uint8_t *)p; -+ -+ return ((uint16_t)bp[0] << 8) | bp[1]; -+} -+ - static inline uint32_t fdt32_ld(const fdt32_t *p) - { - const uint8_t *bp = (const uint8_t *)p; ---- a/scripts/dtc/livetree.c -+++ b/scripts/dtc/livetree.c -@@ -526,7 +526,7 @@ struct node *get_node_by_path(struct nod - p = strchr(path, '/'); - - for_each_child(tree, child) { -- if (p && strprefixeq(path, p - path, child->name)) -+ if (p && strprefixeq(path, (size_t)(p - path), child->name)) - return get_node_by_path(child, p+1); - else if (!p && streq(path, child->name)) - return child; -@@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct - { - struct node *child, *node; - -- if ((phandle == 0) || (phandle == -1)) { -+ if (!phandle_is_valid(phandle)) { - assert(generate_fixups); - return NULL; - } -@@ -594,7 +594,7 @@ cell_t get_node_phandle(struct node *roo - static cell_t phandle = 1; /* FIXME: ick, static local */ - struct data d = empty_data; - -- if ((node->phandle != 0) && (node->phandle != -1)) -+ if (phandle_is_valid(node->phandle)) - return node->phandle; - - while (get_node_by_phandle(root, phandle)) ---- a/scripts/dtc/treesource.c -+++ b/scripts/dtc/treesource.c -@@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, c - } - } - --static bool has_data_type_information(struct marker *m) --{ -- return m->type >= TYPE_UINT8; --} -- --static struct marker *next_type_marker(struct marker *m) --{ -- while (m && !has_data_type_information(m)) -- m = m->next; -- return m; --} -- --size_t type_marker_length(struct marker *m) --{ -- struct marker *next = next_type_marker(m->next); -- -- if (next) -- return next->offset - m->offset; -- return 0; --} -- - static const char *delim_start[] = { - [TYPE_UINT8] = "[", - [TYPE_UINT16] = "/bits/ 16 <", -@@ -229,26 +208,39 @@ static void write_propval(FILE *f, struc - size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; - size_t data_len = type_marker_length(m) ? : len - m->offset; - const char *p = &prop->val.val[m->offset]; -+ struct marker *m_phandle; - -- if (has_data_type_information(m)) { -+ if (is_type_marker(m->type)) { - emit_type = m->type; - fprintf(f, " %s", delim_start[emit_type]); - } else if (m->type == LABEL) - fprintf(f, " %s:", m->ref); -- else if (m->offset) -- fputc(' ', f); - -- if (emit_type == TYPE_NONE) { -- assert(chunk_len == 0); -+ if (emit_type == TYPE_NONE || chunk_len == 0) - continue; -- } - - switch(emit_type) { - case TYPE_UINT16: - write_propval_int(f, p, chunk_len, 2); - break; - case TYPE_UINT32: -- write_propval_int(f, p, chunk_len, 4); -+ m_phandle = prop->val.markers; -+ for_each_marker_of_type(m_phandle, REF_PHANDLE) -+ if (m->offset == m_phandle->offset) -+ break; -+ -+ if (m_phandle) { -+ if (m_phandle->ref[0] == '/') -+ fprintf(f, "&{%s}", m_phandle->ref); -+ else -+ fprintf(f, "&%s", m_phandle->ref); -+ if (chunk_len > 4) { -+ fputc(' ', f); -+ write_propval_int(f, p + 4, chunk_len - 4, 4); -+ } -+ } else { -+ write_propval_int(f, p, chunk_len, 4); -+ } - break; - case TYPE_UINT64: - write_propval_int(f, p, chunk_len, 8); ---- a/scripts/dtc/util.h -+++ b/scripts/dtc/util.h -@@ -13,10 +13,10 @@ - */ - - #ifdef __GNUC__ --#ifdef __clang__ --#define PRINTF(i, j) __attribute__((format (printf, i, j))) --#else -+#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) - #define PRINTF(i, j) __attribute__((format (gnu_printf, i, j))) -+#else -+#define PRINTF(i, j) __attribute__((format (printf, i, j))) - #endif - #define NORETURN __attribute__((noreturn)) - #else ---- a/scripts/dtc/version_gen.h -+++ b/scripts/dtc/version_gen.h -@@ -1 +1 @@ --#define DTC_VERSION "DTC 1.6.0-g183df9e9" -+#define DTC_VERSION "DTC 1.6.1-g0a3a9d34" ---- a/scripts/dtc/yamltree.c -+++ b/scripts/dtc/yamltree.c -@@ -29,11 +29,12 @@ char *yaml_error_name[] = { - (emitter)->problem, __func__, __LINE__); \ - }) - --static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, unsigned int len, int width) -+static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, -+ char *data, unsigned int seq_offset, unsigned int len, int width) - { - yaml_event_t event; - void *tag; -- unsigned int off, start_offset = markers->offset; -+ unsigned int off; - - switch(width) { - case 1: tag = "!u8"; break; -@@ -66,7 +67,7 @@ static void yaml_propval_int(yaml_emitte - m = markers; - is_phandle = false; - for_each_marker_of_type(m, REF_PHANDLE) { -- if (m->offset == (start_offset + off)) { -+ if (m->offset == (seq_offset + off)) { - is_phandle = true; - break; - } -@@ -114,6 +115,7 @@ static void yaml_propval(yaml_emitter_t - yaml_event_t event; - unsigned int len = prop->val.len; - struct marker *m = prop->val.markers; -+ struct marker *markers = prop->val.markers; - - /* Emit the property name */ - yaml_scalar_event_initialize(&event, NULL, -@@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t - - switch(m->type) { - case TYPE_UINT16: -- yaml_propval_int(emitter, m, data, chunk_len, 2); -+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2); - break; - case TYPE_UINT32: -- yaml_propval_int(emitter, m, data, chunk_len, 4); -+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4); - break; - case TYPE_UINT64: -- yaml_propval_int(emitter, m, data, chunk_len, 8); -+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8); - break; - case TYPE_STRING: - yaml_propval_string(emitter, data, chunk_len); - break; - default: -- yaml_propval_int(emitter, m, data, chunk_len, 1); -+ yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1); - break; - } - } diff --git a/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch b/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch deleted file mode 100644 index 18a8752a18f..00000000000 --- a/target/linux/generic/backport-6.1/300-v5.18-pinctrl-qcom-Return--EINVAL-for-setting-affinity-if-no-IRQ-parent.patch +++ /dev/null @@ -1,48 +0,0 @@ -From: Manivannan Sadhasivam -To: linus.walleij@linaro.org -Cc: bjorn.andersson@linaro.org, dianders@chromium.org, - linux-arm-msm@vger.kernel.org, linux-gpio@vger.kernel.org, - linux-kernel@vger.kernel.org, - Manivannan Sadhasivam -Subject: [PATCH] pinctrl: qcom: Return -EINVAL for setting affinity if no IRQ - parent -Date: Thu, 13 Jan 2022 21:56:17 +0530 -Message-Id: <20220113162617.131697-1-manivannan.sadhasivam@linaro.org> - -The MSM GPIO IRQ controller relies on the parent IRQ controller to set the -CPU affinity for the IRQ. And this is only valid if there is any wakeup -parent available and defined in DT. - -For the case of no parent IRQ controller defined in DT, -msm_gpio_irq_set_affinity() and msm_gpio_irq_set_vcpu_affinity() should -return -EINVAL instead of 0 as the affinity can't be set. - -Otherwise, below warning will be printed by genirq: - -genirq: irq_chip msmgpio did not update eff. affinity mask of irq 70 - -Signed-off-by: Manivannan Sadhasivam ---- - drivers/pinctrl/qcom/pinctrl-msm.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/pinctrl/qcom/pinctrl-msm.c -+++ b/drivers/pinctrl/qcom/pinctrl-msm.c -@@ -1157,7 +1157,7 @@ static int msm_gpio_irq_set_affinity(str - if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs)) - return irq_chip_set_affinity_parent(d, dest, force); - -- return 0; -+ return -EINVAL; - } - - static int msm_gpio_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info) -@@ -1168,7 +1168,7 @@ static int msm_gpio_irq_set_vcpu_affinit - if (d->parent_data && test_bit(d->hwirq, pctrl->skip_wake_irqs)) - return irq_chip_set_vcpu_affinity_parent(d, vcpu_info); - -- return 0; -+ return -EINVAL; - } - - static void msm_gpio_irq_handler(struct irq_desc *desc) diff --git a/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch b/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch deleted file mode 100644 index ee0bf9309ff..00000000000 --- a/target/linux/generic/backport-6.1/301-v5.16-soc-qcom-smem-Support-reserved-memory-description.patch +++ /dev/null @@ -1,166 +0,0 @@ -From b5af64fceb04dc298c5e69c517b4d83893ff060b Mon Sep 17 00:00:00 2001 -From: Bjorn Andersson -Date: Thu, 30 Sep 2021 11:21:10 -0700 -Subject: [PATCH 1/1] soc: qcom: smem: Support reserved-memory description - -Practically all modern Qualcomm platforms has a single reserved-memory -region for SMEM. So rather than having to describe SMEM in the form of a -node with a reference to a reserved-memory node, allow the SMEM device -to be instantiated directly from the reserved-memory node. - -The current means of falling back to dereferencing the "memory-region" -is kept as a fallback, if it's determined that the SMEM node is a -reserved-memory node. - -The "qcom,smem" compatible is added to the reserved_mem_matches list, to -allow the reserved-memory device to be probed. - -In order to retain the readability of the code, the resolution of -resources is split from the actual ioremapping. - -Signed-off-by: Bjorn Andersson -Acked-by: Rob Herring -Reviewed-by: Vladimir Zapolskiy -Link: https://lore.kernel.org/r/20210930182111.57353-4-bjorn.andersson@linaro.org ---- - drivers/of/platform.c | 1 + - drivers/soc/qcom/smem.c | 57 ++++++++++++++++++++++++++++------------- - 2 files changed, 40 insertions(+), 18 deletions(-) - ---- a/drivers/of/platform.c -+++ b/drivers/of/platform.c -@@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_po - static const struct of_device_id reserved_mem_matches[] = { - { .compatible = "qcom,rmtfs-mem" }, - { .compatible = "qcom,cmd-db" }, -+ { .compatible = "qcom,smem" }, - { .compatible = "ramoops" }, - { .compatible = "nvmem-rmem" }, - {} ---- a/drivers/soc/qcom/smem.c -+++ b/drivers/soc/qcom/smem.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x - * @size: size of the memory region - */ - struct smem_region { -- u32 aux_base; -+ phys_addr_t aux_base; - void __iomem *virt_base; - size_t size; - }; -@@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct - for (i = 0; i < smem->num_regions; i++) { - region = &smem->regions[i]; - -- if (region->aux_base == aux_base || !aux_base) { -+ if ((u32)region->aux_base == aux_base || !aux_base) { - if (size != NULL) - *size = le32_to_cpu(entry->size); - return region->virt_base + le32_to_cpu(entry->offset); -@@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void - if (p < region->virt_base + region->size) { - u64 offset = p - region->virt_base; - -- return (phys_addr_t)region->aux_base + offset; -+ return region->aux_base + offset; - } - } - -@@ -863,12 +864,12 @@ qcom_smem_enumerate_partitions(struct qc - return 0; - } - --static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, -- const char *name, int i) -+static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name, -+ struct smem_region *region) - { -+ struct device *dev = smem->dev; - struct device_node *np; - struct resource r; -- resource_size_t size; - int ret; - - np = of_parse_phandle(dev->of_node, name, 0); -@@ -881,13 +882,9 @@ static int qcom_smem_map_memory(struct q - of_node_put(np); - if (ret) - return ret; -- size = resource_size(&r); - -- smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); -- if (!smem->regions[i].virt_base) -- return -ENOMEM; -- smem->regions[i].aux_base = (u32)r.start; -- smem->regions[i].size = size; -+ region->aux_base = r.start; -+ region->size = resource_size(&r); - - return 0; - } -@@ -895,12 +892,14 @@ static int qcom_smem_map_memory(struct q - static int qcom_smem_probe(struct platform_device *pdev) - { - struct smem_header *header; -+ struct reserved_mem *rmem; - struct qcom_smem *smem; - size_t array_size; - int num_regions; - int hwlock_id; - u32 version; - int ret; -+ int i; - - num_regions = 1; - if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) -@@ -914,13 +913,35 @@ static int qcom_smem_probe(struct platfo - smem->dev = &pdev->dev; - smem->num_regions = num_regions; - -- ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); -- if (ret) -- return ret; -- -- if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev, -- "qcom,rpm-msg-ram", 1))) -- return ret; -+ rmem = of_reserved_mem_lookup(pdev->dev.of_node); -+ if (rmem) { -+ smem->regions[0].aux_base = rmem->base; -+ smem->regions[0].size = rmem->size; -+ } else { -+ /* -+ * Fall back to the memory-region reference, if we're not a -+ * reserved-memory node. -+ */ -+ ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]); -+ if (ret) -+ return ret; -+ } -+ -+ if (num_regions > 1) { -+ ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]); -+ if (ret) -+ return ret; -+ } -+ -+ for (i = 0; i < num_regions; i++) { -+ smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev, -+ smem->regions[i].aux_base, -+ smem->regions[i].size); -+ if (!smem->regions[i].virt_base) { -+ dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base); -+ return -ENOMEM; -+ } -+ } - - header = smem->regions[0].virt_base; - if (le32_to_cpu(header->initialized) != 1 || diff --git a/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch b/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch deleted file mode 100644 index 84ae5a7fc73..00000000000 --- a/target/linux/generic/backport-6.1/302-v5.16-watchdog-bcm63xx_wdt-fix-fallthrough-warning.patch +++ /dev/null @@ -1,33 +0,0 @@ -From ee1a0696934a8b77a6a2098f92832c46d34ec5da Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Wed, 27 Oct 2021 14:31:35 +0200 -Subject: [PATCH] watchdog: bcm63xx_wdt: fix fallthrough warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes: -drivers/watchdog/bcm63xx_wdt.c: In function 'bcm63xx_wdt_ioctl': -drivers/watchdog/bcm63xx_wdt.c:208:17: warning: this statement may fall through [-Wimplicit-fallthrough=] - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Reviewed-by: Guenter Roeck -Link: https://lore.kernel.org/r/20211027123135.27458-1-zajec5@gmail.com -Signed-off-by: Guenter Roeck -Signed-off-by: Wim Van Sebroeck ---- - drivers/watchdog/bcm63xx_wdt.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/watchdog/bcm63xx_wdt.c -+++ b/drivers/watchdog/bcm63xx_wdt.c -@@ -207,6 +207,8 @@ static long bcm63xx_wdt_ioctl(struct fil - - bcm63xx_wdt_pet(); - -+ fallthrough; -+ - case WDIOC_GETTIMEOUT: - return put_user(wdt_time, p); - diff --git a/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch b/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch deleted file mode 100644 index c66a3f11b4b..00000000000 --- a/target/linux/generic/backport-6.1/330-v5.16-01-MIPS-kernel-proc-add-CPU-option-reporting.patch +++ /dev/null @@ -1,162 +0,0 @@ -From 626bfa03729959ea9917181fb3d8ffaa1594d02a Mon Sep 17 00:00:00 2001 -From: Hauke Mehrtens -Date: Wed, 13 Oct 2021 22:40:18 -0700 -Subject: [PATCH 1/1] MIPS: kernel: proc: add CPU option reporting - -Many MIPS CPUs have optional CPU features which are not activated for -all CPU cores. Print the CPU options, which are implemented in the core, -in /proc/cpuinfo. This makes it possible to see which features are -supported and which are not supported. This should cover all standard -MIPS extensions. Before, it only printed information about the main MIPS -ASEs. - -Signed-off-by: Hauke Mehrtens - -Changes from original patch[0]: -- Remove cpu_has_6k_cache and cpu_has_8k_cache due to commit 6ce91ba8589a - ("MIPS: Remove cpu_has_6k_cache and cpu_has_8k_cache in cpu_cache_init()") -- Add new options: mac2008_only, ftlbparex, gsexcex, mmid, mm_sysad, - mm_full -- Use seq_puts instead of seq_printf as suggested by checkpatch -- Minor commit message reword - -[0]: https://lore.kernel.org/linux-mips/20181223225224.23042-1-hauke@hauke-m.de/ - -Signed-off-by: Ilya Lipnitskiy -Acked-by: Hauke Mehrtens -Signed-off-by: Thomas Bogendoerfer ---- - arch/mips/kernel/proc.c | 122 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 122 insertions(+) - ---- a/arch/mips/kernel/proc.c -+++ b/arch/mips/kernel/proc.c -@@ -138,6 +138,128 @@ static int show_cpuinfo(struct seq_file - seq_printf(m, "micromips kernel\t: %s\n", - (read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no"); - } -+ -+ seq_puts(m, "Options implemented\t:"); -+ if (cpu_has_tlb) -+ seq_puts(m, " tlb"); -+ if (cpu_has_ftlb) -+ seq_puts(m, " ftlb"); -+ if (cpu_has_tlbinv) -+ seq_puts(m, " tlbinv"); -+ if (cpu_has_segments) -+ seq_puts(m, " segments"); -+ if (cpu_has_rixiex) -+ seq_puts(m, " rixiex"); -+ if (cpu_has_ldpte) -+ seq_puts(m, " ldpte"); -+ if (cpu_has_maar) -+ seq_puts(m, " maar"); -+ if (cpu_has_rw_llb) -+ seq_puts(m, " rw_llb"); -+ if (cpu_has_4kex) -+ seq_puts(m, " 4kex"); -+ if (cpu_has_3k_cache) -+ seq_puts(m, " 3k_cache"); -+ if (cpu_has_4k_cache) -+ seq_puts(m, " 4k_cache"); -+ if (cpu_has_tx39_cache) -+ seq_puts(m, " tx39_cache"); -+ if (cpu_has_octeon_cache) -+ seq_puts(m, " octeon_cache"); -+ if (cpu_has_fpu) -+ seq_puts(m, " fpu"); -+ if (cpu_has_32fpr) -+ seq_puts(m, " 32fpr"); -+ if (cpu_has_cache_cdex_p) -+ seq_puts(m, " cache_cdex_p"); -+ if (cpu_has_cache_cdex_s) -+ seq_puts(m, " cache_cdex_s"); -+ if (cpu_has_prefetch) -+ seq_puts(m, " prefetch"); -+ if (cpu_has_mcheck) -+ seq_puts(m, " mcheck"); -+ if (cpu_has_ejtag) -+ seq_puts(m, " ejtag"); -+ if (cpu_has_llsc) -+ seq_puts(m, " llsc"); -+ if (cpu_has_guestctl0ext) -+ seq_puts(m, " guestctl0ext"); -+ if (cpu_has_guestctl1) -+ seq_puts(m, " guestctl1"); -+ if (cpu_has_guestctl2) -+ seq_puts(m, " guestctl2"); -+ if (cpu_has_guestid) -+ seq_puts(m, " guestid"); -+ if (cpu_has_drg) -+ seq_puts(m, " drg"); -+ if (cpu_has_rixi) -+ seq_puts(m, " rixi"); -+ if (cpu_has_lpa) -+ seq_puts(m, " lpa"); -+ if (cpu_has_mvh) -+ seq_puts(m, " mvh"); -+ if (cpu_has_vtag_icache) -+ seq_puts(m, " vtag_icache"); -+ if (cpu_has_dc_aliases) -+ seq_puts(m, " dc_aliases"); -+ if (cpu_has_ic_fills_f_dc) -+ seq_puts(m, " ic_fills_f_dc"); -+ if (cpu_has_pindexed_dcache) -+ seq_puts(m, " pindexed_dcache"); -+ if (cpu_has_userlocal) -+ seq_puts(m, " userlocal"); -+ if (cpu_has_nofpuex) -+ seq_puts(m, " nofpuex"); -+ if (cpu_has_vint) -+ seq_puts(m, " vint"); -+ if (cpu_has_veic) -+ seq_puts(m, " veic"); -+ if (cpu_has_inclusive_pcaches) -+ seq_puts(m, " inclusive_pcaches"); -+ if (cpu_has_perf_cntr_intr_bit) -+ seq_puts(m, " perf_cntr_intr_bit"); -+ if (cpu_has_ufr) -+ seq_puts(m, " ufr"); -+ if (cpu_has_fre) -+ seq_puts(m, " fre"); -+ if (cpu_has_cdmm) -+ seq_puts(m, " cdmm"); -+ if (cpu_has_small_pages) -+ seq_puts(m, " small_pages"); -+ if (cpu_has_nan_legacy) -+ seq_puts(m, " nan_legacy"); -+ if (cpu_has_nan_2008) -+ seq_puts(m, " nan_2008"); -+ if (cpu_has_ebase_wg) -+ seq_puts(m, " ebase_wg"); -+ if (cpu_has_badinstr) -+ seq_puts(m, " badinstr"); -+ if (cpu_has_badinstrp) -+ seq_puts(m, " badinstrp"); -+ if (cpu_has_contextconfig) -+ seq_puts(m, " contextconfig"); -+ if (cpu_has_perf) -+ seq_puts(m, " perf"); -+ if (cpu_has_mac2008_only) -+ seq_puts(m, " mac2008_only"); -+ if (cpu_has_ftlbparex) -+ seq_puts(m, " ftlbparex"); -+ if (cpu_has_gsexcex) -+ seq_puts(m, " gsexcex"); -+ if (cpu_has_shared_ftlb_ram) -+ seq_puts(m, " shared_ftlb_ram"); -+ if (cpu_has_shared_ftlb_entries) -+ seq_puts(m, " shared_ftlb_entries"); -+ if (cpu_has_mipsmt_pertccounters) -+ seq_puts(m, " mipsmt_pertccounters"); -+ if (cpu_has_mmid) -+ seq_puts(m, " mmid"); -+ if (cpu_has_mm_sysad) -+ seq_puts(m, " mm_sysad"); -+ if (cpu_has_mm_full) -+ seq_puts(m, " mm_full"); -+ seq_puts(m, "\n"); -+ - seq_printf(m, "shadow register sets\t: %d\n", - cpu_data[n].srsets); - seq_printf(m, "kscratch registers\t: %d\n", diff --git a/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch b/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch deleted file mode 100644 index 6caf7d06d4e..00000000000 --- a/target/linux/generic/backport-6.1/330-v5.16-02-MIPS-Fix-using-smp_processor_id-in-preemptible-in-sh.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 1cab5bd69eb1f995ced2d7576cb15f8a8941fd85 Mon Sep 17 00:00:00 2001 -From: Tiezhu Yang -Date: Thu, 25 Nov 2021 19:39:32 +0800 -Subject: [PATCH 1/1] MIPS: Fix using smp_processor_id() in preemptible in - show_cpuinfo() - -There exists the following issue under DEBUG_PREEMPT: - - BUG: using smp_processor_id() in preemptible [00000000] code: systemd/1 - caller is show_cpuinfo+0x460/0xea0 - ... - Call Trace: - [] show_stack+0x94/0x128 - [] dump_stack_lvl+0x94/0xd8 - [] check_preemption_disabled+0x104/0x110 - [] show_cpuinfo+0x460/0xea0 - [] seq_read_iter+0xfc/0x4f8 - [] new_sync_read+0x110/0x1b8 - [] vfs_read+0x1b4/0x1d0 - [] ksys_read+0xd0/0x110 - [] syscall_common+0x34/0x58 - -We can see the following call trace: - show_cpuinfo() - cpu_has_fpu - current_cpu_data - smp_processor_id() - - $ addr2line -f -e vmlinux 0xffffffff802209c8 - show_cpuinfo - arch/mips/kernel/proc.c:188 - - $ head -188 arch/mips/kernel/proc.c | tail -1 - if (cpu_has_fpu) - - arch/mips/include/asm/cpu-features.h - # define cpu_has_fpu (current_cpu_data.options & MIPS_CPU_FPU) - - arch/mips/include/asm/cpu-info.h - #define current_cpu_data cpu_data[smp_processor_id()] - -Based on the above analysis, fix the issue by using raw_cpu_has_fpu -which calls raw_smp_processor_id() in show_cpuinfo(). - -Fixes: 626bfa037299 ("MIPS: kernel: proc: add CPU option reporting") -Signed-off-by: Tiezhu Yang -Signed-off-by: Thomas Bogendoerfer ---- - arch/mips/kernel/proc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/mips/kernel/proc.c -+++ b/arch/mips/kernel/proc.c -@@ -166,7 +166,7 @@ static int show_cpuinfo(struct seq_file - seq_puts(m, " tx39_cache"); - if (cpu_has_octeon_cache) - seq_puts(m, " octeon_cache"); -- if (cpu_has_fpu) -+ if (raw_cpu_has_fpu) - seq_puts(m, " fpu"); - if (cpu_has_32fpr) - seq_puts(m, " 32fpr"); diff --git a/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch b/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch deleted file mode 100644 index 541d247542b..00000000000 --- a/target/linux/generic/backport-6.1/331-v5.19-mtd-spinand-Add-support-for-XTX-XT26G0xA.patch +++ /dev/null @@ -1,186 +0,0 @@ -From f4c5c7f9d2e5ab005d57826b740b694b042a737c Mon Sep 17 00:00:00 2001 -From: Felix Matouschek -Date: Mon, 18 Apr 2022 15:28:03 +0200 -Subject: [PATCH 1/1] mtd: spinand: Add support for XTX XT26G0xA - -Add support for XTX Technology XT26G01AXXXXX, XTX26G02AXXXXX and -XTX26G04AXXXXX SPI NAND. - -These are 3V, 1G/2G/4Gbit serial SLC NAND flash devices with on-die ECC -(8bit strength per 512bytes). - -Tested on Teltonika RUTX10 flashed with OpenWrt. - -Links: - - http://www.xtxtech.com/download/?AId=225 - - https://datasheet.lcsc.com/szlcsc/2005251034_XTX-XT26G01AWSEGA_C558841.pdf -Signed-off-by: Felix Matouschek -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220418132803.664103-1-felix@matouschek.org ---- - drivers/mtd/nand/spi/Makefile | 2 +- - drivers/mtd/nand/spi/core.c | 1 + - drivers/mtd/nand/spi/xtx.c | 129 ++++++++++++++++++++++++++++++++++ - include/linux/mtd/spinand.h | 1 + - 4 files changed, 132 insertions(+), 1 deletion(-) - create mode 100644 drivers/mtd/nand/spi/xtx.c - ---- a/drivers/mtd/nand/spi/Makefile -+++ b/drivers/mtd/nand/spi/Makefile -@@ -1,3 +1,3 @@ - # SPDX-License-Identifier: GPL-2.0 --spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o -+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o - obj-$(CONFIG_MTD_SPI_NAND) += spinand.o ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -902,6 +902,7 @@ static const struct spinand_manufacturer - ¶gon_spinand_manufacturer, - &toshiba_spinand_manufacturer, - &winbond_spinand_manufacturer, -+ &xtx_spinand_manufacturer, - }; - - static int spinand_manufacturer_match(struct spinand_device *spinand, ---- /dev/null -+++ b/drivers/mtd/nand/spi/xtx.c -@@ -0,0 +1,129 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Author: -+ * Felix Matouschek -+ */ -+ -+#include -+#include -+#include -+ -+#define SPINAND_MFR_XTX 0x0B -+ -+#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2) -+#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2) -+#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4) -+#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4) -+ -+static SPINAND_OP_VARIANTS(read_cache_variants, -+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); -+ -+static SPINAND_OP_VARIANTS(write_cache_variants, -+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), -+ SPINAND_PROG_LOAD(true, 0, NULL, 0)); -+ -+static SPINAND_OP_VARIANTS(update_cache_variants, -+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), -+ SPINAND_PROG_LOAD(false, 0, NULL, 0)); -+ -+static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section) -+ return -ERANGE; -+ -+ region->offset = 48; -+ region->length = 16; -+ -+ return 0; -+} -+ -+static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section) -+ return -ERANGE; -+ -+ region->offset = 1; -+ region->length = 47; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = { -+ .ecc = xt26g0xa_ooblayout_ecc, -+ .free = xt26g0xa_ooblayout_free, -+}; -+ -+static int xt26g0xa_ecc_get_status(struct spinand_device *spinand, -+ u8 status) -+{ -+ status = status & XT26G0XA_STATUS_ECC_MASK; -+ -+ switch (status) { -+ case XT26G0XA_STATUS_ECC_NO_DETECTED: -+ return 0; -+ case XT26G0XA_STATUS_ECC_8_CORRECTED: -+ return 8; -+ case XT26G0XA_STATUS_ECC_UNCOR_ERROR: -+ return -EBADMSG; -+ default: -+ break; -+ } -+ -+ /* At this point values greater than (2 << 4) are invalid */ -+ if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR) -+ return -EINVAL; -+ -+ /* (1 << 2) through (7 << 2) are 1-7 corrected errors */ -+ return status >> 2; -+} -+ -+static const struct spinand_info xtx_spinand_table[] = { -+ SPINAND_INFO("XT26G01A", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1), -+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&xt26g0xa_ooblayout, -+ xt26g0xa_ecc_get_status)), -+ SPINAND_INFO("XT26G02A", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2), -+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&xt26g0xa_ooblayout, -+ xt26g0xa_ecc_get_status)), -+ SPINAND_INFO("XT26G04A", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3), -+ NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&xt26g0xa_ooblayout, -+ xt26g0xa_ecc_get_status)), -+}; -+ -+static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = { -+}; -+ -+const struct spinand_manufacturer xtx_spinand_manufacturer = { -+ .id = SPINAND_MFR_XTX, -+ .name = "XTX", -+ .chips = xtx_spinand_table, -+ .nchips = ARRAY_SIZE(xtx_spinand_table), -+ .ops = &xtx_spinand_manuf_ops, -+}; ---- a/include/linux/mtd/spinand.h -+++ b/include/linux/mtd/spinand.h -@@ -266,6 +266,7 @@ extern const struct spinand_manufacturer - extern const struct spinand_manufacturer paragon_spinand_manufacturer; - extern const struct spinand_manufacturer toshiba_spinand_manufacturer; - extern const struct spinand_manufacturer winbond_spinand_manufacturer; -+extern const struct spinand_manufacturer xtx_spinand_manufacturer; - - /** - * struct spinand_op_variants - SPI NAND operation variants diff --git a/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch b/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch deleted file mode 100644 index d6c4b4fd1ee..00000000000 --- a/target/linux/generic/backport-6.1/344-v5.18-01-phy-marvell-phy-mvebu-a3700-comphy-Remove-port-from-.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 4bf18d5a2dd02db8c5b16a2cfae513510506df5b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Thu, 3 Feb 2022 22:44:40 +0100 -Subject: [PATCH 1/2] phy: marvell: phy-mvebu-a3700-comphy: Remove port from - driver configuration -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Port number is encoded into argument for SMC call. It is zero for SATA, -PCIe and also both USB 3.0 PHYs. It is non-zero only for Ethernet PHY -(incorrectly called SGMII) on lane 0. Ethernet PHY on lane 1 also uses zero -port number. - -So construct "port" bits for SMC call argument can be constructed directly -from PHY type and lane number. - -Change driver code to always pass zero port number for non-ethernet PHYs -and for ethernet PHYs determinate port number from lane number. This -simplifies the driver. - -As port number from DT PHY configuration is not used anymore, remove whole -driver code which parses it. This also simplifies the driver. - -Signed-off-by: Pali Rohár -Signed-off-by: Marek Behún -Reviewed-by: Miquel Raynal -Link: https://lore.kernel.org/r/20220203214444.1508-2-kabel@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 62 +++++++++----------- - 1 file changed, 29 insertions(+), 33 deletions(-) - ---- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -+++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -@@ -20,7 +20,6 @@ - #include - - #define MVEBU_A3700_COMPHY_LANES 3 --#define MVEBU_A3700_COMPHY_PORTS 2 - - /* COMPHY Fast SMC function identifiers */ - #define COMPHY_SIP_POWER_ON 0x82000001 -@@ -45,51 +44,47 @@ - #define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ - ((idx) << 8) | \ - ((speed) << 2)) --#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \ -+#define COMPHY_FW_PCIE(mode, speed, width) (COMPHY_FW_NET(mode, 0, speed) | \ - ((width) << 18)) - - struct mvebu_a3700_comphy_conf { - unsigned int lane; - enum phy_mode mode; - int submode; -- unsigned int port; - u32 fw_mode; - }; - --#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \ -+#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _fw) \ - { \ - .lane = _lane, \ - .mode = _mode, \ - .submode = _smode, \ -- .port = _port, \ - .fw_mode = _fw, \ - } - --#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \ -- MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw) -+#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _fw) \ -+ MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _fw) - --#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \ -- MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw) -+#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _fw) \ -+ MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _fw) - - static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { - /* lane 0 */ -- MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0, -+ MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, - COMPHY_FW_MODE_USB3H), -- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1, -+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, - COMPHY_FW_MODE_SGMII), -- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1, -+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, - COMPHY_FW_MODE_2500BASEX), - /* lane 1 */ -- MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0, -- COMPHY_FW_MODE_PCIE), -- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0, -+ MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), -+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, - COMPHY_FW_MODE_SGMII), -- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0, -+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, - COMPHY_FW_MODE_2500BASEX), - /* lane 2 */ -- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0, -- COMPHY_FW_MODE_SATA), -- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0, -+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), -+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, - COMPHY_FW_MODE_USB3H), - }; - -@@ -98,7 +93,6 @@ struct mvebu_a3700_comphy_lane { - unsigned int id; - enum phy_mode mode; - int submode; -- int port; - }; - - static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, -@@ -120,7 +114,7 @@ static int mvebu_a3700_comphy_smc(unsign - } - } - --static int mvebu_a3700_comphy_get_fw_mode(int lane, int port, -+static int mvebu_a3700_comphy_get_fw_mode(int lane, - enum phy_mode mode, - int submode) - { -@@ -132,7 +126,6 @@ static int mvebu_a3700_comphy_get_fw_mod - - for (i = 0; i < n; i++) { - if (mvebu_a3700_comphy_modes[i].lane == lane && -- mvebu_a3700_comphy_modes[i].port == port && - mvebu_a3700_comphy_modes[i].mode == mode && - mvebu_a3700_comphy_modes[i].submode == submode) - break; -@@ -153,7 +146,7 @@ static int mvebu_a3700_comphy_set_mode(s - if (submode == PHY_INTERFACE_MODE_1000BASEX) - submode = PHY_INTERFACE_MODE_SGMII; - -- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode, -+ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, mode, - submode); - if (fw_mode < 0) { - dev_err(lane->dev, "invalid COMPHY mode\n"); -@@ -172,9 +165,10 @@ static int mvebu_a3700_comphy_power_on(s - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); - u32 fw_param; - int fw_mode; -+ int fw_port; - int ret; - -- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, -+ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, - lane->mode, lane->submode); - if (fw_mode < 0) { - dev_err(lane->dev, "invalid COMPHY mode\n"); -@@ -191,17 +185,18 @@ static int mvebu_a3700_comphy_power_on(s - fw_param = COMPHY_FW_MODE(fw_mode); - break; - case PHY_MODE_ETHERNET: -+ fw_port = (lane->id == 0) ? 1 : 0; - switch (lane->submode) { - case PHY_INTERFACE_MODE_SGMII: - dev_dbg(lane->dev, "set lane %d to SGMII mode\n", - lane->id); -- fw_param = COMPHY_FW_NET(fw_mode, lane->port, -+ fw_param = COMPHY_FW_NET(fw_mode, fw_port, - COMPHY_FW_SPEED_1_25G); - break; - case PHY_INTERFACE_MODE_2500BASEX: - dev_dbg(lane->dev, "set lane %d to 2500BASEX mode\n", - lane->id); -- fw_param = COMPHY_FW_NET(fw_mode, lane->port, -+ fw_param = COMPHY_FW_NET(fw_mode, fw_port, - COMPHY_FW_SPEED_3_125G); - break; - default: -@@ -212,8 +207,7 @@ static int mvebu_a3700_comphy_power_on(s - break; - case PHY_MODE_PCIE: - dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); -- fw_param = COMPHY_FW_PCIE(fw_mode, lane->port, -- COMPHY_FW_SPEED_5G, -+ fw_param = COMPHY_FW_PCIE(fw_mode, COMPHY_FW_SPEED_5G, - phy->attrs.bus_width); - break; - default: -@@ -247,17 +241,20 @@ static struct phy *mvebu_a3700_comphy_xl - struct of_phandle_args *args) - { - struct mvebu_a3700_comphy_lane *lane; -+ unsigned int port; - struct phy *phy; - -- if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS)) -- return ERR_PTR(-EINVAL); -- - phy = of_phy_simple_xlate(dev, args); - if (IS_ERR(phy)) - return phy; - - lane = phy_get_drvdata(phy); -- lane->port = args->args[0]; -+ -+ port = args->args[0]; -+ if (port != 0 && (port != 1 || lane->id != 0)) { -+ dev_err(lane->dev, "invalid port number %u\n", port); -+ return ERR_PTR(-EINVAL); -+ } - - return phy; - } -@@ -302,7 +299,6 @@ static int mvebu_a3700_comphy_probe(stru - lane->mode = PHY_MODE_INVALID; - lane->submode = PHY_INTERFACE_MODE_NA; - lane->id = lane_id; -- lane->port = -1; - phy_set_drvdata(phy, lane); - } - diff --git a/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch b/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch deleted file mode 100644 index 4593d14bfe6..00000000000 --- a/target/linux/generic/backport-6.1/344-v5.18-02-phy-marvell-phy-mvebu-a3700-comphy-Add-native-kernel.patch +++ /dev/null @@ -1,1552 +0,0 @@ -From 934337080c6c59b75db76b180b509f218640ad48 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Thu, 3 Feb 2022 22:44:41 +0100 -Subject: [PATCH 2/2] phy: marvell: phy-mvebu-a3700-comphy: Add native kernel - implementation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Remove old RPC implementation and add a new native kernel implementation. - -The old implementation uses ARM SMC API to issue RPC calls to ARM Trusted -Firmware which provides real implementation of PHY configuration. - -But older versions of ARM Trusted Firmware do not provide this PHY -configuration functionality, simply returning: operation not supported; or -worse, some versions provide the configuration functionality incorrectly. - -For example the firmware shipped in ESPRESSObin board has this older -version of ARM Trusted Firmware and therefore SATA, USB 3.0 and PCIe -functionality do not work with newer versions of Linux kernel. - -Due to the above reasons, the following commits were introduced into Linux, -to workaround these issues by ignoring -EOPNOTSUPP error code from -phy-mvebu-a3700-comphy driver function phy_power_on(): - -commit 45aefe3d2251 ("ata: ahci: mvebu: Make SATA PHY optional for Armada -3720") -commit 3241929b67d2 ("usb: host: xhci: mvebu: make USB 3.0 PHY optional for -Armada 3720") -commit b0c6ae0f8948 ("PCI: aardvark: Fix initialization with old Marvell's -Arm Trusted Firmware") - -Replace this RPC implementation with proper native kernel implementation, -which is independent on the firmware. Never return -EOPNOTSUPP for proper -arguments. - -This should solve multiple issues with real-world boards, where it is not -possible or really inconvenient to change the firmware. Let's eliminate -these issues. - -This implementation is ported directly from Armada 3720 comphy driver found -in newest version of ARM Trusted Firmware source code, but with various -fixes of register names, some added comments, some refactoring due to the -original code not conforming to kernel standards. Also PCIe mode poweroff -support was added here, and PHY reset support. These changes are also going -to be sent to ARM Trusted Firmware. - -[ Pali did the porting from ATF. - I (Marek) then fixed some register names, some various other things, - added some comments and refactored the code to kernel standards. Also - fixed PHY poweroff and added PHY reset. ] - -Signed-off-by: Pali Rohár -Acked-by: Miquel Raynal -Signed-off-by: Marek Behún -Link: https://lore.kernel.org/r/20220203214444.1508-3-kabel@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 1332 ++++++++++++++++-- - 1 file changed, 1215 insertions(+), 117 deletions(-) - ---- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -+++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -@@ -5,12 +5,16 @@ - * Authors: - * Evan Wang - * Miquèl Raynal -+ * Pali Rohár -+ * Marek Behún - * - * Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart. -- * SMC call initial support done by Grzegorz Jaszczyk. -+ * Comphy code from ARM Trusted Firmware ported by Pali Rohár -+ * and Marek Behún . - */ - --#include -+#include -+#include - #include - #include - #include -@@ -18,103 +22,1118 @@ - #include - #include - #include -+#include - --#define MVEBU_A3700_COMPHY_LANES 3 -+#define PLL_SET_DELAY_US 600 -+#define COMPHY_PLL_SLEEP 1000 -+#define COMPHY_PLL_TIMEOUT 150000 -+ -+/* Comphy lane2 indirect access register offset */ -+#define COMPHY_LANE2_INDIR_ADDR 0x0 -+#define COMPHY_LANE2_INDIR_DATA 0x4 -+ -+/* SATA and USB3 PHY offset compared to SATA PHY */ -+#define COMPHY_LANE2_REGS_BASE 0x200 -+ -+/* -+ * When accessing common PHY lane registers directly, we need to shift by 1, -+ * since the registers are 16-bit. -+ */ -+#define COMPHY_LANE_REG_DIRECT(reg) (((reg) & 0x7FF) << 1) -+ -+/* COMPHY registers */ -+#define COMPHY_POWER_PLL_CTRL 0x01 -+#define PU_IVREF_BIT BIT(15) -+#define PU_PLL_BIT BIT(14) -+#define PU_RX_BIT BIT(13) -+#define PU_TX_BIT BIT(12) -+#define PU_TX_INTP_BIT BIT(11) -+#define PU_DFE_BIT BIT(10) -+#define RESET_DTL_RX_BIT BIT(9) -+#define PLL_LOCK_BIT BIT(8) -+#define REF_FREF_SEL_MASK GENMASK(4, 0) -+#define REF_FREF_SEL_SERDES_25MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x1) -+#define REF_FREF_SEL_SERDES_40MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x3) -+#define REF_FREF_SEL_SERDES_50MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x4) -+#define REF_FREF_SEL_PCIE_USB3_25MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x2) -+#define REF_FREF_SEL_PCIE_USB3_40MHZ FIELD_PREP(REF_FREF_SEL_MASK, 0x3) -+#define COMPHY_MODE_MASK GENMASK(7, 5) -+#define COMPHY_MODE_SATA FIELD_PREP(COMPHY_MODE_MASK, 0x0) -+#define COMPHY_MODE_PCIE FIELD_PREP(COMPHY_MODE_MASK, 0x3) -+#define COMPHY_MODE_SERDES FIELD_PREP(COMPHY_MODE_MASK, 0x4) -+#define COMPHY_MODE_USB3 FIELD_PREP(COMPHY_MODE_MASK, 0x5) -+ -+#define COMPHY_KVCO_CAL_CTRL 0x02 -+#define USE_MAX_PLL_RATE_BIT BIT(12) -+#define SPEED_PLL_MASK GENMASK(7, 2) -+#define SPEED_PLL_VALUE_16 FIELD_PREP(SPEED_PLL_MASK, 0x10) -+ -+#define COMPHY_DIG_LOOPBACK_EN 0x23 -+#define SEL_DATA_WIDTH_MASK GENMASK(11, 10) -+#define DATA_WIDTH_10BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x0) -+#define DATA_WIDTH_20BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x1) -+#define DATA_WIDTH_40BIT FIELD_PREP(SEL_DATA_WIDTH_MASK, 0x2) -+#define PLL_READY_TX_BIT BIT(4) -+ -+#define COMPHY_SYNC_PATTERN 0x24 -+#define TXD_INVERT_BIT BIT(10) -+#define RXD_INVERT_BIT BIT(11) -+ -+#define COMPHY_SYNC_MASK_GEN 0x25 -+#define PHY_GEN_MAX_MASK GENMASK(11, 10) -+#define PHY_GEN_MAX_USB3_5G FIELD_PREP(PHY_GEN_MAX_MASK, 0x1) -+ -+#define COMPHY_ISOLATION_CTRL 0x26 -+#define PHY_ISOLATE_MODE BIT(15) -+ -+#define COMPHY_GEN2_SET2 0x3e -+#define GS2_TX_SSC_AMP_MASK GENMASK(15, 9) -+#define GS2_TX_SSC_AMP_4128 FIELD_PREP(GS2_TX_SSC_AMP_MASK, 0x20) -+#define GS2_VREG_RXTX_MAS_ISET_MASK GENMASK(8, 7) -+#define GS2_VREG_RXTX_MAS_ISET_60U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ -+ 0x0) -+#define GS2_VREG_RXTX_MAS_ISET_80U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ -+ 0x1) -+#define GS2_VREG_RXTX_MAS_ISET_100U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ -+ 0x2) -+#define GS2_VREG_RXTX_MAS_ISET_120U FIELD_PREP(GS2_VREG_RXTX_MAS_ISET_MASK,\ -+ 0x3) -+#define GS2_RSVD_6_0_MASK GENMASK(6, 0) -+ -+#define COMPHY_GEN3_SET2 0x3f -+ -+#define COMPHY_IDLE_SYNC_EN 0x48 -+#define IDLE_SYNC_EN BIT(12) -+ -+#define COMPHY_MISC_CTRL0 0x4F -+#define CLK100M_125M_EN BIT(4) -+#define TXDCLK_2X_SEL BIT(6) -+#define CLK500M_EN BIT(7) -+#define PHY_REF_CLK_SEL BIT(10) -+ -+#define COMPHY_SFT_RESET 0x52 -+#define SFT_RST BIT(9) -+#define SFT_RST_NO_REG BIT(10) -+ -+#define COMPHY_MISC_CTRL1 0x73 -+#define SEL_BITS_PCIE_FORCE BIT(15) -+ -+#define COMPHY_GEN2_SET3 0x112 -+#define GS3_FFE_CAP_SEL_MASK GENMASK(3, 0) -+#define GS3_FFE_CAP_SEL_VALUE FIELD_PREP(GS3_FFE_CAP_SEL_MASK, 0xF) -+ -+/* PIPE registers */ -+#define COMPHY_PIPE_LANE_CFG0 0x180 -+#define PRD_TXDEEMPH0_MASK BIT(0) -+#define PRD_TXMARGIN_MASK GENMASK(3, 1) -+#define PRD_TXSWING_MASK BIT(4) -+#define CFG_TX_ALIGN_POS_MASK GENMASK(8, 5) -+ -+#define COMPHY_PIPE_LANE_CFG1 0x181 -+#define PRD_TXDEEMPH1_MASK BIT(15) -+#define USE_MAX_PLL_RATE_EN BIT(9) -+#define TX_DET_RX_MODE BIT(6) -+#define GEN2_TX_DATA_DLY_MASK GENMASK(4, 3) -+#define GEN2_TX_DATA_DLY_DEFT FIELD_PREP(GEN2_TX_DATA_DLY_MASK, 2) -+#define TX_ELEC_IDLE_MODE_EN BIT(0) -+ -+#define COMPHY_PIPE_LANE_STAT1 0x183 -+#define TXDCLK_PCLK_EN BIT(0) -+ -+#define COMPHY_PIPE_LANE_CFG4 0x188 -+#define SPREAD_SPECTRUM_CLK_EN BIT(7) -+ -+#define COMPHY_PIPE_RST_CLK_CTRL 0x1C1 -+#define PIPE_SOFT_RESET BIT(0) -+#define PIPE_REG_RESET BIT(1) -+#define MODE_CORE_CLK_FREQ_SEL BIT(9) -+#define MODE_PIPE_WIDTH_32 BIT(3) -+#define MODE_REFDIV_MASK GENMASK(5, 4) -+#define MODE_REFDIV_BY_4 FIELD_PREP(MODE_REFDIV_MASK, 0x2) -+ -+#define COMPHY_PIPE_TEST_MODE_CTRL 0x1C2 -+#define MODE_MARGIN_OVERRIDE BIT(2) -+ -+#define COMPHY_PIPE_CLK_SRC_LO 0x1C3 -+#define MODE_CLK_SRC BIT(0) -+#define BUNDLE_PERIOD_SEL BIT(1) -+#define BUNDLE_PERIOD_SCALE_MASK GENMASK(3, 2) -+#define BUNDLE_SAMPLE_CTRL BIT(4) -+#define PLL_READY_DLY_MASK GENMASK(7, 5) -+#define CFG_SEL_20B BIT(15) -+ -+#define COMPHY_PIPE_PWR_MGM_TIM1 0x1D0 -+#define CFG_PM_OSCCLK_WAIT_MASK GENMASK(15, 12) -+#define CFG_PM_RXDEN_WAIT_MASK GENMASK(11, 8) -+#define CFG_PM_RXDEN_WAIT_1_UNIT FIELD_PREP(CFG_PM_RXDEN_WAIT_MASK, 0x1) -+#define CFG_PM_RXDLOZ_WAIT_MASK GENMASK(7, 0) -+#define CFG_PM_RXDLOZ_WAIT_7_UNIT FIELD_PREP(CFG_PM_RXDLOZ_WAIT_MASK, 0x7) -+#define CFG_PM_RXDLOZ_WAIT_12_UNIT FIELD_PREP(CFG_PM_RXDLOZ_WAIT_MASK, 0xC) -+ -+/* -+ * This register is not from PHY lane register space. It only exists in the -+ * indirect register space, before the actual PHY lane 2 registers. So the -+ * offset is absolute, not relative to COMPHY_LANE2_REGS_BASE. -+ * It is used only for SATA PHY initialization. -+ */ -+#define COMPHY_RESERVED_REG 0x0E -+#define PHYCTRL_FRM_PIN_BIT BIT(13) - --/* COMPHY Fast SMC function identifiers */ --#define COMPHY_SIP_POWER_ON 0x82000001 --#define COMPHY_SIP_POWER_OFF 0x82000002 --#define COMPHY_SIP_PLL_LOCK 0x82000003 -- --#define COMPHY_FW_MODE_SATA 0x1 --#define COMPHY_FW_MODE_SGMII 0x2 --#define COMPHY_FW_MODE_2500BASEX 0x3 --#define COMPHY_FW_MODE_USB3H 0x4 --#define COMPHY_FW_MODE_USB3D 0x5 --#define COMPHY_FW_MODE_PCIE 0x6 --#define COMPHY_FW_MODE_USB3 0xa -- --#define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */ --#define COMPHY_FW_SPEED_2_5G 1 --#define COMPHY_FW_SPEED_3_125G 2 /* 2500BASE-X */ --#define COMPHY_FW_SPEED_5G 3 --#define COMPHY_FW_SPEED_MAX 0x3F -- --#define COMPHY_FW_MODE(mode) ((mode) << 12) --#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \ -- ((idx) << 8) | \ -- ((speed) << 2)) --#define COMPHY_FW_PCIE(mode, speed, width) (COMPHY_FW_NET(mode, 0, speed) | \ -- ((width) << 18)) -+/* South Bridge PHY Configuration Registers */ -+#define COMPHY_PHY_REG(lane, reg) (((1 - (lane)) * 0x28) + ((reg) & 0x3f)) -+ -+/* -+ * lane0: USB3/GbE1 PHY Configuration 1 -+ * lane1: PCIe/GbE0 PHY Configuration 1 -+ * (used only by SGMII code) -+ */ -+#define COMPHY_PHY_CFG1 0x0 -+#define PIN_PU_IVREF_BIT BIT(1) -+#define PIN_RESET_CORE_BIT BIT(11) -+#define PIN_RESET_COMPHY_BIT BIT(12) -+#define PIN_PU_PLL_BIT BIT(16) -+#define PIN_PU_RX_BIT BIT(17) -+#define PIN_PU_TX_BIT BIT(18) -+#define PIN_TX_IDLE_BIT BIT(19) -+#define GEN_RX_SEL_MASK GENMASK(25, 22) -+#define GEN_RX_SEL_VALUE(val) FIELD_PREP(GEN_RX_SEL_MASK, (val)) -+#define GEN_TX_SEL_MASK GENMASK(29, 26) -+#define GEN_TX_SEL_VALUE(val) FIELD_PREP(GEN_TX_SEL_MASK, (val)) -+#define SERDES_SPEED_1_25_G 0x6 -+#define SERDES_SPEED_3_125_G 0x8 -+#define PHY_RX_INIT_BIT BIT(30) -+ -+/* -+ * lane0: USB3/GbE1 PHY Status 1 -+ * lane1: PCIe/GbE0 PHY Status 1 -+ * (used only by SGMII code) -+ */ -+#define COMPHY_PHY_STAT1 0x18 -+#define PHY_RX_INIT_DONE_BIT BIT(0) -+#define PHY_PLL_READY_RX_BIT BIT(2) -+#define PHY_PLL_READY_TX_BIT BIT(3) -+ -+/* PHY Selector */ -+#define COMPHY_SELECTOR_PHY_REG 0xFC -+/* bit0: 0: Lane1 is GbE0; 1: Lane1 is PCIe */ -+#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0) -+/* bit4: 0: Lane0 is GbE1; 1: Lane0 is USB3 */ -+#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4) -+/* bit8: 0: Lane0 is USB3 instead of GbE1, Lane2 is SATA; 1: Lane2 is USB3 */ -+#define COMPHY_SELECTOR_USB3_PHY_SEL_BIT BIT(8) - - struct mvebu_a3700_comphy_conf { - unsigned int lane; - enum phy_mode mode; - int submode; -- u32 fw_mode; - }; - --#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _fw) \ -+#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode) \ - { \ - .lane = _lane, \ - .mode = _mode, \ - .submode = _smode, \ -- .fw_mode = _fw, \ - } - --#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _fw) \ -- MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _fw) -+#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode) \ -+ MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA) - --#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _fw) \ -- MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _fw) -+#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode) \ -+ MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode) - - static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = { - /* lane 0 */ -- MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, -- COMPHY_FW_MODE_USB3H), -- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, -- COMPHY_FW_MODE_SGMII), -- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, -- COMPHY_FW_MODE_2500BASEX), -+ MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS), -+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII), -+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_1000BASEX), -+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX), - /* lane 1 */ -- MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), -- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, -- COMPHY_FW_MODE_SGMII), -- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, -- COMPHY_FW_MODE_2500BASEX), -+ MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE), -+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII), -+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_1000BASEX), -+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX), - /* lane 2 */ -- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, COMPHY_FW_MODE_SATA), -- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, -- COMPHY_FW_MODE_USB3H), -+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA), -+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS), -+}; -+ -+struct mvebu_a3700_comphy_priv { -+ void __iomem *comphy_regs; -+ void __iomem *lane0_phy_regs; /* USB3 and GbE1 */ -+ void __iomem *lane1_phy_regs; /* PCIe and GbE0 */ -+ void __iomem *lane2_phy_indirect; /* SATA and USB3 */ -+ spinlock_t lock; /* for PHY selector access */ -+ bool xtal_is_40m; - }; - - struct mvebu_a3700_comphy_lane { -+ struct mvebu_a3700_comphy_priv *priv; - struct device *dev; - unsigned int id; - enum phy_mode mode; - int submode; -+ bool invert_tx; -+ bool invert_rx; -+ bool needs_reset; -+}; -+ -+struct gbe_phy_init_data_fix { -+ u16 addr; -+ u16 value; -+}; -+ -+/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */ -+static struct gbe_phy_init_data_fix gbe_phy_init_fix[] = { -+ { 0x005, 0x07CC }, { 0x015, 0x0000 }, { 0x01B, 0x0000 }, -+ { 0x01D, 0x0000 }, { 0x01E, 0x0000 }, { 0x01F, 0x0000 }, -+ { 0x020, 0x0000 }, { 0x021, 0x0030 }, { 0x026, 0x0888 }, -+ { 0x04D, 0x0152 }, { 0x04F, 0xA020 }, { 0x050, 0x07CC }, -+ { 0x053, 0xE9CA }, { 0x055, 0xBD97 }, { 0x071, 0x3015 }, -+ { 0x076, 0x03AA }, { 0x07C, 0x0FDF }, { 0x0C2, 0x3030 }, -+ { 0x0C3, 0x8000 }, { 0x0E2, 0x5550 }, { 0x0E3, 0x12A4 }, -+ { 0x0E4, 0x7D00 }, { 0x0E6, 0x0C83 }, { 0x101, 0xFCC0 }, -+ { 0x104, 0x0C10 } - }; - --static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane, -- unsigned long mode) -+/* 40M1G25 mode init data */ -+static u16 gbe_phy_init[512] = { -+ /* 0 1 2 3 4 5 6 7 */ -+ /*-----------------------------------------------------------*/ -+ /* 8 9 A B C D E F */ -+ 0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */ -+ 0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */ -+ 0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */ -+ 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */ -+ 0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */ -+ 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */ -+ 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ -+ 0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */ -+ 0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */ -+ 0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */ -+ 0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */ -+ 0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */ -+ 0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */ -+ 0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */ -+ 0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */ -+ 0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */ -+ 0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */ -+ 0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */ -+ 0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */ -+ 0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */ -+ 0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */ -+ 0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */ -+ 0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */ -+ 0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */ -+ 0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */ -+ 0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */ -+ 0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */ -+ 0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */ -+ 0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */ -+ 0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */ -+ 0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */ -+ 0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */ -+ 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */ -+ 0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */ -+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */ -+}; -+ -+static inline void comphy_reg_set(void __iomem *addr, u32 data, u32 mask) - { -- struct arm_smccc_res res; -- s32 ret; -+ u32 val; -+ -+ val = readl(addr); -+ val = (val & ~mask) | (data & mask); -+ writel(val, addr); -+} - -- arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res); -- ret = res.a0; -+static inline void comphy_reg_set16(void __iomem *addr, u16 data, u16 mask) -+{ -+ u16 val; - -- switch (ret) { -- case SMCCC_RET_SUCCESS: -- return 0; -- case SMCCC_RET_NOT_SUPPORTED: -- return -EOPNOTSUPP; -+ val = readw(addr); -+ val = (val & ~mask) | (data & mask); -+ writew(val, addr); -+} -+ -+/* Used for accessing lane 2 registers (SATA/USB3 PHY) */ -+static void comphy_set_indirect(struct mvebu_a3700_comphy_priv *priv, -+ u32 offset, u16 data, u16 mask) -+{ -+ writel(offset, -+ priv->lane2_phy_indirect + COMPHY_LANE2_INDIR_ADDR); -+ comphy_reg_set(priv->lane2_phy_indirect + COMPHY_LANE2_INDIR_DATA, -+ data, mask); -+} -+ -+static void comphy_lane_reg_set(struct mvebu_a3700_comphy_lane *lane, -+ u16 reg, u16 data, u16 mask) -+{ -+ if (lane->id == 2) { -+ /* lane 2 PHY registers are accessed indirectly */ -+ comphy_set_indirect(lane->priv, -+ reg + COMPHY_LANE2_REGS_BASE, -+ data, mask); -+ } else { -+ void __iomem *base = lane->id == 1 ? -+ lane->priv->lane1_phy_regs : -+ lane->priv->lane0_phy_regs; -+ -+ comphy_reg_set16(base + COMPHY_LANE_REG_DIRECT(reg), -+ data, mask); -+ } -+} -+ -+static int comphy_lane_reg_poll(struct mvebu_a3700_comphy_lane *lane, -+ u16 reg, u16 bits, -+ ulong sleep_us, ulong timeout_us) -+{ -+ int ret; -+ -+ if (lane->id == 2) { -+ u32 data; -+ -+ /* lane 2 PHY registers are accessed indirectly */ -+ writel(reg + COMPHY_LANE2_REGS_BASE, -+ lane->priv->lane2_phy_indirect + -+ COMPHY_LANE2_INDIR_ADDR); -+ -+ ret = readl_poll_timeout(lane->priv->lane2_phy_indirect + -+ COMPHY_LANE2_INDIR_DATA, -+ data, (data & bits) == bits, -+ sleep_us, timeout_us); -+ } else { -+ void __iomem *base = lane->id == 1 ? -+ lane->priv->lane1_phy_regs : -+ lane->priv->lane0_phy_regs; -+ u16 data; -+ -+ ret = readw_poll_timeout(base + COMPHY_LANE_REG_DIRECT(reg), -+ data, (data & bits) == bits, -+ sleep_us, timeout_us); -+ } -+ -+ return ret; -+} -+ -+static void comphy_periph_reg_set(struct mvebu_a3700_comphy_lane *lane, -+ u8 reg, u32 data, u32 mask) -+{ -+ comphy_reg_set(lane->priv->comphy_regs + COMPHY_PHY_REG(lane->id, reg), -+ data, mask); -+} -+ -+static int comphy_periph_reg_poll(struct mvebu_a3700_comphy_lane *lane, -+ u8 reg, u32 bits, -+ ulong sleep_us, ulong timeout_us) -+{ -+ u32 data; -+ -+ return readl_poll_timeout(lane->priv->comphy_regs + -+ COMPHY_PHY_REG(lane->id, reg), -+ data, (data & bits) == bits, -+ sleep_us, timeout_us); -+} -+ -+/* PHY selector configures with corresponding modes */ -+static int -+mvebu_a3700_comphy_set_phy_selector(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 old, new, clr = 0, set = 0; -+ unsigned long flags; -+ -+ switch (lane->mode) { -+ case PHY_MODE_SATA: -+ /* SATA must be in Lane2 */ -+ if (lane->id == 2) -+ clr = COMPHY_SELECTOR_USB3_PHY_SEL_BIT; -+ else -+ goto error; -+ break; -+ -+ case PHY_MODE_ETHERNET: -+ if (lane->id == 0) -+ clr = COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; -+ else if (lane->id == 1) -+ clr = COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; -+ else -+ goto error; -+ break; -+ -+ case PHY_MODE_USB_HOST_SS: -+ if (lane->id == 2) -+ set = COMPHY_SELECTOR_USB3_PHY_SEL_BIT; -+ else if (lane->id == 0) -+ set = COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; -+ else -+ goto error; -+ break; -+ -+ case PHY_MODE_PCIE: -+ /* PCIE must be in Lane1 */ -+ if (lane->id == 1) -+ set = COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; -+ else -+ goto error; -+ break; -+ -+ default: -+ goto error; -+ } -+ -+ spin_lock_irqsave(&lane->priv->lock, flags); -+ -+ old = readl(lane->priv->comphy_regs + COMPHY_SELECTOR_PHY_REG); -+ new = (old & ~clr) | set; -+ writel(new, lane->priv->comphy_regs + COMPHY_SELECTOR_PHY_REG); -+ -+ spin_unlock_irqrestore(&lane->priv->lock, flags); -+ -+ dev_dbg(lane->dev, -+ "COMPHY[%d] mode[%d] changed PHY selector 0x%08x -> 0x%08x\n", -+ lane->id, lane->mode, old, new); -+ -+ return 0; -+error: -+ dev_err(lane->dev, "COMPHY[%d] mode[%d] is invalid\n", lane->id, -+ lane->mode); -+ return -EINVAL; -+} -+ -+static int -+mvebu_a3700_comphy_sata_power_on(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 mask, data, ref_clk; -+ int ret; -+ -+ /* Configure phy selector for SATA */ -+ ret = mvebu_a3700_comphy_set_phy_selector(lane); -+ if (ret) -+ return ret; -+ -+ /* Clear phy isolation mode to make it work in normal mode */ -+ comphy_lane_reg_set(lane, COMPHY_ISOLATION_CTRL, -+ 0x0, PHY_ISOLATE_MODE); -+ -+ /* 0. Check the Polarity invert bits */ -+ data = 0x0; -+ if (lane->invert_tx) -+ data |= TXD_INVERT_BIT; -+ if (lane->invert_rx) -+ data |= RXD_INVERT_BIT; -+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; -+ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); -+ -+ /* 1. Select 40-bit data width */ -+ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, -+ DATA_WIDTH_40BIT, SEL_DATA_WIDTH_MASK); -+ -+ /* 2. Select reference clock(25M) and PHY mode (SATA) */ -+ if (lane->priv->xtal_is_40m) -+ ref_clk = REF_FREF_SEL_SERDES_40MHZ; -+ else -+ ref_clk = REF_FREF_SEL_SERDES_25MHZ; -+ -+ data = ref_clk | COMPHY_MODE_SATA; -+ mask = REF_FREF_SEL_MASK | COMPHY_MODE_MASK; -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); -+ -+ /* 3. Use maximum PLL rate (no power save) */ -+ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, -+ USE_MAX_PLL_RATE_BIT, USE_MAX_PLL_RATE_BIT); -+ -+ /* 4. Reset reserved bit */ -+ comphy_set_indirect(lane->priv, COMPHY_RESERVED_REG, -+ 0x0, PHYCTRL_FRM_PIN_BIT); -+ -+ /* 5. Set vendor-specific configuration (It is done in sata driver) */ -+ /* XXX: in U-Boot below sequence was executed in this place, in Linux -+ * not. Now it is done only in U-Boot before this comphy -+ * initialization - tests shows that it works ok, but in case of any -+ * future problem it is left for reference. -+ * reg_set(MVEBU_REGS_BASE + 0xe00a0, 0, 0xffffffff); -+ * reg_set(MVEBU_REGS_BASE + 0xe00a4, BIT(6), BIT(6)); -+ */ -+ -+ /* Wait for > 55 us to allow PLL be enabled */ -+ udelay(PLL_SET_DELAY_US); -+ -+ /* Polling status */ -+ ret = comphy_lane_reg_poll(lane, COMPHY_DIG_LOOPBACK_EN, -+ PLL_READY_TX_BIT, COMPHY_PLL_SLEEP, -+ COMPHY_PLL_TIMEOUT); -+ if (ret) -+ dev_err(lane->dev, "Failed to lock SATA PLL\n"); -+ -+ return ret; -+} -+ -+static void comphy_gbe_phy_init(struct mvebu_a3700_comphy_lane *lane, -+ bool is_1gbps) -+{ -+ int addr, fix_idx; -+ u16 val; -+ -+ fix_idx = 0; -+ for (addr = 0; addr < 512; addr++) { -+ /* -+ * All PHY register values are defined in full for 3.125Gbps -+ * SERDES speed. The values required for 1.25 Gbps are almost -+ * the same and only few registers should be "fixed" in -+ * comparison to 3.125 Gbps values. These register values are -+ * stored in "gbe_phy_init_fix" array. -+ */ -+ if (!is_1gbps && gbe_phy_init_fix[fix_idx].addr == addr) { -+ /* Use new value */ -+ val = gbe_phy_init_fix[fix_idx].value; -+ if (fix_idx < ARRAY_SIZE(gbe_phy_init_fix)) -+ fix_idx++; -+ } else { -+ val = gbe_phy_init[addr]; -+ } -+ -+ comphy_lane_reg_set(lane, addr, val, 0xFFFF); -+ } -+} -+ -+static int -+mvebu_a3700_comphy_ethernet_power_on(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 mask, data, speed_sel; -+ int ret; -+ -+ /* Set selector */ -+ ret = mvebu_a3700_comphy_set_phy_selector(lane); -+ if (ret) -+ return ret; -+ -+ /* -+ * 1. Reset PHY by setting PHY input port PIN_RESET=1. -+ * 2. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep -+ * PHY TXP/TXN output to idle state during PHY initialization -+ * 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0. -+ */ -+ data = PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT; -+ mask = data | PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT | -+ PIN_PU_TX_BIT | PHY_RX_INIT_BIT; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+ -+ /* 4. Release reset to the PHY by setting PIN_RESET=0. */ -+ data = 0x0; -+ mask = PIN_RESET_COMPHY_BIT; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+ -+ /* -+ * 5. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide COMPHY -+ * bit rate -+ */ -+ switch (lane->submode) { -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ /* SGMII 1G, SerDes speed 1.25G */ -+ speed_sel = SERDES_SPEED_1_25_G; -+ break; -+ case PHY_INTERFACE_MODE_2500BASEX: -+ /* 2500Base-X, SerDes speed 3.125G */ -+ speed_sel = SERDES_SPEED_3_125_G; -+ break; - default: -+ /* Other rates are not supported */ -+ dev_err(lane->dev, -+ "unsupported phy speed %d on comphy lane%d\n", -+ lane->submode, lane->id); - return -EINVAL; - } -+ data = GEN_RX_SEL_VALUE(speed_sel) | GEN_TX_SEL_VALUE(speed_sel); -+ mask = GEN_RX_SEL_MASK | GEN_TX_SEL_MASK; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+ -+ /* -+ * 6. Wait 10mS for bandgap and reference clocks to stabilize; then -+ * start SW programming. -+ */ -+ mdelay(10); -+ -+ /* 7. Program COMPHY register PHY_MODE */ -+ data = COMPHY_MODE_SERDES; -+ mask = COMPHY_MODE_MASK; -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); -+ -+ /* -+ * 8. Set COMPHY register REFCLK_SEL to select the correct REFCLK -+ * source -+ */ -+ data = 0x0; -+ mask = PHY_REF_CLK_SEL; -+ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, data, mask); -+ -+ /* -+ * 9. Set correct reference clock frequency in COMPHY register -+ * REF_FREF_SEL. -+ */ -+ if (lane->priv->xtal_is_40m) -+ data = REF_FREF_SEL_SERDES_50MHZ; -+ else -+ data = REF_FREF_SEL_SERDES_25MHZ; -+ -+ mask = REF_FREF_SEL_MASK; -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); -+ -+ /* -+ * 10. Program COMPHY register PHY_GEN_MAX[1:0] -+ * This step is mentioned in the flow received from verification team. -+ * However the PHY_GEN_MAX value is only meaningful for other interfaces -+ * (not SERDES). For instance, it selects SATA speed 1.5/3/6 Gbps or -+ * PCIe speed 2.5/5 Gbps -+ */ -+ -+ /* -+ * 11. Program COMPHY register SEL_BITS to set correct parallel data -+ * bus width -+ */ -+ data = DATA_WIDTH_10BIT; -+ mask = SEL_DATA_WIDTH_MASK; -+ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, data, mask); -+ -+ /* -+ * 12. As long as DFE function needs to be enabled in any mode, -+ * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F -+ * for real chip during COMPHY power on. -+ * The value of the DFE_UPDATE_EN already is 0x3F, because it is the -+ * default value after reset of the PHY. -+ */ -+ -+ /* -+ * 13. Program COMPHY GEN registers. -+ * These registers should be programmed based on the lab testing result -+ * to achieve optimal performance. Please contact the CEA group to get -+ * the related GEN table during real chip bring-up. We only required to -+ * run though the entire registers programming flow defined by -+ * "comphy_gbe_phy_init" when the REF clock is 40 MHz. For REF clock -+ * 25 MHz the default values stored in PHY registers are OK. -+ */ -+ dev_dbg(lane->dev, "Running C-DPI phy init %s mode\n", -+ lane->submode == PHY_INTERFACE_MODE_2500BASEX ? "2G5" : "1G"); -+ if (lane->priv->xtal_is_40m) -+ comphy_gbe_phy_init(lane, -+ lane->submode != PHY_INTERFACE_MODE_2500BASEX); -+ -+ /* -+ * 14. Check the PHY Polarity invert bit -+ */ -+ data = 0x0; -+ if (lane->invert_tx) -+ data |= TXD_INVERT_BIT; -+ if (lane->invert_rx) -+ data |= RXD_INVERT_BIT; -+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; -+ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); -+ -+ /* -+ * 15. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to -+ * start PHY power up sequence. All the PHY register programming should -+ * be done before PIN_PU_PLL=1. There should be no register programming -+ * for normal PHY operation from this point. -+ */ -+ data = PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; -+ mask = data; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+ -+ /* -+ * 16. Wait for PHY power up sequence to finish by checking output ports -+ * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1. -+ */ -+ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, -+ PHY_PLL_READY_TX_BIT | -+ PHY_PLL_READY_RX_BIT, -+ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); -+ if (ret) { -+ dev_err(lane->dev, "Failed to lock PLL for SERDES PHY %d\n", -+ lane->id); -+ return ret; -+ } -+ -+ /* -+ * 17. Set COMPHY input port PIN_TX_IDLE=0 -+ */ -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, 0x0, PIN_TX_IDLE_BIT); -+ -+ /* -+ * 18. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. To -+ * start RX initialization. PIN_RX_INIT_DONE will be cleared to 0 by the -+ * PHY After RX initialization is done, PIN_RX_INIT_DONE will be set to -+ * 1 by COMPHY Set PIN_RX_INIT=0 after PIN_RX_INIT_DONE= 1. Please -+ * refer to RX initialization part for details. -+ */ -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, -+ PHY_RX_INIT_BIT, PHY_RX_INIT_BIT); -+ -+ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, -+ PHY_PLL_READY_TX_BIT | -+ PHY_PLL_READY_RX_BIT, -+ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); -+ if (ret) { -+ dev_err(lane->dev, "Failed to lock PLL for SERDES PHY %d\n", -+ lane->id); -+ return ret; -+ } -+ -+ ret = comphy_periph_reg_poll(lane, COMPHY_PHY_STAT1, -+ PHY_RX_INIT_DONE_BIT, -+ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); -+ if (ret) -+ dev_err(lane->dev, "Failed to init RX of SERDES PHY %d\n", -+ lane->id); -+ -+ return ret; - } - --static int mvebu_a3700_comphy_get_fw_mode(int lane, -+static int -+mvebu_a3700_comphy_usb3_power_on(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 mask, data, cfg, ref_clk; -+ int ret; -+ -+ /* Set phy seclector */ -+ ret = mvebu_a3700_comphy_set_phy_selector(lane); -+ if (ret) -+ return ret; -+ -+ /* -+ * 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The -+ * register belong to UTMI module, so it is set in UTMI phy driver. -+ */ -+ -+ /* -+ * 1. Set PRD_TXDEEMPH (3.5db de-emph) -+ */ -+ data = PRD_TXDEEMPH0_MASK; -+ mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK | -+ CFG_TX_ALIGN_POS_MASK; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG0, data, mask); -+ -+ /* -+ * 2. Set BIT0: enable transmitter in high impedance mode -+ * Set BIT[3:4]: delay 2 clock cycles for HiZ off latency -+ * Set BIT6: Tx detect Rx at HiZ mode -+ * Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db -+ * together with bit 0 of COMPHY_PIPE_LANE_CFG0 register -+ */ -+ data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN; -+ mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK | -+ TX_ELEC_IDLE_MODE_EN; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG1, data, mask); -+ -+ /* -+ * 3. Set Spread Spectrum Clock Enabled -+ */ -+ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG4, -+ SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN); -+ -+ /* -+ * 4. Set Override Margining Controls From the MAC: -+ * Use margining signals from lane configuration -+ */ -+ comphy_lane_reg_set(lane, COMPHY_PIPE_TEST_MODE_CTRL, -+ MODE_MARGIN_OVERRIDE, 0xFFFF); -+ -+ /* -+ * 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles -+ * set Mode Clock Source = PCLK is generated from REFCLK -+ */ -+ data = 0x0; -+ mask = MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE_MASK | -+ BUNDLE_SAMPLE_CTRL | PLL_READY_DLY_MASK; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_CLK_SRC_LO, data, mask); -+ -+ /* -+ * 6. Set G2 Spread Spectrum Clock Amplitude at 4K -+ */ -+ comphy_lane_reg_set(lane, COMPHY_GEN2_SET2, -+ GS2_TX_SSC_AMP_4128, GS2_TX_SSC_AMP_MASK); -+ -+ /* -+ * 7. Unset G3 Spread Spectrum Clock Amplitude -+ * set G3 TX and RX Register Master Current Select -+ */ -+ data = GS2_VREG_RXTX_MAS_ISET_60U; -+ mask = GS2_TX_SSC_AMP_MASK | GS2_VREG_RXTX_MAS_ISET_MASK | -+ GS2_RSVD_6_0_MASK; -+ comphy_lane_reg_set(lane, COMPHY_GEN3_SET2, data, mask); -+ -+ /* -+ * 8. Check crystal jumper setting and program the Power and PLL Control -+ * accordingly Change RX wait -+ */ -+ if (lane->priv->xtal_is_40m) { -+ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ; -+ cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT; -+ } else { -+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ; -+ cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT; -+ } -+ -+ data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | -+ PU_TX_INTP_BIT | PU_DFE_BIT | COMPHY_MODE_USB3 | ref_clk; -+ mask = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | -+ PU_TX_INTP_BIT | PU_DFE_BIT | PLL_LOCK_BIT | COMPHY_MODE_MASK | -+ REF_FREF_SEL_MASK; -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); -+ -+ data = CFG_PM_RXDEN_WAIT_1_UNIT | cfg; -+ mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | -+ CFG_PM_RXDLOZ_WAIT_MASK; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_PWR_MGM_TIM1, data, mask); -+ -+ /* -+ * 9. Enable idle sync -+ */ -+ comphy_lane_reg_set(lane, COMPHY_IDLE_SYNC_EN, -+ IDLE_SYNC_EN, IDLE_SYNC_EN); -+ -+ /* -+ * 10. Enable the output of 500M clock -+ */ -+ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, CLK500M_EN, CLK500M_EN); -+ -+ /* -+ * 11. Set 20-bit data width -+ */ -+ comphy_lane_reg_set(lane, COMPHY_DIG_LOOPBACK_EN, -+ DATA_WIDTH_20BIT, 0xFFFF); -+ -+ /* -+ * 12. Override Speed_PLL value and use MAC PLL -+ */ -+ data = SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT; -+ mask = 0xFFFF; -+ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, data, mask); -+ -+ /* -+ * 13. Check the Polarity invert bit -+ */ -+ data = 0x0; -+ if (lane->invert_tx) -+ data |= TXD_INVERT_BIT; -+ if (lane->invert_rx) -+ data |= RXD_INVERT_BIT; -+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; -+ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); -+ -+ /* -+ * 14. Set max speed generation to USB3.0 5Gbps -+ */ -+ comphy_lane_reg_set(lane, COMPHY_SYNC_MASK_GEN, -+ PHY_GEN_MAX_USB3_5G, PHY_GEN_MAX_MASK); -+ -+ /* -+ * 15. Set capacitor value for FFE gain peaking to 0xF -+ */ -+ comphy_lane_reg_set(lane, COMPHY_GEN2_SET3, -+ GS3_FFE_CAP_SEL_VALUE, GS3_FFE_CAP_SEL_MASK); -+ -+ /* -+ * 16. Release SW reset -+ */ -+ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4; -+ mask = 0xFFFF; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); -+ -+ /* Wait for > 55 us to allow PCLK be enabled */ -+ udelay(PLL_SET_DELAY_US); -+ -+ ret = comphy_lane_reg_poll(lane, COMPHY_PIPE_LANE_STAT1, TXDCLK_PCLK_EN, -+ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); -+ if (ret) -+ dev_err(lane->dev, "Failed to lock USB3 PLL\n"); -+ -+ return ret; -+} -+ -+static int -+mvebu_a3700_comphy_pcie_power_on(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 mask, data, ref_clk; -+ int ret; -+ -+ /* Configure phy selector for PCIe */ -+ ret = mvebu_a3700_comphy_set_phy_selector(lane); -+ if (ret) -+ return ret; -+ -+ /* 1. Enable max PLL. */ -+ comphy_lane_reg_set(lane, COMPHY_PIPE_LANE_CFG1, -+ USE_MAX_PLL_RATE_EN, USE_MAX_PLL_RATE_EN); -+ -+ /* 2. Select 20 bit SERDES interface. */ -+ comphy_lane_reg_set(lane, COMPHY_PIPE_CLK_SRC_LO, -+ CFG_SEL_20B, CFG_SEL_20B); -+ -+ /* 3. Force to use reg setting for PCIe mode */ -+ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL1, -+ SEL_BITS_PCIE_FORCE, SEL_BITS_PCIE_FORCE); -+ -+ /* 4. Change RX wait */ -+ data = CFG_PM_RXDEN_WAIT_1_UNIT | CFG_PM_RXDLOZ_WAIT_12_UNIT; -+ mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | -+ CFG_PM_RXDLOZ_WAIT_MASK; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_PWR_MGM_TIM1, data, mask); -+ -+ /* 5. Enable idle sync */ -+ comphy_lane_reg_set(lane, COMPHY_IDLE_SYNC_EN, -+ IDLE_SYNC_EN, IDLE_SYNC_EN); -+ -+ /* 6. Enable the output of 100M/125M/500M clock */ -+ data = CLK500M_EN | TXDCLK_2X_SEL | CLK100M_125M_EN; -+ mask = data; -+ comphy_lane_reg_set(lane, COMPHY_MISC_CTRL0, data, mask); -+ -+ /* -+ * 7. Enable TX, PCIE global register, 0xd0074814, it is done in -+ * PCI-E driver -+ */ -+ -+ /* -+ * 8. Check crystal jumper setting and program the Power and PLL -+ * Control accordingly -+ */ -+ -+ if (lane->priv->xtal_is_40m) -+ ref_clk = REF_FREF_SEL_PCIE_USB3_40MHZ; -+ else -+ ref_clk = REF_FREF_SEL_PCIE_USB3_25MHZ; -+ -+ data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | -+ PU_TX_INTP_BIT | PU_DFE_BIT | COMPHY_MODE_PCIE | ref_clk; -+ mask = 0xFFFF; -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, data, mask); -+ -+ /* 9. Override Speed_PLL value and use MAC PLL */ -+ comphy_lane_reg_set(lane, COMPHY_KVCO_CAL_CTRL, -+ SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT, -+ 0xFFFF); -+ -+ /* 10. Check the Polarity invert bit */ -+ data = 0x0; -+ if (lane->invert_tx) -+ data |= TXD_INVERT_BIT; -+ if (lane->invert_rx) -+ data |= RXD_INVERT_BIT; -+ mask = TXD_INVERT_BIT | RXD_INVERT_BIT; -+ comphy_lane_reg_set(lane, COMPHY_SYNC_PATTERN, data, mask); -+ -+ /* 11. Release SW reset */ -+ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32; -+ mask = data | PIPE_SOFT_RESET | MODE_REFDIV_MASK; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); -+ -+ /* Wait for > 55 us to allow PCLK be enabled */ -+ udelay(PLL_SET_DELAY_US); -+ -+ ret = comphy_lane_reg_poll(lane, COMPHY_PIPE_LANE_STAT1, TXDCLK_PCLK_EN, -+ COMPHY_PLL_SLEEP, COMPHY_PLL_TIMEOUT); -+ if (ret) -+ dev_err(lane->dev, "Failed to lock PCIE PLL\n"); -+ -+ return ret; -+} -+ -+static void -+mvebu_a3700_comphy_sata_power_off(struct mvebu_a3700_comphy_lane *lane) -+{ -+ /* Set phy isolation mode */ -+ comphy_lane_reg_set(lane, COMPHY_ISOLATION_CTRL, -+ PHY_ISOLATE_MODE, PHY_ISOLATE_MODE); -+ -+ /* Power off PLL, Tx, Rx */ -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, -+ 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); -+} -+ -+static void -+mvebu_a3700_comphy_ethernet_power_off(struct mvebu_a3700_comphy_lane *lane) -+{ -+ u32 mask, data; -+ -+ data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | PIN_PU_IVREF_BIT | -+ PHY_RX_INIT_BIT; -+ mask = data; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+} -+ -+static void -+mvebu_a3700_comphy_pcie_power_off(struct mvebu_a3700_comphy_lane *lane) -+{ -+ /* Power off PLL, Tx, Rx */ -+ comphy_lane_reg_set(lane, COMPHY_POWER_PLL_CTRL, -+ 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); -+} -+ -+static int mvebu_a3700_comphy_reset(struct phy *phy) -+{ -+ struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); -+ u16 mask, data; -+ -+ dev_dbg(lane->dev, "resetting lane %d\n", lane->id); -+ -+ /* COMPHY reset for internal logic */ -+ comphy_lane_reg_set(lane, COMPHY_SFT_RESET, -+ SFT_RST_NO_REG, SFT_RST_NO_REG); -+ -+ /* COMPHY register reset (cleared automatically) */ -+ comphy_lane_reg_set(lane, COMPHY_SFT_RESET, SFT_RST, SFT_RST); -+ -+ /* PIPE soft and register reset */ -+ data = PIPE_SOFT_RESET | PIPE_REG_RESET; -+ mask = data; -+ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); -+ -+ /* Release PIPE register reset */ -+ comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, -+ 0x0, PIPE_REG_RESET); -+ -+ /* Reset SB configuration register (only for lanes 0 and 1) */ -+ if (lane->id == 0 || lane->id == 1) { -+ u32 mask, data; -+ -+ data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | -+ PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; -+ mask = data | PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT; -+ comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -+ } -+ -+ return 0; -+} -+ -+static bool mvebu_a3700_comphy_check_mode(int lane, - enum phy_mode mode, - int submode) - { -@@ -122,7 +1141,7 @@ static int mvebu_a3700_comphy_get_fw_mod - - /* Unused PHY mux value is 0x0 */ - if (mode == PHY_MODE_INVALID) -- return -EINVAL; -+ return false; - - for (i = 0; i < n; i++) { - if (mvebu_a3700_comphy_modes[i].lane == lane && -@@ -132,27 +1151,30 @@ static int mvebu_a3700_comphy_get_fw_mod - } - - if (i == n) -- return -EINVAL; -+ return false; - -- return mvebu_a3700_comphy_modes[i].fw_mode; -+ return true; - } - - static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode, - int submode) - { - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); -- int fw_mode; - -- if (submode == PHY_INTERFACE_MODE_1000BASEX) -- submode = PHY_INTERFACE_MODE_SGMII; -- -- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, mode, -- submode); -- if (fw_mode < 0) { -+ if (!mvebu_a3700_comphy_check_mode(lane->id, mode, submode)) { - dev_err(lane->dev, "invalid COMPHY mode\n"); -- return fw_mode; -+ return -EINVAL; - } - -+ /* Mode cannot be changed while the PHY is powered on */ -+ if (phy->power_count && -+ (lane->mode != mode || lane->submode != submode)) -+ return -EBUSY; -+ -+ /* If changing mode, ensure reset is called */ -+ if (lane->mode != PHY_MODE_INVALID && lane->mode != mode) -+ lane->needs_reset = true; -+ - /* Just remember the mode, ->power_on() will do the real setup */ - lane->mode = mode; - lane->submode = submode; -@@ -163,76 +1185,77 @@ static int mvebu_a3700_comphy_set_mode(s - static int mvebu_a3700_comphy_power_on(struct phy *phy) - { - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); -- u32 fw_param; -- int fw_mode; -- int fw_port; - int ret; - -- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, -- lane->mode, lane->submode); -- if (fw_mode < 0) { -+ if (!mvebu_a3700_comphy_check_mode(lane->id, lane->mode, -+ lane->submode)) { - dev_err(lane->dev, "invalid COMPHY mode\n"); -- return fw_mode; -+ return -EINVAL; -+ } -+ -+ if (lane->needs_reset) { -+ ret = mvebu_a3700_comphy_reset(phy); -+ if (ret) -+ return ret; -+ -+ lane->needs_reset = false; - } - - switch (lane->mode) { - case PHY_MODE_USB_HOST_SS: - dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); -- fw_param = COMPHY_FW_MODE(fw_mode); -- break; -+ return mvebu_a3700_comphy_usb3_power_on(lane); - case PHY_MODE_SATA: - dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id); -- fw_param = COMPHY_FW_MODE(fw_mode); -- break; -+ return mvebu_a3700_comphy_sata_power_on(lane); - case PHY_MODE_ETHERNET: -- fw_port = (lane->id == 0) ? 1 : 0; -- switch (lane->submode) { -- case PHY_INTERFACE_MODE_SGMII: -- dev_dbg(lane->dev, "set lane %d to SGMII mode\n", -- lane->id); -- fw_param = COMPHY_FW_NET(fw_mode, fw_port, -- COMPHY_FW_SPEED_1_25G); -- break; -- case PHY_INTERFACE_MODE_2500BASEX: -- dev_dbg(lane->dev, "set lane %d to 2500BASEX mode\n", -- lane->id); -- fw_param = COMPHY_FW_NET(fw_mode, fw_port, -- COMPHY_FW_SPEED_3_125G); -- break; -- default: -- dev_err(lane->dev, "unsupported PHY submode (%d)\n", -- lane->submode); -- return -ENOTSUPP; -- } -- break; -+ dev_dbg(lane->dev, "set lane %d to Ethernet mode\n", lane->id); -+ return mvebu_a3700_comphy_ethernet_power_on(lane); - case PHY_MODE_PCIE: - dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id); -- fw_param = COMPHY_FW_PCIE(fw_mode, COMPHY_FW_SPEED_5G, -- phy->attrs.bus_width); -- break; -+ return mvebu_a3700_comphy_pcie_power_on(lane); - default: - dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode); -- return -ENOTSUPP; -+ return -EOPNOTSUPP; - } -- -- ret = mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param); -- if (ret == -EOPNOTSUPP) -- dev_err(lane->dev, -- "unsupported SMC call, try updating your firmware\n"); -- -- return ret; - } - - static int mvebu_a3700_comphy_power_off(struct phy *phy) - { - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); - -- return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0); -+ switch (lane->mode) { -+ case PHY_MODE_USB_HOST_SS: -+ /* -+ * The USB3 MAC sets the USB3 PHY to low state, so we do not -+ * need to power off USB3 PHY again. -+ */ -+ break; -+ -+ case PHY_MODE_SATA: -+ mvebu_a3700_comphy_sata_power_off(lane); -+ break; -+ -+ case PHY_MODE_ETHERNET: -+ mvebu_a3700_comphy_ethernet_power_off(lane); -+ break; -+ -+ case PHY_MODE_PCIE: -+ mvebu_a3700_comphy_pcie_power_off(lane); -+ break; -+ -+ default: -+ dev_err(lane->dev, "invalid COMPHY mode\n"); -+ return -EINVAL; -+ } -+ -+ return 0; - } - - static const struct phy_ops mvebu_a3700_comphy_ops = { - .power_on = mvebu_a3700_comphy_power_on, - .power_off = mvebu_a3700_comphy_power_off, -+ .reset = mvebu_a3700_comphy_reset, - .set_mode = mvebu_a3700_comphy_set_mode, - .owner = THIS_MODULE, - }; -@@ -256,13 +1279,75 @@ static struct phy *mvebu_a3700_comphy_xl - return ERR_PTR(-EINVAL); - } - -+ lane->invert_tx = args->args[1] & BIT(0); -+ lane->invert_rx = args->args[1] & BIT(1); -+ - return phy; - } - - static int mvebu_a3700_comphy_probe(struct platform_device *pdev) - { -+ struct mvebu_a3700_comphy_priv *priv; - struct phy_provider *provider; - struct device_node *child; -+ struct resource *res; -+ struct clk *clk; -+ int ret; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ spin_lock_init(&priv->lock); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "comphy"); -+ priv->comphy_regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->comphy_regs)) -+ return PTR_ERR(priv->comphy_regs); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "lane1_pcie_gbe"); -+ priv->lane1_phy_regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->lane1_phy_regs)) -+ return PTR_ERR(priv->lane1_phy_regs); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "lane0_usb3_gbe"); -+ priv->lane0_phy_regs = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->lane0_phy_regs)) -+ return PTR_ERR(priv->lane0_phy_regs); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "lane2_sata_usb3"); -+ priv->lane2_phy_indirect = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(priv->lane2_phy_indirect)) -+ return PTR_ERR(priv->lane2_phy_indirect); -+ -+ /* -+ * Driver needs to know if reference xtal clock is 40MHz or 25MHz. -+ * Old DT bindings do not have xtal clk present. So do not fail here -+ * and expects that default 25MHz reference clock is used. -+ */ -+ clk = clk_get(&pdev->dev, "xtal"); -+ if (IS_ERR(clk)) { -+ if (PTR_ERR(clk) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ dev_warn(&pdev->dev, "missing 'xtal' clk (%ld)\n", -+ PTR_ERR(clk)); -+ } else { -+ ret = clk_prepare_enable(clk); -+ if (ret) { -+ dev_warn(&pdev->dev, "enabling xtal clk failed (%d)\n", -+ ret); -+ } else { -+ if (clk_get_rate(clk) == 40000000) -+ priv->xtal_is_40m = true; -+ clk_disable_unprepare(clk); -+ } -+ clk_put(clk); -+ } -+ -+ dev_set_drvdata(&pdev->dev, priv); - - for_each_available_child_of_node(pdev->dev.of_node, child) { - struct mvebu_a3700_comphy_lane *lane; -@@ -277,7 +1362,7 @@ static int mvebu_a3700_comphy_probe(stru - continue; - } - -- if (lane_id >= MVEBU_A3700_COMPHY_LANES) { -+ if (lane_id >= 3) { - dev_err(&pdev->dev, "invalid 'reg' property\n"); - continue; - } -@@ -295,15 +1380,26 @@ static int mvebu_a3700_comphy_probe(stru - return PTR_ERR(phy); - } - -+ lane->priv = priv; - lane->dev = &pdev->dev; - lane->mode = PHY_MODE_INVALID; - lane->submode = PHY_INTERFACE_MODE_NA; - lane->id = lane_id; -+ lane->invert_tx = false; -+ lane->invert_rx = false; - phy_set_drvdata(phy, lane); -+ -+ /* -+ * To avoid relying on the bootloader/firmware configuration, -+ * power off all comphys. -+ */ -+ mvebu_a3700_comphy_reset(phy); -+ lane->needs_reset = false; - } - - provider = devm_of_phy_provider_register(&pdev->dev, - mvebu_a3700_comphy_xlate); -+ - return PTR_ERR_OR_ZERO(provider); - } - -@@ -323,5 +1419,7 @@ static struct platform_driver mvebu_a370 - module_platform_driver(mvebu_a3700_comphy_driver); - - MODULE_AUTHOR("Miquèl Raynal "); -+MODULE_AUTHOR("Pali Rohár "); -+MODULE_AUTHOR("Marek Behún "); - MODULE_DESCRIPTION("Common PHY driver for A3700"); - MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch b/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch deleted file mode 100644 index 03b6a5754d9..00000000000 --- a/target/linux/generic/backport-6.1/345-v5.17-arm64-dts-marvell-armada-37xx-Add-xtal-clock-to-comp.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 73a78b6130d9e13daca22b86ad52f063b9403e03 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Wed, 8 Dec 2021 03:40:35 +0100 -Subject: [PATCH 1/1] arm64: dts: marvell: armada-37xx: Add xtal clock to - comphy node -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Kernel driver phy-mvebu-a3700-comphy.c needs to know the rate of the -reference xtal clock. So add missing xtal clock source into comphy device -tree node. If the property is not present, the driver defaults to 25 MHz -xtal rate (which, as far as we know, is used by all the existing boards). - -Signed-off-by: Pali Rohár -Signed-off-by: Marek Behún -Signed-off-by: Gregory CLEMENT ---- - arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi -+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi -@@ -265,6 +265,8 @@ - "lane2_sata_usb3"; - #address-cells = <1>; - #size-cells = <0>; -+ clocks = <&xtalclk>; -+ clock-names = "xtal"; - - comphy0: phy@0 { - reg = <0>; diff --git a/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch b/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch deleted file mode 100644 index b254e7c0b3f..00000000000 --- a/target/linux/generic/backport-6.1/346-v5.18-01-Revert-ata-ahci-mvebu-Make-SATA-PHY-optional-for-Arm.patch +++ /dev/null @@ -1,64 +0,0 @@ -From ee995101fde67f85a3cd4c74f4f92fc4592e726b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Thu, 3 Feb 2022 22:44:42 +0100 -Subject: [PATCH 1/3] Revert "ata: ahci: mvebu: Make SATA PHY optional for - Armada 3720" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit 45aefe3d2251e4e229d7662052739f96ad1d08d9. - -Armada 3720 PHY driver (phy-mvebu-a3700-comphy.c) does not return --EOPNOTSUPP from phy_power_on() callback anymore. - -So remove AHCI_HFLAG_IGN_NOTSUPP_POWER_ON flag from Armada 3720 plat data. - -AHCI_HFLAG_IGN_NOTSUPP_POWER_ON is not used by any other ahci driver, so -remove this flag completely. - -Signed-off-by: Pali Rohár -Signed-off-by: Marek Behún -Acked-by: Miquel Raynal -Acked-by: Damien Le Moal -Link: https://lore.kernel.org/r/20220203214444.1508-4-kabel@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/ata/ahci.h | 2 -- - drivers/ata/ahci_mvebu.c | 2 +- - drivers/ata/libahci_platform.c | 2 +- - 3 files changed, 2 insertions(+), 4 deletions(-) - ---- a/drivers/ata/ahci.h -+++ b/drivers/ata/ahci.h -@@ -240,8 +240,6 @@ enum { - as default lpm_policy */ - AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during - suspend/resume */ -- AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = (1 << 27), /* ignore -EOPNOTSUPP -- from phy_power_on() */ - AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */ - - /* ap->flags bits */ ---- a/drivers/ata/ahci_mvebu.c -+++ b/drivers/ata/ahci_mvebu.c -@@ -227,7 +227,7 @@ static const struct ahci_mvebu_plat_data - - static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = { - .plat_config = ahci_mvebu_armada_3700_config, -- .flags = AHCI_HFLAG_SUSPEND_PHYS | AHCI_HFLAG_IGN_NOTSUPP_POWER_ON, -+ .flags = AHCI_HFLAG_SUSPEND_PHYS, - }; - - static const struct of_device_id ahci_mvebu_of_match[] = { ---- a/drivers/ata/libahci_platform.c -+++ b/drivers/ata/libahci_platform.c -@@ -59,7 +59,7 @@ int ahci_platform_enable_phys(struct ahc - } - - rc = phy_power_on(hpriv->phys[i]); -- if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) { -+ if (rc) { - phy_exit(hpriv->phys[i]); - goto disable_phys; - } diff --git a/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch b/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch deleted file mode 100644 index 1e8afb7bbf5..00000000000 --- a/target/linux/generic/backport-6.1/346-v5.18-02-Revert-usb-host-xhci-mvebu-make-USB-3.0-PHY-optional.patch +++ /dev/null @@ -1,166 +0,0 @@ -From 8e10548f7f4814e530857d2049d6af6bc78add53 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Thu, 3 Feb 2022 22:44:43 +0100 -Subject: [PATCH 2/3] Revert "usb: host: xhci: mvebu: make USB 3.0 PHY optional - for Armada 3720" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit 3241929b67d28c83945d3191c6816a3271fd6b85. - -Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return --EOPNOTSUPP from phy_power_on() callback anymore. - -So remove XHCI_SKIP_PHY_INIT flag from xhci_mvebu_a3700_plat_setup() and -then also whole xhci_mvebu_a3700_plat_setup() function which is there just -to handle -EOPNOTSUPP for XHCI_SKIP_PHY_INIT. - -xhci plat_setup callback is not used by any other xhci plat driver, so -remove this callback completely. - -Signed-off-by: Pali Rohár -Signed-off-by: Marek Behún -Acked-by: Miquel Raynal -Acked-by: Greg Kroah-Hartman -Link: https://lore.kernel.org/r/20220203214444.1508-5-kabel@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/usb/host/xhci-mvebu.c | 42 ----------------------------------- - drivers/usb/host/xhci-mvebu.h | 6 ----- - drivers/usb/host/xhci-plat.c | 20 +---------------- - drivers/usb/host/xhci-plat.h | 1 - - 4 files changed, 1 insertion(+), 68 deletions(-) - ---- a/drivers/usb/host/xhci-mvebu.c -+++ b/drivers/usb/host/xhci-mvebu.c -@@ -8,7 +8,6 @@ - #include - #include - #include --#include - - #include - #include -@@ -74,47 +73,6 @@ int xhci_mvebu_mbus_init_quirk(struct us - - return 0; - } -- --int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd) --{ -- struct xhci_hcd *xhci = hcd_to_xhci(hcd); -- struct device *dev = hcd->self.controller; -- struct phy *phy; -- int ret; -- -- /* Old bindings miss the PHY handle */ -- phy = of_phy_get(dev->of_node, "usb3-phy"); -- if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER) -- return -EPROBE_DEFER; -- else if (IS_ERR(phy)) -- goto phy_out; -- -- ret = phy_init(phy); -- if (ret) -- goto phy_put; -- -- ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS); -- if (ret) -- goto phy_exit; -- -- ret = phy_power_on(phy); -- if (ret == -EOPNOTSUPP) { -- /* Skip initializatin of XHCI PHY when it is unsupported by firmware */ -- dev_warn(dev, "PHY unsupported by firmware\n"); -- xhci->quirks |= XHCI_SKIP_PHY_INIT; -- } -- if (ret) -- goto phy_exit; -- -- phy_power_off(phy); --phy_exit: -- phy_exit(phy); --phy_put: -- of_phy_put(phy); --phy_out: -- -- return 0; --} - - int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) - { ---- a/drivers/usb/host/xhci-mvebu.h -+++ b/drivers/usb/host/xhci-mvebu.h -@@ -12,18 +12,12 @@ struct usb_hcd; - - #if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) - int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd); --int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd); - int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd); - #else - static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd) - { - return 0; - } -- --static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd) --{ -- return 0; --} - - static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd) - { ---- a/drivers/usb/host/xhci-plat.c -+++ b/drivers/usb/host/xhci-plat.c -@@ -44,16 +44,6 @@ static void xhci_priv_plat_start(struct - priv->plat_start(hcd); - } - --static int xhci_priv_plat_setup(struct usb_hcd *hcd) --{ -- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); -- -- if (!priv->plat_setup) -- return 0; -- -- return priv->plat_setup(hcd); --} -- - static int xhci_priv_init_quirk(struct usb_hcd *hcd) - { - struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); -@@ -121,7 +111,6 @@ static const struct xhci_plat_priv xhci_ - }; - - static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = { -- .plat_setup = xhci_mvebu_a3700_plat_setup, - .init_quirk = xhci_mvebu_a3700_init_quirk, - }; - -@@ -341,14 +330,7 @@ static int xhci_plat_probe(struct platfo - - hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node); - xhci->shared_hcd->tpl_support = hcd->tpl_support; -- -- if (priv) { -- ret = xhci_priv_plat_setup(hcd); -- if (ret) -- goto disable_usb_phy; -- } -- -- if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))) -+ if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)) - hcd->skip_phy_initialization = 1; - - if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK)) ---- a/drivers/usb/host/xhci-plat.h -+++ b/drivers/usb/host/xhci-plat.h -@@ -13,7 +13,6 @@ - struct xhci_plat_priv { - const char *firmware_name; - unsigned long long quirks; -- int (*plat_setup)(struct usb_hcd *); - void (*plat_start)(struct usb_hcd *); - int (*init_quirk)(struct usb_hcd *); - int (*suspend_quirk)(struct usb_hcd *); diff --git a/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch b/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch deleted file mode 100644 index fcfb02d35a1..00000000000 --- a/target/linux/generic/backport-6.1/346-v5.18-03-Revert-PCI-aardvark-Fix-initialization-with-old-Marv.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 9a4556dad7bd0a6b8339cb72e169f5c76f2af6f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Thu, 3 Feb 2022 22:44:44 +0100 -Subject: [PATCH 3/3] Revert "PCI: aardvark: Fix initialization with old - Marvell's Arm Trusted Firmware" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This reverts commit b0c6ae0f8948a2be6bf4e8b4bbab9ca1343289b6. - -Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return --EOPNOTSUPP from phy_power_on() callback anymore. - -So remove dead code which handles -EOPNOTSUPP return value. - -Signed-off-by: Pali Rohár -Signed-off-by: Marek Behún -Acked-by: Miquel Raynal -Acked-by: Lorenzo Pieralisi -Link: https://lore.kernel.org/r/20220203214444.1508-6-kabel@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/pci/controller/pci-aardvark.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - ---- a/drivers/pci/controller/pci-aardvark.c -+++ b/drivers/pci/controller/pci-aardvark.c -@@ -1642,9 +1642,7 @@ static int advk_pcie_enable_phy(struct a - } - - ret = phy_power_on(pcie->phy); -- if (ret == -EOPNOTSUPP) { -- dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n"); -- } else if (ret) { -+ if (ret) { - phy_exit(pcie->phy); - return ret; - } diff --git a/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch b/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch deleted file mode 100644 index a2c897b7a9a..00000000000 --- a/target/linux/generic/backport-6.1/347-v6.0-phy-marvell-phy-mvebu-a3700-comphy-Remove-broken-res.patch +++ /dev/null @@ -1,194 +0,0 @@ -From 0a6fc70d76bddf98278af2ac000379c82aec8f11 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Pali=20Roh=C3=A1r?= -Date: Mon, 29 Aug 2022 10:30:46 +0200 -Subject: [PATCH] phy: marvell: phy-mvebu-a3700-comphy: Remove broken reset - support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reset support for SATA PHY is somehow broken and after calling it, kernel -is not able to detect and initialize SATA disk Samsung SSD 850 EMT0 [1]. - -Reset support was introduced in commit 934337080c6c ("phy: marvell: -phy-mvebu-a3700-comphy: Add native kernel implementation") as part of -complete rewrite of this driver. v1 patch series of that commit [2] did -not contain reset support and was tested that is working fine with -Ethernet, SATA and USB PHYs without issues too. - -So for now remove broken reset support and change implementation of -power_off callback to power off all functions on specified lane (and not -only selected function) because during startup kernel does not know which -function was selected and configured by bootloader. Same logic was used -also in v1 patch series of that commit. - -This change fixes issues with initialization of SATA disk Samsung SSD 850 -and disk is working again, like before mentioned commit. - -Once problem with PHY reset callback is solved its functionality could be -re-introduced. But for now it is unknown why it does not work. - -[1] - https://lore.kernel.org/r/20220531124159.3e4lgn2v462irbtz@shindev/ -[2] - https://lore.kernel.org/r/20211028184242.22105-1-kabel@kernel.org/ - -Reported-by: Shinichiro Kawasaki -Fixes: 934337080c6c ("phy: marvell: phy-mvebu-a3700-comphy: Add native kernel implementation") -Cc: stable@vger.kernel.org # v5.18+ -Signed-off-by: Pali Rohár -Tested-by: Shinichiro Kawasaki -Link: https://lore.kernel.org/r/20220829083046.15082-1-pali@kernel.org -Signed-off-by: Vinod Koul ---- - drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 87 ++++---------------- - 1 file changed, 17 insertions(+), 70 deletions(-) - ---- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -+++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c -@@ -274,7 +274,6 @@ struct mvebu_a3700_comphy_lane { - int submode; - bool invert_tx; - bool invert_rx; -- bool needs_reset; - }; - - struct gbe_phy_init_data_fix { -@@ -1097,40 +1096,12 @@ mvebu_a3700_comphy_pcie_power_off(struct - 0x0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT); - } - --static int mvebu_a3700_comphy_reset(struct phy *phy) -+static void mvebu_a3700_comphy_usb3_power_off(struct mvebu_a3700_comphy_lane *lane) - { -- struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); -- u16 mask, data; -- -- dev_dbg(lane->dev, "resetting lane %d\n", lane->id); -- -- /* COMPHY reset for internal logic */ -- comphy_lane_reg_set(lane, COMPHY_SFT_RESET, -- SFT_RST_NO_REG, SFT_RST_NO_REG); -- -- /* COMPHY register reset (cleared automatically) */ -- comphy_lane_reg_set(lane, COMPHY_SFT_RESET, SFT_RST, SFT_RST); -- -- /* PIPE soft and register reset */ -- data = PIPE_SOFT_RESET | PIPE_REG_RESET; -- mask = data; -- comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, data, mask); -- -- /* Release PIPE register reset */ -- comphy_lane_reg_set(lane, COMPHY_PIPE_RST_CLK_CTRL, -- 0x0, PIPE_REG_RESET); -- -- /* Reset SB configuration register (only for lanes 0 and 1) */ -- if (lane->id == 0 || lane->id == 1) { -- u32 mask, data; -- -- data = PIN_RESET_CORE_BIT | PIN_RESET_COMPHY_BIT | -- PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; -- mask = data | PIN_PU_IVREF_BIT | PIN_TX_IDLE_BIT; -- comphy_periph_reg_set(lane, COMPHY_PHY_CFG1, data, mask); -- } -- -- return 0; -+ /* -+ * The USB3 MAC sets the USB3 PHY to low state, so we do not -+ * need to power off USB3 PHY again. -+ */ - } - - static bool mvebu_a3700_comphy_check_mode(int lane, -@@ -1171,10 +1142,6 @@ static int mvebu_a3700_comphy_set_mode(s - (lane->mode != mode || lane->submode != submode)) - return -EBUSY; - -- /* If changing mode, ensure reset is called */ -- if (lane->mode != PHY_MODE_INVALID && lane->mode != mode) -- lane->needs_reset = true; -- - /* Just remember the mode, ->power_on() will do the real setup */ - lane->mode = mode; - lane->submode = submode; -@@ -1185,7 +1152,6 @@ static int mvebu_a3700_comphy_set_mode(s - static int mvebu_a3700_comphy_power_on(struct phy *phy) - { - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); -- int ret; - - if (!mvebu_a3700_comphy_check_mode(lane->id, lane->mode, - lane->submode)) { -@@ -1193,14 +1159,6 @@ static int mvebu_a3700_comphy_power_on(s - return -EINVAL; - } - -- if (lane->needs_reset) { -- ret = mvebu_a3700_comphy_reset(phy); -- if (ret) -- return ret; -- -- lane->needs_reset = false; -- } -- - switch (lane->mode) { - case PHY_MODE_USB_HOST_SS: - dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id); -@@ -1224,38 +1182,28 @@ static int mvebu_a3700_comphy_power_off( - { - struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy); - -- switch (lane->mode) { -- case PHY_MODE_USB_HOST_SS: -- /* -- * The USB3 MAC sets the USB3 PHY to low state, so we do not -- * need to power off USB3 PHY again. -- */ -- break; -- -- case PHY_MODE_SATA: -- mvebu_a3700_comphy_sata_power_off(lane); -- break; -- -- case PHY_MODE_ETHERNET: -+ switch (lane->id) { -+ case 0: -+ mvebu_a3700_comphy_usb3_power_off(lane); - mvebu_a3700_comphy_ethernet_power_off(lane); -- break; -- -- case PHY_MODE_PCIE: -+ return 0; -+ case 1: - mvebu_a3700_comphy_pcie_power_off(lane); -- break; -- -+ mvebu_a3700_comphy_ethernet_power_off(lane); -+ return 0; -+ case 2: -+ mvebu_a3700_comphy_usb3_power_off(lane); -+ mvebu_a3700_comphy_sata_power_off(lane); -+ return 0; - default: - dev_err(lane->dev, "invalid COMPHY mode\n"); - return -EINVAL; - } -- -- return 0; - } - - static const struct phy_ops mvebu_a3700_comphy_ops = { - .power_on = mvebu_a3700_comphy_power_on, - .power_off = mvebu_a3700_comphy_power_off, -- .reset = mvebu_a3700_comphy_reset, - .set_mode = mvebu_a3700_comphy_set_mode, - .owner = THIS_MODULE, - }; -@@ -1393,8 +1341,7 @@ static int mvebu_a3700_comphy_probe(stru - * To avoid relying on the bootloader/firmware configuration, - * power off all comphys. - */ -- mvebu_a3700_comphy_reset(phy); -- lane->needs_reset = false; -+ mvebu_a3700_comphy_power_off(phy); - } - - provider = devm_of_phy_provider_register(&pdev->dev, diff --git a/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch b/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch deleted file mode 100644 index 99cd89ea002..00000000000 --- a/target/linux/generic/backport-6.1/350-v5.18-regmap-add-configurable-downshift-for-addresses.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 86fc59ef818beb0e1945d17f8e734898baba7e4e Mon Sep 17 00:00:00 2001 -From: Colin Foster -Date: Sun, 13 Mar 2022 15:45:23 -0700 -Subject: [PATCH 1/2] regmap: add configurable downshift for addresses - -Add an additional reg_downshift to be applied to register addresses before -any register accesses. An example of a device that uses this is a VSC7514 -chip, which require each register address to be downshifted by two if the -access is performed over a SPI bus. - -Signed-off-by: Colin Foster -Link: https://lore.kernel.org/r/20220313224524.399947-2-colin.foster@in-advantage.com -Signed-off-by: Mark Brown ---- - drivers/base/regmap/internal.h | 1 + - drivers/base/regmap/regmap.c | 5 +++++ - include/linux/regmap.h | 3 +++ - 3 files changed, 9 insertions(+) - ---- a/drivers/base/regmap/internal.h -+++ b/drivers/base/regmap/internal.h -@@ -31,6 +31,7 @@ struct regmap_format { - size_t buf_size; - size_t reg_bytes; - size_t pad_bytes; -+ size_t reg_downshift; - size_t val_bytes; - void (*format_write)(struct regmap *map, - unsigned int reg, unsigned int val); ---- a/drivers/base/regmap/regmap.c -+++ b/drivers/base/regmap/regmap.c -@@ -823,6 +823,7 @@ struct regmap *__regmap_init(struct devi - - map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); - map->format.pad_bytes = config->pad_bits / 8; -+ map->format.reg_downshift = config->reg_downshift; - map->format.val_bytes = DIV_ROUND_UP(config->val_bits, 8); - map->format.buf_size = DIV_ROUND_UP(config->reg_bits + - config->val_bits + config->pad_bits, 8); -@@ -1735,6 +1736,7 @@ static int _regmap_raw_write_impl(struct - return ret; - } - -+ reg >>= map->format.reg_downshift; - map->format.format_reg(map->work_buf, reg, map->reg_shift); - regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, - map->write_flag_mask); -@@ -1905,6 +1907,7 @@ static int _regmap_bus_formatted_write(v - return ret; - } - -+ reg >>= map->format.reg_downshift; - map->format.format_write(map, reg, val); - - trace_regmap_hw_write_start(map, reg, 1); -@@ -2346,6 +2349,7 @@ static int _regmap_raw_multi_reg_write(s - unsigned int reg = regs[i].reg; - unsigned int val = regs[i].def; - trace_regmap_hw_write_start(map, reg, 1); -+ reg >>= map->format.reg_downshift; - map->format.format_reg(u8, reg, map->reg_shift); - u8 += reg_bytes + pad_bytes; - map->format.format_val(u8, val, 0); -@@ -2673,6 +2677,7 @@ static int _regmap_raw_read(struct regma - return ret; - } - -+ reg >>= map->format.reg_downshift; - map->format.format_reg(map->work_buf, reg, map->reg_shift); - regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, - map->read_flag_mask); ---- a/include/linux/regmap.h -+++ b/include/linux/regmap.h -@@ -237,6 +237,8 @@ typedef void (*regmap_unlock)(void *); - * @reg_stride: The register address stride. Valid register addresses are a - * multiple of this value. If set to 0, a value of 1 will be - * used. -+ * @reg_downshift: The number of bits to downshift the register before -+ * performing any operations. - * @pad_bits: Number of bits of padding between register and value. - * @val_bits: Number of bits in a register value, mandatory. - * -@@ -360,6 +362,7 @@ struct regmap_config { - - int reg_bits; - int reg_stride; -+ int reg_downshift; - int pad_bits; - int val_bits; - diff --git a/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch b/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch deleted file mode 100644 index 0f32288fcab..00000000000 --- a/target/linux/generic/backport-6.1/351-v5.18-regmap-allow-a-defined-reg_base-to-be-added-to-every.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 0074f3f2b1e43d3cedd97e47fb6980db6d2ba79e Mon Sep 17 00:00:00 2001 -From: Colin Foster -Date: Sun, 13 Mar 2022 15:45:24 -0700 -Subject: [PATCH 2/2] regmap: allow a defined reg_base to be added to every - address - -There's an inconsistency that arises when a register set can be accessed -internally via MMIO, or externally via SPI. The VSC7514 chip allows both -modes of operation. When internally accessed, the system utilizes __iomem, -devm_ioremap_resource, and devm_regmap_init_mmio. - -For SPI it isn't possible to utilize memory-mapped IO. To properly operate, -the resource base must be added to the register before every operation. - -Signed-off-by: Colin Foster -Link: https://lore.kernel.org/r/20220313224524.399947-3-colin.foster@in-advantage.com -Signed-off-by: Mark Brown ---- - drivers/base/regmap/internal.h | 1 + - drivers/base/regmap/regmap.c | 6 ++++++ - include/linux/regmap.h | 3 +++ - 3 files changed, 10 insertions(+) - ---- a/drivers/base/regmap/internal.h -+++ b/drivers/base/regmap/internal.h -@@ -63,6 +63,7 @@ struct regmap { - regmap_unlock unlock; - void *lock_arg; /* This is passed to lock/unlock functions */ - gfp_t alloc_flags; -+ unsigned int reg_base; - - struct device *dev; /* Device we do I/O on */ - void *work_buf; /* Scratch buffer used to format I/O */ ---- a/drivers/base/regmap/regmap.c -+++ b/drivers/base/regmap/regmap.c -@@ -821,6 +821,8 @@ struct regmap *__regmap_init(struct devi - else - map->alloc_flags = GFP_KERNEL; - -+ map->reg_base = config->reg_base; -+ - map->format.reg_bytes = DIV_ROUND_UP(config->reg_bits, 8); - map->format.pad_bytes = config->pad_bits / 8; - map->format.reg_downshift = config->reg_downshift; -@@ -1736,6 +1738,7 @@ static int _regmap_raw_write_impl(struct - return ret; - } - -+ reg += map->reg_base; - reg >>= map->format.reg_downshift; - map->format.format_reg(map->work_buf, reg, map->reg_shift); - regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, -@@ -1907,6 +1910,7 @@ static int _regmap_bus_formatted_write(v - return ret; - } - -+ reg += map->reg_base; - reg >>= map->format.reg_downshift; - map->format.format_write(map, reg, val); - -@@ -2349,6 +2353,7 @@ static int _regmap_raw_multi_reg_write(s - unsigned int reg = regs[i].reg; - unsigned int val = regs[i].def; - trace_regmap_hw_write_start(map, reg, 1); -+ reg += map->reg_base; - reg >>= map->format.reg_downshift; - map->format.format_reg(u8, reg, map->reg_shift); - u8 += reg_bytes + pad_bytes; -@@ -2677,6 +2682,7 @@ static int _regmap_raw_read(struct regma - return ret; - } - -+ reg += map->reg_base; - reg >>= map->format.reg_downshift; - map->format.format_reg(map->work_buf, reg, map->reg_shift); - regmap_set_work_buf_flag_mask(map, map->format.reg_bytes, ---- a/include/linux/regmap.h -+++ b/include/linux/regmap.h -@@ -239,6 +239,8 @@ typedef void (*regmap_unlock)(void *); - * used. - * @reg_downshift: The number of bits to downshift the register before - * performing any operations. -+ * @reg_base: Value to be added to every register address before performing any -+ * operation. - * @pad_bits: Number of bits of padding between register and value. - * @val_bits: Number of bits in a register value, mandatory. - * -@@ -363,6 +365,7 @@ struct regmap_config { - int reg_bits; - int reg_stride; - int reg_downshift; -+ unsigned int reg_base; - int pad_bits; - int val_bits; - diff --git a/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch b/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch deleted file mode 100644 index 804f68d23c5..00000000000 --- a/target/linux/generic/backport-6.1/352-v6.3-regmap-apply-reg_base-and-reg_downshift-for-single-r.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 697c3892d825fb78f42ec8e53bed065dd728db3e Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Mon, 30 Jan 2023 02:04:57 +0000 -Subject: [PATCH] regmap: apply reg_base and reg_downshift for single register - ops - -reg_base and reg_downshift currently don't have any effect if used with -a regmap_bus or regmap_config which only offers single register -operations (ie. reg_read, reg_write and optionally reg_update_bits). - -Fix that and take them into account also for regmap_bus with only -reg_read and read_write operations by applying reg_base and -reg_downshift in _regmap_bus_reg_write, _regmap_bus_reg_read. - -Also apply reg_base and reg_downshift in _regmap_update_bits, but only -in case the operation is carried out with a reg_update_bits call -defined in either regmap_bus or regmap_config. - -Fixes: 0074f3f2b1e43d ("regmap: allow a defined reg_base to be added to every address") -Fixes: 86fc59ef818beb ("regmap: add configurable downshift for addresses") -Signed-off-by: Daniel Golle -Tested-by: Colin Foster -Link: https://lore.kernel.org/r/Y9clyVS3tQEHlUhA@makrotopia.org -Signed-off-by: Mark Brown ---- - drivers/base/regmap/regmap.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/base/regmap/regmap.c -+++ b/drivers/base/regmap/regmap.c -@@ -1929,6 +1929,8 @@ static int _regmap_bus_reg_write(void *c - { - struct regmap *map = context; - -+ reg += map->reg_base; -+ reg >>= map->format.reg_downshift; - return map->bus->reg_write(map->bus_context, reg, val); - } - -@@ -2703,6 +2705,8 @@ static int _regmap_bus_reg_read(void *co - { - struct regmap *map = context; - -+ reg += map->reg_base; -+ reg >>= map->format.reg_downshift; - return map->bus->reg_read(map->bus_context, reg, val); - } - -@@ -3078,6 +3082,8 @@ static int _regmap_update_bits(struct re - *change = false; - - if (regmap_volatile(map, reg) && map->reg_update_bits) { -+ reg += map->reg_base; -+ reg >>= map->format.reg_downshift; - ret = map->reg_update_bits(map->bus_context, reg, mask, val); - if (ret == 0 && change) - *change = true; diff --git a/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch b/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch deleted file mode 100644 index 1f3aae13b4d..00000000000 --- a/target/linux/generic/backport-6.1/400-v5.19-mtd-call-of_platform_populate-for-MTD-partitions.patch +++ /dev/null @@ -1,72 +0,0 @@ -From bcdf0315a61a29eb753a607d3a85a4032de72d94 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Tue, 10 May 2022 15:12:59 +0200 -Subject: [PATCH] mtd: call of_platform_populate() for MTD partitions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Until this change MTD subsystem supported handling partitions only with -MTD partitions parsers. That's a specific / limited API designed around -partitions. - -Some MTD partitions may however require different handling. They may -contain specific data that needs to be parsed and somehow extracted. For -that purpose MTD subsystem should allow binding of standard platform -drivers. - -An example can be U-Boot (sub)partition with environment variables. -There exist a "u-boot,env" DT binding for MTD (sub)partition that -requires an NVMEM driver. - -Ref: 5db1c2dbc04c ("dt-bindings: nvmem: add U-Boot environment variables binding") -Signed-off-by: Rafał Miłecki -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220510131259.555-1-zajec5@gmail.com ---- - drivers/mtd/mtdpart.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - ---- a/drivers/mtd/mtdpart.c -+++ b/drivers/mtd/mtdpart.c -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - - #include "mtdcore.h" - -@@ -577,10 +578,16 @@ static int mtd_part_of_parse(struct mtd_ - struct mtd_part_parser *parser; - struct device_node *np; - struct property *prop; -+ struct device *dev; - const char *compat; - const char *fixed = "fixed-partitions"; - int ret, err = 0; - -+ dev = &master->dev; -+ /* Use parent device (controller) if the top level MTD is not registered */ -+ if (!IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) && !mtd_is_partition(master)) -+ dev = master->dev.parent; -+ - np = mtd_get_of_node(master); - if (mtd_is_partition(master)) - of_node_get(np); -@@ -593,6 +600,7 @@ static int mtd_part_of_parse(struct mtd_ - continue; - ret = mtd_part_do_parse(parser, master, pparts, NULL); - if (ret > 0) { -+ of_platform_populate(np, NULL, NULL, dev); - of_node_put(np); - return ret; - } -@@ -600,6 +608,7 @@ static int mtd_part_of_parse(struct mtd_ - if (ret < 0 && !err) - err = ret; - } -+ of_platform_populate(np, NULL, NULL, dev); - of_node_put(np); - - /* diff --git a/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch b/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch deleted file mode 100644 index 113a96ad42e..00000000000 --- a/target/linux/generic/backport-6.1/401-v6.0-mtd-parsers-add-support-for-Sercomm-partitions.patch +++ /dev/null @@ -1,302 +0,0 @@ -From 9b78ef0c7997052e9eaa0f7a4513d546fa17358c Mon Sep 17 00:00:00 2001 -From: Mikhail Zhilkin -Date: Sun, 29 May 2022 11:07:14 +0000 -Subject: [PATCH] mtd: parsers: add support for Sercomm partitions - -This adds an MTD partition parser for the Sercomm partition table that -is used in some Beeline, Netgear and Sercomm routers. - -The Sercomm partition map table contains real partition offsets, which -may differ from device to device depending on the number and location of -bad blocks on NAND. - -Original patch (proposed by NOGUCHI Hiroshi): -Link: https://github.com/openwrt/openwrt/pull/1318#issuecomment-420607394 - -Signed-off-by: NOGUCHI Hiroshi -Signed-off-by: Mikhail Zhilkin -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220529110714.189732-1-csharper2005@gmail.com ---- - drivers/mtd/parsers/Kconfig | 9 ++ - drivers/mtd/parsers/Makefile | 1 + - drivers/mtd/parsers/scpart.c | 248 +++++++++++++++++++++++++++++++++++ - 3 files changed, 258 insertions(+) - create mode 100644 drivers/mtd/parsers/scpart.c - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -186,3 +186,12 @@ config MTD_QCOMSMEM_PARTS - help - This provides support for parsing partitions from Shared Memory (SMEM) - for NAND and SPI flash on Qualcomm platforms. -+ -+config MTD_SERCOMM_PARTS -+ tristate "Sercomm partition table parser" -+ depends on MTD && RALINK -+ help -+ This provides partitions table parser for devices with Sercomm -+ partition map. This partition table contains real partition -+ offsets, which may differ from device to device depending on the -+ number and location of bad blocks on NAND. ---- a/drivers/mtd/parsers/Makefile -+++ b/drivers/mtd/parsers/Makefile -@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS) - obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o - obj-$(CONFIG_MTD_AFS_PARTS) += afs.o - obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o -+obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpart.o - obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o - obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o - obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o ---- /dev/null -+++ b/drivers/mtd/parsers/scpart.c -@@ -0,0 +1,248 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * drivers/mtd/scpart.c: Sercomm Partition Parser -+ * -+ * Copyright (C) 2018 NOGUCHI Hiroshi -+ * Copyright (C) 2022 Mikhail Zhilkin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define MOD_NAME "scpart" -+ -+#ifdef pr_fmt -+#undef pr_fmt -+#endif -+ -+#define pr_fmt(fmt) MOD_NAME ": " fmt -+ -+#define ID_ALREADY_FOUND 0xffffffffUL -+ -+#define MAP_OFFS_IN_BLK 0x800 -+#define MAP_MIRROR_NUM 2 -+ -+static const char sc_part_magic[] = { -+ 'S', 'C', 'F', 'L', 'M', 'A', 'P', 'O', 'K', '\0', -+}; -+#define PART_MAGIC_LEN sizeof(sc_part_magic) -+ -+/* assumes that all fields are set by CPU native endian */ -+struct sc_part_desc { -+ uint32_t part_id; -+ uint32_t part_offs; -+ uint32_t part_bytes; -+}; -+ -+static uint32_t scpart_desc_is_valid(struct sc_part_desc *pdesc) -+{ -+ return ((pdesc->part_id != 0xffffffffUL) && -+ (pdesc->part_offs != 0xffffffffUL) && -+ (pdesc->part_bytes != 0xffffffffUL)); -+} -+ -+static int scpart_scan_partmap(struct mtd_info *master, loff_t partmap_offs, -+ struct sc_part_desc **ppdesc) -+{ -+ int cnt = 0; -+ int res = 0; -+ int res2; -+ loff_t offs; -+ size_t retlen; -+ struct sc_part_desc *pdesc = NULL; -+ struct sc_part_desc *tmpdesc; -+ uint8_t *buf; -+ -+ buf = kzalloc(master->erasesize, GFP_KERNEL); -+ if (!buf) { -+ res = -ENOMEM; -+ goto out; -+ } -+ -+ res2 = mtd_read(master, partmap_offs, master->erasesize, &retlen, buf); -+ if (res2 || retlen != master->erasesize) { -+ res = -EIO; -+ goto free; -+ } -+ -+ for (offs = MAP_OFFS_IN_BLK; -+ offs < master->erasesize - sizeof(*tmpdesc); -+ offs += sizeof(*tmpdesc)) { -+ tmpdesc = (struct sc_part_desc *)&buf[offs]; -+ if (!scpart_desc_is_valid(tmpdesc)) -+ break; -+ cnt++; -+ } -+ -+ if (cnt > 0) { -+ int bytes = cnt * sizeof(*pdesc); -+ -+ pdesc = kcalloc(cnt, sizeof(*pdesc), GFP_KERNEL); -+ if (!pdesc) { -+ res = -ENOMEM; -+ goto free; -+ } -+ memcpy(pdesc, &(buf[MAP_OFFS_IN_BLK]), bytes); -+ -+ *ppdesc = pdesc; -+ res = cnt; -+ } -+ -+free: -+ kfree(buf); -+ -+out: -+ return res; -+} -+ -+static int scpart_find_partmap(struct mtd_info *master, -+ struct sc_part_desc **ppdesc) -+{ -+ int magic_found = 0; -+ int res = 0; -+ int res2; -+ loff_t offs = 0; -+ size_t retlen; -+ uint8_t rdbuf[PART_MAGIC_LEN]; -+ -+ while ((magic_found < MAP_MIRROR_NUM) && -+ (offs < master->size) && -+ !mtd_block_isbad(master, offs)) { -+ res2 = mtd_read(master, offs, PART_MAGIC_LEN, &retlen, rdbuf); -+ if (res2 || retlen != PART_MAGIC_LEN) { -+ res = -EIO; -+ goto out; -+ } -+ if (!memcmp(rdbuf, sc_part_magic, PART_MAGIC_LEN)) { -+ pr_debug("Signature found at 0x%llx\n", offs); -+ magic_found++; -+ res = scpart_scan_partmap(master, offs, ppdesc); -+ if (res > 0) -+ goto out; -+ } -+ offs += master->erasesize; -+ } -+ -+out: -+ if (res > 0) -+ pr_info("Valid 'SC PART MAP' (%d partitions) found at 0x%llx\n", res, offs); -+ else -+ pr_info("No valid 'SC PART MAP' was found\n"); -+ -+ return res; -+} -+ -+static int scpart_parse(struct mtd_info *master, -+ const struct mtd_partition **pparts, -+ struct mtd_part_parser_data *data) -+{ -+ const char *partname; -+ int n; -+ int nr_scparts; -+ int nr_parts = 0; -+ int res = 0; -+ struct sc_part_desc *scpart_map = NULL; -+ struct mtd_partition *parts = NULL; -+ struct device_node *mtd_node; -+ struct device_node *ofpart_node; -+ struct device_node *pp; -+ -+ mtd_node = mtd_get_of_node(master); -+ if (!mtd_node) { -+ res = -ENOENT; -+ goto out; -+ } -+ -+ ofpart_node = of_get_child_by_name(mtd_node, "partitions"); -+ if (!ofpart_node) { -+ pr_info("%s: 'partitions' subnode not found on %pOF.\n", -+ master->name, mtd_node); -+ res = -ENOENT; -+ goto out; -+ } -+ -+ nr_scparts = scpart_find_partmap(master, &scpart_map); -+ if (nr_scparts <= 0) { -+ pr_info("No any partitions was found in 'SC PART MAP'.\n"); -+ res = -ENOENT; -+ goto free; -+ } -+ -+ parts = kcalloc(of_get_child_count(ofpart_node), sizeof(*parts), -+ GFP_KERNEL); -+ if (!parts) { -+ res = -ENOMEM; -+ goto free; -+ } -+ -+ for_each_child_of_node(ofpart_node, pp) { -+ u32 scpart_id; -+ -+ if (of_property_read_u32(pp, "sercomm,scpart-id", &scpart_id)) -+ continue; -+ -+ for (n = 0 ; n < nr_scparts ; n++) -+ if ((scpart_map[n].part_id != ID_ALREADY_FOUND) && -+ (scpart_id == scpart_map[n].part_id)) -+ break; -+ if (n >= nr_scparts) -+ /* not match */ -+ continue; -+ -+ /* add the partition found in OF into MTD partition array */ -+ parts[nr_parts].offset = scpart_map[n].part_offs; -+ parts[nr_parts].size = scpart_map[n].part_bytes; -+ parts[nr_parts].of_node = pp; -+ -+ if (!of_property_read_string(pp, "label", &partname)) -+ parts[nr_parts].name = partname; -+ if (of_property_read_bool(pp, "read-only")) -+ parts[nr_parts].mask_flags |= MTD_WRITEABLE; -+ if (of_property_read_bool(pp, "lock")) -+ parts[nr_parts].mask_flags |= MTD_POWERUP_LOCK; -+ -+ /* mark as 'done' */ -+ scpart_map[n].part_id = ID_ALREADY_FOUND; -+ -+ nr_parts++; -+ } -+ -+ if (nr_parts > 0) { -+ *pparts = parts; -+ res = nr_parts; -+ } else -+ pr_info("No partition in OF matches partition ID with 'SC PART MAP'.\n"); -+ -+ of_node_put(pp); -+ -+free: -+ kfree(scpart_map); -+ if (res <= 0) -+ kfree(parts); -+ -+out: -+ return res; -+} -+ -+static const struct of_device_id scpart_parser_of_match_table[] = { -+ { .compatible = "sercomm,sc-partitions" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, scpart_parser_of_match_table); -+ -+static struct mtd_part_parser scpart_parser = { -+ .parse_fn = scpart_parse, -+ .name = "scpart", -+ .of_match_table = scpart_parser_of_match_table, -+}; -+module_mtd_part_parser(scpart_parser); -+ -+/* mtd parsers will request the module by parser name */ -+MODULE_ALIAS("scpart"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("NOGUCHI Hiroshi "); -+MODULE_AUTHOR("Mikhail Zhilkin "); -+MODULE_DESCRIPTION("Sercomm partition parser"); diff --git a/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch b/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch deleted file mode 100644 index ee385416d1d..00000000000 --- a/target/linux/generic/backport-6.1/402-v6.0-mtd-next-mtd-core-introduce-of-support-for-dynamic-partitions.patch +++ /dev/null @@ -1,106 +0,0 @@ -From ad9b10d1eaada169bd764abcab58f08538877e26 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 22 Jun 2022 03:06:28 +0200 -Subject: mtd: core: introduce of support for dynamic partitions - -We have many parser that register mtd partitions at runtime. One example -is the cmdlinepart or the smem-part parser where the compatible is defined -in the dts and the partitions gets detected and registered by the -parser. This is problematic for the NVMEM subsystem that requires an OF -node to detect NVMEM cells. - -To fix this problem, introduce an additional logic that will try to -assign an OF node to the MTD if declared. - -On MTD addition, it will be checked if the MTD has an OF node and if -not declared will check if a partition with the same label / node name is -declared in DTS. If an exact match is found, the partition dynamically -allocated by the parser will have a connected OF node. - -The NVMEM subsystem will detect the OF node and register any NVMEM cells -declared statically in the DTS. - -Signed-off-by: Christian Marangi -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220622010628.30414-4-ansuelsmth@gmail.com ---- - drivers/mtd/mtdcore.c | 61 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 61 insertions(+) - ---- a/drivers/mtd/mtdcore.c -+++ b/drivers/mtd/mtdcore.c -@@ -564,6 +564,66 @@ static int mtd_nvmem_add(struct mtd_info - return 0; - } - -+static void mtd_check_of_node(struct mtd_info *mtd) -+{ -+ struct device_node *partitions, *parent_dn, *mtd_dn = NULL; -+ const char *pname, *prefix = "partition-"; -+ int plen, mtd_name_len, offset, prefix_len; -+ struct mtd_info *parent; -+ bool found = false; -+ -+ /* Check if MTD already has a device node */ -+ if (dev_of_node(&mtd->dev)) -+ return; -+ -+ /* Check if a partitions node exist */ -+ parent = mtd->parent; -+ parent_dn = dev_of_node(&parent->dev); -+ if (!parent_dn) -+ return; -+ -+ partitions = of_get_child_by_name(parent_dn, "partitions"); -+ if (!partitions) -+ goto exit_parent; -+ -+ prefix_len = strlen(prefix); -+ mtd_name_len = strlen(mtd->name); -+ -+ /* Search if a partition is defined with the same name */ -+ for_each_child_of_node(partitions, mtd_dn) { -+ offset = 0; -+ -+ /* Skip partition with no/wrong prefix */ -+ if (!of_node_name_prefix(mtd_dn, "partition-")) -+ continue; -+ -+ /* Label have priority. Check that first */ -+ if (of_property_read_string(mtd_dn, "label", &pname)) { -+ of_property_read_string(mtd_dn, "name", &pname); -+ offset = prefix_len; -+ } -+ -+ plen = strlen(pname) - offset; -+ if (plen == mtd_name_len && -+ !strncmp(mtd->name, pname + offset, plen)) { -+ found = true; -+ break; -+ } -+ } -+ -+ if (!found) -+ goto exit_partitions; -+ -+ /* Set of_node only for nvmem */ -+ if (of_device_is_compatible(mtd_dn, "nvmem-cells")) -+ mtd_set_of_node(mtd, mtd_dn); -+ -+exit_partitions: -+ of_node_put(partitions); -+exit_parent: -+ of_node_put(parent_dn); -+} -+ - /** - * add_mtd_device - register an MTD device - * @mtd: pointer to new MTD device info structure -@@ -669,6 +729,7 @@ int add_mtd_device(struct mtd_info *mtd) - mtd->dev.devt = MTD_DEVT(i); - dev_set_name(&mtd->dev, "mtd%d", i); - dev_set_drvdata(&mtd->dev, mtd); -+ mtd_check_of_node(mtd); - of_node_get(mtd_get_of_node(mtd)); - error = device_register(&mtd->dev); - if (error) { diff --git a/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch b/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch deleted file mode 100644 index 3039eabea50..00000000000 --- a/target/linux/generic/backport-6.1/403-v6.1-mtd-allow-getting-MTD-device-associated-with-a-speci.patch +++ /dev/null @@ -1,72 +0,0 @@ -From b0321721be50b80c03a51866a94fde4f94690e18 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Wed, 15 Jun 2022 21:42:59 +0200 -Subject: [PATCH] mtd: allow getting MTD device associated with a specific DT - node -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -MTD subsystem API allows interacting with MTD devices (e.g. reading, -writing, handling bad blocks). So far a random driver could get MTD -device only by its name (get_mtd_device_nm()). This change allows -getting them also by a DT node. - -This API is required for drivers handling DT defined MTD partitions in a -specific way (e.g. U-Boot (sub)partition with environment variables). - -Signed-off-by: Rafał Miłecki -Acked-by: Miquel Raynal -Signed-off-by: Srinivas Kandagatla ---- - drivers/mtd/mtdcore.c | 28 ++++++++++++++++++++++++++++ - include/linux/mtd/mtd.h | 1 + - 2 files changed, 29 insertions(+) - ---- a/drivers/mtd/mtdcore.c -+++ b/drivers/mtd/mtdcore.c -@@ -1236,6 +1236,34 @@ int __get_mtd_device(struct mtd_info *mt - EXPORT_SYMBOL_GPL(__get_mtd_device); - - /** -+ * of_get_mtd_device_by_node - obtain an MTD device associated with a given node -+ * -+ * @np: device tree node -+ */ -+struct mtd_info *of_get_mtd_device_by_node(struct device_node *np) -+{ -+ struct mtd_info *mtd = NULL; -+ struct mtd_info *tmp; -+ int err; -+ -+ mutex_lock(&mtd_table_mutex); -+ -+ err = -EPROBE_DEFER; -+ mtd_for_each_device(tmp) { -+ if (mtd_get_of_node(tmp) == np) { -+ mtd = tmp; -+ err = __get_mtd_device(mtd); -+ break; -+ } -+ } -+ -+ mutex_unlock(&mtd_table_mutex); -+ -+ return err ? ERR_PTR(err) : mtd; -+} -+EXPORT_SYMBOL_GPL(of_get_mtd_device_by_node); -+ -+/** - * get_mtd_device_nm - obtain a validated handle for an MTD device by - * device name - * @name: MTD device name to open ---- a/include/linux/mtd/mtd.h -+++ b/include/linux/mtd/mtd.h -@@ -682,6 +682,7 @@ extern int mtd_device_unregister(struct - extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); - extern int __get_mtd_device(struct mtd_info *mtd); - extern void __put_mtd_device(struct mtd_info *mtd); -+extern struct mtd_info *of_get_mtd_device_by_node(struct device_node *np); - extern struct mtd_info *get_mtd_device_nm(const char *name); - extern void put_mtd_device(struct mtd_info *mtd); - diff --git a/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch b/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch deleted file mode 100644 index e45e2ab48e3..00000000000 --- a/target/linux/generic/backport-6.1/404-v6.0-mtd-core-check-partition-before-dereference.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 7ec4cdb321738d44ae5d405e7b6ac73dfbf99caa Mon Sep 17 00:00:00 2001 -From: Tetsuo Handa -Date: Mon, 25 Jul 2022 22:49:25 +0900 -Subject: [PATCH] mtd: core: check partition before dereference - -syzbot is reporting NULL pointer dereference at mtd_check_of_node() [1], -for mtdram test device (CONFIG_MTD_MTDRAM) is not partition. - -Link: https://syzkaller.appspot.com/bug?extid=fe013f55a2814a9e8cfd [1] -Reported-by: syzbot -Reported-by: kernel test robot -Fixes: ad9b10d1eaada169 ("mtd: core: introduce of support for dynamic partitions") -Signed-off-by: Tetsuo Handa -CC: stable@vger.kernel.org -Signed-off-by: Richard Weinberger ---- - drivers/mtd/mtdcore.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/mtd/mtdcore.c -+++ b/drivers/mtd/mtdcore.c -@@ -577,6 +577,8 @@ static void mtd_check_of_node(struct mtd - return; - - /* Check if a partitions node exist */ -+ if (!mtd_is_partition(mtd)) -+ return; - parent = mtd->parent; - parent_dn = dev_of_node(&parent->dev); - if (!parent_dn) diff --git a/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch b/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch deleted file mode 100644 index 9399a00aa16..00000000000 --- a/target/linux/generic/backport-6.1/405-v6.1-mtd-core-add-missing-of_node_get-in-dynamic-partitio.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 12b58961de0bd88b3c7dfa5d21f6d67f4678b780 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Tue, 18 Oct 2022 07:18:22 +0200 -Subject: [PATCH] mtd: core: add missing of_node_get() in dynamic partitions - code -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes unbalanced of_node_put(): -[ 1.078910] 6 cmdlinepart partitions found on MTD device gpmi-nand -[ 1.085116] Creating 6 MTD partitions on "gpmi-nand": -[ 1.090181] 0x000000000000-0x000008000000 : "nandboot" -[ 1.096952] 0x000008000000-0x000009000000 : "nandfit" -[ 1.103547] 0x000009000000-0x00000b000000 : "nandkernel" -[ 1.110317] 0x00000b000000-0x00000c000000 : "nanddtb" -[ 1.115525] ------------[ cut here ]------------ -[ 1.120141] refcount_t: addition on 0; use-after-free. -[ 1.125328] WARNING: CPU: 0 PID: 1 at lib/refcount.c:25 refcount_warn_saturate+0xdc/0x148 -[ 1.133528] Modules linked in: -[ 1.136589] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.0.0-rc7-next-20220930-04543-g8cf3f7 -[ 1.146342] Hardware name: Freescale i.MX8DXL DDR3L EVK (DT) -[ 1.151999] pstate: 600000c5 (nZCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) -[ 1.158965] pc : refcount_warn_saturate+0xdc/0x148 -[ 1.163760] lr : refcount_warn_saturate+0xdc/0x148 -[ 1.168556] sp : ffff800009ddb080 -[ 1.171866] x29: ffff800009ddb080 x28: ffff800009ddb35a x27: 0000000000000002 -[ 1.179015] x26: ffff8000098b06ad x25: ffffffffffffffff x24: ffff0a00ffffff05 -[ 1.186165] x23: ffff00001fdf6470 x22: ffff800009ddb367 x21: 0000000000000000 -[ 1.193314] x20: ffff00001fdfebe8 x19: ffff00001fdfec50 x18: ffffffffffffffff -[ 1.200464] x17: 0000000000000000 x16: 0000000000000118 x15: 0000000000000004 -[ 1.207614] x14: 0000000000000fff x13: ffff800009bca248 x12: 0000000000000003 -[ 1.214764] x11: 00000000ffffefff x10: c0000000ffffefff x9 : 4762cb2ccb52de00 -[ 1.221914] x8 : 4762cb2ccb52de00 x7 : 205d313431303231 x6 : 312e31202020205b -[ 1.229063] x5 : ffff800009d55c1f x4 : 0000000000000001 x3 : 0000000000000000 -[ 1.236213] x2 : 0000000000000000 x1 : ffff800009954be6 x0 : 000000000000002a -[ 1.243365] Call trace: -[ 1.245806] refcount_warn_saturate+0xdc/0x148 -[ 1.250253] kobject_get+0x98/0x9c -[ 1.253658] of_node_get+0x20/0x34 -[ 1.257072] of_fwnode_get+0x3c/0x54 -[ 1.260652] fwnode_get_nth_parent+0xd8/0xf4 -[ 1.264926] fwnode_full_name_string+0x3c/0xb4 -[ 1.269373] device_node_string+0x498/0x5b4 -[ 1.273561] pointer+0x41c/0x5d0 -[ 1.276793] vsnprintf+0x4d8/0x694 -[ 1.280198] vprintk_store+0x164/0x528 -[ 1.283951] vprintk_emit+0x98/0x164 -[ 1.287530] vprintk_default+0x44/0x6c -[ 1.291284] vprintk+0xf0/0x134 -[ 1.294428] _printk+0x54/0x7c -[ 1.297486] of_node_release+0xe8/0x128 -[ 1.301326] kobject_put+0x98/0xfc -[ 1.304732] of_node_put+0x1c/0x28 -[ 1.308137] add_mtd_device+0x484/0x6d4 -[ 1.311977] add_mtd_partitions+0xf0/0x1d0 -[ 1.316078] parse_mtd_partitions+0x45c/0x518 -[ 1.320439] mtd_device_parse_register+0xb0/0x274 -[ 1.325147] gpmi_nand_probe+0x51c/0x650 -[ 1.329074] platform_probe+0xa8/0xd0 -[ 1.332740] really_probe+0x130/0x334 -[ 1.336406] __driver_probe_device+0xb4/0xe0 -[ 1.340681] driver_probe_device+0x3c/0x1f8 -[ 1.344869] __driver_attach+0xdc/0x1a4 -[ 1.348708] bus_for_each_dev+0x80/0xcc -[ 1.352548] driver_attach+0x24/0x30 -[ 1.356127] bus_add_driver+0x108/0x1f4 -[ 1.359967] driver_register+0x78/0x114 -[ 1.363807] __platform_driver_register+0x24/0x30 -[ 1.368515] gpmi_nand_driver_init+0x1c/0x28 -[ 1.372798] do_one_initcall+0xbc/0x238 -[ 1.376638] do_initcall_level+0x94/0xb4 -[ 1.380565] do_initcalls+0x54/0x94 -[ 1.384058] do_basic_setup+0x1c/0x28 -[ 1.387724] kernel_init_freeable+0x110/0x188 -[ 1.392084] kernel_init+0x20/0x1a0 -[ 1.395578] ret_from_fork+0x10/0x20 -[ 1.399157] ---[ end trace 0000000000000000 ]--- -[ 1.403782] ------------[ cut here ]------------ - -Reported-by: Han Xu -Fixes: ad9b10d1eaada169 ("mtd: core: introduce of support for dynamic partitions") -Signed-off-by: Rafał Miłecki -Tested-by: Han Xu -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20221018051822.28685-1-zajec5@gmail.com ---- - drivers/mtd/mtdcore.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/mtd/mtdcore.c -+++ b/drivers/mtd/mtdcore.c -@@ -580,7 +580,7 @@ static void mtd_check_of_node(struct mtd - if (!mtd_is_partition(mtd)) - return; - parent = mtd->parent; -- parent_dn = dev_of_node(&parent->dev); -+ parent_dn = of_node_get(dev_of_node(&parent->dev)); - if (!parent_dn) - return; - diff --git a/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch b/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch deleted file mode 100644 index 0efad99157a..00000000000 --- a/target/linux/generic/backport-6.1/407-v5.17-mtd-parsers-qcom-Don-t-print-error-message-on-EPROBE.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 26bccc9671ba5e01f7153addbe94e7dc3f677375 Mon Sep 17 00:00:00 2001 -From: Bryan O'Donoghue -Date: Mon, 3 Jan 2022 03:03:16 +0000 -Subject: [PATCH 13/14] mtd: parsers: qcom: Don't print error message on - -EPROBE_DEFER - -Its possible for the main smem driver to not be loaded by the time we come -along to parse the smem partition description but, this is a perfectly -normal thing. - -No need to print out an error message in this case. - -Signed-off-by: Bryan O'Donoghue -Reviewed-by: Manivannan Sadhasivam -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220103030316.58301-3-bryan.odonoghue@linaro.org ---- - drivers/mtd/parsers/qcomsmempart.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/mtd/parsers/qcomsmempart.c -+++ b/drivers/mtd/parsers/qcomsmempart.c -@@ -75,7 +75,8 @@ static int parse_qcomsmem_part(struct mt - pr_debug("Parsing partition table info from SMEM\n"); - ptable = qcom_smem_get(SMEM_APPS, SMEM_AARM_PARTITION_TABLE, &len); - if (IS_ERR(ptable)) { -- pr_err("Error reading partition table header\n"); -+ if (PTR_ERR(ptable) != -EPROBE_DEFER) -+ pr_err("Error reading partition table header\n"); - return PTR_ERR(ptable); - } - diff --git a/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch b/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch deleted file mode 100644 index 5c49841760f..00000000000 --- a/target/linux/generic/backport-6.1/410-v5.18-mtd-parsers-trx-allow-to-use-on-MediaTek-MIPS-SoCs.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 2365f91c861cbfeef7141c69842848c7b2d3c2db Mon Sep 17 00:00:00 2001 -From: INAGAKI Hiroshi -Date: Sun, 13 Feb 2022 15:40:44 +0900 -Subject: [PATCH] mtd: parsers: trx: allow to use on MediaTek MIPS SoCs - -Buffalo sells some router devices which have trx-formatted firmware, -based on MediaTek MIPS SoCs. To use parser_trx on those devices, add -"RALINK" to dependency and allow to compile for MediaTek MIPS SoCs. - -examples: - -- WCR-1166DS (MT7628) -- WSR-1166DHP (MT7621) -- WSR-2533DHP (MT7621) - -Signed-off-by: INAGAKI Hiroshi -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220213064045.1781-1-musashino.open@gmail.com ---- - drivers/mtd/parsers/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/mtd/parsers/Kconfig -+++ b/drivers/mtd/parsers/Kconfig -@@ -115,7 +115,7 @@ config MTD_AFS_PARTS - - config MTD_PARSER_TRX - tristate "Parser for TRX format partitions" -- depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || COMPILE_TEST) -+ depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) - help - TRX is a firmware format used by Broadcom on their devices. It - may contain up to 3/4 partitions (depending on the version). diff --git a/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch deleted file mode 100644 index 181c912fbfc..00000000000 --- a/target/linux/generic/backport-6.1/420-v5.19-02-mtd-spinand-gigadevice-add-support-for-GD5FxGQ4xExxG.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 573eec222bc82fb5e724586267fbbb1aed9ffd03 Mon Sep 17 00:00:00 2001 -From: Chuanhong Guo -Date: Sun, 20 Mar 2022 17:59:58 +0800 -Subject: [PATCH 2/5] mtd: spinand: gigadevice: add support for GD5FxGQ4xExxG - -Add support for: - GD5F1GQ4RExxG - GD5F2GQ4{U,R}ExxG - -These chips differ from GD5F1GQ4UExxG only in chip ID, voltage -and capacity. - -Signed-off-by: Chuanhong Guo -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-3-gch981213@gmail.com ---- - drivers/mtd/nand/spi/gigadevice.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - ---- a/drivers/mtd/nand/spi/gigadevice.c -+++ b/drivers/mtd/nand/spi/gigadevice.c -@@ -333,6 +333,36 @@ static const struct spinand_info gigadev - SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F1GQ4RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1), -+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GQ4UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GQ4RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), - SPINAND_INFO("GD5F1GQ4UFxxG", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48), - NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), diff --git a/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch deleted file mode 100644 index 3a1cc9efcfb..00000000000 --- a/target/linux/generic/backport-6.1/420-v5.19-03-mtd-spinand-gigadevice-add-support-for-GD5F1GQ5RExxG.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 620a988813403318023296b61228ee8f3fcdb8e0 Mon Sep 17 00:00:00 2001 -From: Chuanhong Guo -Date: Sun, 20 Mar 2022 17:59:59 +0800 -Subject: [PATCH 3/5] mtd: spinand: gigadevice: add support for GD5F1GQ5RExxG - -This chip is the 1.8v version of GD5F1GQ5UExxG. - -Signed-off-by: Chuanhong Guo -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-4-gch981213@gmail.com ---- - drivers/mtd/nand/spi/gigadevice.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/drivers/mtd/nand/spi/gigadevice.c -+++ b/drivers/mtd/nand/spi/gigadevice.c -@@ -383,6 +383,16 @@ static const struct spinand_info gigadev - SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F1GQ5RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41), -+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq5xexxg_ecc_get_status)), - }; - - static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch b/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch deleted file mode 100644 index cee9d9db3eb..00000000000 --- a/target/linux/generic/backport-6.1/420-v5.19-04-mtd-spinand-gigadevice-add-support-for-GD5F-2-4-GQ5x.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 194ec04b3a9e7fa97d1fbef296410631bc3cf1c8 Mon Sep 17 00:00:00 2001 -From: Chuanhong Guo -Date: Sun, 20 Mar 2022 18:00:00 +0800 -Subject: [PATCH 4/5] mtd: spinand: gigadevice: add support for GD5F{2, - 4}GQ5xExxG - -Add support for: - GD5F2GQ5{U,R}ExxG - GD5F4GQ6{U,R}ExxG - -These chips uses 4 dummy bytes for quad io and 2 dummy bytes for dual io. -Besides that and memory layout, they are identical to their 1G variant. - -Signed-off-by: Chuanhong Guo -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-5-gch981213@gmail.com ---- - drivers/mtd/nand/spi/gigadevice.c | 48 +++++++++++++++++++++++++++++++ - 1 file changed, 48 insertions(+) - ---- a/drivers/mtd/nand/spi/gigadevice.c -+++ b/drivers/mtd/nand/spi/gigadevice.c -@@ -47,6 +47,14 @@ static SPINAND_OP_VARIANTS(read_cache_va - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); - -+static SPINAND_OP_VARIANTS(read_cache_variants_2gq5, -+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), -+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); -+ - static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); -@@ -391,6 +399,46 @@ static const struct spinand_info gigadev - &write_cache_variants, - &update_cache_variants), - SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GQ5UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GQ5RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F4GQ6UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F4GQ6RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1), -+ NAND_ECCREQ(4, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq5xexxg_ecc_get_status)), - }; diff --git a/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch b/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch deleted file mode 100644 index d63113e1a66..00000000000 --- a/target/linux/generic/backport-6.1/420-v5.19-05-mtd-spinand-gigadevice-add-support-for-GD5FxGM7xExxG.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 54647cd003c08b714474a5b599a147ec6a160486 Mon Sep 17 00:00:00 2001 -From: Chuanhong Guo -Date: Sun, 20 Mar 2022 18:00:01 +0800 -Subject: [PATCH 5/5] mtd: spinand: gigadevice: add support for GD5FxGM7xExxG - -Add support for: - GD5F{1,2}GM7{U,R}ExxG - GD5F4GM8{U,R}ExxG - -These are new 27nm counterparts for the GD5FxGQ4 chips from GigaDevice -with 8b/512b on-die ECC capability. -These chips (and currently supported GD5FxGQ5 chips) have QIO DTR -instruction for reading page cache. It isn't added in this patch because -I don't have a DTR spi controller for testing. - -Signed-off-by: Chuanhong Guo -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220320100001.247905-6-gch981213@gmail.com ---- - drivers/mtd/nand/spi/gigadevice.c | 60 +++++++++++++++++++++++++++++++ - 1 file changed, 60 insertions(+) - ---- a/drivers/mtd/nand/spi/gigadevice.c -+++ b/drivers/mtd/nand/spi/gigadevice.c -@@ -441,6 +441,66 @@ static const struct spinand_info gigadev - SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, - gd5fxgq5xexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F1GM7UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91), -+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F1GM7RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81), -+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GM7UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F2GM7RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F4GM8UExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95), -+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), -+ SPINAND_INFO("GD5F4GM8RExxG", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85), -+ NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, -+ &write_cache_variants, -+ &update_cache_variants), -+ SPINAND_HAS_QE_BIT, -+ SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, -+ gd5fxgq4uexxg_ecc_get_status)), - }; - - static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch b/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch deleted file mode 100644 index 2358352e93c..00000000000 --- a/target/linux/generic/backport-6.1/422-v5.19-mtd-spi-nor-support-eon-en25qh256a.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 6abef37d16d0c570ef5a149e63762fba2a30804b Mon Sep 17 00:00:00 2001 -From: "Leon M. George" -Date: Wed, 30 Mar 2022 16:16:56 +0200 -Subject: [PATCH] mtd: spi-nor: support eon en25qh256a variant - -The EN25QH256A variant of the EN25QH256 doesn't initialize correctly from SFDP -alone and only accesses memory below 8m (addr_width is 4 but read_opcode takes -only 3 bytes). - -Set SNOR_F_4B_OPCODES if the flash chip variant was detected using hwcaps. - -The fix submitted upstream uses the PARSE_SFDP initializer that is not -available in the kernel used with Openwrt. - -Signed-off-by: Leon M. George ---- - drivers/mtd/spi-nor/eon.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/drivers/mtd/spi-nor/eon.c -+++ b/drivers/mtd/spi-nor/eon.c -@@ -8,6 +8,16 @@ - - #include "core.h" - -+static void en25qh256_post_sfdp_fixups(struct spi_nor *nor) -+{ -+ if (nor->params->hwcaps.mask & SNOR_HWCAPS_READ_1_1_4) -+ nor->flags |= SNOR_F_4B_OPCODES; -+} -+ -+static const struct spi_nor_fixups en25qh256_fixups = { -+ .post_sfdp = en25qh256_post_sfdp_fixups, -+}; -+ - static const struct flash_info eon_parts[] = { - /* EON -- en25xxx */ - { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, -@@ -23,7 +33,9 @@ static const struct flash_info eon_parts - { "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ) }, - { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, -- { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, -+ { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, -+ SPI_NOR_DUAL_READ) -+ .fixups = &en25qh256_fixups }, - { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, - }; - diff --git a/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch b/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch deleted file mode 100644 index 9f1757caa79..00000000000 --- a/target/linux/generic/backport-6.1/423-v6.1-0001-mtd-track-maximum-number-of-bitflips-for-each-read-r.patch +++ /dev/null @@ -1,73 +0,0 @@ -From e237285113963bd1dd2e925770aa8b3aa8a1894c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= -Date: Wed, 29 Jun 2022 14:57:34 +0200 -Subject: [PATCH 1/4] mtd: track maximum number of bitflips for each read - request -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -mtd_read_oob() callers are currently oblivious to the details of ECC -errors detected during the read operation - they only learn (through the -return value) whether any corrected bitflips or uncorrectable errors -occurred. More detailed ECC information can be useful to user-space -applications for making better-informed choices about moving data -around. - -Extend struct mtd_oob_ops with a pointer to a newly-introduced struct -mtd_req_stats and set its 'max_bitflips' field to the maximum number of -bitflips found in a single ECC step during the read operation performed -by mtd_read_oob(). This is a prerequisite for ultimately passing that -value back to user space. - -Suggested-by: Boris Brezillon -Signed-off-by: Michał Kępień -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-2-kernel@kempniu.pl ---- - drivers/mtd/mtdcore.c | 5 +++++ - include/linux/mtd/mtd.h | 5 +++++ - 2 files changed, 10 insertions(+) - ---- a/drivers/mtd/mtdcore.c -+++ b/drivers/mtd/mtdcore.c -@@ -1676,6 +1676,9 @@ int mtd_read_oob(struct mtd_info *mtd, l - if (!master->_read_oob && (!master->_read || ops->oobbuf)) - return -EOPNOTSUPP; - -+ if (ops->stats) -+ memset(ops->stats, 0, sizeof(*ops->stats)); -+ - if (mtd->flags & MTD_SLC_ON_MLC_EMULATION) - ret_code = mtd_io_emulated_slc(mtd, from, true, ops); - else -@@ -1693,6 +1696,8 @@ int mtd_read_oob(struct mtd_info *mtd, l - return ret_code; - if (mtd->ecc_strength == 0) - return 0; /* device lacks ecc */ -+ if (ops->stats) -+ ops->stats->max_bitflips = ret_code; - return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0; - } - EXPORT_SYMBOL_GPL(mtd_read_oob); ---- a/include/linux/mtd/mtd.h -+++ b/include/linux/mtd/mtd.h -@@ -40,6 +40,10 @@ struct mtd_erase_region_info { - unsigned long *lockmap; /* If keeping bitmap of locks */ - }; - -+struct mtd_req_stats { -+ unsigned int max_bitflips; -+}; -+ - /** - * struct mtd_oob_ops - oob operation operands - * @mode: operation mode -@@ -70,6 +74,7 @@ struct mtd_oob_ops { - uint32_t ooboffs; - uint8_t *datbuf; - uint8_t *oobbuf; -+ struct mtd_req_stats *stats; - }; - - #define MTD_MAX_OOBFREE_ENTRIES_LARGE 32 diff --git a/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch b/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch deleted file mode 100644 index 1484624e4e5..00000000000 --- a/target/linux/generic/backport-6.1/423-v6.1-0002-mtd-always-initialize-stats-in-struct-mtd_oob_ops.patch +++ /dev/null @@ -1,325 +0,0 @@ -From e97709c9d18903f5acd5fbe2985dd054da0432b1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= -Date: Wed, 29 Jun 2022 14:57:35 +0200 -Subject: [PATCH 2/4] mtd: always initialize 'stats' in struct mtd_oob_ops -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As the 'stats' field in struct mtd_oob_ops is used in conditional -expressions, ensure it is always zero-initialized in all such structures -to prevent random stack garbage from being interpreted as a pointer. - -Strictly speaking, this problem currently only needs to be fixed for -struct mtd_oob_ops structures subsequently passed to mtd_read_oob(). -However, this commit goes a step further and makes all instances of -struct mtd_oob_ops in the tree zero-initialized, in hope of preventing -future problems, e.g. if struct mtd_req_stats gets extended with write -statistics at some point. - -Signed-off-by: Michał Kępień -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-3-kernel@kempniu.pl ---- - drivers/mtd/inftlcore.c | 6 +++--- - drivers/mtd/mtdswap.c | 6 +++--- - drivers/mtd/nand/onenand/onenand_base.c | 4 ++-- - drivers/mtd/nand/onenand/onenand_bbt.c | 2 +- - drivers/mtd/nand/raw/nand_bbt.c | 8 ++++---- - drivers/mtd/nand/raw/sm_common.c | 2 +- - drivers/mtd/nftlcore.c | 6 +++--- - drivers/mtd/sm_ftl.c | 4 ++-- - drivers/mtd/ssfdc.c | 2 +- - drivers/mtd/tests/nandbiterrs.c | 2 +- - drivers/mtd/tests/oobtest.c | 8 ++++---- - drivers/mtd/tests/readtest.c | 2 +- - fs/jffs2/wbuf.c | 6 +++--- - 13 files changed, 29 insertions(+), 29 deletions(-) - ---- a/drivers/mtd/inftlcore.c -+++ b/drivers/mtd/inftlcore.c -@@ -136,7 +136,7 @@ static void inftl_remove_dev(struct mtd_ - int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, - size_t *retlen, uint8_t *buf) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; -@@ -156,7 +156,7 @@ int inftl_read_oob(struct mtd_info *mtd, - int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, - size_t *retlen, uint8_t *buf) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; -@@ -176,7 +176,7 @@ int inftl_write_oob(struct mtd_info *mtd - static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, - size_t *retlen, uint8_t *buf, uint8_t *oob) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; ---- a/drivers/mtd/mtdswap.c -+++ b/drivers/mtd/mtdswap.c -@@ -323,7 +323,7 @@ static int mtdswap_read_markers(struct m - struct mtdswap_oobdata *data, *data2; - int ret; - loff_t offset; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - offset = mtdswap_eb_offset(d, eb); - -@@ -370,7 +370,7 @@ static int mtdswap_write_marker(struct m - struct mtdswap_oobdata n; - int ret; - loff_t offset; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - ops.ooboffs = 0; - ops.oobbuf = (uint8_t *)&n; -@@ -879,7 +879,7 @@ static unsigned int mtdswap_eblk_passes( - loff_t base, pos; - unsigned int *p1 = (unsigned int *)d->page_buf; - unsigned char *p2 = (unsigned char *)d->oob_buf; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int ret; - - ops.mode = MTD_OPS_AUTO_OOB; ---- a/drivers/mtd/nand/onenand/onenand_base.c -+++ b/drivers/mtd/nand/onenand/onenand_base.c -@@ -2935,7 +2935,7 @@ static int do_otp_write(struct mtd_info - struct onenand_chip *this = mtd->priv; - unsigned char *pbuf = buf; - int ret; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - /* Force buffer page aligned */ - if (len < mtd->writesize) { -@@ -2977,7 +2977,7 @@ static int do_otp_lock(struct mtd_info * - size_t *retlen, u_char *buf) - { - struct onenand_chip *this = mtd->priv; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int ret; - - if (FLEXONENAND(this)) { ---- a/drivers/mtd/nand/onenand/onenand_bbt.c -+++ b/drivers/mtd/nand/onenand/onenand_bbt.c -@@ -61,7 +61,7 @@ static int create_bbt(struct mtd_info *m - int startblock; - loff_t from; - size_t readlen, ooblen; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int rgn; - - printk(KERN_INFO "Scanning device for bad blocks\n"); ---- a/drivers/mtd/nand/raw/nand_bbt.c -+++ b/drivers/mtd/nand/raw/nand_bbt.c -@@ -313,7 +313,7 @@ static int scan_read_oob(struct nand_chi - size_t len) - { - struct mtd_info *mtd = nand_to_mtd(this); -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res, ret = 0; - - ops.mode = MTD_OPS_PLACE_OOB; -@@ -354,7 +354,7 @@ static int scan_write_bbt(struct nand_ch - uint8_t *buf, uint8_t *oob) - { - struct mtd_info *mtd = nand_to_mtd(this); -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.ooboffs = 0; -@@ -416,7 +416,7 @@ static int scan_block_fast(struct nand_c - { - struct mtd_info *mtd = nand_to_mtd(this); - -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int ret, page_offset; - - ops.ooblen = mtd->oobsize; -@@ -756,7 +756,7 @@ static int write_bbt(struct nand_chip *t - uint8_t rcode = td->reserved_block_code; - size_t retlen, len = 0; - loff_t to; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - ops.ooblen = mtd->oobsize; - ops.ooboffs = 0; ---- a/drivers/mtd/nand/raw/sm_common.c -+++ b/drivers/mtd/nand/raw/sm_common.c -@@ -99,7 +99,7 @@ static const struct mtd_ooblayout_ops oo - static int sm_block_markbad(struct nand_chip *chip, loff_t ofs) - { - struct mtd_info *mtd = nand_to_mtd(chip); -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - struct sm_oob oob; - int ret; - ---- a/drivers/mtd/nftlcore.c -+++ b/drivers/mtd/nftlcore.c -@@ -124,7 +124,7 @@ int nftl_read_oob(struct mtd_info *mtd, - size_t *retlen, uint8_t *buf) - { - loff_t mask = mtd->writesize - 1; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; -@@ -145,7 +145,7 @@ int nftl_write_oob(struct mtd_info *mtd, - size_t *retlen, uint8_t *buf) - { - loff_t mask = mtd->writesize - 1; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; -@@ -168,7 +168,7 @@ static int nftl_write(struct mtd_info *m - size_t *retlen, uint8_t *buf, uint8_t *oob) - { - loff_t mask = mtd->writesize - 1; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int res; - - ops.mode = MTD_OPS_PLACE_OOB; ---- a/drivers/mtd/sm_ftl.c -+++ b/drivers/mtd/sm_ftl.c -@@ -239,7 +239,7 @@ static int sm_read_sector(struct sm_ftl - uint8_t *buffer, struct sm_oob *oob) - { - struct mtd_info *mtd = ftl->trans->mtd; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - struct sm_oob tmp_oob; - int ret = -EIO; - int try = 0; -@@ -323,7 +323,7 @@ static int sm_write_sector(struct sm_ftl - int zone, int block, int boffset, - uint8_t *buffer, struct sm_oob *oob) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - struct mtd_info *mtd = ftl->trans->mtd; - int ret; - ---- a/drivers/mtd/ssfdc.c -+++ b/drivers/mtd/ssfdc.c -@@ -163,7 +163,7 @@ static int read_physical_sector(struct m - /* Read redundancy area (wrapper to MTD_READ_OOB */ - static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int ret; - - ops.mode = MTD_OPS_RAW; ---- a/drivers/mtd/tests/nandbiterrs.c -+++ b/drivers/mtd/tests/nandbiterrs.c -@@ -99,7 +99,7 @@ static int write_page(int log) - static int rewrite_page(int log) - { - int err = 0; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - if (log) - pr_info("rewrite page\n"); ---- a/drivers/mtd/tests/oobtest.c -+++ b/drivers/mtd/tests/oobtest.c -@@ -56,7 +56,7 @@ static void do_vary_offset(void) - static int write_eraseblock(int ebnum) - { - int i; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int err = 0; - loff_t addr = (loff_t)ebnum * mtd->erasesize; - -@@ -165,7 +165,7 @@ static size_t memffshow(loff_t addr, lof - static int verify_eraseblock(int ebnum) - { - int i; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int err = 0; - loff_t addr = (loff_t)ebnum * mtd->erasesize; - size_t bitflips; -@@ -260,7 +260,7 @@ static int verify_eraseblock(int ebnum) - - static int verify_eraseblock_in_one_go(int ebnum) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int err = 0; - loff_t addr = (loff_t)ebnum * mtd->erasesize; - size_t len = mtd->oobavail * pgcnt; -@@ -338,7 +338,7 @@ static int __init mtd_oobtest_init(void) - int err = 0; - unsigned int i; - uint64_t tmp; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - loff_t addr = 0, addr0; - - printk(KERN_INFO "\n"); ---- a/drivers/mtd/tests/readtest.c -+++ b/drivers/mtd/tests/readtest.c -@@ -47,7 +47,7 @@ static int read_eraseblock_by_page(int e - err = ret; - } - if (mtd->oobsize) { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - ops.mode = MTD_OPS_PLACE_OOB; - ops.len = 0; ---- a/fs/jffs2/wbuf.c -+++ b/fs/jffs2/wbuf.c -@@ -1035,7 +1035,7 @@ int jffs2_check_oob_empty(struct jffs2_s - { - int i, ret; - int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - - ops.mode = MTD_OPS_AUTO_OOB; - ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail; -@@ -1076,7 +1076,7 @@ int jffs2_check_oob_empty(struct jffs2_s - int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, - struct jffs2_eraseblock *jeb) - { -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); - - ops.mode = MTD_OPS_AUTO_OOB; -@@ -1101,7 +1101,7 @@ int jffs2_write_nand_cleanmarker(struct - struct jffs2_eraseblock *jeb) - { - int ret; -- struct mtd_oob_ops ops; -+ struct mtd_oob_ops ops = { }; - int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE); - - ops.mode = MTD_OPS_AUTO_OOB; diff --git a/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch b/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch deleted file mode 100644 index f2f45eb7bc7..00000000000 --- a/target/linux/generic/backport-6.1/423-v6.1-0003-mtd-add-ECC-error-accounting-for-each-read-request.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 2ed18d818d1f7492172f8dd5904344c7d367e8ed Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= -Date: Wed, 29 Jun 2022 14:57:36 +0200 -Subject: [PATCH 3/4] mtd: add ECC error accounting for each read request -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Extend struct mtd_req_stats with two new fields holding the number of -corrected bitflips and uncorrectable errors detected during a read -operation. This is a prerequisite for ultimately passing those counters -to user space, where they can be useful to applications for making -better-informed choices about moving data around. - -Unlike 'max_bitflips' (which is set - in a common code path - to the -return value of a function called while the MTD device's mutex is held), -these counters have to be maintained in each MTD driver which defines -the '_read_oob' callback because the statistics need to be calculated -while the MTD device's mutex is held. - -Suggested-by: Boris Brezillon -Signed-off-by: Michał Kępień -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-4-kernel@kempniu.pl ---- - drivers/mtd/devices/docg3.c | 8 ++++++++ - drivers/mtd/nand/onenand/onenand_base.c | 12 ++++++++++++ - drivers/mtd/nand/raw/nand_base.c | 10 ++++++++++ - drivers/mtd/nand/spi/core.c | 10 ++++++++++ - include/linux/mtd/mtd.h | 2 ++ - 5 files changed, 42 insertions(+) - ---- a/drivers/mtd/devices/docg3.c -+++ b/drivers/mtd/devices/docg3.c -@@ -871,6 +871,7 @@ static int doc_read_oob(struct mtd_info - u8 *buf = ops->datbuf; - size_t len, ooblen, nbdata, nboob; - u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; -+ struct mtd_ecc_stats old_stats; - int max_bitflips = 0; - - if (buf) -@@ -895,6 +896,7 @@ static int doc_read_oob(struct mtd_info - ret = 0; - skip = from % DOC_LAYOUT_PAGE_SIZE; - mutex_lock(&docg3->cascade->lock); -+ old_stats = mtd->ecc_stats; - while (ret >= 0 && (len > 0 || ooblen > 0)) { - calc_block_sector(from - skip, &block0, &block1, &page, &ofs, - docg3->reliable); -@@ -966,6 +968,12 @@ static int doc_read_oob(struct mtd_info - } - - out: -+ if (ops->stats) { -+ ops->stats->uncorrectable_errors += -+ mtd->ecc_stats.failed - old_stats.failed; -+ ops->stats->corrected_bitflips += -+ mtd->ecc_stats.corrected - old_stats.corrected; -+ } - mutex_unlock(&docg3->cascade->lock); - return ret; - err_in_read: ---- a/drivers/mtd/nand/onenand/onenand_base.c -+++ b/drivers/mtd/nand/onenand/onenand_base.c -@@ -1440,6 +1440,7 @@ static int onenand_read_oob(struct mtd_i - struct mtd_oob_ops *ops) - { - struct onenand_chip *this = mtd->priv; -+ struct mtd_ecc_stats old_stats; - int ret; - - switch (ops->mode) { -@@ -1453,12 +1454,23 @@ static int onenand_read_oob(struct mtd_i - } - - onenand_get_device(mtd, FL_READING); -+ -+ old_stats = mtd->ecc_stats; -+ - if (ops->datbuf) - ret = ONENAND_IS_4KB_PAGE(this) ? - onenand_mlc_read_ops_nolock(mtd, from, ops) : - onenand_read_ops_nolock(mtd, from, ops); - else - ret = onenand_read_oob_nolock(mtd, from, ops); -+ -+ if (ops->stats) { -+ ops->stats->uncorrectable_errors += -+ mtd->ecc_stats.failed - old_stats.failed; -+ ops->stats->corrected_bitflips += -+ mtd->ecc_stats.corrected - old_stats.corrected; -+ } -+ - onenand_release_device(mtd); - - return ret; ---- a/drivers/mtd/nand/raw/nand_base.c -+++ b/drivers/mtd/nand/raw/nand_base.c -@@ -3815,6 +3815,7 @@ static int nand_read_oob(struct mtd_info - struct mtd_oob_ops *ops) - { - struct nand_chip *chip = mtd_to_nand(mtd); -+ struct mtd_ecc_stats old_stats; - int ret; - - ops->retlen = 0; -@@ -3826,11 +3827,20 @@ static int nand_read_oob(struct mtd_info - - nand_get_device(chip); - -+ old_stats = mtd->ecc_stats; -+ - if (!ops->datbuf) - ret = nand_do_read_oob(chip, from, ops); - else - ret = nand_do_read_ops(chip, from, ops); - -+ if (ops->stats) { -+ ops->stats->uncorrectable_errors += -+ mtd->ecc_stats.failed - old_stats.failed; -+ ops->stats->corrected_bitflips += -+ mtd->ecc_stats.corrected - old_stats.corrected; -+ } -+ - nand_release_device(chip); - return ret; - } ---- a/drivers/mtd/nand/spi/core.c -+++ b/drivers/mtd/nand/spi/core.c -@@ -629,6 +629,7 @@ static int spinand_mtd_read(struct mtd_i - { - struct spinand_device *spinand = mtd_to_spinand(mtd); - struct nand_device *nand = mtd_to_nanddev(mtd); -+ struct mtd_ecc_stats old_stats; - unsigned int max_bitflips = 0; - struct nand_io_iter iter; - bool disable_ecc = false; -@@ -640,6 +641,8 @@ static int spinand_mtd_read(struct mtd_i - - mutex_lock(&spinand->lock); - -+ old_stats = mtd->ecc_stats; -+ - nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) { - if (disable_ecc) - iter.req.mode = MTD_OPS_RAW; -@@ -662,6 +665,13 @@ static int spinand_mtd_read(struct mtd_i - ops->oobretlen += iter.req.ooblen; - } - -+ if (ops->stats) { -+ ops->stats->uncorrectable_errors += -+ mtd->ecc_stats.failed - old_stats.failed; -+ ops->stats->corrected_bitflips += -+ mtd->ecc_stats.corrected - old_stats.corrected; -+ } -+ - mutex_unlock(&spinand->lock); - - if (ecc_failed && !ret) ---- a/include/linux/mtd/mtd.h -+++ b/include/linux/mtd/mtd.h -@@ -41,6 +41,8 @@ struct mtd_erase_region_info { - }; - - struct mtd_req_stats { -+ unsigned int uncorrectable_errors; -+ unsigned int corrected_bitflips; - unsigned int max_bitflips; - }; - diff --git a/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch b/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch deleted file mode 100644 index 182e4f6ab56..00000000000 --- a/target/linux/generic/backport-6.1/423-v6.1-0004-mtdchar-add-MEMREAD-ioctl.patch +++ /dev/null @@ -1,321 +0,0 @@ -From 2c9745d36e04ac27161acd78514f647b9b587ad4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= -Date: Wed, 29 Jun 2022 14:57:37 +0200 -Subject: [PATCH 4/4] mtdchar: add MEMREAD ioctl -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -User-space applications making use of MTD devices via /dev/mtd* -character devices currently have limited capabilities for reading data: - - - only deprecated methods of accessing OOB layout information exist, - - - there is no way to explicitly specify MTD operation mode to use; it - is auto-selected based on the MTD file mode (MTD_FILE_MODE_*) set - for the character device; in particular, this prevents using - MTD_OPS_AUTO_OOB for reads, - - - all existing user-space interfaces which cause mtd_read() or - mtd_read_oob() to be called (via mtdchar_read() and - mtdchar_read_oob(), respectively) return success even when those - functions return -EUCLEAN or -EBADMSG; this renders user-space - applications using these interfaces unaware of any corrected - bitflips or uncorrectable ECC errors detected during reads. - -Note that the existing MEMWRITE ioctl allows the MTD operation mode to -be explicitly set, allowing user-space applications to write page data -and OOB data without requiring them to know anything about the OOB -layout of the MTD device they are writing to (MTD_OPS_AUTO_OOB). Also, -the MEMWRITE ioctl does not mangle the return value of mtd_write_oob(). - -Add a new ioctl, MEMREAD, which addresses the above issues. It is -intended to be a read-side counterpart of the existing MEMWRITE ioctl. -Similarly to the latter, the read operation is performed in a loop which -processes at most mtd->erasesize bytes in each iteration. This is done -to prevent unbounded memory allocations caused by calling kmalloc() with -the 'size' argument taken directly from the struct mtd_read_req provided -by user space. However, the new ioctl is implemented so that the values -it returns match those that would have been returned if just a single -mtd_read_oob() call was issued to handle the entire read operation in -one go. - -Note that while just returning -EUCLEAN or -EBADMSG to user space would -already be a valid and useful indication of the ECC algorithm detecting -errors during a read operation, that signal would not be granular enough -to cover all use cases. For example, knowing the maximum number of -bitflips detected in a single ECC step during a read operation performed -on a given page may be useful when dealing with an MTD partition whose -ECC layout varies across pages (e.g. a partition consisting of a -bootloader area using a "custom" ECC layout followed by data pages using -a "standard" ECC layout). To address that, include ECC statistics in -the structure returned to user space by the new MEMREAD ioctl. - -Link: https://www.infradead.org/pipermail/linux-mtd/2016-April/067085.html - -Suggested-by: Boris Brezillon -Signed-off-by: Michał Kępień -Acked-by: Richard Weinberger -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220629125737.14418-5-kernel@kempniu.pl ---- - drivers/mtd/mtdchar.c | 139 +++++++++++++++++++++++++++++++++++++ - include/uapi/mtd/mtd-abi.h | 64 +++++++++++++++-- - 2 files changed, 198 insertions(+), 5 deletions(-) - ---- a/drivers/mtd/mtdchar.c -+++ b/drivers/mtd/mtdchar.c -@@ -621,6 +621,137 @@ static int mtdchar_write_ioctl(struct mt - return ret; - } - -+static int mtdchar_read_ioctl(struct mtd_info *mtd, -+ struct mtd_read_req __user *argp) -+{ -+ struct mtd_info *master = mtd_get_master(mtd); -+ struct mtd_read_req req; -+ void __user *usr_data, *usr_oob; -+ uint8_t *datbuf = NULL, *oobbuf = NULL; -+ size_t datbuf_len, oobbuf_len; -+ size_t orig_len, orig_ooblen; -+ int ret = 0; -+ -+ if (copy_from_user(&req, argp, sizeof(req))) -+ return -EFAULT; -+ -+ orig_len = req.len; -+ orig_ooblen = req.ooblen; -+ -+ usr_data = (void __user *)(uintptr_t)req.usr_data; -+ usr_oob = (void __user *)(uintptr_t)req.usr_oob; -+ -+ if (!master->_read_oob) -+ return -EOPNOTSUPP; -+ -+ if (!usr_data) -+ req.len = 0; -+ -+ if (!usr_oob) -+ req.ooblen = 0; -+ -+ req.ecc_stats.uncorrectable_errors = 0; -+ req.ecc_stats.corrected_bitflips = 0; -+ req.ecc_stats.max_bitflips = 0; -+ -+ req.len &= 0xffffffff; -+ req.ooblen &= 0xffffffff; -+ -+ if (req.start + req.len > mtd->size) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ datbuf_len = min_t(size_t, req.len, mtd->erasesize); -+ if (datbuf_len > 0) { -+ datbuf = kvmalloc(datbuf_len, GFP_KERNEL); -+ if (!datbuf) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ } -+ -+ oobbuf_len = min_t(size_t, req.ooblen, mtd->erasesize); -+ if (oobbuf_len > 0) { -+ oobbuf = kvmalloc(oobbuf_len, GFP_KERNEL); -+ if (!oobbuf) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ } -+ -+ while (req.len > 0 || (!usr_data && req.ooblen > 0)) { -+ struct mtd_req_stats stats; -+ struct mtd_oob_ops ops = { -+ .mode = req.mode, -+ .len = min_t(size_t, req.len, datbuf_len), -+ .ooblen = min_t(size_t, req.ooblen, oobbuf_len), -+ .datbuf = datbuf, -+ .oobbuf = oobbuf, -+ .stats = &stats, -+ }; -+ -+ /* -+ * Shorten non-page-aligned, eraseblock-sized reads so that the -+ * read ends on an eraseblock boundary. This is necessary in -+ * order to prevent OOB data for some pages from being -+ * duplicated in the output of non-page-aligned reads requiring -+ * multiple mtd_read_oob() calls to be completed. -+ */ -+ if (ops.len == mtd->erasesize) -+ ops.len -= mtd_mod_by_ws(req.start + ops.len, mtd); -+ -+ ret = mtd_read_oob(mtd, (loff_t)req.start, &ops); -+ -+ req.ecc_stats.uncorrectable_errors += -+ stats.uncorrectable_errors; -+ req.ecc_stats.corrected_bitflips += stats.corrected_bitflips; -+ req.ecc_stats.max_bitflips = -+ max(req.ecc_stats.max_bitflips, stats.max_bitflips); -+ -+ if (ret && !mtd_is_bitflip_or_eccerr(ret)) -+ break; -+ -+ if (copy_to_user(usr_data, ops.datbuf, ops.retlen) || -+ copy_to_user(usr_oob, ops.oobbuf, ops.oobretlen)) { -+ ret = -EFAULT; -+ break; -+ } -+ -+ req.start += ops.retlen; -+ req.len -= ops.retlen; -+ usr_data += ops.retlen; -+ -+ req.ooblen -= ops.oobretlen; -+ usr_oob += ops.oobretlen; -+ } -+ -+ /* -+ * As multiple iterations of the above loop (and therefore multiple -+ * mtd_read_oob() calls) may be necessary to complete the read request, -+ * adjust the final return code to ensure it accounts for all detected -+ * ECC errors. -+ */ -+ if (!ret || mtd_is_bitflip(ret)) { -+ if (req.ecc_stats.uncorrectable_errors > 0) -+ ret = -EBADMSG; -+ else if (req.ecc_stats.corrected_bitflips > 0) -+ ret = -EUCLEAN; -+ } -+ -+out: -+ req.len = orig_len - req.len; -+ req.ooblen = orig_ooblen - req.ooblen; -+ -+ if (copy_to_user(argp, &req, sizeof(req))) -+ ret = -EFAULT; -+ -+ kvfree(datbuf); -+ kvfree(oobbuf); -+ -+ return ret; -+} -+ - static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg) - { - struct mtd_file_info *mfi = file->private_data; -@@ -643,6 +774,7 @@ static int mtdchar_ioctl(struct file *fi - case MEMGETINFO: - case MEMREADOOB: - case MEMREADOOB64: -+ case MEMREAD: - case MEMISLOCKED: - case MEMGETOOBSEL: - case MEMGETBADBLOCK: -@@ -817,6 +949,13 @@ static int mtdchar_ioctl(struct file *fi - break; - } - -+ case MEMREAD: -+ { -+ ret = mtdchar_read_ioctl(mtd, -+ (struct mtd_read_req __user *)arg); -+ break; -+ } -+ - case MEMLOCK: - { - struct erase_info_user einfo; ---- a/include/uapi/mtd/mtd-abi.h -+++ b/include/uapi/mtd/mtd-abi.h -@@ -55,9 +55,9 @@ struct mtd_oob_buf64 { - * @MTD_OPS_RAW: data are transferred as-is, with no error correction; - * this mode implies %MTD_OPS_PLACE_OOB - * -- * These modes can be passed to ioctl(MEMWRITE) and are also used internally. -- * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. -- * %MTD_FILE_MODE_RAW. -+ * These modes can be passed to ioctl(MEMWRITE) and ioctl(MEMREAD); they are -+ * also used internally. See notes on "MTD file modes" for discussion on -+ * %MTD_OPS_RAW vs. %MTD_FILE_MODE_RAW. - */ - enum { - MTD_OPS_PLACE_OOB = 0, -@@ -91,6 +91,53 @@ struct mtd_write_req { - __u8 padding[7]; - }; - -+/** -+ * struct mtd_read_req_ecc_stats - ECC statistics for a read operation -+ * -+ * @uncorrectable_errors: the number of uncorrectable errors that happened -+ * during the read operation -+ * @corrected_bitflips: the number of bitflips corrected during the read -+ * operation -+ * @max_bitflips: the maximum number of bitflips detected in any single ECC -+ * step for the data read during the operation; this information -+ * can be used to decide whether the data stored in a specific -+ * region of the MTD device should be moved somewhere else to -+ * avoid data loss. -+ */ -+struct mtd_read_req_ecc_stats { -+ __u32 uncorrectable_errors; -+ __u32 corrected_bitflips; -+ __u32 max_bitflips; -+}; -+ -+/** -+ * struct mtd_read_req - data structure for requesting a read operation -+ * -+ * @start: start address -+ * @len: length of data buffer (only lower 32 bits are used) -+ * @ooblen: length of OOB buffer (only lower 32 bits are used) -+ * @usr_data: user-provided data buffer -+ * @usr_oob: user-provided OOB buffer -+ * @mode: MTD mode (see "MTD operation modes") -+ * @padding: reserved, must be set to 0 -+ * @ecc_stats: ECC statistics for the read operation -+ * -+ * This structure supports ioctl(MEMREAD) operations, allowing data and/or OOB -+ * reads in various modes. To read from OOB-only, set @usr_data == NULL, and to -+ * read data-only, set @usr_oob == NULL. However, setting both @usr_data and -+ * @usr_oob to NULL is not allowed. -+ */ -+struct mtd_read_req { -+ __u64 start; -+ __u64 len; -+ __u64 ooblen; -+ __u64 usr_data; -+ __u64 usr_oob; -+ __u8 mode; -+ __u8 padding[7]; -+ struct mtd_read_req_ecc_stats ecc_stats; -+}; -+ - #define MTD_ABSENT 0 - #define MTD_RAM 1 - #define MTD_ROM 2 -@@ -207,6 +254,12 @@ struct otp_info { - #define MEMWRITE _IOWR('M', 24, struct mtd_write_req) - /* Erase a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ - #define OTPERASE _IOW('M', 25, struct otp_info) -+/* -+ * Most generic read interface; can read in-band and/or out-of-band in various -+ * modes (see "struct mtd_read_req"). This ioctl is not supported for flashes -+ * without OOB, e.g., NOR flash. -+ */ -+#define MEMREAD _IOWR('M', 26, struct mtd_read_req) - - /* - * Obsolete legacy interface. Keep it in order not to break userspace -@@ -270,8 +323,9 @@ struct mtd_ecc_stats { - * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - - * raw access to the flash, without error correction or autoplacement schemes. - * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode -- * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is -- * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). -+ * (e.g., when using ioctl(MEMWRITE) or ioctl(MEMREAD)), but in some cases, the -+ * MTD_FILE_MODE is used out of necessity (e.g., `write()', -+ * ioctl(MEMWRITEOOB64)). - */ - enum mtd_file_modes { - MTD_FILE_MODE_NORMAL = MTD_OTP_OFF, diff --git a/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch b/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch deleted file mode 100644 index 9e383de92cd..00000000000 --- a/target/linux/generic/backport-6.1/600-v5.18-page_pool-Add-allocation-stats.patch +++ /dev/null @@ -1,165 +0,0 @@ -From 8610037e8106b48c79cfe0afb92b2b2466e51c3d Mon Sep 17 00:00:00 2001 -From: Joe Damato -Date: Tue, 1 Mar 2022 23:55:47 -0800 -Subject: [PATCH] page_pool: Add allocation stats - -Add per-pool statistics counters for the allocation path of a page pool. -These stats are incremented in softirq context, so no locking or per-cpu -variables are needed. - -This code is disabled by default and a kernel config option is provided for -users who wish to enable them. - -The statistics added are: - - fast: successful fast path allocations - - slow: slow path order-0 allocations - - slow_high_order: slow path high order allocations - - empty: ptr ring is empty, so a slow path allocation was forced. - - refill: an allocation which triggered a refill of the cache - - waive: pages obtained from the ptr ring that cannot be added to - the cache due to a NUMA mismatch. - -Signed-off-by: Joe Damato -Acked-by: Jesper Dangaard Brouer -Reviewed-by: Ilias Apalodimas -Signed-off-by: David S. Miller ---- - include/net/page_pool.h | 18 ++++++++++++++++++ - net/Kconfig | 13 +++++++++++++ - net/core/page_pool.c | 24 ++++++++++++++++++++---- - 3 files changed, 51 insertions(+), 4 deletions(-) - ---- a/include/net/page_pool.h -+++ b/include/net/page_pool.h -@@ -82,6 +82,19 @@ struct page_pool_params { - unsigned int offset; /* DMA addr offset */ - }; - -+#ifdef CONFIG_PAGE_POOL_STATS -+struct page_pool_alloc_stats { -+ u64 fast; /* fast path allocations */ -+ u64 slow; /* slow-path order 0 allocations */ -+ u64 slow_high_order; /* slow-path high order allocations */ -+ u64 empty; /* failed refills due to empty ptr ring, forcing -+ * slow path allocation -+ */ -+ u64 refill; /* allocations via successful refill */ -+ u64 waive; /* failed refills due to numa zone mismatch */ -+}; -+#endif -+ - struct page_pool { - struct page_pool_params p; - -@@ -132,6 +145,11 @@ struct page_pool { - refcount_t user_cnt; - - u64 destroy_cnt; -+ -+#ifdef CONFIG_PAGE_POOL_STATS -+ /* these stats are incremented while in softirq context */ -+ struct page_pool_alloc_stats alloc_stats; -+#endif - }; - - struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp); ---- a/net/Kconfig -+++ b/net/Kconfig -@@ -434,6 +434,19 @@ config NET_DEVLINK - config PAGE_POOL - bool - -+config PAGE_POOL_STATS -+ default n -+ bool "Page pool stats" -+ depends on PAGE_POOL -+ help -+ Enable page pool statistics to track page allocation and recycling -+ in page pools. This option incurs additional CPU cost in allocation -+ and recycle paths and additional memory cost to store the statistics. -+ These statistics are only available if this option is enabled and if -+ the driver using the page pool supports exporting this data. -+ -+ If unsure, say N. -+ - config FAILOVER - tristate "Generic failover module" - help ---- a/net/core/page_pool.c -+++ b/net/core/page_pool.c -@@ -26,6 +26,13 @@ - - #define BIAS_MAX LONG_MAX - -+#ifdef CONFIG_PAGE_POOL_STATS -+/* alloc_stat_inc is intended to be used in softirq context */ -+#define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) -+#else -+#define alloc_stat_inc(pool, __stat) -+#endif -+ - static int page_pool_init(struct page_pool *pool, - const struct page_pool_params *params) - { -@@ -117,8 +124,10 @@ static struct page *page_pool_refill_all - int pref_nid; /* preferred NUMA node */ - - /* Quicker fallback, avoid locks when ring is empty */ -- if (__ptr_ring_empty(r)) -+ if (__ptr_ring_empty(r)) { -+ alloc_stat_inc(pool, empty); - return NULL; -+ } - - /* Softirq guarantee CPU and thus NUMA node is stable. This, - * assumes CPU refilling driver RX-ring will also run RX-NAPI. -@@ -148,14 +157,17 @@ static struct page *page_pool_refill_all - * This limit stress on page buddy alloactor. - */ - page_pool_return_page(pool, page); -+ alloc_stat_inc(pool, waive); - page = NULL; - break; - } - } while (pool->alloc.count < PP_ALLOC_CACHE_REFILL); - - /* Return last page */ -- if (likely(pool->alloc.count > 0)) -+ if (likely(pool->alloc.count > 0)) { - page = pool->alloc.cache[--pool->alloc.count]; -+ alloc_stat_inc(pool, refill); -+ } - - spin_unlock(&r->consumer_lock); - return page; -@@ -170,6 +182,7 @@ static struct page *__page_pool_get_cach - if (likely(pool->alloc.count)) { - /* Fast-path */ - page = pool->alloc.cache[--pool->alloc.count]; -+ alloc_stat_inc(pool, fast); - } else { - page = page_pool_refill_alloc_cache(pool); - } -@@ -241,6 +254,7 @@ static struct page *__page_pool_alloc_pa - return NULL; - } - -+ alloc_stat_inc(pool, slow_high_order); - page_pool_set_pp_info(pool, page); - - /* Track how many pages are held 'in-flight' */ -@@ -295,10 +309,12 @@ static struct page *__page_pool_alloc_pa - } - - /* Return last page */ -- if (likely(pool->alloc.count > 0)) -+ if (likely(pool->alloc.count > 0)) { - page = pool->alloc.cache[--pool->alloc.count]; -- else -+ alloc_stat_inc(pool, slow); -+ } else { - page = NULL; -+ } - - /* When page just alloc'ed is should/must have refcnt 1. */ - return page; diff --git a/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch b/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch deleted file mode 100644 index fb11f0035f8..00000000000 --- a/target/linux/generic/backport-6.1/601-v5.18-page_pool-Add-recycle-stats.patch +++ /dev/null @@ -1,140 +0,0 @@ -From ad6fa1e1ab1b8164f1ba296b1b4dc556a483bcad Mon Sep 17 00:00:00 2001 -From: Joe Damato -Date: Tue, 1 Mar 2022 23:55:48 -0800 -Subject: [PATCH 2/3] page_pool: Add recycle stats - -Add per-cpu stats tracking page pool recycling events: - - cached: recycling placed page in the page pool cache - - cache_full: page pool cache was full - - ring: page placed into the ptr ring - - ring_full: page released from page pool because the ptr ring was full - - released_refcnt: page released (and not recycled) because refcnt > 1 - -Signed-off-by: Joe Damato -Acked-by: Jesper Dangaard Brouer -Reviewed-by: Ilias Apalodimas -Signed-off-by: David S. Miller ---- - include/net/page_pool.h | 16 ++++++++++++++++ - net/core/page_pool.c | 30 ++++++++++++++++++++++++++++-- - 2 files changed, 44 insertions(+), 2 deletions(-) - ---- a/include/net/page_pool.h -+++ b/include/net/page_pool.h -@@ -93,6 +93,18 @@ struct page_pool_alloc_stats { - u64 refill; /* allocations via successful refill */ - u64 waive; /* failed refills due to numa zone mismatch */ - }; -+ -+struct page_pool_recycle_stats { -+ u64 cached; /* recycling placed page in the cache. */ -+ u64 cache_full; /* cache was full */ -+ u64 ring; /* recycling placed page back into ptr ring */ -+ u64 ring_full; /* page was released from page-pool because -+ * PTR ring was full. -+ */ -+ u64 released_refcnt; /* page released because of elevated -+ * refcnt -+ */ -+}; - #endif - - struct page_pool { -@@ -136,6 +148,10 @@ struct page_pool { - */ - struct ptr_ring ring; - -+#ifdef CONFIG_PAGE_POOL_STATS -+ /* recycle stats are per-cpu to avoid locking */ -+ struct page_pool_recycle_stats __percpu *recycle_stats; -+#endif - atomic_t pages_state_release_cnt; - - /* A page_pool is strictly tied to a single RX-queue being ---- a/net/core/page_pool.c -+++ b/net/core/page_pool.c -@@ -29,8 +29,15 @@ - #ifdef CONFIG_PAGE_POOL_STATS - /* alloc_stat_inc is intended to be used in softirq context */ - #define alloc_stat_inc(pool, __stat) (pool->alloc_stats.__stat++) -+/* recycle_stat_inc is safe to use when preemption is possible. */ -+#define recycle_stat_inc(pool, __stat) \ -+ do { \ -+ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ -+ this_cpu_inc(s->__stat); \ -+ } while (0) - #else - #define alloc_stat_inc(pool, __stat) -+#define recycle_stat_inc(pool, __stat) - #endif - - static int page_pool_init(struct page_pool *pool, -@@ -80,6 +87,12 @@ static int page_pool_init(struct page_po - pool->p.flags & PP_FLAG_PAGE_FRAG) - return -EINVAL; - -+#ifdef CONFIG_PAGE_POOL_STATS -+ pool->recycle_stats = alloc_percpu(struct page_pool_recycle_stats); -+ if (!pool->recycle_stats) -+ return -ENOMEM; -+#endif -+ - if (ptr_ring_init(&pool->ring, ring_qsize, GFP_KERNEL) < 0) - return -ENOMEM; - -@@ -412,7 +425,12 @@ static bool page_pool_recycle_in_ring(st - else - ret = ptr_ring_produce_bh(&pool->ring, page); - -- return (ret == 0) ? true : false; -+ if (!ret) { -+ recycle_stat_inc(pool, ring); -+ return true; -+ } -+ -+ return false; - } - - /* Only allow direct recycling in special circumstances, into the -@@ -423,11 +441,14 @@ static bool page_pool_recycle_in_ring(st - static bool page_pool_recycle_in_cache(struct page *page, - struct page_pool *pool) - { -- if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) -+ if (unlikely(pool->alloc.count == PP_ALLOC_CACHE_SIZE)) { -+ recycle_stat_inc(pool, cache_full); - return false; -+ } - - /* Caller MUST have verified/know (page_ref_count(page) == 1) */ - pool->alloc.cache[pool->alloc.count++] = page; -+ recycle_stat_inc(pool, cached); - return true; - } - -@@ -482,6 +503,7 @@ __page_pool_put_page(struct page_pool *p - * doing refcnt based recycle tricks, meaning another process - * will be invoking put_page. - */ -+ recycle_stat_inc(pool, released_refcnt); - /* Do not replace this with page_pool_return_page() */ - page_pool_release_page(pool, page); - put_page(page); -@@ -495,6 +517,7 @@ void page_pool_put_page(struct page_pool - page = __page_pool_put_page(pool, page, dma_sync_size, allow_direct); - if (page && !page_pool_recycle_in_ring(pool, page)) { - /* Cache full, fallback to free pages */ -+ recycle_stat_inc(pool, ring_full); - page_pool_return_page(pool, page); - } - } -@@ -641,6 +664,9 @@ static void page_pool_free(struct page_p - if (pool->p.flags & PP_FLAG_DMA_MAP) - put_device(pool->p.dev); - -+#ifdef CONFIG_PAGE_POOL_STATS -+ free_percpu(pool->recycle_stats); -+#endif - kfree(pool); - } - diff --git a/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch b/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch deleted file mode 100644 index 41188fb7f27..00000000000 --- a/target/linux/generic/backport-6.1/602-v5.18-page_pool-Add-function-to-batch-and-return-stats.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 6b95e3388b1ea0ca63500c5a6e39162dbf828433 Mon Sep 17 00:00:00 2001 -From: Joe Damato -Date: Tue, 1 Mar 2022 23:55:49 -0800 -Subject: [PATCH 3/3] page_pool: Add function to batch and return stats - -Adds a function page_pool_get_stats which can be used by drivers to obtain -stats for a specified page_pool. - -Signed-off-by: Joe Damato -Acked-by: Jesper Dangaard Brouer -Reviewed-by: Ilias Apalodimas -Signed-off-by: David S. Miller ---- - include/net/page_pool.h | 17 +++++++++++++++++ - net/core/page_pool.c | 25 +++++++++++++++++++++++++ - 2 files changed, 42 insertions(+) - ---- a/include/net/page_pool.h -+++ b/include/net/page_pool.h -@@ -105,6 +105,23 @@ struct page_pool_recycle_stats { - * refcnt - */ - }; -+ -+/* This struct wraps the above stats structs so users of the -+ * page_pool_get_stats API can pass a single argument when requesting the -+ * stats for the page pool. -+ */ -+struct page_pool_stats { -+ struct page_pool_alloc_stats alloc_stats; -+ struct page_pool_recycle_stats recycle_stats; -+}; -+ -+/* -+ * Drivers that wish to harvest page pool stats and report them to users -+ * (perhaps via ethtool, debugfs, or another mechanism) can allocate a -+ * struct page_pool_stats call page_pool_get_stats to get stats for the specified pool. -+ */ -+bool page_pool_get_stats(struct page_pool *pool, -+ struct page_pool_stats *stats); - #endif - - struct page_pool { ---- a/net/core/page_pool.c -+++ b/net/core/page_pool.c -@@ -35,6 +35,31 @@ - struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ - this_cpu_inc(s->__stat); \ - } while (0) -+ -+bool page_pool_get_stats(struct page_pool *pool, -+ struct page_pool_stats *stats) -+{ -+ int cpu = 0; -+ -+ if (!stats) -+ return false; -+ -+ memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); -+ -+ for_each_possible_cpu(cpu) { -+ const struct page_pool_recycle_stats *pcpu = -+ per_cpu_ptr(pool->recycle_stats, cpu); -+ -+ stats->recycle_stats.cached += pcpu->cached; -+ stats->recycle_stats.cache_full += pcpu->cache_full; -+ stats->recycle_stats.ring += pcpu->ring; -+ stats->recycle_stats.ring_full += pcpu->ring_full; -+ stats->recycle_stats.released_refcnt += pcpu->released_refcnt; -+ } -+ -+ return true; -+} -+EXPORT_SYMBOL(page_pool_get_stats); - #else - #define alloc_stat_inc(pool, __stat) - #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch b/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch deleted file mode 100644 index 6ae3fb71331..00000000000 --- a/target/linux/generic/backport-6.1/603-v5.19-page_pool-Add-recycle-stats-to-page_pool_put_page_bu.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 590032a4d2133ecc10d3078a8db1d85a4842f12c Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Mon, 11 Apr 2022 16:05:26 +0200 -Subject: [PATCH] page_pool: Add recycle stats to page_pool_put_page_bulk - -Add missing recycle stats to page_pool_put_page_bulk routine. - -Reviewed-by: Joe Damato -Signed-off-by: Lorenzo Bianconi -Reviewed-by: Ilias Apalodimas -Link: https://lore.kernel.org/r/3712178b51c007cfaed910ea80e68f00c916b1fa.1649685634.git.lorenzo@kernel.org -Signed-off-by: Paolo Abeni ---- - net/core/page_pool.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - ---- a/net/core/page_pool.c -+++ b/net/core/page_pool.c -@@ -36,6 +36,12 @@ - this_cpu_inc(s->__stat); \ - } while (0) - -+#define recycle_stat_add(pool, __stat, val) \ -+ do { \ -+ struct page_pool_recycle_stats __percpu *s = pool->recycle_stats; \ -+ this_cpu_add(s->__stat, val); \ -+ } while (0) -+ - bool page_pool_get_stats(struct page_pool *pool, - struct page_pool_stats *stats) - { -@@ -63,6 +69,7 @@ EXPORT_SYMBOL(page_pool_get_stats); - #else - #define alloc_stat_inc(pool, __stat) - #define recycle_stat_inc(pool, __stat) -+#define recycle_stat_add(pool, __stat, val) - #endif - - static int page_pool_init(struct page_pool *pool, -@@ -569,9 +576,13 @@ void page_pool_put_page_bulk(struct page - /* Bulk producer into ptr_ring page_pool cache */ - page_pool_ring_lock(pool); - for (i = 0; i < bulk_len; i++) { -- if (__ptr_ring_produce(&pool->ring, data[i])) -- break; /* ring full */ -+ if (__ptr_ring_produce(&pool->ring, data[i])) { -+ /* ring full */ -+ recycle_stat_inc(pool, ring_full); -+ break; -+ } - } -+ recycle_stat_add(pool, ring, i); - page_pool_ring_unlock(pool); - - /* Hopefully all pages was return into ptr_ring */ diff --git a/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch b/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch deleted file mode 100644 index e5cf91ceeed..00000000000 --- a/target/linux/generic/backport-6.1/604-v5.19-net-page_pool-introduce-ethtool-stats.patch +++ /dev/null @@ -1,147 +0,0 @@ -From f3c5264f452a5b0ac1de1f2f657efbabdea3c76a Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Tue, 12 Apr 2022 18:31:58 +0200 -Subject: [PATCH] net: page_pool: introduce ethtool stats - -Introduce page_pool APIs to report stats through ethtool and reduce -duplicated code in each driver. - -Signed-off-by: Lorenzo Bianconi -Reviewed-by: Jakub Kicinski -Reviewed-by: Ilias Apalodimas -Signed-off-by: David S. Miller ---- - include/net/page_pool.h | 21 ++++++++++++++ - net/core/page_pool.c | 63 ++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 83 insertions(+), 1 deletion(-) - ---- a/include/net/page_pool.h -+++ b/include/net/page_pool.h -@@ -115,6 +115,10 @@ struct page_pool_stats { - struct page_pool_recycle_stats recycle_stats; - }; - -+int page_pool_ethtool_stats_get_count(void); -+u8 *page_pool_ethtool_stats_get_strings(u8 *data); -+u64 *page_pool_ethtool_stats_get(u64 *data, void *stats); -+ - /* - * Drivers that wish to harvest page pool stats and report them to users - * (perhaps via ethtool, debugfs, or another mechanism) can allocate a -@@ -122,6 +126,23 @@ struct page_pool_stats { - */ - bool page_pool_get_stats(struct page_pool *pool, - struct page_pool_stats *stats); -+#else -+ -+static inline int page_pool_ethtool_stats_get_count(void) -+{ -+ return 0; -+} -+ -+static inline u8 *page_pool_ethtool_stats_get_strings(u8 *data) -+{ -+ return data; -+} -+ -+static inline u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) -+{ -+ return data; -+} -+ - #endif - - struct page_pool { ---- a/net/core/page_pool.c -+++ b/net/core/page_pool.c -@@ -18,6 +18,7 @@ - #include - #include /* for __put_page() */ - #include -+#include - - #include - -@@ -42,6 +43,20 @@ - this_cpu_add(s->__stat, val); \ - } while (0) - -+static const char pp_stats[][ETH_GSTRING_LEN] = { -+ "rx_pp_alloc_fast", -+ "rx_pp_alloc_slow", -+ "rx_pp_alloc_slow_ho", -+ "rx_pp_alloc_empty", -+ "rx_pp_alloc_refill", -+ "rx_pp_alloc_waive", -+ "rx_pp_recycle_cached", -+ "rx_pp_recycle_cache_full", -+ "rx_pp_recycle_ring", -+ "rx_pp_recycle_ring_full", -+ "rx_pp_recycle_released_ref", -+}; -+ - bool page_pool_get_stats(struct page_pool *pool, - struct page_pool_stats *stats) - { -@@ -50,7 +65,13 @@ bool page_pool_get_stats(struct page_poo - if (!stats) - return false; - -- memcpy(&stats->alloc_stats, &pool->alloc_stats, sizeof(pool->alloc_stats)); -+ /* The caller is responsible to initialize stats. */ -+ stats->alloc_stats.fast += pool->alloc_stats.fast; -+ stats->alloc_stats.slow += pool->alloc_stats.slow; -+ stats->alloc_stats.slow_high_order += pool->alloc_stats.slow_high_order; -+ stats->alloc_stats.empty += pool->alloc_stats.empty; -+ stats->alloc_stats.refill += pool->alloc_stats.refill; -+ stats->alloc_stats.waive += pool->alloc_stats.waive; - - for_each_possible_cpu(cpu) { - const struct page_pool_recycle_stats *pcpu = -@@ -66,6 +87,46 @@ bool page_pool_get_stats(struct page_poo - return true; - } - EXPORT_SYMBOL(page_pool_get_stats); -+ -+u8 *page_pool_ethtool_stats_get_strings(u8 *data) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(pp_stats); i++) { -+ memcpy(data, pp_stats[i], ETH_GSTRING_LEN); -+ data += ETH_GSTRING_LEN; -+ } -+ -+ return data; -+} -+EXPORT_SYMBOL(page_pool_ethtool_stats_get_strings); -+ -+int page_pool_ethtool_stats_get_count(void) -+{ -+ return ARRAY_SIZE(pp_stats); -+} -+EXPORT_SYMBOL(page_pool_ethtool_stats_get_count); -+ -+u64 *page_pool_ethtool_stats_get(u64 *data, void *stats) -+{ -+ struct page_pool_stats *pool_stats = stats; -+ -+ *data++ = pool_stats->alloc_stats.fast; -+ *data++ = pool_stats->alloc_stats.slow; -+ *data++ = pool_stats->alloc_stats.slow_high_order; -+ *data++ = pool_stats->alloc_stats.empty; -+ *data++ = pool_stats->alloc_stats.refill; -+ *data++ = pool_stats->alloc_stats.waive; -+ *data++ = pool_stats->recycle_stats.cached; -+ *data++ = pool_stats->recycle_stats.cache_full; -+ *data++ = pool_stats->recycle_stats.ring; -+ *data++ = pool_stats->recycle_stats.ring_full; -+ *data++ = pool_stats->recycle_stats.released_refcnt; -+ -+ return data; -+} -+EXPORT_SYMBOL(page_pool_ethtool_stats_get); -+ - #else - #define alloc_stat_inc(pool, __stat) - #define recycle_stat_inc(pool, __stat) diff --git a/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch b/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch deleted file mode 100644 index 4a914404a2f..00000000000 --- a/target/linux/generic/backport-6.1/605-v5.18-xdp-introduce-flags-field-in-xdp_buff-xdp_frame.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 2e88d4ff03013937028f5397268b21e10cf68713 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 21 Jan 2022 11:09:45 +0100 -Subject: [PATCH] xdp: introduce flags field in xdp_buff/xdp_frame - -Introduce flags field in xdp_frame and xdp_buffer data structures -to define additional buffer features. At the moment the only -supported buffer feature is frags bit (XDP_FLAGS_HAS_FRAGS). -frags bit is used to specify if this is a linear buffer -(XDP_FLAGS_HAS_FRAGS not set) or a frags frame (XDP_FLAGS_HAS_FRAGS -set). In the latter case the driver is expected to initialize the -skb_shared_info structure at the end of the first buffer to link together -subsequent buffers belonging to the same frame. - -Acked-by: Toke Hoiland-Jorgensen -Acked-by: John Fastabend -Acked-by: Jesper Dangaard Brouer -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/e389f14f3a162c0a5bc6a2e1aa8dd01a90be117d.1642758637.git.lorenzo@kernel.org -Signed-off-by: Alexei Starovoitov ---- - include/net/xdp.h | 29 +++++++++++++++++++++++++++++ - 1 file changed, 29 insertions(+) - ---- a/include/net/xdp.h -+++ b/include/net/xdp.h -@@ -66,6 +66,10 @@ struct xdp_txq_info { - struct net_device *dev; - }; - -+enum xdp_buff_flags { -+ XDP_FLAGS_HAS_FRAGS = BIT(0), /* non-linear xdp buff */ -+}; -+ - struct xdp_buff { - void *data; - void *data_end; -@@ -74,13 +78,30 @@ struct xdp_buff { - struct xdp_rxq_info *rxq; - struct xdp_txq_info *txq; - u32 frame_sz; /* frame size to deduce data_hard_end/reserved tailroom*/ -+ u32 flags; /* supported values defined in xdp_buff_flags */ - }; - -+static __always_inline bool xdp_buff_has_frags(struct xdp_buff *xdp) -+{ -+ return !!(xdp->flags & XDP_FLAGS_HAS_FRAGS); -+} -+ -+static __always_inline void xdp_buff_set_frags_flag(struct xdp_buff *xdp) -+{ -+ xdp->flags |= XDP_FLAGS_HAS_FRAGS; -+} -+ -+static __always_inline void xdp_buff_clear_frags_flag(struct xdp_buff *xdp) -+{ -+ xdp->flags &= ~XDP_FLAGS_HAS_FRAGS; -+} -+ - static __always_inline void - xdp_init_buff(struct xdp_buff *xdp, u32 frame_sz, struct xdp_rxq_info *rxq) - { - xdp->frame_sz = frame_sz; - xdp->rxq = rxq; -+ xdp->flags = 0; - } - - static __always_inline void -@@ -122,8 +143,14 @@ struct xdp_frame { - */ - struct xdp_mem_info mem; - struct net_device *dev_rx; /* used by cpumap */ -+ u32 flags; /* supported values defined in xdp_buff_flags */ - }; - -+static __always_inline bool xdp_frame_has_frags(struct xdp_frame *frame) -+{ -+ return !!(frame->flags & XDP_FLAGS_HAS_FRAGS); -+} -+ - #define XDP_BULK_QUEUE_SIZE 16 - struct xdp_frame_bulk { - int count; -@@ -180,6 +207,7 @@ void xdp_convert_frame_to_buff(struct xd - xdp->data_end = frame->data + frame->len; - xdp->data_meta = frame->data - frame->metasize; - xdp->frame_sz = frame->frame_sz; -+ xdp->flags = frame->flags; - } - - static inline -@@ -206,6 +234,7 @@ int xdp_update_frame_from_buff(struct xd - xdp_frame->headroom = headroom - sizeof(*xdp_frame); - xdp_frame->metasize = metasize; - xdp_frame->frame_sz = xdp->frame_sz; -+ xdp_frame->flags = xdp->flags; - - return 0; - } diff --git a/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch b/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch deleted file mode 100644 index 86d24367dd6..00000000000 --- a/target/linux/generic/backport-6.1/606-v5.18-xdp-add-frags-support-to-xdp_return_-buff-frame.patch +++ /dev/null @@ -1,137 +0,0 @@ -From 7c48cb0176c6d6d3b55029f7ff4ffa05faee6446 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 21 Jan 2022 11:09:50 +0100 -Subject: [PATCH] xdp: add frags support to xdp_return_{buff/frame} - -Take into account if the received xdp_buff/xdp_frame is non-linear -recycling/returning the frame memory to the allocator or into -xdp_frame_bulk. - -Acked-by: Toke Hoiland-Jorgensen -Acked-by: John Fastabend -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/a961069febc868508ce1bdf5e53a343eb4e57cb2.1642758637.git.lorenzo@kernel.org -Signed-off-by: Alexei Starovoitov ---- - include/net/xdp.h | 18 ++++++++++++++-- - net/core/xdp.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++- - 2 files changed, 69 insertions(+), 3 deletions(-) - ---- a/include/net/xdp.h -+++ b/include/net/xdp.h -@@ -275,10 +275,24 @@ void __xdp_release_frame(void *data, str - static inline void xdp_release_frame(struct xdp_frame *xdpf) - { - struct xdp_mem_info *mem = &xdpf->mem; -+ struct skb_shared_info *sinfo; -+ int i; - - /* Curr only page_pool needs this */ -- if (mem->type == MEM_TYPE_PAGE_POOL) -- __xdp_release_frame(xdpf->data, mem); -+ if (mem->type != MEM_TYPE_PAGE_POOL) -+ return; -+ -+ if (likely(!xdp_frame_has_frags(xdpf))) -+ goto out; -+ -+ sinfo = xdp_get_shared_info_from_frame(xdpf); -+ for (i = 0; i < sinfo->nr_frags; i++) { -+ struct page *page = skb_frag_page(&sinfo->frags[i]); -+ -+ __xdp_release_frame(page_address(page), mem); -+ } -+out: -+ __xdp_release_frame(xdpf->data, mem); - } - - int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, ---- a/net/core/xdp.c -+++ b/net/core/xdp.c -@@ -376,12 +376,38 @@ static void __xdp_return(void *data, str - - void xdp_return_frame(struct xdp_frame *xdpf) - { -+ struct skb_shared_info *sinfo; -+ int i; -+ -+ if (likely(!xdp_frame_has_frags(xdpf))) -+ goto out; -+ -+ sinfo = xdp_get_shared_info_from_frame(xdpf); -+ for (i = 0; i < sinfo->nr_frags; i++) { -+ struct page *page = skb_frag_page(&sinfo->frags[i]); -+ -+ __xdp_return(page_address(page), &xdpf->mem, false, NULL); -+ } -+out: - __xdp_return(xdpf->data, &xdpf->mem, false, NULL); - } - EXPORT_SYMBOL_GPL(xdp_return_frame); - - void xdp_return_frame_rx_napi(struct xdp_frame *xdpf) - { -+ struct skb_shared_info *sinfo; -+ int i; -+ -+ if (likely(!xdp_frame_has_frags(xdpf))) -+ goto out; -+ -+ sinfo = xdp_get_shared_info_from_frame(xdpf); -+ for (i = 0; i < sinfo->nr_frags; i++) { -+ struct page *page = skb_frag_page(&sinfo->frags[i]); -+ -+ __xdp_return(page_address(page), &xdpf->mem, true, NULL); -+ } -+out: - __xdp_return(xdpf->data, &xdpf->mem, true, NULL); - } - EXPORT_SYMBOL_GPL(xdp_return_frame_rx_napi); -@@ -417,7 +443,7 @@ void xdp_return_frame_bulk(struct xdp_fr - struct xdp_mem_allocator *xa; - - if (mem->type != MEM_TYPE_PAGE_POOL) { -- __xdp_return(xdpf->data, &xdpf->mem, false, NULL); -+ xdp_return_frame(xdpf); - return; - } - -@@ -436,12 +462,38 @@ void xdp_return_frame_bulk(struct xdp_fr - bq->xa = rhashtable_lookup(mem_id_ht, &mem->id, mem_id_rht_params); - } - -+ if (unlikely(xdp_frame_has_frags(xdpf))) { -+ struct skb_shared_info *sinfo; -+ int i; -+ -+ sinfo = xdp_get_shared_info_from_frame(xdpf); -+ for (i = 0; i < sinfo->nr_frags; i++) { -+ skb_frag_t *frag = &sinfo->frags[i]; -+ -+ bq->q[bq->count++] = skb_frag_address(frag); -+ if (bq->count == XDP_BULK_QUEUE_SIZE) -+ xdp_flush_frame_bulk(bq); -+ } -+ } - bq->q[bq->count++] = xdpf->data; - } - EXPORT_SYMBOL_GPL(xdp_return_frame_bulk); - - void xdp_return_buff(struct xdp_buff *xdp) - { -+ struct skb_shared_info *sinfo; -+ int i; -+ -+ if (likely(!xdp_buff_has_frags(xdp))) -+ goto out; -+ -+ sinfo = xdp_get_shared_info_from_buff(xdp); -+ for (i = 0; i < sinfo->nr_frags; i++) { -+ struct page *page = skb_frag_page(&sinfo->frags[i]); -+ -+ __xdp_return(page_address(page), &xdp->rxq->mem, true, xdp); -+ } -+out: - __xdp_return(xdp->data, &xdp->rxq->mem, true, xdp); - } - diff --git a/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch b/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch deleted file mode 100644 index 36f55d511ad..00000000000 --- a/target/linux/generic/backport-6.1/607-v5.18-net-skbuff-add-size-metadata-to-skb_shared_info-for-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d16697cb6261d4cc23422e6b1cb2759df8aa76d0 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 21 Jan 2022 11:09:44 +0100 -Subject: [PATCH] net: skbuff: add size metadata to skb_shared_info for xdp - -Introduce xdp_frags_size field in skb_shared_info data structure -to store xdp_buff/xdp_frame frame paged size (xdp_frags_size will -be used in xdp frags support). In order to not increase -skb_shared_info size we will use a hole due to skb_shared_info -alignment. - -Acked-by: Toke Hoiland-Jorgensen -Acked-by: John Fastabend -Acked-by: Jesper Dangaard Brouer -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/8a849819a3e0a143d540f78a3a5add76e17e980d.1642758637.git.lorenzo@kernel.org -Signed-off-by: Alexei Starovoitov ---- - include/linux/skbuff.h | 1 + - 1 file changed, 1 insertion(+) - ---- a/include/linux/skbuff.h -+++ b/include/linux/skbuff.h -@@ -568,6 +568,7 @@ struct skb_shared_info { - * Warning : all fields before dataref are cleared in __alloc_skb() - */ - atomic_t dataref; -+ unsigned int xdp_frags_size; - - /* Intermediate layers must ensure that destructor_arg - * remains valid until skb destructor */ diff --git a/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch b/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch deleted file mode 100644 index 3bdba8728cf..00000000000 --- a/target/linux/generic/backport-6.1/608-v5.18-net-veth-Account-total-xdp_frame-len-running-ndo_xdp.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 5142239a22219921a7863cf00c9ab853c00689d8 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 11 Mar 2022 10:14:18 +0100 -Subject: [PATCH] net: veth: Account total xdp_frame len running ndo_xdp_xmit - -Even if this is a theoretical issue since it is not possible to perform -XDP_REDIRECT on a non-linear xdp_frame, veth driver does not account -paged area in ndo_xdp_xmit function pointer. -Introduce xdp_get_frame_len utility routine to get the xdp_frame full -length and account total frame size running XDP_REDIRECT of a -non-linear xdp frame into a veth device. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: Daniel Borkmann -Acked-by: Toke Hoiland-Jorgensen -Acked-by: John Fastabend -Link: https://lore.kernel.org/bpf/54f9fd3bb65d190daf2c0bbae2f852ff16cfbaa0.1646989407.git.lorenzo@kernel.org ---- - drivers/net/veth.c | 4 ++-- - include/net/xdp.h | 14 ++++++++++++++ - 2 files changed, 16 insertions(+), 2 deletions(-) - ---- a/drivers/net/veth.c -+++ b/drivers/net/veth.c -@@ -501,7 +501,7 @@ static int veth_xdp_xmit(struct net_devi - struct xdp_frame *frame = frames[i]; - void *ptr = veth_xdp_to_ptr(frame); - -- if (unlikely(frame->len > max_len || -+ if (unlikely(xdp_get_frame_len(frame) > max_len || - __ptr_ring_produce(&rq->xdp_ring, ptr))) - break; - nxmit++; -@@ -862,7 +862,7 @@ static int veth_xdp_rcv(struct veth_rq * - /* ndo_xdp_xmit */ - struct xdp_frame *frame = veth_ptr_to_xdp(ptr); - -- stats->xdp_bytes += frame->len; -+ stats->xdp_bytes += xdp_get_frame_len(frame); - frame = veth_xdp_rcv_one(rq, frame, bq, stats); - if (frame) { - /* XDP_PASS */ ---- a/include/net/xdp.h -+++ b/include/net/xdp.h -@@ -295,6 +295,20 @@ out: - __xdp_release_frame(xdpf->data, mem); - } - -+static __always_inline unsigned int xdp_get_frame_len(struct xdp_frame *xdpf) -+{ -+ struct skb_shared_info *sinfo; -+ unsigned int len = xdpf->len; -+ -+ if (likely(!xdp_frame_has_frags(xdpf))) -+ goto out; -+ -+ sinfo = xdp_get_shared_info_from_frame(xdpf); -+ len += sinfo->xdp_frags_size; -+out: -+ return len; -+} -+ - int xdp_rxq_info_reg(struct xdp_rxq_info *xdp_rxq, - struct net_device *dev, u32 queue_index, unsigned int napi_id); - void xdp_rxq_info_unreg(struct xdp_rxq_info *xdp_rxq); diff --git a/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch b/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch deleted file mode 100644 index 31b44f11707..00000000000 --- a/target/linux/generic/backport-6.1/609-v5.18-veth-Allow-jumbo-frames-in-xdp-mode.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 7cda76d858a4e71ac4a04066c093679a12e1312c Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 11 Mar 2022 10:14:20 +0100 -Subject: [PATCH] veth: Allow jumbo frames in xdp mode -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Allow increasing the MTU over page boundaries on veth devices -if the attached xdp program declares to support xdp fragments. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: Daniel Borkmann -Acked-by: Toke Høiland-Jørgensen -Acked-by: John Fastabend -Link: https://lore.kernel.org/bpf/d5dc039c3d4123426e7023a488c449181a7bc57f.1646989407.git.lorenzo@kernel.org ---- - drivers/net/veth.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - ---- a/drivers/net/veth.c -+++ b/drivers/net/veth.c -@@ -1471,9 +1471,14 @@ static int veth_xdp_set(struct net_devic - goto err; - } - -- max_mtu = PAGE_SIZE - VETH_XDP_HEADROOM - -- peer->hard_header_len - -- SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); -+ max_mtu = SKB_WITH_OVERHEAD(PAGE_SIZE - VETH_XDP_HEADROOM) - -+ peer->hard_header_len; -+ /* Allow increasing the max_mtu if the program supports -+ * XDP fragments. -+ */ -+ //if (prog->aux->xdp_has_frags) -+ max_mtu += PAGE_SIZE * MAX_SKB_FRAGS; -+ - if (peer->mtu > max_mtu) { - NL_SET_ERR_MSG_MOD(extack, "Peer MTU is too large to set XDP"); - err = -ERANGE; diff --git a/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch b/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch deleted file mode 100644 index f2b651f0c61..00000000000 --- a/target/linux/generic/backport-6.1/700-v5.17-net-dsa-introduce-tagger-owned-storage-for-private.patch +++ /dev/null @@ -1,279 +0,0 @@ -From dc452a471dbae8aca8257c565174212620880093 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Fri, 10 Dec 2021 01:34:37 +0200 -Subject: net: dsa: introduce tagger-owned storage for private and shared data - -Ansuel is working on register access over Ethernet for the qca8k switch -family. This requires the qca8k tagging protocol driver to receive -frames which aren't intended for the network stack, but instead for the -qca8k switch driver itself. - -The dp->priv is currently the prevailing method for passing data back -and forth between the tagging protocol driver and the switch driver. -However, this method is riddled with caveats. - -The DSA design allows in principle for any switch driver to return any -protocol it desires in ->get_tag_protocol(). The dsa_loop driver can be -modified to do just that. But in the current design, the memory behind -dp->priv has to be allocated by the switch driver, so if the tagging -protocol is paired to an unexpected switch driver, we may end up in NULL -pointer dereferences inside the kernel, or worse (a switch driver may -allocate dp->priv according to the expectations of a different tagger). - -The latter possibility is even more plausible considering that DSA -switches can dynamically change tagging protocols in certain cases -(dsa <-> edsa, ocelot <-> ocelot-8021q), and the current design lends -itself to mistakes that are all too easy to make. - -This patch proposes that the tagging protocol driver should manage its -own memory, instead of relying on the switch driver to do so. -After analyzing the different in-tree needs, it can be observed that the -required tagger storage is per switch, therefore a ds->tagger_data -pointer is introduced. In principle, per-port storage could also be -introduced, although there is no need for it at the moment. Future -changes will replace the current usage of dp->priv with ds->tagger_data. - -We define a "binding" event between the DSA switch tree and the tagging -protocol. During this binding event, the tagging protocol's ->connect() -method is called first, and this may allocate some memory for each -switch of the tree. Then a cross-chip notifier is emitted for the -switches within that tree, and they are given the opportunity to fix up -the tagger's memory (for example, they might set up some function -pointers that represent virtual methods for consuming packets). -Because the memory is owned by the tagger, there exists a ->disconnect() -method for the tagger (which is the place to free the resources), but -there doesn't exist a ->disconnect() method for the switch driver. -This is part of the design. The switch driver should make minimal use of -the public part of the tagger data, and only after type-checking it -using the supplied "proto" argument. - -In the code there are in fact two binding events, one is the initial -event in dsa_switch_setup_tag_protocol(). At this stage, the cross chip -notifier chains aren't initialized, so we call each switch's connect() -method by hand. Then there is dsa_tree_bind_tag_proto() during -dsa_tree_change_tag_proto(), and here we have an old protocol and a new -one. We first connect to the new one before disconnecting from the old -one, to simplify error handling a bit and to ensure we remain in a valid -state at all times. - -Co-developed-by: Ansuel Smith -Signed-off-by: Ansuel Smith -Signed-off-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 12 +++++++++ - net/dsa/dsa2.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++--- - net/dsa/dsa_priv.h | 1 + - net/dsa/switch.c | 14 +++++++++++ - 4 files changed, 96 insertions(+), 4 deletions(-) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -80,12 +80,15 @@ enum dsa_tag_protocol { - }; - - struct dsa_switch; -+struct dsa_switch_tree; - - struct dsa_device_ops { - struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); - struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev); - void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, - int *offset); -+ int (*connect)(struct dsa_switch_tree *dst); -+ void (*disconnect)(struct dsa_switch_tree *dst); - unsigned int needed_headroom; - unsigned int needed_tailroom; - const char *name; -@@ -329,6 +332,8 @@ struct dsa_switch { - */ - void *priv; - -+ void *tagger_data; -+ - /* - * Configuration data for this switch. - */ -@@ -584,6 +589,13 @@ struct dsa_switch_ops { - enum dsa_tag_protocol mprot); - int (*change_tag_protocol)(struct dsa_switch *ds, int port, - enum dsa_tag_protocol proto); -+ /* -+ * Method for switch drivers to connect to the tagging protocol driver -+ * in current use. The switch driver can provide handlers for certain -+ * types of packets for switch management. -+ */ -+ int (*connect_tag_protocol)(struct dsa_switch *ds, -+ enum dsa_tag_protocol proto); - - /* Optional switch-wide initialization and destruction methods */ - int (*setup)(struct dsa_switch *ds); ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -230,8 +230,12 @@ static struct dsa_switch_tree *dsa_tree_ - - static void dsa_tree_free(struct dsa_switch_tree *dst) - { -- if (dst->tag_ops) -+ if (dst->tag_ops) { -+ if (dst->tag_ops->disconnect) -+ dst->tag_ops->disconnect(dst); -+ - dsa_tag_driver_put(dst->tag_ops); -+ } - list_del(&dst->list); - kfree(dst); - } -@@ -805,7 +809,7 @@ static int dsa_switch_setup_tag_protocol - int port, err; - - if (tag_ops->proto == dst->default_proto) -- return 0; -+ goto connect; - - for (port = 0; port < ds->num_ports; port++) { - if (!dsa_is_cpu_port(ds, port)) -@@ -821,6 +825,17 @@ static int dsa_switch_setup_tag_protocol - } - } - -+connect: -+ if (ds->ops->connect_tag_protocol) { -+ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); -+ if (err) { -+ dev_err(ds->dev, -+ "Unable to connect to tag protocol \"%s\": %pe\n", -+ tag_ops->name, ERR_PTR(err)); -+ return err; -+ } -+ } -+ - return 0; - } - -@@ -1132,6 +1147,46 @@ static void dsa_tree_teardown(struct dsa - dst->setup = false; - } - -+static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst, -+ const struct dsa_device_ops *tag_ops) -+{ -+ const struct dsa_device_ops *old_tag_ops = dst->tag_ops; -+ struct dsa_notifier_tag_proto_info info; -+ int err; -+ -+ dst->tag_ops = tag_ops; -+ -+ /* Notify the new tagger about the connection to this tree */ -+ if (tag_ops->connect) { -+ err = tag_ops->connect(dst); -+ if (err) -+ goto out_revert; -+ } -+ -+ /* Notify the switches from this tree about the connection -+ * to the new tagger -+ */ -+ info.tag_ops = tag_ops; -+ err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_CONNECT, &info); -+ if (err && err != -EOPNOTSUPP) -+ goto out_disconnect; -+ -+ /* Notify the old tagger about the disconnection from this tree */ -+ if (old_tag_ops->disconnect) -+ old_tag_ops->disconnect(dst); -+ -+ return 0; -+ -+out_disconnect: -+ /* Revert the new tagger's connection to this tree */ -+ if (tag_ops->disconnect) -+ tag_ops->disconnect(dst); -+out_revert: -+ dst->tag_ops = old_tag_ops; -+ -+ return err; -+} -+ - /* Since the dsa/tagging sysfs device attribute is per master, the assumption - * is that all DSA switches within a tree share the same tagger, otherwise - * they would have formed disjoint trees (different "dsa,member" values). -@@ -1164,12 +1219,15 @@ int dsa_tree_change_tag_proto(struct dsa - goto out_unlock; - } - -+ /* Notify the tag protocol change */ - info.tag_ops = tag_ops; - err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info); - if (err) -- goto out_unwind_tagger; -+ return err; - -- dst->tag_ops = tag_ops; -+ err = dsa_tree_bind_tag_proto(dst, tag_ops); -+ if (err) -+ goto out_unwind_tagger; - - rtnl_unlock(); - -@@ -1257,6 +1315,7 @@ static int dsa_port_parse_cpu(struct dsa - struct dsa_switch *ds = dp->ds; - struct dsa_switch_tree *dst = ds->dst; - enum dsa_tag_protocol default_proto; -+ int err; - - /* Find out which protocol the switch would prefer. */ - default_proto = dsa_get_tag_protocol(dp, master); -@@ -1311,6 +1370,12 @@ static int dsa_port_parse_cpu(struct dsa - */ - dsa_tag_driver_put(tag_ops); - } else { -+ if (tag_ops->connect) { -+ err = tag_ops->connect(dst); -+ if (err) -+ return err; -+ } -+ - dst->tag_ops = tag_ops; - } - ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -37,6 +37,7 @@ enum { - DSA_NOTIFIER_VLAN_DEL, - DSA_NOTIFIER_MTU, - DSA_NOTIFIER_TAG_PROTO, -+ DSA_NOTIFIER_TAG_PROTO_CONNECT, - DSA_NOTIFIER_MRP_ADD, - DSA_NOTIFIER_MRP_DEL, - DSA_NOTIFIER_MRP_ADD_RING_ROLE, ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -616,6 +616,17 @@ static int dsa_switch_change_tag_proto(s - return 0; - } - -+static int dsa_switch_connect_tag_proto(struct dsa_switch *ds, -+ struct dsa_notifier_tag_proto_info *info) -+{ -+ const struct dsa_device_ops *tag_ops = info->tag_ops; -+ -+ if (!ds->ops->connect_tag_protocol) -+ return -EOPNOTSUPP; -+ -+ return ds->ops->connect_tag_protocol(ds, tag_ops->proto); -+} -+ - static int dsa_switch_mrp_add(struct dsa_switch *ds, - struct dsa_notifier_mrp_info *info) - { -@@ -735,6 +746,9 @@ static int dsa_switch_event(struct notif - case DSA_NOTIFIER_TAG_PROTO: - err = dsa_switch_change_tag_proto(ds, info); - break; -+ case DSA_NOTIFIER_TAG_PROTO_CONNECT: -+ err = dsa_switch_connect_tag_proto(ds, info); -+ break; - case DSA_NOTIFIER_MRP_ADD: - err = dsa_switch_mrp_add(ds, info); - break; diff --git a/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch b/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch deleted file mode 100644 index 0c50ae6fb9d..00000000000 --- a/target/linux/generic/backport-6.1/701-v5.17-dsa-make-tagging-protocols-connect-to-individual-switches.patch +++ /dev/null @@ -1,274 +0,0 @@ -From 7f2973149c22e7a6fee4c0c9fa6b8e4108e9c208 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Tue, 14 Dec 2021 03:45:36 +0200 -Subject: net: dsa: make tagging protocols connect to individual switches from - a tree - -On the NXP Bluebox 3 board which uses a multi-switch setup with sja1105, -the mechanism through which the tagger connects to the switch tree is -broken, due to improper DSA code design. At the time when tag_ops->connect() -is called in dsa_port_parse_cpu(), DSA hasn't finished "touching" all -the ports, so it doesn't know how large the tree is and how many ports -it has. It has just seen the first CPU port by this time. As a result, -this function will call the tagger's ->connect method too early, and the -tagger will connect only to the first switch from the tree. - -This could be perhaps addressed a bit more simply by just moving the -tag_ops->connect(dst) call a bit later (for example in dsa_tree_setup), -but there is already a design inconsistency at present: on the switch -side, the notification is on a per-switch basis, but on the tagger side, -it is on a per-tree basis. Furthermore, the persistent storage itself is -per switch (ds->tagger_data). And the tagger connect and disconnect -procedures (at least the ones that exist currently) could see a fair bit -of simplification if they didn't have to iterate through the switches of -a tree. - -To fix the issue, this change transforms tag_ops->connect(dst) into -tag_ops->connect(ds) and moves it somewhere where we already iterate -over all switches of a tree. That is in dsa_switch_setup_tag_protocol(), -which is a good placement because we already have there the connection -call to the switch side of things. - -As for the dsa_tree_bind_tag_proto() method (called from the code path -that changes the tag protocol), things are a bit more complicated -because we receive the tree as argument, yet when we unwind on errors, -it would be nice to not call tag_ops->disconnect(ds) where we didn't -previously call tag_ops->connect(ds). We didn't have this problem before -because the tag_ops connection operations passed the entire dst before, -and this is more fine grained now. To solve the error rewind case using -the new API, we have to create yet one more cross-chip notifier for -disconnection, and stay connected with the old tag protocol to all the -switches in the tree until we've succeeded to connect with the new one -as well. So if something fails half way, the whole tree is still -connected to the old tagger. But there may still be leaks if the tagger -fails to connect to the 2nd out of 3 switches in a tree: somebody needs -to tell the tagger to disconnect from the first switch. Nothing comes -for free, and this was previously handled privately by the tagging -protocol driver before, but now we need to emit a disconnect cross-chip -notifier for that, because DSA has to take care of the unwind path. We -assume that the tagging protocol has connected to a switch if it has set -ds->tagger_data to something, otherwise we avoid calling its -disconnection method in the error rewind path. - -The rest of the changes are in the tagging protocol drivers, and have to -do with the replacement of dst with ds. The iteration is removed and the -error unwind path is simplified, as mentioned above. - -Signed-off-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 5 ++-- - net/dsa/dsa2.c | 44 +++++++++++++----------------- - net/dsa/dsa_priv.h | 1 + - net/dsa/switch.c | 52 ++++++++++++++++++++++++++++++++--- - net/dsa/tag_ocelot_8021q.c | 53 +++++++++++------------------------- - net/dsa/tag_sja1105.c | 67 ++++++++++++++++------------------------------ - 6 files changed, 109 insertions(+), 113 deletions(-) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -80,15 +80,14 @@ enum dsa_tag_protocol { - }; - - struct dsa_switch; --struct dsa_switch_tree; - - struct dsa_device_ops { - struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev); - struct sk_buff *(*rcv)(struct sk_buff *skb, struct net_device *dev); - void (*flow_dissect)(const struct sk_buff *skb, __be16 *proto, - int *offset); -- int (*connect)(struct dsa_switch_tree *dst); -- void (*disconnect)(struct dsa_switch_tree *dst); -+ int (*connect)(struct dsa_switch *ds); -+ void (*disconnect)(struct dsa_switch *ds); - unsigned int needed_headroom; - unsigned int needed_tailroom; - const char *name; ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -230,12 +230,8 @@ static struct dsa_switch_tree *dsa_tree_ - - static void dsa_tree_free(struct dsa_switch_tree *dst) - { -- if (dst->tag_ops) { -- if (dst->tag_ops->disconnect) -- dst->tag_ops->disconnect(dst); -- -+ if (dst->tag_ops) - dsa_tag_driver_put(dst->tag_ops); -- } - list_del(&dst->list); - kfree(dst); - } -@@ -826,17 +822,29 @@ static int dsa_switch_setup_tag_protocol - } - - connect: -+ if (tag_ops->connect) { -+ err = tag_ops->connect(ds); -+ if (err) -+ return err; -+ } -+ - if (ds->ops->connect_tag_protocol) { - err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); - if (err) { - dev_err(ds->dev, - "Unable to connect to tag protocol \"%s\": %pe\n", - tag_ops->name, ERR_PTR(err)); -- return err; -+ goto disconnect; - } - } - - return 0; -+ -+disconnect: -+ if (tag_ops->disconnect) -+ tag_ops->disconnect(ds); -+ -+ return err; - } - - static int dsa_switch_setup(struct dsa_switch *ds) -@@ -1156,13 +1164,6 @@ static int dsa_tree_bind_tag_proto(struc - - dst->tag_ops = tag_ops; - -- /* Notify the new tagger about the connection to this tree */ -- if (tag_ops->connect) { -- err = tag_ops->connect(dst); -- if (err) -- goto out_revert; -- } -- - /* Notify the switches from this tree about the connection - * to the new tagger - */ -@@ -1172,16 +1173,14 @@ static int dsa_tree_bind_tag_proto(struc - goto out_disconnect; - - /* Notify the old tagger about the disconnection from this tree */ -- if (old_tag_ops->disconnect) -- old_tag_ops->disconnect(dst); -+ info.tag_ops = old_tag_ops; -+ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info); - - return 0; - - out_disconnect: -- /* Revert the new tagger's connection to this tree */ -- if (tag_ops->disconnect) -- tag_ops->disconnect(dst); --out_revert: -+ info.tag_ops = tag_ops; -+ dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, &info); - dst->tag_ops = old_tag_ops; - - return err; -@@ -1315,7 +1314,6 @@ static int dsa_port_parse_cpu(struct dsa - struct dsa_switch *ds = dp->ds; - struct dsa_switch_tree *dst = ds->dst; - enum dsa_tag_protocol default_proto; -- int err; - - /* Find out which protocol the switch would prefer. */ - default_proto = dsa_get_tag_protocol(dp, master); -@@ -1370,12 +1368,6 @@ static int dsa_port_parse_cpu(struct dsa - */ - dsa_tag_driver_put(tag_ops); - } else { -- if (tag_ops->connect) { -- err = tag_ops->connect(dst); -- if (err) -- return err; -- } -- - dst->tag_ops = tag_ops; - } - ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -38,6 +38,7 @@ enum { - DSA_NOTIFIER_MTU, - DSA_NOTIFIER_TAG_PROTO, - DSA_NOTIFIER_TAG_PROTO_CONNECT, -+ DSA_NOTIFIER_TAG_PROTO_DISCONNECT, - DSA_NOTIFIER_MRP_ADD, - DSA_NOTIFIER_MRP_DEL, - DSA_NOTIFIER_MRP_ADD_RING_ROLE, ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -616,15 +616,58 @@ static int dsa_switch_change_tag_proto(s - return 0; - } - --static int dsa_switch_connect_tag_proto(struct dsa_switch *ds, -- struct dsa_notifier_tag_proto_info *info) -+/* We use the same cross-chip notifiers to inform both the tagger side, as well -+ * as the switch side, of connection and disconnection events. -+ * Since ds->tagger_data is owned by the tagger, it isn't a hard error if the -+ * switch side doesn't support connecting to this tagger, and therefore, the -+ * fact that we don't disconnect the tagger side doesn't constitute a memory -+ * leak: the tagger will still operate with persistent per-switch memory, just -+ * with the switch side unconnected to it. What does constitute a hard error is -+ * when the switch side supports connecting but fails. -+ */ -+static int -+dsa_switch_connect_tag_proto(struct dsa_switch *ds, -+ struct dsa_notifier_tag_proto_info *info) - { - const struct dsa_device_ops *tag_ops = info->tag_ops; -+ int err; -+ -+ /* Notify the new tagger about the connection to this switch */ -+ if (tag_ops->connect) { -+ err = tag_ops->connect(ds); -+ if (err) -+ return err; -+ } - - if (!ds->ops->connect_tag_protocol) - return -EOPNOTSUPP; - -- return ds->ops->connect_tag_protocol(ds, tag_ops->proto); -+ /* Notify the switch about the connection to the new tagger */ -+ err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); -+ if (err) { -+ /* Revert the new tagger's connection to this tree */ -+ if (tag_ops->disconnect) -+ tag_ops->disconnect(ds); -+ return err; -+ } -+ -+ return 0; -+} -+ -+static int -+dsa_switch_disconnect_tag_proto(struct dsa_switch *ds, -+ struct dsa_notifier_tag_proto_info *info) -+{ -+ const struct dsa_device_ops *tag_ops = info->tag_ops; -+ -+ /* Notify the tagger about the disconnection from this switch */ -+ if (tag_ops->disconnect && ds->tagger_data) -+ tag_ops->disconnect(ds); -+ -+ /* No need to notify the switch, since it shouldn't have any -+ * resources to tear down -+ */ -+ return 0; - } - - static int dsa_switch_mrp_add(struct dsa_switch *ds, -@@ -749,6 +792,9 @@ static int dsa_switch_event(struct notif - case DSA_NOTIFIER_TAG_PROTO_CONNECT: - err = dsa_switch_connect_tag_proto(ds, info); - break; -+ case DSA_NOTIFIER_TAG_PROTO_DISCONNECT: -+ err = dsa_switch_disconnect_tag_proto(ds, info); -+ break; - case DSA_NOTIFIER_MRP_ADD: - err = dsa_switch_mrp_add(ds, info); - break; diff --git a/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch b/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch deleted file mode 100644 index c83d659d1c0..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-00-net-ethernet-mtk_eth_soc-add-support-for-coherent-DM.patch +++ /dev/null @@ -1,327 +0,0 @@ -From: Felix Fietkau -Date: Sat, 5 Feb 2022 17:59:07 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent - DMA - -It improves performance by eliminating the need for a cache flush on rx and tx -In preparation for supporting WED (Wireless Ethernet Dispatch), also add a -function for disabling coherent DMA at runtime. - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -840,7 +841,7 @@ static int mtk_init_fq_dma(struct mtk_et - dma_addr_t dma_addr; - int i; - -- eth->scratch_ring = dma_alloc_coherent(eth->dev, -+ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, - cnt * sizeof(struct mtk_tx_dma), - ð->phy_scratch_ring, - GFP_ATOMIC); -@@ -852,10 +853,10 @@ static int mtk_init_fq_dma(struct mtk_et - if (unlikely(!eth->scratch_head)) - return -ENOMEM; - -- dma_addr = dma_map_single(eth->dev, -+ dma_addr = dma_map_single(eth->dma_dev, - eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE, - DMA_FROM_DEVICE); -- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) -+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; - - phy_ring_tail = eth->phy_scratch_ring + -@@ -909,26 +910,26 @@ static void mtk_tx_unmap(struct mtk_eth - { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { - if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) { -- dma_unmap_single(eth->dev, -+ dma_unmap_single(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) { -- dma_unmap_page(eth->dev, -+ dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } - } else { - if (dma_unmap_len(tx_buf, dma_len0)) { -- dma_unmap_page(eth->dev, -+ dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr0), - dma_unmap_len(tx_buf, dma_len0), - DMA_TO_DEVICE); - } - - if (dma_unmap_len(tx_buf, dma_len1)) { -- dma_unmap_page(eth->dev, -+ dma_unmap_page(eth->dma_dev, - dma_unmap_addr(tx_buf, dma_addr1), - dma_unmap_len(tx_buf, dma_len1), - DMA_TO_DEVICE); -@@ -1006,9 +1007,9 @@ static int mtk_tx_map(struct sk_buff *sk - if (skb_vlan_tag_present(skb)) - txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); - -- mapped_addr = dma_map_single(eth->dev, skb->data, -+ mapped_addr = dma_map_single(eth->dma_dev, skb->data, - skb_headlen(skb), DMA_TO_DEVICE); -- if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) -+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) - return -ENOMEM; - - WRITE_ONCE(itxd->txd1, mapped_addr); -@@ -1047,10 +1048,10 @@ static int mtk_tx_map(struct sk_buff *sk - - - frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); -- mapped_addr = skb_frag_dma_map(eth->dev, frag, offset, -+ mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset, - frag_map_size, - DMA_TO_DEVICE); -- if (unlikely(dma_mapping_error(eth->dev, mapped_addr))) -+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) - goto err_dma; - - if (i == nr_frags - 1 && -@@ -1331,18 +1332,18 @@ static int mtk_poll_rx(struct napi_struc - netdev->stats.rx_dropped++; - goto release_desc; - } -- dma_addr = dma_map_single(eth->dev, -+ dma_addr = dma_map_single(eth->dma_dev, - new_data + NET_SKB_PAD + - eth->ip_align, - ring->buf_size, - DMA_FROM_DEVICE); -- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) { -+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { - skb_free_frag(new_data); - netdev->stats.rx_dropped++; - goto release_desc; - } - -- dma_unmap_single(eth->dev, trxd.rxd1, -+ dma_unmap_single(eth->dma_dev, trxd.rxd1, - ring->buf_size, DMA_FROM_DEVICE); - - /* receive data */ -@@ -1615,7 +1616,7 @@ static int mtk_tx_alloc(struct mtk_eth * - if (!ring->buf) - goto no_tx_mem; - -- ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, -+ ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, - &ring->phys, GFP_ATOMIC); - if (!ring->dma) - goto no_tx_mem; -@@ -1633,7 +1634,7 @@ static int mtk_tx_alloc(struct mtk_eth * - * descriptors in ring->dma_pdma. - */ - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -- ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz, -+ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, - &ring->phys_pdma, - GFP_ATOMIC); - if (!ring->dma_pdma) -@@ -1692,7 +1693,7 @@ static void mtk_tx_clean(struct mtk_eth - } - - if (ring->dma) { -- dma_free_coherent(eth->dev, -+ dma_free_coherent(eth->dma_dev, - MTK_DMA_SIZE * sizeof(*ring->dma), - ring->dma, - ring->phys); -@@ -1700,7 +1701,7 @@ static void mtk_tx_clean(struct mtk_eth - } - - if (ring->dma_pdma) { -- dma_free_coherent(eth->dev, -+ dma_free_coherent(eth->dma_dev, - MTK_DMA_SIZE * sizeof(*ring->dma_pdma), - ring->dma_pdma, - ring->phys_pdma); -@@ -1748,18 +1749,18 @@ static int mtk_rx_alloc(struct mtk_eth * - return -ENOMEM; - } - -- ring->dma = dma_alloc_coherent(eth->dev, -+ ring->dma = dma_alloc_coherent(eth->dma_dev, - rx_dma_size * sizeof(*ring->dma), - &ring->phys, GFP_ATOMIC); - if (!ring->dma) - return -ENOMEM; - - for (i = 0; i < rx_dma_size; i++) { -- dma_addr_t dma_addr = dma_map_single(eth->dev, -+ dma_addr_t dma_addr = dma_map_single(eth->dma_dev, - ring->data[i] + NET_SKB_PAD + eth->ip_align, - ring->buf_size, - DMA_FROM_DEVICE); -- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) -+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; - ring->dma[i].rxd1 = (unsigned int)dma_addr; - -@@ -1795,7 +1796,7 @@ static void mtk_rx_clean(struct mtk_eth - continue; - if (!ring->dma[i].rxd1) - continue; -- dma_unmap_single(eth->dev, -+ dma_unmap_single(eth->dma_dev, - ring->dma[i].rxd1, - ring->buf_size, - DMA_FROM_DEVICE); -@@ -1806,7 +1807,7 @@ static void mtk_rx_clean(struct mtk_eth - } - - if (ring->dma) { -- dma_free_coherent(eth->dev, -+ dma_free_coherent(eth->dma_dev, - ring->dma_size * sizeof(*ring->dma), - ring->dma, - ring->phys); -@@ -2162,7 +2163,7 @@ static void mtk_dma_free(struct mtk_eth - if (eth->netdev[i]) - netdev_reset_queue(eth->netdev[i]); - if (eth->scratch_ring) { -- dma_free_coherent(eth->dev, -+ dma_free_coherent(eth->dma_dev, - MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), - eth->scratch_ring, - eth->phy_scratch_ring); -@@ -2514,6 +2515,8 @@ static void mtk_dim_tx(struct work_struc - - static int mtk_hw_init(struct mtk_eth *eth) - { -+ u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -+ ETHSYS_DMA_AG_MAP_PPE; - int i, val, ret; - - if (test_and_set_bit(MTK_HW_INIT, ð->state)) -@@ -2526,6 +2529,10 @@ static int mtk_hw_init(struct mtk_eth *e - if (ret) - goto err_disable_pm; - -+ if (eth->ethsys) -+ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask, -+ of_dma_is_coherent(eth->dma_dev->of_node) * dma_mask); -+ - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { - ret = device_reset(eth->dev); - if (ret) { -@@ -3079,6 +3086,35 @@ free_netdev: - return err; - } - -+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev) -+{ -+ struct net_device *dev, *tmp; -+ LIST_HEAD(dev_list); -+ int i; -+ -+ rtnl_lock(); -+ -+ for (i = 0; i < MTK_MAC_COUNT; i++) { -+ dev = eth->netdev[i]; -+ -+ if (!dev || !(dev->flags & IFF_UP)) -+ continue; -+ -+ list_add_tail(&dev->close_list, &dev_list); -+ } -+ -+ dev_close_many(&dev_list, false); -+ -+ eth->dma_dev = dma_dev; -+ -+ list_for_each_entry_safe(dev, tmp, &dev_list, close_list) { -+ list_del_init(&dev->close_list); -+ dev_open(dev, NULL); -+ } -+ -+ rtnl_unlock(); -+} -+ - static int mtk_probe(struct platform_device *pdev) - { - struct device_node *mac_np; -@@ -3092,6 +3128,7 @@ static int mtk_probe(struct platform_dev - eth->soc = of_device_get_match_data(&pdev->dev); - - eth->dev = &pdev->dev; -+ eth->dma_dev = &pdev->dev; - eth->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(eth->base)) - return PTR_ERR(eth->base); -@@ -3140,6 +3177,16 @@ static int mtk_probe(struct platform_dev - } - } - -+ if (of_dma_is_coherent(pdev->dev.of_node)) { -+ struct regmap *cci; -+ -+ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, -+ "mediatek,cci-control"); -+ /* enable CPU/bus coherency */ -+ if (!IS_ERR(cci)) -+ regmap_write(cci, 0, 3); -+ } -+ - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { - eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii), - GFP_KERNEL); ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -463,6 +463,12 @@ - #define RSTCTRL_FE BIT(6) - #define RSTCTRL_PPE BIT(31) - -+/* ethernet dma channel agent map */ -+#define ETHSYS_DMA_AG_MAP 0x408 -+#define ETHSYS_DMA_AG_MAP_PDMA BIT(0) -+#define ETHSYS_DMA_AG_MAP_QDMA BIT(1) -+#define ETHSYS_DMA_AG_MAP_PPE BIT(2) -+ - /* SGMII subsystem config registers */ - /* Register to auto-negotiation restart */ - #define SGMSYS_PCS_CONTROL_1 0x0 -@@ -880,6 +886,7 @@ struct mtk_sgmii { - /* struct mtk_eth - This is the main datasructure for holding the state - * of the driver - * @dev: The device pointer -+ * @dev: The device pointer used for dma mapping/alloc - * @base: The mapped register i/o base - * @page_lock: Make sure that register operations are atomic - * @tx_irq__lock: Make sure that IRQ register operations are atomic -@@ -923,6 +930,7 @@ struct mtk_sgmii { - - struct mtk_eth { - struct device *dev; -+ struct device *dma_dev; - void __iomem *base; - spinlock_t page_lock; - spinlock_t tx_irq_lock; -@@ -1021,6 +1029,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk - int mtk_eth_offload_init(struct mtk_eth *eth); - int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, - void *type_data); -+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev); - - - #endif /* MTK_ETH_H */ diff --git a/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch b/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch deleted file mode 100644 index 9f2512a1d05..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-01-arm64-dts-mediatek-mt7622-add-support-for-coherent-D.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: Felix Fietkau -Date: Mon, 7 Feb 2022 10:27:22 +0100 -Subject: [PATCH] arm64: dts: mediatek: mt7622: add support for coherent - DMA - -It improves performance by eliminating the need for a cache flush on rx and tx - -Signed-off-by: Felix Fietkau ---- - ---- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi -+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -357,7 +357,7 @@ - }; - - cci_control2: slave-if@5000 { -- compatible = "arm,cci-400-ctrl-if"; -+ compatible = "arm,cci-400-ctrl-if", "syscon"; - interface-type = "ace"; - reg = <0x5000 0x1000>; - }; -@@ -938,6 +938,8 @@ - power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; - mediatek,ethsys = <ðsys>; - mediatek,sgmiisys = <&sgmiisys>; -+ mediatek,cci-control = <&cci_control2>; -+ dma-coherent; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; diff --git a/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch b/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch deleted file mode 100644 index 2f3a0827fe4..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-02-net-ethernet-mtk_eth_soc-add-support-for-Wireless-Et.patch +++ /dev/null @@ -1,1679 +0,0 @@ -From: Felix Fietkau -Date: Sat, 5 Feb 2022 17:56:08 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for Wireless - Ethernet Dispatch (WED) - -The Wireless Ethernet Dispatch subsystem on the MT7622 SoC can be -configured to intercept and handle access to the DMA queues and -PCIe interrupts for a MT7615/MT7915 wireless card. -It can manage the internal WDMA (Wireless DMA) controller, which allows -ethernet packets to be passed from the packet switch engine (PSE) to the -wireless card, bypassing the CPU entirely. -This can be used to implement hardware flow offloading from ethernet to -WLAN. - -Signed-off-by: Felix Fietkau ---- - create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.c - create mode 100644 drivers/net/ethernet/mediatek/mtk_wed.h - create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_debugfs.c - create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_ops.c - create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_regs.h - create mode 100644 include/linux/soc/mediatek/mtk_wed.h - ---- a/drivers/net/ethernet/mediatek/Kconfig -+++ b/drivers/net/ethernet/mediatek/Kconfig -@@ -7,6 +7,10 @@ config NET_VENDOR_MEDIATEK - - if NET_VENDOR_MEDIATEK - -+config NET_MEDIATEK_SOC_WED -+ depends on ARCH_MEDIATEK || COMPILE_TEST -+ def_bool NET_MEDIATEK_SOC != n -+ - config NET_MEDIATEK_SOC - tristate "MediaTek SoC Gigabit Ethernet support" - depends on NET_DSA || !NET_DSA ---- a/drivers/net/ethernet/mediatek/Makefile -+++ b/drivers/net/ethernet/mediatek/Makefile -@@ -5,4 +5,9 @@ - - obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o - mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o -+mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o -+ifdef CONFIG_DEBUG_FS -+mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o -+endif -+obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o - obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -24,6 +24,7 @@ - #include - - #include "mtk_eth_soc.h" -+#include "mtk_wed.h" - - static int mtk_msg_level = -1; - module_param_named(msg_level, mtk_msg_level, int, 0); -@@ -3209,6 +3210,22 @@ static int mtk_probe(struct platform_dev - } - } - -+ for (i = 0;; i++) { -+ struct device_node *np = of_parse_phandle(pdev->dev.of_node, -+ "mediatek,wed", i); -+ static const u32 wdma_regs[] = { -+ MTK_WDMA0_BASE, -+ MTK_WDMA1_BASE -+ }; -+ void __iomem *wdma; -+ -+ if (!np || i >= ARRAY_SIZE(wdma_regs)) -+ break; -+ -+ wdma = eth->base + wdma_regs[i]; -+ mtk_wed_add_hw(np, eth, wdma, i); -+ } -+ - for (i = 0; i < 3; i++) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_INT) && i > 0) - eth->irq[i] = eth->irq[0]; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -295,6 +295,9 @@ - #define MTK_GDM1_TX_GPCNT 0x2438 - #define MTK_STAT_OFFSET 0x40 - -+#define MTK_WDMA0_BASE 0x2800 -+#define MTK_WDMA1_BASE 0x2c00 -+ - /* QDMA descriptor txd4 */ - #define TX_DMA_CHKSUM (0x7 << 29) - #define TX_DMA_TSO BIT(28) ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -0,0 +1,875 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* Copyright (C) 2021 Felix Fietkau */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include "mtk_eth_soc.h" -+#include "mtk_wed_regs.h" -+#include "mtk_wed.h" -+#include "mtk_ppe.h" -+ -+#define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000) -+ -+#define MTK_WED_PKT_SIZE 1900 -+#define MTK_WED_BUF_SIZE 2048 -+#define MTK_WED_BUF_PER_PAGE (PAGE_SIZE / 2048) -+ -+#define MTK_WED_TX_RING_SIZE 2048 -+#define MTK_WED_WDMA_RING_SIZE 1024 -+ -+static struct mtk_wed_hw *hw_list[2]; -+static DEFINE_MUTEX(hw_lock); -+ -+static void -+wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) -+{ -+ regmap_update_bits(dev->hw->regs, reg, mask | val, val); -+} -+ -+static void -+wed_set(struct mtk_wed_device *dev, u32 reg, u32 mask) -+{ -+ return wed_m32(dev, reg, 0, mask); -+} -+ -+static void -+wed_clr(struct mtk_wed_device *dev, u32 reg, u32 mask) -+{ -+ return wed_m32(dev, reg, mask, 0); -+} -+ -+static void -+wdma_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) -+{ -+ wdma_w32(dev, reg, (wdma_r32(dev, reg) & ~mask) | val); -+} -+ -+static void -+wdma_set(struct mtk_wed_device *dev, u32 reg, u32 mask) -+{ -+ wdma_m32(dev, reg, 0, mask); -+} -+ -+static u32 -+mtk_wed_read_reset(struct mtk_wed_device *dev) -+{ -+ return wed_r32(dev, MTK_WED_RESET); -+} -+ -+static void -+mtk_wed_reset(struct mtk_wed_device *dev, u32 mask) -+{ -+ u32 status; -+ -+ wed_w32(dev, MTK_WED_RESET, mask); -+ if (readx_poll_timeout(mtk_wed_read_reset, dev, status, -+ !(status & mask), 0, 1000)) -+ WARN_ON_ONCE(1); -+} -+ -+static struct mtk_wed_hw * -+mtk_wed_assign(struct mtk_wed_device *dev) -+{ -+ struct mtk_wed_hw *hw; -+ -+ hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; -+ if (!hw || hw->wed_dev) -+ return NULL; -+ -+ hw->wed_dev = dev; -+ return hw; -+} -+ -+static int -+mtk_wed_buffer_alloc(struct mtk_wed_device *dev) -+{ -+ struct mtk_wdma_desc *desc; -+ dma_addr_t desc_phys; -+ void **page_list; -+ int token = dev->wlan.token_start; -+ int ring_size; -+ int n_pages; -+ int i, page_idx; -+ -+ ring_size = dev->wlan.nbuf & ~(MTK_WED_BUF_PER_PAGE - 1); -+ n_pages = ring_size / MTK_WED_BUF_PER_PAGE; -+ -+ page_list = kcalloc(n_pages, sizeof(*page_list), GFP_KERNEL); -+ if (!page_list) -+ return -ENOMEM; -+ -+ dev->buf_ring.size = ring_size; -+ dev->buf_ring.pages = page_list; -+ -+ desc = dma_alloc_coherent(dev->hw->dev, ring_size * sizeof(*desc), -+ &desc_phys, GFP_KERNEL); -+ if (!desc) -+ return -ENOMEM; -+ -+ dev->buf_ring.desc = desc; -+ dev->buf_ring.desc_phys = desc_phys; -+ -+ for (i = 0, page_idx = 0; i < ring_size; i += MTK_WED_BUF_PER_PAGE) { -+ dma_addr_t page_phys, buf_phys; -+ struct page *page; -+ void *buf; -+ int s; -+ -+ page = __dev_alloc_pages(GFP_KERNEL, 0); -+ if (!page) -+ return -ENOMEM; -+ -+ page_phys = dma_map_page(dev->hw->dev, page, 0, PAGE_SIZE, -+ DMA_BIDIRECTIONAL); -+ if (dma_mapping_error(dev->hw->dev, page_phys)) { -+ __free_page(page); -+ return -ENOMEM; -+ } -+ -+ page_list[page_idx++] = page; -+ dma_sync_single_for_cpu(dev->hw->dev, page_phys, PAGE_SIZE, -+ DMA_BIDIRECTIONAL); -+ -+ buf = page_to_virt(page); -+ buf_phys = page_phys; -+ -+ for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) { -+ u32 txd_size; -+ -+ txd_size = dev->wlan.init_buf(buf, buf_phys, token++); -+ -+ desc->buf0 = buf_phys; -+ desc->buf1 = buf_phys + txd_size; -+ desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, -+ txd_size) | -+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, -+ MTK_WED_BUF_SIZE - txd_size) | -+ MTK_WDMA_DESC_CTRL_LAST_SEG1; -+ desc->info = 0; -+ desc++; -+ -+ buf += MTK_WED_BUF_SIZE; -+ buf_phys += MTK_WED_BUF_SIZE; -+ } -+ -+ dma_sync_single_for_device(dev->hw->dev, page_phys, PAGE_SIZE, -+ DMA_BIDIRECTIONAL); -+ } -+ -+ return 0; -+} -+ -+static void -+mtk_wed_free_buffer(struct mtk_wed_device *dev) -+{ -+ struct mtk_wdma_desc *desc = dev->buf_ring.desc; -+ void **page_list = dev->buf_ring.pages; -+ int page_idx; -+ int i; -+ -+ if (!page_list) -+ return; -+ -+ if (!desc) -+ goto free_pagelist; -+ -+ for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) { -+ void *page = page_list[page_idx++]; -+ -+ if (!page) -+ break; -+ -+ dma_unmap_page(dev->hw->dev, desc[i].buf0, -+ PAGE_SIZE, DMA_BIDIRECTIONAL); -+ __free_page(page); -+ } -+ -+ dma_free_coherent(dev->hw->dev, dev->buf_ring.size * sizeof(*desc), -+ desc, dev->buf_ring.desc_phys); -+ -+free_pagelist: -+ kfree(page_list); -+} -+ -+static void -+mtk_wed_free_ring(struct mtk_wed_device *dev, struct mtk_wed_ring *ring) -+{ -+ if (!ring->desc) -+ return; -+ -+ dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc), -+ ring->desc, ring->desc_phys); -+} -+ -+static void -+mtk_wed_free_tx_rings(struct mtk_wed_device *dev) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) -+ mtk_wed_free_ring(dev, &dev->tx_ring[i]); -+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) -+ mtk_wed_free_ring(dev, &dev->tx_wdma[i]); -+} -+ -+static void -+mtk_wed_set_ext_int(struct mtk_wed_device *dev, bool en) -+{ -+ u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; -+ -+ if (!dev->hw->num_flows) -+ mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; -+ -+ wed_w32(dev, MTK_WED_EXT_INT_MASK, en ? mask : 0); -+ wed_r32(dev, MTK_WED_EXT_INT_MASK); -+} -+ -+static void -+mtk_wed_stop(struct mtk_wed_device *dev) -+{ -+ regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); -+ mtk_wed_set_ext_int(dev, false); -+ -+ wed_clr(dev, MTK_WED_CTRL, -+ MTK_WED_CTRL_WDMA_INT_AGENT_EN | -+ MTK_WED_CTRL_WPDMA_INT_AGENT_EN | -+ MTK_WED_CTRL_WED_TX_BM_EN | -+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); -+ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0); -+ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0); -+ wdma_w32(dev, MTK_WDMA_INT_MASK, 0); -+ wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); -+ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); -+ -+ wed_clr(dev, MTK_WED_GLO_CFG, -+ MTK_WED_GLO_CFG_TX_DMA_EN | -+ MTK_WED_GLO_CFG_RX_DMA_EN); -+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); -+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, -+ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); -+} -+ -+static void -+mtk_wed_detach(struct mtk_wed_device *dev) -+{ -+ struct device_node *wlan_node = dev->wlan.pci_dev->dev.of_node; -+ struct mtk_wed_hw *hw = dev->hw; -+ -+ mutex_lock(&hw_lock); -+ -+ mtk_wed_stop(dev); -+ -+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); -+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); -+ -+ mtk_wed_reset(dev, MTK_WED_RESET_WED); -+ -+ mtk_wed_free_buffer(dev); -+ mtk_wed_free_tx_rings(dev); -+ -+ if (of_dma_is_coherent(wlan_node)) -+ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, -+ BIT(hw->index), BIT(hw->index)); -+ -+ if (!hw_list[!hw->index]->wed_dev && -+ hw->eth->dma_dev != hw->eth->dev) -+ mtk_eth_set_dma_device(hw->eth, hw->eth->dev); -+ -+ memset(dev, 0, sizeof(*dev)); -+ module_put(THIS_MODULE); -+ -+ hw->wed_dev = NULL; -+ mutex_unlock(&hw_lock); -+} -+ -+static void -+mtk_wed_hw_init_early(struct mtk_wed_device *dev) -+{ -+ u32 mask, set; -+ u32 offset; -+ -+ mtk_wed_stop(dev); -+ mtk_wed_reset(dev, MTK_WED_RESET_WED); -+ -+ mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE | -+ MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE | -+ MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE; -+ set = FIELD_PREP(MTK_WED_WDMA_GLO_CFG_BT_SIZE, 2) | -+ MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP | -+ MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; -+ wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); -+ -+ wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES); -+ -+ offset = dev->hw->index ? 0x04000400 : 0; -+ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); -+ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); -+ -+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index)); -+ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); -+} -+ -+static void -+mtk_wed_hw_init(struct mtk_wed_device *dev) -+{ -+ if (dev->init_done) -+ return; -+ -+ dev->init_done = true; -+ mtk_wed_set_ext_int(dev, false); -+ wed_w32(dev, MTK_WED_TX_BM_CTRL, -+ MTK_WED_TX_BM_CTRL_PAUSE | -+ FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, -+ dev->buf_ring.size / 128) | -+ FIELD_PREP(MTK_WED_TX_BM_CTRL_RSV_GRP_NUM, -+ MTK_WED_TX_RING_SIZE / 256)); -+ -+ wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); -+ -+ wed_w32(dev, MTK_WED_TX_BM_TKID, -+ FIELD_PREP(MTK_WED_TX_BM_TKID_START, -+ dev->wlan.token_start) | -+ FIELD_PREP(MTK_WED_TX_BM_TKID_END, -+ dev->wlan.token_start + dev->wlan.nbuf - 1)); -+ -+ wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); -+ -+ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, -+ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | -+ MTK_WED_TX_BM_DYN_THR_HI); -+ -+ mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); -+ -+ wed_set(dev, MTK_WED_CTRL, -+ MTK_WED_CTRL_WED_TX_BM_EN | -+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); -+ -+ wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); -+} -+ -+static void -+mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size) -+{ -+ int i; -+ -+ for (i = 0; i < size; i++) { -+ desc[i].buf0 = 0; -+ desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); -+ desc[i].buf1 = 0; -+ desc[i].info = 0; -+ } -+} -+ -+static u32 -+mtk_wed_check_busy(struct mtk_wed_device *dev) -+{ -+ if (wed_r32(dev, MTK_WED_GLO_CFG) & MTK_WED_GLO_CFG_TX_DMA_BUSY) -+ return true; -+ -+ if (wed_r32(dev, MTK_WED_WPDMA_GLO_CFG) & -+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY) -+ return true; -+ -+ if (wed_r32(dev, MTK_WED_CTRL) & MTK_WED_CTRL_WDMA_INT_AGENT_BUSY) -+ return true; -+ -+ if (wed_r32(dev, MTK_WED_WDMA_GLO_CFG) & -+ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) -+ return true; -+ -+ if (wdma_r32(dev, MTK_WDMA_GLO_CFG) & -+ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY) -+ return true; -+ -+ if (wed_r32(dev, MTK_WED_CTRL) & -+ (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY)) -+ return true; -+ -+ return false; -+} -+ -+static int -+mtk_wed_poll_busy(struct mtk_wed_device *dev) -+{ -+ int sleep = 15000; -+ int timeout = 100 * sleep; -+ u32 val; -+ -+ return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep, -+ timeout, false, dev); -+} -+ -+static void -+mtk_wed_reset_dma(struct mtk_wed_device *dev) -+{ -+ bool busy = false; -+ u32 val; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) { -+ struct mtk_wdma_desc *desc = dev->tx_ring[i].desc; -+ -+ if (!desc) -+ continue; -+ -+ mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE); -+ } -+ -+ if (mtk_wed_poll_busy(dev)) -+ busy = mtk_wed_check_busy(dev); -+ -+ if (busy) { -+ mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA); -+ } else { -+ wed_w32(dev, MTK_WED_RESET_IDX, -+ MTK_WED_RESET_IDX_TX | -+ MTK_WED_RESET_IDX_RX); -+ wed_w32(dev, MTK_WED_RESET_IDX, 0); -+ } -+ -+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); -+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); -+ -+ if (busy) { -+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); -+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV); -+ } else { -+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX, -+ MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV); -+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0); -+ -+ wed_set(dev, MTK_WED_WDMA_GLO_CFG, -+ MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); -+ -+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, -+ MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); -+ } -+ -+ for (i = 0; i < 100; i++) { -+ val = wed_r32(dev, MTK_WED_TX_BM_INTF); -+ if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40) -+ break; -+ } -+ -+ mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT); -+ mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); -+ -+ if (busy) { -+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT); -+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV); -+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV); -+ } else { -+ wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, -+ MTK_WED_WPDMA_RESET_IDX_TX | -+ MTK_WED_WPDMA_RESET_IDX_RX); -+ wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); -+ } -+ -+} -+ -+static int -+mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, -+ int size) -+{ -+ ring->desc = dma_alloc_coherent(dev->hw->dev, -+ size * sizeof(*ring->desc), -+ &ring->desc_phys, GFP_KERNEL); -+ if (!ring->desc) -+ return -ENOMEM; -+ -+ ring->size = size; -+ mtk_wed_ring_reset(ring->desc, size); -+ -+ return 0; -+} -+ -+static int -+mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) -+{ -+ struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; -+ -+ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE)) -+ return -ENOMEM; -+ -+ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, -+ wdma->desc_phys); -+ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT, -+ size); -+ wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); -+ -+ wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, -+ wdma->desc_phys); -+ wed_w32(dev, MTK_WED_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_COUNT, -+ size); -+ -+ return 0; -+} -+ -+static void -+mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) -+{ -+ u32 wdma_mask; -+ u32 val; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) -+ if (!dev->tx_wdma[i].desc) -+ mtk_wed_wdma_ring_setup(dev, i, 16); -+ -+ wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); -+ -+ mtk_wed_hw_init(dev); -+ -+ wed_set(dev, MTK_WED_CTRL, -+ MTK_WED_CTRL_WDMA_INT_AGENT_EN | -+ MTK_WED_CTRL_WPDMA_INT_AGENT_EN | -+ MTK_WED_CTRL_WED_TX_BM_EN | -+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); -+ -+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS); -+ -+ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, -+ MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | -+ MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); -+ -+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, -+ MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); -+ -+ wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); -+ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); -+ -+ wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); -+ wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); -+ -+ wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask); -+ wed_w32(dev, MTK_WED_INT_MASK, irq_mask); -+ -+ wed_set(dev, MTK_WED_GLO_CFG, -+ MTK_WED_GLO_CFG_TX_DMA_EN | -+ MTK_WED_GLO_CFG_RX_DMA_EN); -+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); -+ wed_set(dev, MTK_WED_WDMA_GLO_CFG, -+ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); -+ -+ mtk_wed_set_ext_int(dev, true); -+ val = dev->wlan.wpdma_phys | -+ MTK_PCIE_MIRROR_MAP_EN | -+ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index); -+ -+ if (dev->hw->index) -+ val |= BIT(1); -+ val |= BIT(0); -+ regmap_write(dev->hw->mirror, dev->hw->index * 4, val); -+ -+ dev->running = true; -+} -+ -+static int -+mtk_wed_attach(struct mtk_wed_device *dev) -+ __releases(RCU) -+{ -+ struct mtk_wed_hw *hw; -+ int ret = 0; -+ -+ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), -+ "mtk_wed_attach without holding the RCU read lock"); -+ -+ if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 || -+ !try_module_get(THIS_MODULE)) -+ ret = -ENODEV; -+ -+ rcu_read_unlock(); -+ -+ if (ret) -+ return ret; -+ -+ mutex_lock(&hw_lock); -+ -+ hw = mtk_wed_assign(dev); -+ if (!hw) { -+ module_put(THIS_MODULE); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index); -+ -+ dev->hw = hw; -+ dev->dev = hw->dev; -+ dev->irq = hw->irq; -+ dev->wdma_idx = hw->index; -+ -+ if (hw->eth->dma_dev == hw->eth->dev && -+ of_dma_is_coherent(hw->eth->dev->of_node)) -+ mtk_eth_set_dma_device(hw->eth, hw->dev); -+ -+ ret = mtk_wed_buffer_alloc(dev); -+ if (ret) { -+ mtk_wed_detach(dev); -+ goto out; -+ } -+ -+ mtk_wed_hw_init_early(dev); -+ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0); -+ -+out: -+ mutex_unlock(&hw_lock); -+ -+ return ret; -+} -+ -+static int -+mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs) -+{ -+ struct mtk_wed_ring *ring = &dev->tx_ring[idx]; -+ -+ /* -+ * Tx ring redirection: -+ * Instead of configuring the WLAN PDMA TX ring directly, the WLAN -+ * driver allocated DMA ring gets configured into WED MTK_WED_RING_TX(n) -+ * registers. -+ * -+ * WED driver posts its own DMA ring as WLAN PDMA TX and configures it -+ * into MTK_WED_WPDMA_RING_TX(n) registers. -+ * It gets filled with packets picked up from WED TX ring and from -+ * WDMA RX. -+ */ -+ -+ BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); -+ -+ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) -+ return -ENOMEM; -+ -+ if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) -+ return -ENOMEM; -+ -+ ring->reg_base = MTK_WED_RING_TX(idx); -+ ring->wpdma = regs; -+ -+ /* WED -> WPDMA */ -+ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_BASE, ring->desc_phys); -+ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_COUNT, MTK_WED_TX_RING_SIZE); -+ wpdma_tx_w32(dev, idx, MTK_WED_RING_OFS_CPU_IDX, 0); -+ -+ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE, -+ ring->desc_phys); -+ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_COUNT, -+ MTK_WED_TX_RING_SIZE); -+ wed_w32(dev, MTK_WED_WPDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); -+ -+ return 0; -+} -+ -+static int -+mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs) -+{ -+ struct mtk_wed_ring *ring = &dev->txfree_ring; -+ int i; -+ -+ /* -+ * For txfree event handling, the same DMA ring is shared between WED -+ * and WLAN. The WLAN driver accesses the ring index registers through -+ * WED -+ */ -+ ring->reg_base = MTK_WED_RING_RX(1); -+ ring->wpdma = regs; -+ -+ for (i = 0; i < 12; i += 4) { -+ u32 val = readl(regs + i); -+ -+ wed_w32(dev, MTK_WED_RING_RX(1) + i, val); -+ wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val); -+ } -+ -+ return 0; -+} -+ -+static u32 -+mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) -+{ -+ u32 val; -+ -+ val = wed_r32(dev, MTK_WED_EXT_INT_STATUS); -+ wed_w32(dev, MTK_WED_EXT_INT_STATUS, val); -+ val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK; -+ if (!dev->hw->num_flows) -+ val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; -+ if (val && net_ratelimit()) -+ pr_err("mtk_wed%d: error status=%08x\n", dev->hw->index, val); -+ -+ val = wed_r32(dev, MTK_WED_INT_STATUS); -+ val &= mask; -+ wed_w32(dev, MTK_WED_INT_STATUS, val); /* ACK */ -+ -+ return val; -+} -+ -+static void -+mtk_wed_irq_set_mask(struct mtk_wed_device *dev, u32 mask) -+{ -+ if (!dev->running) -+ return; -+ -+ mtk_wed_set_ext_int(dev, !!mask); -+ wed_w32(dev, MTK_WED_INT_MASK, mask); -+} -+ -+int mtk_wed_flow_add(int index) -+{ -+ struct mtk_wed_hw *hw = hw_list[index]; -+ int ret; -+ -+ if (!hw || !hw->wed_dev) -+ return -ENODEV; -+ -+ if (hw->num_flows) { -+ hw->num_flows++; -+ return 0; -+ } -+ -+ mutex_lock(&hw_lock); -+ if (!hw->wed_dev) { -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ ret = hw->wed_dev->wlan.offload_enable(hw->wed_dev); -+ if (!ret) -+ hw->num_flows++; -+ mtk_wed_set_ext_int(hw->wed_dev, true); -+ -+out: -+ mutex_unlock(&hw_lock); -+ -+ return ret; -+} -+ -+void mtk_wed_flow_remove(int index) -+{ -+ struct mtk_wed_hw *hw = hw_list[index]; -+ -+ if (!hw) -+ return; -+ -+ if (--hw->num_flows) -+ return; -+ -+ mutex_lock(&hw_lock); -+ if (!hw->wed_dev) -+ goto out; -+ -+ hw->wed_dev->wlan.offload_disable(hw->wed_dev); -+ mtk_wed_set_ext_int(hw->wed_dev, true); -+ -+out: -+ mutex_unlock(&hw_lock); -+} -+ -+void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -+ void __iomem *wdma, int index) -+{ -+ static const struct mtk_wed_ops wed_ops = { -+ .attach = mtk_wed_attach, -+ .tx_ring_setup = mtk_wed_tx_ring_setup, -+ .txfree_ring_setup = mtk_wed_txfree_ring_setup, -+ .start = mtk_wed_start, -+ .stop = mtk_wed_stop, -+ .reset_dma = mtk_wed_reset_dma, -+ .reg_read = wed_r32, -+ .reg_write = wed_w32, -+ .irq_get = mtk_wed_irq_get, -+ .irq_set_mask = mtk_wed_irq_set_mask, -+ .detach = mtk_wed_detach, -+ }; -+ struct device_node *eth_np = eth->dev->of_node; -+ struct platform_device *pdev; -+ struct mtk_wed_hw *hw; -+ struct regmap *regs; -+ int irq; -+ -+ if (!np) -+ return; -+ -+ pdev = of_find_device_by_node(np); -+ if (!pdev) -+ return; -+ -+ get_device(&pdev->dev); -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return; -+ -+ regs = syscon_regmap_lookup_by_phandle(np, NULL); -+ if (!regs) -+ return; -+ -+ rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); -+ -+ mutex_lock(&hw_lock); -+ -+ if (WARN_ON(hw_list[index])) -+ goto unlock; -+ -+ hw = kzalloc(sizeof(*hw), GFP_KERNEL); -+ hw->node = np; -+ hw->regs = regs; -+ hw->eth = eth; -+ hw->dev = &pdev->dev; -+ hw->wdma = wdma; -+ hw->index = index; -+ hw->irq = irq; -+ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, -+ "mediatek,pcie-mirror"); -+ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, -+ "mediatek,hifsys"); -+ if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { -+ kfree(hw); -+ goto unlock; -+ } -+ -+ if (!index) { -+ regmap_write(hw->mirror, 0, 0); -+ regmap_write(hw->mirror, 4, 0); -+ } -+ mtk_wed_hw_add_debugfs(hw); -+ -+ hw_list[index] = hw; -+ -+unlock: -+ mutex_unlock(&hw_lock); -+} -+ -+void mtk_wed_exit(void) -+{ -+ int i; -+ -+ rcu_assign_pointer(mtk_soc_wed_ops, NULL); -+ -+ synchronize_rcu(); -+ -+ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { -+ struct mtk_wed_hw *hw; -+ -+ hw = hw_list[i]; -+ if (!hw) -+ continue; -+ -+ hw_list[i] = NULL; -+ debugfs_remove(hw->debugfs_dir); -+ put_device(hw->dev); -+ kfree(hw); -+ } -+} ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_wed.h -@@ -0,0 +1,128 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* Copyright (C) 2021 Felix Fietkau */ -+ -+#ifndef __MTK_WED_PRIV_H -+#define __MTK_WED_PRIV_H -+ -+#include -+#include -+#include -+ -+struct mtk_eth; -+ -+struct mtk_wed_hw { -+ struct device_node *node; -+ struct mtk_eth *eth; -+ struct regmap *regs; -+ struct regmap *hifsys; -+ struct device *dev; -+ void __iomem *wdma; -+ struct regmap *mirror; -+ struct dentry *debugfs_dir; -+ struct mtk_wed_device *wed_dev; -+ u32 debugfs_reg; -+ u32 num_flows; -+ char dirname[5]; -+ int irq; -+ int index; -+}; -+ -+ -+#ifdef CONFIG_NET_MEDIATEK_SOC_WED -+static inline void -+wed_w32(struct mtk_wed_device *dev, u32 reg, u32 val) -+{ -+ regmap_write(dev->hw->regs, reg, val); -+} -+ -+static inline u32 -+wed_r32(struct mtk_wed_device *dev, u32 reg) -+{ -+ unsigned int val; -+ -+ regmap_read(dev->hw->regs, reg, &val); -+ -+ return val; -+} -+ -+static inline void -+wdma_w32(struct mtk_wed_device *dev, u32 reg, u32 val) -+{ -+ writel(val, dev->hw->wdma + reg); -+} -+ -+static inline u32 -+wdma_r32(struct mtk_wed_device *dev, u32 reg) -+{ -+ return readl(dev->hw->wdma + reg); -+} -+ -+static inline u32 -+wpdma_tx_r32(struct mtk_wed_device *dev, int ring, u32 reg) -+{ -+ if (!dev->tx_ring[ring].wpdma) -+ return 0; -+ -+ return readl(dev->tx_ring[ring].wpdma + reg); -+} -+ -+static inline void -+wpdma_tx_w32(struct mtk_wed_device *dev, int ring, u32 reg, u32 val) -+{ -+ if (!dev->tx_ring[ring].wpdma) -+ return; -+ -+ writel(val, dev->tx_ring[ring].wpdma + reg); -+} -+ -+static inline u32 -+wpdma_txfree_r32(struct mtk_wed_device *dev, u32 reg) -+{ -+ if (!dev->txfree_ring.wpdma) -+ return 0; -+ -+ return readl(dev->txfree_ring.wpdma + reg); -+} -+ -+static inline void -+wpdma_txfree_w32(struct mtk_wed_device *dev, u32 reg, u32 val) -+{ -+ if (!dev->txfree_ring.wpdma) -+ return; -+ -+ writel(val, dev->txfree_ring.wpdma + reg); -+} -+ -+void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -+ void __iomem *wdma, int index); -+void mtk_wed_exit(void); -+int mtk_wed_flow_add(int index); -+void mtk_wed_flow_remove(int index); -+#else -+static inline void -+mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -+ void __iomem *wdma, int index) -+{ -+} -+static inline void -+mtk_wed_exit(void) -+{ -+} -+static inline int mtk_wed_flow_add(int index) -+{ -+ return -EINVAL; -+} -+static inline void mtk_wed_flow_remove(int index) -+{ -+} -+#endif -+ -+#ifdef CONFIG_DEBUG_FS -+void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw); -+#else -+static inline void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw) -+{ -+} -+#endif -+ -+#endif ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c -@@ -0,0 +1,175 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* Copyright (C) 2021 Felix Fietkau */ -+ -+#include -+#include "mtk_wed.h" -+#include "mtk_wed_regs.h" -+ -+struct reg_dump { -+ const char *name; -+ u16 offset; -+ u8 type; -+ u8 base; -+}; -+ -+enum { -+ DUMP_TYPE_STRING, -+ DUMP_TYPE_WED, -+ DUMP_TYPE_WDMA, -+ DUMP_TYPE_WPDMA_TX, -+ DUMP_TYPE_WPDMA_TXFREE, -+}; -+ -+#define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING } -+#define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ } -+#define DUMP_RING(_prefix, _base, ...) \ -+ { _prefix " BASE", _base, __VA_ARGS__ }, \ -+ { _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \ -+ { _prefix " CIDX", _base + 0x8, __VA_ARGS__ }, \ -+ { _prefix " DIDX", _base + 0xc, __VA_ARGS__ } -+ -+#define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED) -+#define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED) -+ -+#define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA) -+#define DUMP_WDMA_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WDMA) -+ -+#define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n) -+#define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE) -+ -+static void -+print_reg_val(struct seq_file *s, const char *name, u32 val) -+{ -+ seq_printf(s, "%-32s %08x\n", name, val); -+} -+ -+static void -+dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev, -+ const struct reg_dump *regs, int n_regs) -+{ -+ const struct reg_dump *cur; -+ u32 val; -+ -+ for (cur = regs; cur < ®s[n_regs]; cur++) { -+ switch (cur->type) { -+ case DUMP_TYPE_STRING: -+ seq_printf(s, "%s======== %s:\n", -+ cur > regs ? "\n" : "", -+ cur->name); -+ continue; -+ case DUMP_TYPE_WED: -+ val = wed_r32(dev, cur->offset); -+ break; -+ case DUMP_TYPE_WDMA: -+ val = wdma_r32(dev, cur->offset); -+ break; -+ case DUMP_TYPE_WPDMA_TX: -+ val = wpdma_tx_r32(dev, cur->base, cur->offset); -+ break; -+ case DUMP_TYPE_WPDMA_TXFREE: -+ val = wpdma_txfree_r32(dev, cur->offset); -+ break; -+ } -+ print_reg_val(s, cur->name, val); -+ } -+} -+ -+ -+static int -+wed_txinfo_show(struct seq_file *s, void *data) -+{ -+ static const struct reg_dump regs[] = { -+ DUMP_STR("WED TX"), -+ DUMP_WED(WED_TX_MIB(0)), -+ DUMP_WED_RING(WED_RING_TX(0)), -+ -+ DUMP_WED(WED_TX_MIB(1)), -+ DUMP_WED_RING(WED_RING_TX(1)), -+ -+ DUMP_STR("WPDMA TX"), -+ DUMP_WED(WED_WPDMA_TX_MIB(0)), -+ DUMP_WED_RING(WED_WPDMA_RING_TX(0)), -+ DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(0)), -+ -+ DUMP_WED(WED_WPDMA_TX_MIB(1)), -+ DUMP_WED_RING(WED_WPDMA_RING_TX(1)), -+ DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(1)), -+ -+ DUMP_STR("WPDMA TX"), -+ DUMP_WPDMA_TX_RING(0), -+ DUMP_WPDMA_TX_RING(1), -+ -+ DUMP_STR("WED WDMA RX"), -+ DUMP_WED(WED_WDMA_RX_MIB(0)), -+ DUMP_WED_RING(WED_WDMA_RING_RX(0)), -+ DUMP_WED(WED_WDMA_RX_THRES(0)), -+ DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(0)), -+ DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(0)), -+ -+ DUMP_WED(WED_WDMA_RX_MIB(1)), -+ DUMP_WED_RING(WED_WDMA_RING_RX(1)), -+ DUMP_WED(WED_WDMA_RX_THRES(1)), -+ DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(1)), -+ DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(1)), -+ -+ DUMP_STR("WDMA RX"), -+ DUMP_WDMA(WDMA_GLO_CFG), -+ DUMP_WDMA_RING(WDMA_RING_RX(0)), -+ DUMP_WDMA_RING(WDMA_RING_RX(1)), -+ }; -+ struct mtk_wed_hw *hw = s->private; -+ struct mtk_wed_device *dev = hw->wed_dev; -+ -+ if (!dev) -+ return 0; -+ -+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs)); -+ -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(wed_txinfo); -+ -+ -+static int -+mtk_wed_reg_set(void *data, u64 val) -+{ -+ struct mtk_wed_hw *hw = data; -+ -+ regmap_write(hw->regs, hw->debugfs_reg, val); -+ -+ return 0; -+} -+ -+static int -+mtk_wed_reg_get(void *data, u64 *val) -+{ -+ struct mtk_wed_hw *hw = data; -+ unsigned int regval; -+ int ret; -+ -+ ret = regmap_read(hw->regs, hw->debugfs_reg, ®val); -+ if (ret) -+ return ret; -+ -+ *val = regval; -+ -+ return 0; -+} -+ -+DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set, -+ "0x%08llx\n"); -+ -+void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw) -+{ -+ struct dentry *dir; -+ -+ snprintf(hw->dirname, sizeof(hw->dirname), "wed%d", hw->index); -+ dir = debugfs_create_dir(hw->dirname, NULL); -+ if (!dir) -+ return; -+ -+ hw->debugfs_dir = dir; -+ debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg); -+ debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval); -+ debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops); -+} ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_wed_ops.c -@@ -0,0 +1,8 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* Copyright (C) 2020 Felix Fietkau */ -+ -+#include -+#include -+ -+const struct mtk_wed_ops __rcu *mtk_soc_wed_ops; -+EXPORT_SYMBOL_GPL(mtk_soc_wed_ops); ---- /dev/null -+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h -@@ -0,0 +1,251 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* Copyright (C) 2020 Felix Fietkau */ -+ -+#ifndef __MTK_WED_REGS_H -+#define __MTK_WED_REGS_H -+ -+#define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0) -+#define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15) -+#define MTK_WDMA_DESC_CTRL_BURST BIT(16) -+#define MTK_WDMA_DESC_CTRL_LEN0 GENMASK(29, 16) -+#define MTK_WDMA_DESC_CTRL_LAST_SEG0 BIT(30) -+#define MTK_WDMA_DESC_CTRL_DMA_DONE BIT(31) -+ -+struct mtk_wdma_desc { -+ __le32 buf0; -+ __le32 ctrl; -+ __le32 buf1; -+ __le32 info; -+} __packed __aligned(4); -+ -+#define MTK_WED_RESET 0x008 -+#define MTK_WED_RESET_TX_BM BIT(0) -+#define MTK_WED_RESET_TX_FREE_AGENT BIT(4) -+#define MTK_WED_RESET_WPDMA_TX_DRV BIT(8) -+#define MTK_WED_RESET_WPDMA_RX_DRV BIT(9) -+#define MTK_WED_RESET_WPDMA_INT_AGENT BIT(11) -+#define MTK_WED_RESET_WED_TX_DMA BIT(12) -+#define MTK_WED_RESET_WDMA_RX_DRV BIT(17) -+#define MTK_WED_RESET_WDMA_INT_AGENT BIT(19) -+#define MTK_WED_RESET_WED BIT(31) -+ -+#define MTK_WED_CTRL 0x00c -+#define MTK_WED_CTRL_WPDMA_INT_AGENT_EN BIT(0) -+#define MTK_WED_CTRL_WPDMA_INT_AGENT_BUSY BIT(1) -+#define MTK_WED_CTRL_WDMA_INT_AGENT_EN BIT(2) -+#define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3) -+#define MTK_WED_CTRL_WED_TX_BM_EN BIT(8) -+#define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9) -+#define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10) -+#define MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY BIT(11) -+#define MTK_WED_CTRL_RESERVE_EN BIT(12) -+#define MTK_WED_CTRL_RESERVE_BUSY BIT(13) -+#define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24) -+#define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28) -+ -+#define MTK_WED_EXT_INT_STATUS 0x020 -+#define MTK_WED_EXT_INT_STATUS_TF_LEN_ERR BIT(0) -+#define MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD BIT(1) -+#define MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID BIT(4) -+#define MTK_WED_EXT_INT_STATUS_TX_FBUF_LO_TH BIT(8) -+#define MTK_WED_EXT_INT_STATUS_TX_FBUF_HI_TH BIT(9) -+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH BIT(12) -+#define MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH BIT(13) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR BIT(16) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR BIT(17) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT BIT(18) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20) -+#define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21) -+#define MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR BIT(22) -+#define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24) -+#define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ -+ MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ -+ MTK_WED_EXT_INT_STATUS_TKID_TITO_INVALID | \ -+ MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \ -+ MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \ -+ MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \ -+ MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR | \ -+ MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR) -+ -+#define MTK_WED_EXT_INT_MASK 0x028 -+ -+#define MTK_WED_STATUS 0x060 -+#define MTK_WED_STATUS_TX GENMASK(15, 8) -+ -+#define MTK_WED_TX_BM_CTRL 0x080 -+#define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0) -+#define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16) -+#define MTK_WED_TX_BM_CTRL_PAUSE BIT(28) -+ -+#define MTK_WED_TX_BM_BASE 0x084 -+ -+#define MTK_WED_TX_BM_TKID 0x088 -+#define MTK_WED_TX_BM_TKID_START GENMASK(15, 0) -+#define MTK_WED_TX_BM_TKID_END GENMASK(31, 16) -+ -+#define MTK_WED_TX_BM_BUF_LEN 0x08c -+ -+#define MTK_WED_TX_BM_INTF 0x09c -+#define MTK_WED_TX_BM_INTF_TKID GENMASK(15, 0) -+#define MTK_WED_TX_BM_INTF_TKFIFO_FDEP GENMASK(23, 16) -+#define MTK_WED_TX_BM_INTF_TKID_VALID BIT(28) -+#define MTK_WED_TX_BM_INTF_TKID_READ BIT(29) -+ -+#define MTK_WED_TX_BM_DYN_THR 0x0a0 -+#define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0) -+#define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16) -+ -+#define MTK_WED_INT_STATUS 0x200 -+#define MTK_WED_INT_MASK 0x204 -+ -+#define MTK_WED_GLO_CFG 0x208 -+#define MTK_WED_GLO_CFG_TX_DMA_EN BIT(0) -+#define MTK_WED_GLO_CFG_TX_DMA_BUSY BIT(1) -+#define MTK_WED_GLO_CFG_RX_DMA_EN BIT(2) -+#define MTK_WED_GLO_CFG_RX_DMA_BUSY BIT(3) -+#define MTK_WED_GLO_CFG_RX_BT_SIZE GENMASK(5, 4) -+#define MTK_WED_GLO_CFG_TX_WB_DDONE BIT(6) -+#define MTK_WED_GLO_CFG_BIG_ENDIAN BIT(7) -+#define MTK_WED_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8) -+#define MTK_WED_GLO_CFG_TX_BT_SIZE_LO BIT(9) -+#define MTK_WED_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10) -+#define MTK_WED_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) -+#define MTK_WED_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13) -+#define MTK_WED_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22) -+#define MTK_WED_GLO_CFG_SW_RESET BIT(24) -+#define MTK_WED_GLO_CFG_FIRST_TOKEN_ONLY BIT(26) -+#define MTK_WED_GLO_CFG_OMIT_RX_INFO BIT(27) -+#define MTK_WED_GLO_CFG_OMIT_TX_INFO BIT(28) -+#define MTK_WED_GLO_CFG_BYTE_SWAP BIT(29) -+#define MTK_WED_GLO_CFG_RX_2B_OFFSET BIT(31) -+ -+#define MTK_WED_RESET_IDX 0x20c -+#define MTK_WED_RESET_IDX_TX GENMASK(3, 0) -+#define MTK_WED_RESET_IDX_RX GENMASK(17, 16) -+ -+#define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4) -+ -+#define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10) -+ -+#define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10) -+ -+#define MTK_WED_WPDMA_INT_TRIGGER 0x504 -+#define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1) -+#define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4) -+ -+#define MTK_WED_WPDMA_GLO_CFG 0x508 -+#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN BIT(0) -+#define MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY BIT(1) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN BIT(2) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY BIT(3) -+#define MTK_WED_WPDMA_GLO_CFG_RX_BT_SIZE GENMASK(5, 4) -+#define MTK_WED_WPDMA_GLO_CFG_TX_WB_DDONE BIT(6) -+#define MTK_WED_WPDMA_GLO_CFG_BIG_ENDIAN BIT(7) -+#define MTK_WED_WPDMA_GLO_CFG_DIS_BT_SIZE_ALIGN BIT(8) -+#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_LO BIT(9) -+#define MTK_WED_WPDMA_GLO_CFG_MULTI_DMA_EN GENMASK(11, 10) -+#define MTK_WED_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12) -+#define MTK_WED_WPDMA_GLO_CFG_MI_DEPTH_RD GENMASK(21, 13) -+#define MTK_WED_WPDMA_GLO_CFG_TX_BT_SIZE_HI GENMASK(23, 22) -+#define MTK_WED_WPDMA_GLO_CFG_SW_RESET BIT(24) -+#define MTK_WED_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY BIT(26) -+#define MTK_WED_WPDMA_GLO_CFG_OMIT_RX_INFO BIT(27) -+#define MTK_WED_WPDMA_GLO_CFG_OMIT_TX_INFO BIT(28) -+#define MTK_WED_WPDMA_GLO_CFG_BYTE_SWAP BIT(29) -+#define MTK_WED_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) -+ -+#define MTK_WED_WPDMA_RESET_IDX 0x50c -+#define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0) -+#define MTK_WED_WPDMA_RESET_IDX_RX GENMASK(17, 16) -+ -+#define MTK_WED_WPDMA_INT_CTRL 0x520 -+#define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) -+ -+#define MTK_WED_WPDMA_INT_MASK 0x524 -+ -+#define MTK_WED_PCIE_CFG_BASE 0x560 -+ -+#define MTK_WED_PCIE_INT_TRIGGER 0x570 -+#define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16) -+ -+#define MTK_WED_WPDMA_CFG_BASE 0x580 -+ -+#define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4) -+#define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4) -+ -+#define MTK_WED_WPDMA_RING_TX(_n) (0x600 + (_n) * 0x10) -+#define MTK_WED_WPDMA_RING_RX(_n) (0x700 + (_n) * 0x10) -+#define MTK_WED_WDMA_RING_RX(_n) (0x900 + (_n) * 0x10) -+#define MTK_WED_WDMA_RX_THRES(_n) (0x940 + (_n) * 0x4) -+ -+#define MTK_WED_WDMA_GLO_CFG 0xa04 -+#define MTK_WED_WDMA_GLO_CFG_TX_DRV_EN BIT(0) -+#define MTK_WED_WDMA_GLO_CFG_RX_DRV_EN BIT(2) -+#define MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY BIT(3) -+#define MTK_WED_WDMA_GLO_CFG_BT_SIZE GENMASK(5, 4) -+#define MTK_WED_WDMA_GLO_CFG_TX_WB_DDONE BIT(6) -+#define MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE BIT(13) -+#define MTK_WED_WDMA_GLO_CFG_WCOMPLETE_SEL BIT(16) -+#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_RXDMA_BYPASS BIT(17) -+#define MTK_WED_WDMA_GLO_CFG_INIT_PHASE_BYPASS BIT(18) -+#define MTK_WED_WDMA_GLO_CFG_FSM_RETURN_IDLE BIT(19) -+#define MTK_WED_WDMA_GLO_CFG_WAIT_COHERENT BIT(20) -+#define MTK_WED_WDMA_GLO_CFG_AXI_W_AFTER_AW BIT(21) -+#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY_SINGLE_W BIT(22) -+#define MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY BIT(23) -+#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_SKIP_DMAD_PREP BIT(24) -+#define MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE BIT(25) -+#define MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE BIT(26) -+#define MTK_WED_WDMA_GLO_CFG_RXDRV_CLKGATE_BYPASS BIT(30) -+ -+#define MTK_WED_WDMA_RESET_IDX 0xa08 -+#define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16) -+#define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24) -+ -+#define MTK_WED_WDMA_INT_TRIGGER 0xa28 -+#define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16) -+ -+#define MTK_WED_WDMA_INT_CTRL 0xa2c -+#define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16) -+ -+#define MTK_WED_WDMA_OFFSET0 0xaa4 -+#define MTK_WED_WDMA_OFFSET1 0xaa8 -+ -+#define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4) -+#define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4) -+#define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4) -+ -+#define MTK_WED_RING_OFS_BASE 0x00 -+#define MTK_WED_RING_OFS_COUNT 0x04 -+#define MTK_WED_RING_OFS_CPU_IDX 0x08 -+#define MTK_WED_RING_OFS_DMA_IDX 0x0c -+ -+#define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) -+ -+#define MTK_WDMA_GLO_CFG 0x204 -+#define MTK_WDMA_GLO_CFG_RX_INFO_PRERES GENMASK(28, 26) -+ -+#define MTK_WDMA_RESET_IDX 0x208 -+#define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) -+#define MTK_WDMA_RESET_IDX_RX GENMASK(17, 16) -+ -+#define MTK_WDMA_INT_MASK 0x228 -+#define MTK_WDMA_INT_MASK_TX_DONE GENMASK(3, 0) -+#define MTK_WDMA_INT_MASK_RX_DONE GENMASK(17, 16) -+#define MTK_WDMA_INT_MASK_TX_DELAY BIT(28) -+#define MTK_WDMA_INT_MASK_TX_COHERENT BIT(29) -+#define MTK_WDMA_INT_MASK_RX_DELAY BIT(30) -+#define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31) -+ -+#define MTK_WDMA_INT_GRP1 0x250 -+#define MTK_WDMA_INT_GRP2 0x254 -+ -+#define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0) -+#define MTK_PCIE_MIRROR_MAP_EN BIT(0) -+#define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1) -+ -+/* DMA channel mapping */ -+#define HIFSYS_DMA_AG_MAP 0x008 -+ -+#endif ---- /dev/null -+++ b/include/linux/soc/mediatek/mtk_wed.h -@@ -0,0 +1,131 @@ -+#ifndef __MTK_WED_H -+#define __MTK_WED_H -+ -+#include -+#include -+#include -+#include -+ -+#define MTK_WED_TX_QUEUES 2 -+ -+struct mtk_wed_hw; -+struct mtk_wdma_desc; -+ -+struct mtk_wed_ring { -+ struct mtk_wdma_desc *desc; -+ dma_addr_t desc_phys; -+ int size; -+ -+ u32 reg_base; -+ void __iomem *wpdma; -+}; -+ -+struct mtk_wed_device { -+#ifdef CONFIG_NET_MEDIATEK_SOC_WED -+ const struct mtk_wed_ops *ops; -+ struct device *dev; -+ struct mtk_wed_hw *hw; -+ bool init_done, running; -+ int wdma_idx; -+ int irq; -+ -+ struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES]; -+ struct mtk_wed_ring txfree_ring; -+ struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES]; -+ -+ struct { -+ int size; -+ void **pages; -+ struct mtk_wdma_desc *desc; -+ dma_addr_t desc_phys; -+ } buf_ring; -+ -+ /* filled by driver: */ -+ struct { -+ struct pci_dev *pci_dev; -+ -+ u32 wpdma_phys; -+ -+ u16 token_start; -+ unsigned int nbuf; -+ -+ u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); -+ int (*offload_enable)(struct mtk_wed_device *wed); -+ void (*offload_disable)(struct mtk_wed_device *wed); -+ } wlan; -+#endif -+}; -+ -+struct mtk_wed_ops { -+ int (*attach)(struct mtk_wed_device *dev); -+ int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring, -+ void __iomem *regs); -+ int (*txfree_ring_setup)(struct mtk_wed_device *dev, -+ void __iomem *regs); -+ void (*detach)(struct mtk_wed_device *dev); -+ -+ void (*stop)(struct mtk_wed_device *dev); -+ void (*start)(struct mtk_wed_device *dev, u32 irq_mask); -+ void (*reset_dma)(struct mtk_wed_device *dev); -+ -+ u32 (*reg_read)(struct mtk_wed_device *dev, u32 reg); -+ void (*reg_write)(struct mtk_wed_device *dev, u32 reg, u32 val); -+ -+ u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask); -+ void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask); -+}; -+ -+extern const struct mtk_wed_ops __rcu *mtk_soc_wed_ops; -+ -+static inline int -+mtk_wed_device_attach(struct mtk_wed_device *dev) -+{ -+ int ret = -ENODEV; -+ -+#ifdef CONFIG_NET_MEDIATEK_SOC_WED -+ rcu_read_lock(); -+ dev->ops = rcu_dereference(mtk_soc_wed_ops); -+ if (dev->ops) -+ ret = dev->ops->attach(dev); -+ else -+ rcu_read_unlock(); -+ -+ if (ret) -+ dev->ops = NULL; -+#endif -+ -+ return ret; -+} -+ -+#ifdef CONFIG_NET_MEDIATEK_SOC_WED -+#define mtk_wed_device_active(_dev) !!(_dev)->ops -+#define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev) -+#define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask) -+#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) \ -+ (_dev)->ops->tx_ring_setup(_dev, _ring, _regs) -+#define mtk_wed_device_txfree_ring_setup(_dev, _regs) \ -+ (_dev)->ops->txfree_ring_setup(_dev, _regs) -+#define mtk_wed_device_reg_read(_dev, _reg) \ -+ (_dev)->ops->reg_read(_dev, _reg) -+#define mtk_wed_device_reg_write(_dev, _reg, _val) \ -+ (_dev)->ops->reg_write(_dev, _reg, _val) -+#define mtk_wed_device_irq_get(_dev, _mask) \ -+ (_dev)->ops->irq_get(_dev, _mask) -+#define mtk_wed_device_irq_set_mask(_dev, _mask) \ -+ (_dev)->ops->irq_set_mask(_dev, _mask) -+#else -+static inline bool mtk_wed_device_active(struct mtk_wed_device *dev) -+{ -+ return false; -+} -+#define mtk_wed_device_detach(_dev) do {} while (0) -+#define mtk_wed_device_start(_dev, _mask) do {} while (0) -+#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV -+#define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV -+#define mtk_wed_device_reg_read(_dev, _reg) 0 -+#define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0) -+#define mtk_wed_device_irq_get(_dev, _mask) 0 -+#define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0) -+#endif -+ -+#endif diff --git a/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch b/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch deleted file mode 100644 index 50d65b1eb6f..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-03-net-ethernet-mtk_eth_soc-implement-flow-offloading-t.patch +++ /dev/null @@ -1,269 +0,0 @@ -From: Felix Fietkau -Date: Sat, 5 Feb 2022 18:29:22 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: implement flow offloading - to WED devices - -This allows hardware flow offloading from Ethernet to WLAN on MT7622 SoC - -Co-developed-by: Lorenzo Bianconi -Signed-off-by: Lorenzo Bianconi -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_f - return 0; - } - -+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, -+ int bss, int wcid) -+{ -+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); -+ u32 *ib2 = mtk_foe_entry_ib2(entry); -+ -+ *ib2 &= ~MTK_FOE_IB2_PORT_MG; -+ *ib2 |= MTK_FOE_IB2_WDMA_WINFO; -+ if (wdma_idx) -+ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; -+ -+ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | -+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | -+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); -+ -+ return 0; -+} -+ - static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry) - { - return !(entry->ib1 & MTK_FOE_IB1_STATIC) && ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -48,9 +48,9 @@ enum { - #define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5) - #define MTK_FOE_IB2_MULTICAST BIT(8) - --#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12) --#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16) --#define MTK_FOE_IB2_WHNAT_NAT BIT(17) -+#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12) -+#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16) -+#define MTK_FOE_IB2_WDMA_WINFO BIT(17) - - #define MTK_FOE_IB2_PORT_MG GENMASK(17, 12) - -@@ -58,9 +58,9 @@ enum { - - #define MTK_FOE_IB2_DSCP GENMASK(31, 24) - --#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0) --#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6) --#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14) -+#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0) -+#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6) -+#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14) - - enum { - MTK_FOE_STATE_INVALID, -@@ -281,6 +281,8 @@ int mtk_foe_entry_set_ipv6_tuple(struct - int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port); - int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); - int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); -+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, -+ int bss, int wcid); - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, - u16 timestamp); - int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -10,6 +10,7 @@ - #include - #include - #include "mtk_eth_soc.h" -+#include "mtk_wed.h" - - struct mtk_flow_data { - struct ethhdr eth; -@@ -39,6 +40,7 @@ struct mtk_flow_entry { - struct rhash_head node; - unsigned long cookie; - u16 hash; -+ s8 wed_index; - }; - - static const struct rhashtable_params mtk_flow_ht_params = { -@@ -80,6 +82,35 @@ mtk_flow_offload_mangle_eth(const struct - memcpy(dest, src, act->mangle.mask ? 2 : 4); - } - -+static int -+mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info) -+{ -+ struct net_device_path_ctx ctx = { -+ .dev = dev, -+ .daddr = addr, -+ }; -+ struct net_device_path path = {}; -+ -+ if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) -+ return -1; -+ -+ if (!dev->netdev_ops->ndo_fill_forward_path) -+ return -1; -+ -+ if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path)) -+ return -1; -+ -+ if (path.type != DEV_PATH_MTK_WDMA) -+ return -1; -+ -+ info->wdma_idx = path.mtk_wdma.wdma_idx; -+ info->queue = path.mtk_wdma.queue; -+ info->bss = path.mtk_wdma.bss; -+ info->wcid = path.mtk_wdma.wcid; -+ -+ return 0; -+} -+ - - static int - mtk_flow_mangle_ports(const struct flow_action_entry *act, -@@ -149,10 +180,20 @@ mtk_flow_get_dsa_port(struct net_device - - static int - mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe, -- struct net_device *dev) -+ struct net_device *dev, const u8 *dest_mac, -+ int *wed_index) - { -+ struct mtk_wdma_info info = {}; - int pse_port, dsa_port; - -+ if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { -+ mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss, -+ info.wcid); -+ pse_port = 3; -+ *wed_index = info.wdma_idx; -+ goto out; -+ } -+ - dsa_port = mtk_flow_get_dsa_port(&dev); - if (dsa_port >= 0) - mtk_foe_entry_set_dsa(foe, dsa_port); -@@ -164,6 +205,7 @@ mtk_flow_set_output_device(struct mtk_et - else - return -EOPNOTSUPP; - -+out: - mtk_foe_entry_set_pse_port(foe, pse_port); - - return 0; -@@ -179,6 +221,7 @@ mtk_flow_offload_replace(struct mtk_eth - struct net_device *odev = NULL; - struct mtk_flow_entry *entry; - int offload_type = 0; -+ int wed_index = -1; - u16 addr_type = 0; - u32 timestamp; - u8 l4proto = 0; -@@ -326,10 +369,14 @@ mtk_flow_offload_replace(struct mtk_eth - if (data.pppoe.num == 1) - mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); - -- err = mtk_flow_set_output_device(eth, &foe, odev); -+ err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest, -+ &wed_index); - if (err) - return err; - -+ if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0) -+ return err; -+ - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; -@@ -343,6 +390,7 @@ mtk_flow_offload_replace(struct mtk_eth - } - - entry->hash = hash; -+ entry->wed_index = wed_index; - err = rhashtable_insert_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); - if (err < 0) -@@ -353,6 +401,8 @@ clear_flow: - mtk_foe_entry_clear(ð->ppe, hash); - free: - kfree(entry); -+ if (wed_index >= 0) -+ mtk_wed_flow_remove(wed_index); - return err; - } - -@@ -369,6 +419,8 @@ mtk_flow_offload_destroy(struct mtk_eth - mtk_foe_entry_clear(ð->ppe, entry->hash); - rhashtable_remove_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); -+ if (entry->wed_index >= 0) -+ mtk_wed_flow_remove(entry->wed_index); - kfree(entry); - - return 0; ---- a/drivers/net/ethernet/mediatek/mtk_wed.h -+++ b/drivers/net/ethernet/mediatek/mtk_wed.h -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - - struct mtk_eth; - -@@ -27,6 +28,12 @@ struct mtk_wed_hw { - int index; - }; - -+struct mtk_wdma_info { -+ u8 wdma_idx; -+ u8 queue; -+ u16 wcid; -+ u8 bss; -+}; - - #ifdef CONFIG_NET_MEDIATEK_SOC_WED - static inline void ---- a/include/linux/netdevice.h -+++ b/include/linux/netdevice.h -@@ -872,6 +872,7 @@ enum net_device_path_type { - DEV_PATH_BRIDGE, - DEV_PATH_PPPOE, - DEV_PATH_DSA, -+ DEV_PATH_MTK_WDMA, - }; - - struct net_device_path { -@@ -897,6 +898,12 @@ struct net_device_path { - int port; - u16 proto; - } dsa; -+ struct { -+ u8 wdma_idx; -+ u8 queue; -+ u16 wcid; -+ u8 bss; -+ } mtk_wdma; - }; - }; - ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -763,6 +763,10 @@ int dev_fill_forward_path(const struct n - if (WARN_ON_ONCE(last_dev == ctx.dev)) - return -1; - } -+ -+ if (!ctx.dev) -+ return ret; -+ - path = dev_fwd_path(stack); - if (!path) - return -1; diff --git a/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch b/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch deleted file mode 100644 index 2c6e3fd3cd3..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-04-arm64-dts-mediatek-mt7622-introduce-nodes-for-Wirele.patch +++ /dev/null @@ -1,62 +0,0 @@ -From: Felix Fietkau -Date: Sat, 5 Feb 2022 18:36:36 +0100 -Subject: [PATCH] arm64: dts: mediatek: mt7622: introduce nodes for - Wireless Ethernet Dispatch - -Introduce wed0 and wed1 nodes in order to enable offloading forwarding -between ethernet and wireless devices on the mt7622 chipset. - -Signed-off-by: Felix Fietkau ---- - ---- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi -+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -894,6 +894,11 @@ - }; - }; - -+ hifsys: syscon@1af00000 { -+ compatible = "mediatek,mt7622-hifsys", "syscon"; -+ reg = <0 0x1af00000 0 0x70>; -+ }; -+ - ethsys: syscon@1b000000 { - compatible = "mediatek,mt7622-ethsys", - "syscon"; -@@ -912,6 +917,26 @@ - #dma-cells = <1>; - }; - -+ pcie_mirror: pcie-mirror@10000400 { -+ compatible = "mediatek,mt7622-pcie-mirror", -+ "syscon"; -+ reg = <0 0x10000400 0 0x10>; -+ }; -+ -+ wed0: wed@1020a000 { -+ compatible = "mediatek,mt7622-wed", -+ "syscon"; -+ reg = <0 0x1020a000 0 0x1000>; -+ interrupts = ; -+ }; -+ -+ wed1: wed@1020b000 { -+ compatible = "mediatek,mt7622-wed", -+ "syscon"; -+ reg = <0 0x1020b000 0 0x1000>; -+ interrupts = ; -+ }; -+ - eth: ethernet@1b100000 { - compatible = "mediatek,mt7622-eth", - "mediatek,mt2701-eth", -@@ -939,6 +964,9 @@ - mediatek,ethsys = <ðsys>; - mediatek,sgmiisys = <&sgmiisys>; - mediatek,cci-control = <&cci_control2>; -+ mediatek,wed = <&wed0>, <&wed1>; -+ mediatek,pcie-mirror = <&pcie_mirror>; -+ mediatek,hifsys = <&hifsys>; - dma-coherent; - #address-cells = <1>; - #size-cells = <0>; diff --git a/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch b/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch deleted file mode 100644 index 9adb067015e..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-05-net-ethernet-mtk_eth_soc-add-ipv6-flow-offload-suppo.patch +++ /dev/null @@ -1,79 +0,0 @@ -From: David Bentham -Date: Mon, 21 Feb 2022 15:36:16 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add ipv6 flow offload - support - -Add the missing IPv6 flow offloading support for routing only. -Hardware flow offloading is done by the packet processing engine (PPE) -of the Ethernet MAC and as it doesn't support mangling of IPv6 packets, -IPv6 NAT cannot be supported. - -Signed-off-by: David Bentham -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -6,6 +6,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -20,6 +21,11 @@ struct mtk_flow_data { - __be32 src_addr; - __be32 dst_addr; - } v4; -+ -+ struct { -+ struct in6_addr src_addr; -+ struct in6_addr dst_addr; -+ } v6; - }; - - __be16 src_port; -@@ -65,6 +71,14 @@ mtk_flow_set_ipv4_addr(struct mtk_foe_en - data->v4.dst_addr, data->dst_port); - } - -+static int -+mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data) -+{ -+ return mtk_foe_entry_set_ipv6_tuple(foe, -+ data->v6.src_addr.s6_addr32, data->src_port, -+ data->v6.dst_addr.s6_addr32, data->dst_port); -+} -+ - static void - mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth) - { -@@ -296,6 +310,9 @@ mtk_flow_offload_replace(struct mtk_eth - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: - offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; - break; -+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS: -+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; -+ break; - default: - return -EOPNOTSUPP; - } -@@ -331,6 +348,17 @@ mtk_flow_offload_replace(struct mtk_eth - mtk_flow_set_ipv4_addr(&foe, &data, false); - } - -+ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { -+ struct flow_match_ipv6_addrs addrs; -+ -+ flow_rule_match_ipv6_addrs(rule, &addrs); -+ -+ data.v6.src_addr = addrs.key->src; -+ data.v6.dst_addr = addrs.key->dst; -+ -+ mtk_flow_set_ipv6_addr(&foe, &data); -+ } -+ - flow_action_for_each(i, act, &rule->action) { - if (act->id != FLOW_ACTION_MANGLE) - continue; diff --git a/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch b/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch deleted file mode 100644 index 1950d81ebba..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-06-net-ethernet-mtk_eth_soc-support-TC_SETUP_BLOCK-for-.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Felix Fietkau -Date: Mon, 21 Feb 2022 15:37:21 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: support TC_SETUP_BLOCK for - PPE offload - -This allows offload entries to be created from user space - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -564,10 +564,13 @@ mtk_eth_setup_tc_block(struct net_device - int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, - void *type_data) - { -- if (type == TC_SETUP_FT) -+ switch (type) { -+ case TC_SETUP_BLOCK: -+ case TC_SETUP_FT: - return mtk_eth_setup_tc_block(dev, type_data); -- -- return -EOPNOTSUPP; -+ default: -+ return -EOPNOTSUPP; -+ } - } - - int mtk_eth_offload_init(struct mtk_eth *eth) diff --git a/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch b/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch deleted file mode 100644 index f18a816b703..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-07-net-ethernet-mtk_eth_soc-allocate-struct-mtk_ppe-sep.patch +++ /dev/null @@ -1,159 +0,0 @@ -From: Felix Fietkau -Date: Mon, 21 Feb 2022 15:38:20 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: allocate struct mtk_ppe - separately - -Preparation for adding more data to it, which will increase its size. - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2335,7 +2335,7 @@ static int mtk_open(struct net_device *d - return err; - } - -- if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0) -+ if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0) - gdm_config = MTK_GDMA_TO_PPE; - - mtk_gdm_config(eth, gdm_config); -@@ -2409,7 +2409,7 @@ static int mtk_stop(struct net_device *d - mtk_dma_free(eth); - - if (eth->soc->offload_version) -- mtk_ppe_stop(ð->ppe); -+ mtk_ppe_stop(eth->ppe); - - return 0; - } -@@ -3301,10 +3301,11 @@ static int mtk_probe(struct platform_dev - } - - if (eth->soc->offload_version) { -- err = mtk_ppe_init(ð->ppe, eth->dev, -- eth->base + MTK_ETH_PPE_BASE, 2); -- if (err) -+ eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2); -+ if (!eth->ppe) { -+ err = -ENOMEM; - goto err_free_dev; -+ } - - err = mtk_eth_offload_init(eth); - if (err) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -983,7 +983,7 @@ struct mtk_eth { - u32 rx_dma_l4_valid; - int ip_align; - -- struct mtk_ppe ppe; -+ struct mtk_ppe *ppe; - struct rhashtable flow_table; - }; - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -384,10 +384,15 @@ int mtk_foe_entry_commit(struct mtk_ppe - return hash; - } - --int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, -+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, - int version) - { - struct mtk_foe_entry *foe; -+ struct mtk_ppe *ppe; -+ -+ ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); -+ if (!ppe) -+ return NULL; - - /* need to allocate a separate device, since it PPE DMA access is - * not coherent. -@@ -399,13 +404,13 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st - foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), - &ppe->foe_phys, GFP_KERNEL); - if (!foe) -- return -ENOMEM; -+ return NULL; - - ppe->foe_table = foe; - - mtk_ppe_debugfs_init(ppe); - -- return 0; -+ return ppe; - } - - static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe) ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -246,8 +246,7 @@ struct mtk_ppe { - void *acct_table; - }; - --int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base, -- int version); -+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version); - int mtk_ppe_start(struct mtk_ppe *ppe); - int mtk_ppe_stop(struct mtk_ppe *ppe); - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -411,7 +411,7 @@ mtk_flow_offload_replace(struct mtk_eth - - entry->cookie = f->cookie; - timestamp = mtk_eth_timestamp(eth); -- hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp); -+ hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp); - if (hash < 0) { - err = hash; - goto free; -@@ -426,7 +426,7 @@ mtk_flow_offload_replace(struct mtk_eth - - return 0; - clear_flow: -- mtk_foe_entry_clear(ð->ppe, hash); -+ mtk_foe_entry_clear(eth->ppe, hash); - free: - kfree(entry); - if (wed_index >= 0) -@@ -444,7 +444,7 @@ mtk_flow_offload_destroy(struct mtk_eth - if (!entry) - return -ENOENT; - -- mtk_foe_entry_clear(ð->ppe, entry->hash); -+ mtk_foe_entry_clear(eth->ppe, entry->hash); - rhashtable_remove_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); - if (entry->wed_index >= 0) -@@ -466,7 +466,7 @@ mtk_flow_offload_stats(struct mtk_eth *e - if (!entry) - return -ENOENT; - -- timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash); -+ timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash); - if (timestamp < 0) - return -ETIMEDOUT; - -@@ -522,7 +522,7 @@ mtk_eth_setup_tc_block(struct net_device - struct flow_block_cb *block_cb; - flow_setup_cb_t *cb; - -- if (!eth->ppe.foe_table) -+ if (!eth->ppe || !eth->ppe->foe_table) - return -EOPNOTSUPP; - - if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) -@@ -575,7 +575,7 @@ int mtk_eth_setup_tc(struct net_device * - - int mtk_eth_offload_init(struct mtk_eth *eth) - { -- if (!eth->ppe.foe_table) -+ if (!eth->ppe || !eth->ppe->foe_table) - return 0; - - return rhashtable_init(ð->flow_table, &mtk_flow_ht_params); diff --git a/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch b/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch deleted file mode 100644 index 2609cbedec2..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-08-net-ethernet-mtk_eth_soc-rework-hardware-flow-table-.patch +++ /dev/null @@ -1,424 +0,0 @@ -From: Felix Fietkau -Date: Mon, 21 Feb 2022 15:39:18 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rework hardware flow table - management - -The hardware was designed to handle flow detection and creation of flow entries -by itself, relying on the software primarily for filling in egress routing -information. -When there is a hash collision between multiple flows, this allows the hardware -to maintain the entry for the most active flow. -Additionally, the hardware only keeps offloading active for entries with at -least 30 packets per second. - -With this rework, the code no longer creates a hardware entries directly. -Instead, the hardware entry is only created when the PPE reports a matching -unbound flow with the minimum target rate. -In order to reduce CPU overhead, looking for flows belonging to a hash entry -is rate limited to once every 100ms. - -This rework is also used as preparation for emulating bridge offload by -managing L4 offload entries on demand. - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - #include - - #include "mtk_eth_soc.h" -@@ -1293,7 +1294,7 @@ static int mtk_poll_rx(struct napi_struc - struct net_device *netdev; - unsigned int pktlen; - dma_addr_t dma_addr; -- u32 hash; -+ u32 hash, reason; - int mac; - - ring = mtk_get_rx_ring(eth); -@@ -1372,6 +1373,11 @@ static int mtk_poll_rx(struct napi_struc - skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); - } - -+ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); -+ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) -+ mtk_ppe_check_skb(eth->ppe, skb, -+ trxd.rxd4 & MTK_RXD4_FOE_ENTRY); -+ - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && - (trxd.rxd2 & RX_DMA_VTAG)) - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -@@ -3301,7 +3307,7 @@ static int mtk_probe(struct platform_dev - } - - if (eth->soc->offload_version) { -- eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2); -+ eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2); - if (!eth->ppe) { - err = -ENOMEM; - goto err_free_dev; ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -6,9 +6,12 @@ - #include - #include - #include -+#include "mtk_eth_soc.h" - #include "mtk_ppe.h" - #include "mtk_ppe_regs.h" - -+static DEFINE_SPINLOCK(ppe_lock); -+ - static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) - { - writel(val, ppe->base + reg); -@@ -41,6 +44,11 @@ static u32 ppe_clear(struct mtk_ppe *ppe - return ppe_m32(ppe, reg, val, 0); - } - -+static u32 mtk_eth_timestamp(struct mtk_eth *eth) -+{ -+ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; -+} -+ - static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) - { - int ret; -@@ -353,26 +361,59 @@ static inline bool mtk_foe_entry_usable( - FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; - } - --int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, -- u16 timestamp) -+static bool -+mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data) -+{ -+ int type, len; -+ -+ if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) -+ return false; -+ -+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); -+ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) -+ len = offsetof(struct mtk_foe_entry, ipv6._rsv); -+ else -+ len = offsetof(struct mtk_foe_entry, ipv4.ib2); -+ -+ return !memcmp(&entry->data.data, &data->data, len - 4); -+} -+ -+static void -+mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { - struct mtk_foe_entry *hwe; -- u32 hash; -+ struct mtk_foe_entry foe; - -+ spin_lock_bh(&ppe_lock); -+ if (entry->hash == 0xffff) -+ goto out; -+ -+ hwe = &ppe->foe_table[entry->hash]; -+ memcpy(&foe, hwe, sizeof(foe)); -+ if (!mtk_flow_entry_match(entry, &foe)) { -+ entry->hash = 0xffff; -+ goto out; -+ } -+ -+ entry->data.ib1 = foe.ib1; -+ -+out: -+ spin_unlock_bh(&ppe_lock); -+} -+ -+static void -+__mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, -+ u16 hash) -+{ -+ struct mtk_foe_entry *hwe; -+ u16 timestamp; -+ -+ timestamp = mtk_eth_timestamp(ppe->eth); - timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; - entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; - entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); - -- hash = mtk_ppe_hash_entry(entry); - hwe = &ppe->foe_table[hash]; -- if (!mtk_foe_entry_usable(hwe)) { -- hwe++; -- hash++; -- -- if (!mtk_foe_entry_usable(hwe)) -- return -ENOSPC; -- } -- - memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); - wmb(); - hwe->ib1 = entry->ib1; -@@ -380,13 +421,77 @@ int mtk_foe_entry_commit(struct mtk_ppe - dma_wmb(); - - mtk_ppe_cache_clear(ppe); -+} - -- return hash; -+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ spin_lock_bh(&ppe_lock); -+ hlist_del_init(&entry->list); -+ if (entry->hash != 0xffff) { -+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; -+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, -+ MTK_FOE_STATE_BIND); -+ dma_wmb(); -+ } -+ entry->hash = 0xffff; -+ spin_unlock_bh(&ppe_lock); -+} -+ -+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ u32 hash = mtk_ppe_hash_entry(&entry->data); -+ -+ entry->hash = 0xffff; -+ spin_lock_bh(&ppe_lock); -+ hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); -+ spin_unlock_bh(&ppe_lock); -+ -+ return 0; -+} -+ -+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) -+{ -+ struct hlist_head *head = &ppe->foe_flow[hash / 2]; -+ struct mtk_flow_entry *entry; -+ struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; -+ bool found = false; -+ -+ if (hlist_empty(head)) -+ return; -+ -+ spin_lock_bh(&ppe_lock); -+ hlist_for_each_entry(entry, head, list) { -+ if (found || !mtk_flow_entry_match(entry, hwe)) { -+ if (entry->hash != 0xffff) -+ entry->hash = 0xffff; -+ continue; -+ } -+ -+ entry->hash = hash; -+ __mtk_foe_entry_commit(ppe, &entry->data, hash); -+ found = true; -+ } -+ spin_unlock_bh(&ppe_lock); -+} -+ -+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; -+ u16 timestamp; -+ -+ mtk_flow_entry_update(ppe, entry); -+ timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; -+ -+ if (timestamp > now) -+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; -+ else -+ return now - timestamp; - } - --struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, -+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, - int version) - { -+ struct device *dev = eth->dev; - struct mtk_foe_entry *foe; - struct mtk_ppe *ppe; - -@@ -398,6 +503,7 @@ struct mtk_ppe *mtk_ppe_init(struct devi - * not coherent. - */ - ppe->base = base; -+ ppe->eth = eth; - ppe->dev = dev; - ppe->version = version; - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -235,7 +235,17 @@ enum { - MTK_PPE_CPU_REASON_INVALID = 0x1f, - }; - -+struct mtk_flow_entry { -+ struct rhash_head node; -+ struct hlist_node list; -+ unsigned long cookie; -+ struct mtk_foe_entry data; -+ u16 hash; -+ s8 wed_index; -+}; -+ - struct mtk_ppe { -+ struct mtk_eth *eth; - struct device *dev; - void __iomem *base; - int version; -@@ -243,18 +253,33 @@ struct mtk_ppe { - struct mtk_foe_entry *foe_table; - dma_addr_t foe_phys; - -+ u16 foe_check_time[MTK_PPE_ENTRIES]; -+ struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; -+ - void *acct_table; - }; - --struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version); -+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version); - int mtk_ppe_start(struct mtk_ppe *ppe); - int mtk_ppe_stop(struct mtk_ppe *ppe); - -+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); -+ - static inline void --mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash) -+mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) - { -- ppe->foe_table[hash].ib1 = 0; -- dma_wmb(); -+ u16 now, diff; -+ -+ if (!ppe) -+ return; -+ -+ now = (u16)jiffies; -+ diff = now - ppe->foe_check_time[hash]; -+ if (diff < HZ / 10) -+ return; -+ -+ ppe->foe_check_time[hash] = now; -+ __mtk_ppe_check_skb(ppe, skb, hash); - } - - static inline int -@@ -282,8 +307,9 @@ int mtk_foe_entry_set_vlan(struct mtk_fo - int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); - int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, - int bss, int wcid); --int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, -- u16 timestamp); -+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); -+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); -+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); - int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); - - #endif ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -42,13 +42,6 @@ struct mtk_flow_data { - } pppoe; - }; - --struct mtk_flow_entry { -- struct rhash_head node; -- unsigned long cookie; -- u16 hash; -- s8 wed_index; --}; -- - static const struct rhashtable_params mtk_flow_ht_params = { - .head_offset = offsetof(struct mtk_flow_entry, node), - .key_offset = offsetof(struct mtk_flow_entry, cookie), -@@ -56,12 +49,6 @@ static const struct rhashtable_params mt - .automatic_shrinking = true, - }; - --static u32 --mtk_eth_timestamp(struct mtk_eth *eth) --{ -- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; --} -- - static int - mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data, - bool egress) -@@ -237,10 +224,8 @@ mtk_flow_offload_replace(struct mtk_eth - int offload_type = 0; - int wed_index = -1; - u16 addr_type = 0; -- u32 timestamp; - u8 l4proto = 0; - int err = 0; -- int hash; - int i; - - if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params)) -@@ -410,23 +395,21 @@ mtk_flow_offload_replace(struct mtk_eth - return -ENOMEM; - - entry->cookie = f->cookie; -- timestamp = mtk_eth_timestamp(eth); -- hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp); -- if (hash < 0) { -- err = hash; -+ memcpy(&entry->data, &foe, sizeof(entry->data)); -+ entry->wed_index = wed_index; -+ -+ if (mtk_foe_entry_commit(eth->ppe, entry) < 0) - goto free; -- } - -- entry->hash = hash; -- entry->wed_index = wed_index; - err = rhashtable_insert_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); - if (err < 0) -- goto clear_flow; -+ goto clear; - - return 0; --clear_flow: -- mtk_foe_entry_clear(eth->ppe, hash); -+ -+clear: -+ mtk_foe_entry_clear(eth->ppe, entry); - free: - kfree(entry); - if (wed_index >= 0) -@@ -444,7 +427,7 @@ mtk_flow_offload_destroy(struct mtk_eth - if (!entry) - return -ENOENT; - -- mtk_foe_entry_clear(eth->ppe, entry->hash); -+ mtk_foe_entry_clear(eth->ppe, entry); - rhashtable_remove_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); - if (entry->wed_index >= 0) -@@ -458,7 +441,6 @@ static int - mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f) - { - struct mtk_flow_entry *entry; -- int timestamp; - u32 idle; - - entry = rhashtable_lookup(ð->flow_table, &f->cookie, -@@ -466,11 +448,7 @@ mtk_flow_offload_stats(struct mtk_eth *e - if (!entry) - return -ENOENT; - -- timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash); -- if (timestamp < 0) -- return -ETIMEDOUT; -- -- idle = mtk_eth_timestamp(eth) - timestamp; -+ idle = mtk_foe_entry_idle_time(eth->ppe, entry); - f->stats.lastused = jiffies - idle * HZ; - - return 0; diff --git a/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch b/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch deleted file mode 100644 index 2ff0b341f91..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-09-net-ethernet-mtk_eth_soc-remove-bridge-flow-offload-.patch +++ /dev/null @@ -1,44 +0,0 @@ -From: Felix Fietkau -Date: Mon, 21 Feb 2022 15:55:19 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: remove bridge flow offload - type entry support - -According to MediaTek, this feature is not supported in current hardware - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -84,13 +84,6 @@ static u32 mtk_ppe_hash_entry(struct mtk - u32 hash; - - switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { -- case MTK_PPE_PKT_TYPE_BRIDGE: -- hv1 = e->bridge.src_mac_lo; -- hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16); -- hv2 = e->bridge.src_mac_hi >> 16; -- hv2 ^= e->bridge.dest_mac_lo; -- hv3 = e->bridge.dest_mac_hi; -- break; - case MTK_PPE_PKT_TYPE_IPV4_ROUTE: - case MTK_PPE_PKT_TYPE_IPV4_HNAPT: - hv1 = e->ipv4.orig.ports; -@@ -572,7 +565,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe) - MTK_PPE_FLOW_CFG_IP4_NAT | - MTK_PPE_FLOW_CFG_IP4_NAPT | - MTK_PPE_FLOW_CFG_IP4_DSLITE | -- MTK_PPE_FLOW_CFG_L2_BRIDGE | - MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; - ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -@@ -32,7 +32,6 @@ static const char *mtk_foe_pkt_type_str( - static const char * const type_str[] = { - [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T", - [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T", -- [MTK_PPE_PKT_TYPE_BRIDGE] = "L2", - [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE", - [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T", - [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T", diff --git a/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch b/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch deleted file mode 100644 index 209c65e66aa..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-10-net-ethernet-mtk_eth_soc-support-creating-mac-addres.patch +++ /dev/null @@ -1,553 +0,0 @@ -From: Felix Fietkau -Date: Wed, 23 Feb 2022 10:56:34 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: support creating mac - address based offload entries - -This will be used to implement a limited form of bridge offloading. -Since the hardware does not support flow table entries with just source -and destination MAC address, the driver has to emulate it. - -The hardware automatically creates entries entries for incoming flows, even -when they are bridged instead of routed, and reports when packets for these -flows have reached the minimum PPS rate for offloading. - -After this happens, we look up the L2 flow offload entry based on the MAC -header and fill in the output routing information in the flow table. -The dynamically created per-flow entries are automatically removed when -either the hardware flowtable entry expires, is replaced, or if the offload -rule they belong to is removed - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -6,12 +6,22 @@ - #include - #include - #include -+#include -+#include -+#include - #include "mtk_eth_soc.h" - #include "mtk_ppe.h" - #include "mtk_ppe_regs.h" - - static DEFINE_SPINLOCK(ppe_lock); - -+static const struct rhashtable_params mtk_flow_l2_ht_params = { -+ .head_offset = offsetof(struct mtk_flow_entry, l2_node), -+ .key_offset = offsetof(struct mtk_flow_entry, data.bridge), -+ .key_len = offsetof(struct mtk_foe_bridge, key_end), -+ .automatic_shrinking = true, -+}; -+ - static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val) - { - writel(val, ppe->base + reg); -@@ -123,6 +133,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e - { - int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); - -+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return &entry->bridge.l2; -+ - if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) - return &entry->ipv6.l2; - -@@ -134,6 +147,9 @@ mtk_foe_entry_ib2(struct mtk_foe_entry * - { - int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); - -+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return &entry->bridge.ib2; -+ - if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) - return &entry->ipv6.ib2; - -@@ -168,7 +184,12 @@ int mtk_foe_entry_prepare(struct mtk_foe - if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T) - entry->ipv6.ports = ports_pad; - -- if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { -+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) { -+ ether_addr_copy(entry->bridge.src_mac, src_mac); -+ ether_addr_copy(entry->bridge.dest_mac, dest_mac); -+ entry->bridge.ib2 = val; -+ l2 = &entry->bridge.l2; -+ } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) { - entry->ipv6.ib2 = val; - l2 = &entry->ipv6.l2; - } else { -@@ -372,12 +393,96 @@ mtk_flow_entry_match(struct mtk_flow_ent - } - - static void -+__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ struct hlist_head *head; -+ struct hlist_node *tmp; -+ -+ if (entry->type == MTK_FLOW_TYPE_L2) { -+ rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node, -+ mtk_flow_l2_ht_params); -+ -+ head = &entry->l2_flows; -+ hlist_for_each_entry_safe(entry, tmp, head, l2_data.list) -+ __mtk_foe_entry_clear(ppe, entry); -+ return; -+ } -+ -+ hlist_del_init(&entry->list); -+ if (entry->hash != 0xffff) { -+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; -+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, -+ MTK_FOE_STATE_BIND); -+ dma_wmb(); -+ } -+ entry->hash = 0xffff; -+ -+ if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) -+ return; -+ -+ hlist_del_init(&entry->l2_data.list); -+ kfree(entry); -+} -+ -+static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) -+{ -+ u16 timestamp; -+ u16 now; -+ -+ now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; -+ timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; -+ -+ if (timestamp > now) -+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; -+ else -+ return now - timestamp; -+} -+ -+static void -+mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ struct mtk_flow_entry *cur; -+ struct mtk_foe_entry *hwe; -+ struct hlist_node *tmp; -+ int idle; -+ -+ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1); -+ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) { -+ int cur_idle; -+ u32 ib1; -+ -+ hwe = &ppe->foe_table[cur->hash]; -+ ib1 = READ_ONCE(hwe->ib1); -+ -+ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { -+ cur->hash = 0xffff; -+ __mtk_foe_entry_clear(ppe, cur); -+ continue; -+ } -+ -+ cur_idle = __mtk_foe_entry_idle_time(ppe, ib1); -+ if (cur_idle >= idle) -+ continue; -+ -+ idle = cur_idle; -+ entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; -+ entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; -+ } -+} -+ -+static void - mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { - struct mtk_foe_entry *hwe; - struct mtk_foe_entry foe; - - spin_lock_bh(&ppe_lock); -+ -+ if (entry->type == MTK_FLOW_TYPE_L2) { -+ mtk_flow_entry_update_l2(ppe, entry); -+ goto out; -+ } -+ - if (entry->hash == 0xffff) - goto out; - -@@ -419,21 +524,28 @@ __mtk_foe_entry_commit(struct mtk_ppe *p - void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { - spin_lock_bh(&ppe_lock); -- hlist_del_init(&entry->list); -- if (entry->hash != 0xffff) { -- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; -- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, -- MTK_FOE_STATE_BIND); -- dma_wmb(); -- } -- entry->hash = 0xffff; -+ __mtk_foe_entry_clear(ppe, entry); - spin_unlock_bh(&ppe_lock); - } - -+static int -+mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) -+{ -+ entry->type = MTK_FLOW_TYPE_L2; -+ -+ return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node, -+ mtk_flow_l2_ht_params); -+} -+ - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { -- u32 hash = mtk_ppe_hash_entry(&entry->data); -+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); -+ u32 hash; -+ -+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return mtk_foe_entry_commit_l2(ppe, entry); - -+ hash = mtk_ppe_hash_entry(&entry->data); - entry->hash = 0xffff; - spin_lock_bh(&ppe_lock); - hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); -@@ -442,18 +554,72 @@ int mtk_foe_entry_commit(struct mtk_ppe - return 0; - } - -+static void -+mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, -+ u16 hash) -+{ -+ struct mtk_flow_entry *flow_info; -+ struct mtk_foe_entry foe, *hwe; -+ struct mtk_foe_mac_info *l2; -+ u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; -+ int type; -+ -+ flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), -+ GFP_ATOMIC); -+ if (!flow_info) -+ return; -+ -+ flow_info->l2_data.base_flow = entry; -+ flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; -+ flow_info->hash = hash; -+ hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); -+ hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); -+ -+ hwe = &ppe->foe_table[hash]; -+ memcpy(&foe, hwe, sizeof(foe)); -+ foe.ib1 &= ib1_mask; -+ foe.ib1 |= entry->data.ib1 & ~ib1_mask; -+ -+ l2 = mtk_foe_entry_l2(&foe); -+ memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); -+ -+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); -+ if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) -+ memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); -+ else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) -+ l2->etype = ETH_P_IPV6; -+ -+ *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; -+ -+ __mtk_foe_entry_commit(ppe, &foe, hash); -+} -+ - void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) - { - struct hlist_head *head = &ppe->foe_flow[hash / 2]; -- struct mtk_flow_entry *entry; - struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; -+ struct mtk_flow_entry *entry; -+ struct mtk_foe_bridge key = {}; -+ struct ethhdr *eh; - bool found = false; -- -- if (hlist_empty(head)) -- return; -+ u8 *tag; - - spin_lock_bh(&ppe_lock); -+ -+ if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) -+ goto out; -+ - hlist_for_each_entry(entry, head, list) { -+ if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { -+ if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == -+ MTK_FOE_STATE_BIND)) -+ continue; -+ -+ entry->hash = 0xffff; -+ __mtk_foe_entry_clear(ppe, entry); -+ continue; -+ } -+ - if (found || !mtk_flow_entry_match(entry, hwe)) { - if (entry->hash != 0xffff) - entry->hash = 0xffff; -@@ -464,21 +630,50 @@ void __mtk_ppe_check_skb(struct mtk_ppe - __mtk_foe_entry_commit(ppe, &entry->data, hash); - found = true; - } -+ -+ if (found) -+ goto out; -+ -+ eh = eth_hdr(skb); -+ ether_addr_copy(key.dest_mac, eh->h_dest); -+ ether_addr_copy(key.src_mac, eh->h_source); -+ tag = skb->data - 2; -+ key.vlan = 0; -+ switch (skb->protocol) { -+#if IS_ENABLED(CONFIG_NET_DSA) -+ case htons(ETH_P_XDSA): -+ if (!netdev_uses_dsa(skb->dev) || -+ skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) -+ goto out; -+ -+ tag += 4; -+ if (get_unaligned_be16(tag) != ETH_P_8021Q) -+ break; -+ -+ fallthrough; -+#endif -+ case htons(ETH_P_8021Q): -+ key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK; -+ break; -+ default: -+ break; -+ } -+ -+ entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params); -+ if (!entry) -+ goto out; -+ -+ mtk_foe_entry_commit_subflow(ppe, entry, hash); -+ -+out: - spin_unlock_bh(&ppe_lock); - } - - int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { -- u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; -- u16 timestamp; -- - mtk_flow_entry_update(ppe, entry); -- timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; - -- if (timestamp > now) -- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; -- else -- return now - timestamp; -+ return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); - } - - struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, -@@ -492,6 +687,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - if (!ppe) - return NULL; - -+ rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params); -+ - /* need to allocate a separate device, since it PPE DMA access is - * not coherent. - */ ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -6,6 +6,7 @@ - - #include - #include -+#include - - #define MTK_ETH_PPE_BASE 0xc00 - -@@ -84,19 +85,16 @@ struct mtk_foe_mac_info { - u16 src_mac_lo; - }; - -+/* software-only entry type */ - struct mtk_foe_bridge { -- u32 dest_mac_hi; -- -- u16 src_mac_lo; -- u16 dest_mac_lo; -+ u8 dest_mac[ETH_ALEN]; -+ u8 src_mac[ETH_ALEN]; -+ u16 vlan; - -- u32 src_mac_hi; -+ struct {} key_end; - - u32 ib2; - -- u32 _rsv[5]; -- -- u32 udf_tsid; - struct mtk_foe_mac_info l2; - }; - -@@ -235,13 +233,33 @@ enum { - MTK_PPE_CPU_REASON_INVALID = 0x1f, - }; - -+enum { -+ MTK_FLOW_TYPE_L4, -+ MTK_FLOW_TYPE_L2, -+ MTK_FLOW_TYPE_L2_SUBFLOW, -+}; -+ - struct mtk_flow_entry { -+ union { -+ struct hlist_node list; -+ struct { -+ struct rhash_head l2_node; -+ struct hlist_head l2_flows; -+ }; -+ }; -+ u8 type; -+ s8 wed_index; -+ u16 hash; -+ union { -+ struct mtk_foe_entry data; -+ struct { -+ struct mtk_flow_entry *base_flow; -+ struct hlist_node list; -+ struct {} end; -+ } l2_data; -+ }; - struct rhash_head node; -- struct hlist_node list; - unsigned long cookie; -- struct mtk_foe_entry data; -- u16 hash; -- s8 wed_index; - }; - - struct mtk_ppe { -@@ -256,6 +274,8 @@ struct mtk_ppe { - u16 foe_check_time[MTK_PPE_ENTRIES]; - struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; - -+ struct rhashtable l2_flows; -+ - void *acct_table; - }; - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -31,6 +31,8 @@ struct mtk_flow_data { - __be16 src_port; - __be16 dst_port; - -+ u16 vlan_in; -+ - struct { - u16 id; - __be16 proto; -@@ -257,9 +259,45 @@ mtk_flow_offload_replace(struct mtk_eth - return -EOPNOTSUPP; - } - -+ switch (addr_type) { -+ case 0: -+ offload_type = MTK_PPE_PKT_TYPE_BRIDGE; -+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) { -+ struct flow_match_eth_addrs match; -+ -+ flow_rule_match_eth_addrs(rule, &match); -+ memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN); -+ memcpy(data.eth.h_source, match.key->src, ETH_ALEN); -+ } else { -+ return -EOPNOTSUPP; -+ } -+ -+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) { -+ struct flow_match_vlan match; -+ -+ flow_rule_match_vlan(rule, &match); -+ -+ if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q)) -+ return -EOPNOTSUPP; -+ -+ data.vlan_in = match.key->vlan_id; -+ } -+ break; -+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS: -+ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; -+ break; -+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS: -+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ - flow_action_for_each(i, act, &rule->action) { - switch (act->id) { - case FLOW_ACTION_MANGLE: -+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return -EOPNOTSUPP; - if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH) - mtk_flow_offload_mangle_eth(act, &data.eth); - break; -@@ -291,17 +329,6 @@ mtk_flow_offload_replace(struct mtk_eth - } - } - -- switch (addr_type) { -- case FLOW_DISSECTOR_KEY_IPV4_ADDRS: -- offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT; -- break; -- case FLOW_DISSECTOR_KEY_IPV6_ADDRS: -- offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T; -- break; -- default: -- return -EOPNOTSUPP; -- } -- - if (!is_valid_ether_addr(data.eth.h_source) || - !is_valid_ether_addr(data.eth.h_dest)) - return -EINVAL; -@@ -315,10 +342,13 @@ mtk_flow_offload_replace(struct mtk_eth - if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) { - struct flow_match_ports ports; - -+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return -EOPNOTSUPP; -+ - flow_rule_match_ports(rule, &ports); - data.src_port = ports.key->src; - data.dst_port = ports.key->dst; -- } else { -+ } else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) { - return -EOPNOTSUPP; - } - -@@ -348,6 +378,9 @@ mtk_flow_offload_replace(struct mtk_eth - if (act->id != FLOW_ACTION_MANGLE) - continue; - -+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) -+ return -EOPNOTSUPP; -+ - switch (act->mangle.htype) { - case FLOW_ACT_MANGLE_HDR_TYPE_TCP: - case FLOW_ACT_MANGLE_HDR_TYPE_UDP: -@@ -373,6 +406,9 @@ mtk_flow_offload_replace(struct mtk_eth - return err; - } - -+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE) -+ foe.bridge.vlan = data.vlan_in; -+ - if (data.vlan.num == 1) { - if (data.vlan.proto != htons(ETH_P_8021Q)) - return -EOPNOTSUPP; diff --git a/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch b/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch deleted file mode 100644 index 8f3dfe82399..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-11-net-ethernet-mtk_eth_soc-wed-fix-sparse-endian-warni.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Felix Fietkau -Date: Fri, 8 Apr 2022 10:59:45 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc/wed: fix sparse endian warnings - -Descriptor fields are little-endian - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Reported-by: kernel test robot -Signed-off-by: Felix Fietkau -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -144,16 +144,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi - - for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) { - u32 txd_size; -+ u32 ctrl; - - txd_size = dev->wlan.init_buf(buf, buf_phys, token++); - -- desc->buf0 = buf_phys; -- desc->buf1 = buf_phys + txd_size; -- desc->ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, -- txd_size) | -- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, -- MTK_WED_BUF_SIZE - txd_size) | -- MTK_WDMA_DESC_CTRL_LAST_SEG1; -+ desc->buf0 = cpu_to_le32(buf_phys); -+ desc->buf1 = cpu_to_le32(buf_phys + txd_size); -+ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | -+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, -+ MTK_WED_BUF_SIZE - txd_size) | -+ MTK_WDMA_DESC_CTRL_LAST_SEG1; -+ desc->ctrl = cpu_to_le32(ctrl); - desc->info = 0; - desc++; - -@@ -184,12 +185,14 @@ mtk_wed_free_buffer(struct mtk_wed_devic - - for (i = 0, page_idx = 0; i < dev->buf_ring.size; i += MTK_WED_BUF_PER_PAGE) { - void *page = page_list[page_idx++]; -+ dma_addr_t buf_addr; - - if (!page) - break; - -- dma_unmap_page(dev->hw->dev, desc[i].buf0, -- PAGE_SIZE, DMA_BIDIRECTIONAL); -+ buf_addr = le32_to_cpu(desc[i].buf0); -+ dma_unmap_page(dev->hw->dev, buf_addr, PAGE_SIZE, -+ DMA_BIDIRECTIONAL); - __free_page(page); - } - diff --git a/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch deleted file mode 100644 index 4ec8fe74bc7..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-12-net-ethernet-mtk_eth_soc-fix-return-value-check-in-m.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Yang Yingliang -Date: Fri, 8 Apr 2022 11:22:46 +0800 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix return value check in - mtk_wed_add_hw() - -If syscon_regmap_lookup_by_phandle() fails, it never return NULL pointer, -change the check to IS_ERR(). - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Reported-by: Hulk Robot -Signed-off-by: Yang Yingliang -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -816,7 +816,7 @@ void mtk_wed_add_hw(struct device_node * - return; - - regs = syscon_regmap_lookup_by_phandle(np, NULL); -- if (!regs) -+ if (IS_ERR(regs)) - return; - - rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); diff --git a/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch b/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch deleted file mode 100644 index a7c5f08f100..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-13-net-ethernet-mtk_eth_soc-use-standard-property-for-c.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Lorenzo Bianconi -Date: Mon, 11 Apr 2022 12:13:25 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: use standard property for - cci-control-port - -Rely on standard cci-control-port property to identify CCI port -reference. -Update mt7622 dts binding. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi -+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi -@@ -963,7 +963,7 @@ - power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>; - mediatek,ethsys = <ðsys>; - mediatek,sgmiisys = <&sgmiisys>; -- mediatek,cci-control = <&cci_control2>; -+ cci-control-port = <&cci_control2>; - mediatek,wed = <&wed0>, <&wed1>; - mediatek,pcie-mirror = <&pcie_mirror>; - mediatek,hifsys = <&hifsys>; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3188,7 +3188,7 @@ static int mtk_probe(struct platform_dev - struct regmap *cci; - - cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, -- "mediatek,cci-control"); -+ "cci-control-port"); - /* enable CPU/bus coherency */ - if (!IS_ERR(cci)) - regmap_write(cci, 0, 3); diff --git a/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch b/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch deleted file mode 100644 index 656b3a159e8..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-14-net-ethernet-mtk_eth_soc-use-after-free-in-__mtk_ppe.patch +++ /dev/null @@ -1,33 +0,0 @@ -From: Dan Carpenter -Date: Tue, 12 Apr 2022 12:24:19 +0300 -Subject: [PATCH] net: ethernet: mtk_eth_soc: use after free in - __mtk_ppe_check_skb() - -The __mtk_foe_entry_clear() function frees "entry" so we have to use -the _safe() version of hlist_for_each_entry() to prevent a use after -free. - -Fixes: 33fc42de3327 ("net: ethernet: mtk_eth_soc: support creating mac address based offload entries") -Signed-off-by: Dan Carpenter -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -600,6 +600,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe - struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; - struct mtk_flow_entry *entry; - struct mtk_foe_bridge key = {}; -+ struct hlist_node *n; - struct ethhdr *eh; - bool found = false; - u8 *tag; -@@ -609,7 +610,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe - if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) - goto out; - -- hlist_for_each_entry(entry, head, list) { -+ hlist_for_each_entry_safe(entry, n, head, list) { - if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) { - if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == - MTK_FOE_STATE_BIND)) diff --git a/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch b/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch deleted file mode 100644 index 714163c86bb..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-15-net-ethernet-mtk_eth_soc-add-check-for-allocation-fa.patch +++ /dev/null @@ -1,22 +0,0 @@ -From: Dan Carpenter -Date: Thu, 21 Apr 2022 18:49:02 +0300 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add check for allocation failure - -Check if the kzalloc() failed. - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Signed-off-by: Dan Carpenter -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -827,6 +827,8 @@ void mtk_wed_add_hw(struct device_node * - goto unlock; - - hw = kzalloc(sizeof(*hw), GFP_KERNEL); -+ if (!hw) -+ goto unlock; - hw->node = np; - hw->regs = regs; - hw->eth = eth; diff --git a/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch b/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch deleted file mode 100644 index aa98745ac60..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-16-eth-mtk_eth_soc-silence-the-GCC-12-array-bounds-warn.patch +++ /dev/null @@ -1,26 +0,0 @@ -From: Jakub Kicinski -Date: Fri, 20 May 2022 12:56:03 -0700 -Subject: [PATCH] eth: mtk_eth_soc: silence the GCC 12 array-bounds warning - -GCC 12 gets upset because in mtk_foe_entry_commit_subflow() -this driver allocates a partial structure. The writes are -within bounds. - -Silence these warnings for now, our build bot runs GCC 12 -so we won't allow any new instances. - -Signed-off-by: Jakub Kicinski -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/Makefile -+++ b/drivers/net/ethernet/mediatek/Makefile -@@ -11,3 +11,8 @@ mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) + - endif - obj-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_ops.o - obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o -+ -+# FIXME: temporarily silence -Warray-bounds on non W=1+ builds -+ifndef KBUILD_EXTRA_WARN -+CFLAGS_mtk_ppe.o += -Wno-array-bounds -+endif diff --git a/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch b/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch deleted file mode 100644 index 9b6321f1daf..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-17-net-ethernet-mtk_eth_soc-rely-on-GFP_KERNEL-for-dma_.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:26 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on GFP_KERNEL for - dma_alloc_coherent whenever possible - -Rely on GFP_KERNEL for dma descriptors mappings in mtk_tx_alloc(), -mtk_rx_alloc() and mtk_init_fq_dma() since they are run in non-irq -context. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -846,7 +846,7 @@ static int mtk_init_fq_dma(struct mtk_et - eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, - cnt * sizeof(struct mtk_tx_dma), - ð->phy_scratch_ring, -- GFP_ATOMIC); -+ GFP_KERNEL); - if (unlikely(!eth->scratch_ring)) - return -ENOMEM; - -@@ -1624,7 +1624,7 @@ static int mtk_tx_alloc(struct mtk_eth * - goto no_tx_mem; - - ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, -- &ring->phys, GFP_ATOMIC); -+ &ring->phys, GFP_KERNEL); - if (!ring->dma) - goto no_tx_mem; - -@@ -1642,8 +1642,7 @@ static int mtk_tx_alloc(struct mtk_eth * - */ - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { - ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, -- &ring->phys_pdma, -- GFP_ATOMIC); -+ &ring->phys_pdma, GFP_KERNEL); - if (!ring->dma_pdma) - goto no_tx_mem; - -@@ -1758,7 +1757,7 @@ static int mtk_rx_alloc(struct mtk_eth * - - ring->dma = dma_alloc_coherent(eth->dma_dev, - rx_dma_size * sizeof(*ring->dma), -- &ring->phys, GFP_ATOMIC); -+ &ring->phys, GFP_KERNEL); - if (!ring->dma) - return -ENOMEM; - diff --git a/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch b/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch deleted file mode 100644 index 8e16ea25566..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-18-net-ethernet-mtk_eth_soc-move-tx-dma-desc-configurat.patch +++ /dev/null @@ -1,206 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:27 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: move tx dma desc configuration in - mtk_tx_set_dma_desc - -Move tx dma descriptor configuration in mtk_tx_set_dma_desc routine. -This is a preliminary patch to introduce mt7986 ethernet support since -it relies on a different tx dma descriptor layout. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -972,18 +972,51 @@ static void setup_tx_buf(struct mtk_eth - } - } - -+static void mtk_tx_set_dma_desc(struct net_device *dev, struct mtk_tx_dma *desc, -+ struct mtk_tx_dma_desc_info *info) -+{ -+ struct mtk_mac *mac = netdev_priv(dev); -+ u32 data; -+ -+ WRITE_ONCE(desc->txd1, info->addr); -+ -+ data = TX_DMA_SWC | TX_DMA_PLEN0(info->size); -+ if (info->last) -+ data |= TX_DMA_LS0; -+ WRITE_ONCE(desc->txd3, data); -+ -+ data = (mac->id + 1) << TX_DMA_FPORT_SHIFT; /* forward port */ -+ if (info->first) { -+ if (info->gso) -+ data |= TX_DMA_TSO; -+ /* tx checksum offload */ -+ if (info->csum) -+ data |= TX_DMA_CHKSUM; -+ /* vlan header offload */ -+ if (info->vlan) -+ data |= TX_DMA_INS_VLAN | info->vlan_tci; -+ } -+ WRITE_ONCE(desc->txd4, data); -+} -+ - static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, - int tx_num, struct mtk_tx_ring *ring, bool gso) - { -+ struct mtk_tx_dma_desc_info txd_info = { -+ .size = skb_headlen(skb), -+ .gso = gso, -+ .csum = skb->ip_summed == CHECKSUM_PARTIAL, -+ .vlan = skb_vlan_tag_present(skb), -+ .vlan_tci = skb_vlan_tag_get(skb), -+ .first = true, -+ .last = !skb_is_nonlinear(skb), -+ }; - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; - struct mtk_tx_dma *itxd, *txd; - struct mtk_tx_dma *itxd_pdma, *txd_pdma; - struct mtk_tx_buf *itx_buf, *tx_buf; -- dma_addr_t mapped_addr; -- unsigned int nr_frags; - int i, n_desc = 1; -- u32 txd4 = 0, fport; - int k = 0; - - itxd = ring->next_free; -@@ -991,49 +1024,32 @@ static int mtk_tx_map(struct sk_buff *sk - if (itxd == ring->last_free) - return -ENOMEM; - -- /* set the forward port */ -- fport = (mac->id + 1) << TX_DMA_FPORT_SHIFT; -- txd4 |= fport; -- - itx_buf = mtk_desc_to_tx_buf(ring, itxd); - memset(itx_buf, 0, sizeof(*itx_buf)); - -- if (gso) -- txd4 |= TX_DMA_TSO; -- -- /* TX Checksum offload */ -- if (skb->ip_summed == CHECKSUM_PARTIAL) -- txd4 |= TX_DMA_CHKSUM; -- -- /* VLAN header offload */ -- if (skb_vlan_tag_present(skb)) -- txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb); -- -- mapped_addr = dma_map_single(eth->dma_dev, skb->data, -- skb_headlen(skb), DMA_TO_DEVICE); -- if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) -+ txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, -+ DMA_TO_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) - return -ENOMEM; - -- WRITE_ONCE(itxd->txd1, mapped_addr); -+ mtk_tx_set_dma_desc(dev, itxd, &txd_info); -+ - itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; - itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : - MTK_TX_FLAGS_FPORT1; -- setup_tx_buf(eth, itx_buf, itxd_pdma, mapped_addr, skb_headlen(skb), -+ setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, - k++); - - /* TX SG offload */ - txd = itxd; - txd_pdma = qdma_to_pdma(ring, txd); -- nr_frags = skb_shinfo(skb)->nr_frags; - -- for (i = 0; i < nr_frags; i++) { -+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - unsigned int offset = 0; - int frag_size = skb_frag_size(frag); - - while (frag_size) { -- bool last_frag = false; -- unsigned int frag_map_size; - bool new_desc = true; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || -@@ -1048,23 +1064,17 @@ static int mtk_tx_map(struct sk_buff *sk - new_desc = false; - } - -- -- frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN); -- mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset, -- frag_map_size, -- DMA_TO_DEVICE); -- if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr))) -+ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); -+ txd_info.size = min(frag_size, MTK_TX_DMA_BUF_LEN); -+ txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && -+ !(frag_size - txd_info.size); -+ txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, -+ offset, txd_info.size, -+ DMA_TO_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) - goto err_dma; - -- if (i == nr_frags - 1 && -- (frag_size - frag_map_size) == 0) -- last_frag = true; -- -- WRITE_ONCE(txd->txd1, mapped_addr); -- WRITE_ONCE(txd->txd3, (TX_DMA_SWC | -- TX_DMA_PLEN0(frag_map_size) | -- last_frag * TX_DMA_LS0)); -- WRITE_ONCE(txd->txd4, fport); -+ mtk_tx_set_dma_desc(dev, txd, &txd_info); - - tx_buf = mtk_desc_to_tx_buf(ring, txd); - if (new_desc) -@@ -1074,20 +1084,17 @@ static int mtk_tx_map(struct sk_buff *sk - tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : - MTK_TX_FLAGS_FPORT1; - -- setup_tx_buf(eth, tx_buf, txd_pdma, mapped_addr, -- frag_map_size, k++); -+ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, -+ txd_info.size, k++); - -- frag_size -= frag_map_size; -- offset += frag_map_size; -+ frag_size -= txd_info.size; -+ offset += txd_info.size; - } - } - - /* store skb to cleanup */ - itx_buf->skb = skb; - -- WRITE_ONCE(itxd->txd4, txd4); -- WRITE_ONCE(itxd->txd3, (TX_DMA_SWC | TX_DMA_PLEN0(skb_headlen(skb)) | -- (!nr_frags * TX_DMA_LS0))); - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { - if (k & 0x1) - txd_pdma->txd2 |= TX_DMA_LS0; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -843,6 +843,17 @@ enum mkt_eth_capabilities { - MTK_MUX_U3_GMAC2_TO_QPHY | \ - MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) - -+struct mtk_tx_dma_desc_info { -+ dma_addr_t addr; -+ u32 size; -+ u16 vlan_tci; -+ u8 gso:1; -+ u8 csum:1; -+ u8 vlan:1; -+ u8 first:1; -+ u8 last:1; -+}; -+ - /* struct mtk_eth_data - This is the structure holding all differences - * among various plaforms - * @ana_rgc3: The offset for register ANA_RGC3 related to diff --git a/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch deleted file mode 100644 index f5206bba00b..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-19-net-ethernet-mtk_eth_soc-add-txd_size-to-mtk_soc_dat.patch +++ /dev/null @@ -1,167 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:28 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add txd_size to mtk_soc_data - -In order to remove mtk_tx_dma size dependency, introduce txd_size in -mtk_soc_data data structure. Rely on txd_size in mtk_init_fq_dma() and -mtk_dma_free() routines. -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -838,20 +838,20 @@ static void *mtk_max_lro_buf_alloc(gfp_t - /* the qdma core needs scratch memory to be setup */ - static int mtk_init_fq_dma(struct mtk_eth *eth) - { -+ const struct mtk_soc_data *soc = eth->soc; - dma_addr_t phy_ring_tail; - int cnt = MTK_DMA_SIZE; - dma_addr_t dma_addr; - int i; - - eth->scratch_ring = dma_alloc_coherent(eth->dma_dev, -- cnt * sizeof(struct mtk_tx_dma), -+ cnt * soc->txrx.txd_size, - ð->phy_scratch_ring, - GFP_KERNEL); - if (unlikely(!eth->scratch_ring)) - return -ENOMEM; - -- eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, -- GFP_KERNEL); -+ eth->scratch_head = kcalloc(cnt, MTK_QDMA_PAGE_SIZE, GFP_KERNEL); - if (unlikely(!eth->scratch_head)) - return -ENOMEM; - -@@ -861,16 +861,19 @@ static int mtk_init_fq_dma(struct mtk_et - if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; - -- phy_ring_tail = eth->phy_scratch_ring + -- (sizeof(struct mtk_tx_dma) * (cnt - 1)); -+ phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); - - for (i = 0; i < cnt; i++) { -- eth->scratch_ring[i].txd1 = -- (dma_addr + (i * MTK_QDMA_PAGE_SIZE)); -+ struct mtk_tx_dma *txd; -+ -+ txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; -+ txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; - if (i < cnt - 1) -- eth->scratch_ring[i].txd2 = (eth->phy_scratch_ring + -- ((i + 1) * sizeof(struct mtk_tx_dma))); -- eth->scratch_ring[i].txd3 = TX_DMA_SDL(MTK_QDMA_PAGE_SIZE); -+ txd->txd2 = eth->phy_scratch_ring + -+ (i + 1) * soc->txrx.txd_size; -+ -+ txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); -+ txd->txd4 = 0; - } - - mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); -@@ -2170,6 +2173,7 @@ static int mtk_dma_init(struct mtk_eth * - - static void mtk_dma_free(struct mtk_eth *eth) - { -+ const struct mtk_soc_data *soc = eth->soc; - int i; - - for (i = 0; i < MTK_MAC_COUNT; i++) -@@ -2177,9 +2181,8 @@ static void mtk_dma_free(struct mtk_eth - netdev_reset_queue(eth->netdev[i]); - if (eth->scratch_ring) { - dma_free_coherent(eth->dma_dev, -- MTK_DMA_SIZE * sizeof(struct mtk_tx_dma), -- eth->scratch_ring, -- eth->phy_scratch_ring); -+ MTK_DMA_SIZE * soc->txrx.txd_size, -+ eth->scratch_ring, eth->phy_scratch_ring); - eth->scratch_ring = NULL; - eth->phy_scratch_ring = 0; - } -@@ -3391,6 +3394,9 @@ static const struct mtk_soc_data mt2701_ - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7623_CLKS_BITMAP, - .required_pctl = true, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - static const struct mtk_soc_data mt7621_data = { -@@ -3399,6 +3405,9 @@ static const struct mtk_soc_data mt7621_ - .required_clks = MT7621_CLKS_BITMAP, - .required_pctl = false, - .offload_version = 2, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - static const struct mtk_soc_data mt7622_data = { -@@ -3408,6 +3417,9 @@ static const struct mtk_soc_data mt7622_ - .required_clks = MT7622_CLKS_BITMAP, - .required_pctl = false, - .offload_version = 2, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - static const struct mtk_soc_data mt7623_data = { -@@ -3416,6 +3428,9 @@ static const struct mtk_soc_data mt7623_ - .required_clks = MT7623_CLKS_BITMAP, - .required_pctl = true, - .offload_version = 2, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - static const struct mtk_soc_data mt7629_data = { -@@ -3424,6 +3439,9 @@ static const struct mtk_soc_data mt7629_ - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7629_CLKS_BITMAP, - .required_pctl = false, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - static const struct mtk_soc_data rt5350_data = { -@@ -3431,6 +3449,9 @@ static const struct mtk_soc_data rt5350_ - .hw_features = MTK_HW_FEATURES_MT7628, - .required_clks = MT7628_CLKS_BITMAP, - .required_pctl = false, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma), -+ }, - }; - - const struct of_device_id of_mtk_match[] = { ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -864,6 +864,7 @@ struct mtk_tx_dma_desc_info { - * the target SoC - * @required_pctl A bool value to show whether the SoC requires - * the extra setup for those pins used by GMAC. -+ * @txd_size Tx DMA descriptor size. - */ - struct mtk_soc_data { - u32 ana_rgc3; -@@ -872,6 +873,9 @@ struct mtk_soc_data { - bool required_pctl; - u8 offload_version; - netdev_features_t hw_features; -+ struct { -+ u32 txd_size; -+ } txrx; - }; - - /* currently no SoC has more than 2 macs */ diff --git a/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch b/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch deleted file mode 100644 index ebe1ee3d59a..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-20-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_tx_.patch +++ /dev/null @@ -1,78 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:29 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in - mtk_tx_alloc/mtk_tx_clean - -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1625,8 +1625,10 @@ static int mtk_napi_rx(struct napi_struc - - static int mtk_tx_alloc(struct mtk_eth *eth) - { -+ const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_ring *ring = ð->tx_ring; -- int i, sz = sizeof(*ring->dma); -+ int i, sz = soc->txrx.txd_size; -+ struct mtk_tx_dma *txd; - - ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), - GFP_KERNEL); -@@ -1642,8 +1644,10 @@ static int mtk_tx_alloc(struct mtk_eth * - int next = (i + 1) % MTK_DMA_SIZE; - u32 next_ptr = ring->phys + next * sz; - -- ring->dma[i].txd2 = next_ptr; -- ring->dma[i].txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; -+ txd = (void *)ring->dma + i * sz; -+ txd->txd2 = next_ptr; -+ txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; -+ txd->txd4 = 0; - } - - /* On MT7688 (PDMA only) this driver uses the ring->dma structs -@@ -1665,7 +1669,7 @@ static int mtk_tx_alloc(struct mtk_eth * - ring->dma_size = MTK_DMA_SIZE; - atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); - ring->next_free = &ring->dma[0]; -- ring->last_free = &ring->dma[MTK_DMA_SIZE - 1]; -+ ring->last_free = (void *)txd; - ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); - ring->thresh = MAX_SKB_FRAGS; - -@@ -1698,6 +1702,7 @@ no_tx_mem: - - static void mtk_tx_clean(struct mtk_eth *eth) - { -+ const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_ring *ring = ð->tx_ring; - int i; - -@@ -1710,17 +1715,15 @@ static void mtk_tx_clean(struct mtk_eth - - if (ring->dma) { - dma_free_coherent(eth->dma_dev, -- MTK_DMA_SIZE * sizeof(*ring->dma), -- ring->dma, -- ring->phys); -+ MTK_DMA_SIZE * soc->txrx.txd_size, -+ ring->dma, ring->phys); - ring->dma = NULL; - } - - if (ring->dma_pdma) { - dma_free_coherent(eth->dma_dev, -- MTK_DMA_SIZE * sizeof(*ring->dma_pdma), -- ring->dma_pdma, -- ring->phys_pdma); -+ MTK_DMA_SIZE * soc->txrx.txd_size, -+ ring->dma_pdma, ring->phys_pdma); - ring->dma_pdma = NULL; - } - } diff --git a/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch b/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch deleted file mode 100644 index 053412e7490..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-21-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-mtk_des.patch +++ /dev/null @@ -1,109 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:30 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in - mtk_desc_to_tx_buf - -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -891,10 +891,11 @@ static inline void *mtk_qdma_phys_to_vir - return ret + (desc - ring->phys); - } - --static inline struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, -- struct mtk_tx_dma *txd) -+static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, -+ struct mtk_tx_dma *txd, -+ u32 txd_size) - { -- int idx = txd - ring->dma; -+ int idx = ((void *)txd - (void *)ring->dma) / txd_size; - - return &ring->buf[idx]; - } -@@ -1016,6 +1017,7 @@ static int mtk_tx_map(struct sk_buff *sk - }; - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; -+ const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_dma *itxd, *txd; - struct mtk_tx_dma *itxd_pdma, *txd_pdma; - struct mtk_tx_buf *itx_buf, *tx_buf; -@@ -1027,7 +1029,7 @@ static int mtk_tx_map(struct sk_buff *sk - if (itxd == ring->last_free) - return -ENOMEM; - -- itx_buf = mtk_desc_to_tx_buf(ring, itxd); -+ itx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size); - memset(itx_buf, 0, sizeof(*itx_buf)); - - txd_info.addr = dma_map_single(eth->dma_dev, skb->data, txd_info.size, -@@ -1055,7 +1057,7 @@ static int mtk_tx_map(struct sk_buff *sk - while (frag_size) { - bool new_desc = true; - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA) || -+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || - (i & 0x1)) { - txd = mtk_qdma_phys_to_virt(ring, txd->txd2); - txd_pdma = qdma_to_pdma(ring, txd); -@@ -1079,7 +1081,8 @@ static int mtk_tx_map(struct sk_buff *sk - - mtk_tx_set_dma_desc(dev, txd, &txd_info); - -- tx_buf = mtk_desc_to_tx_buf(ring, txd); -+ tx_buf = mtk_desc_to_tx_buf(ring, txd, -+ soc->txrx.txd_size); - if (new_desc) - memset(tx_buf, 0, sizeof(*tx_buf)); - tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; -@@ -1098,7 +1101,7 @@ static int mtk_tx_map(struct sk_buff *sk - /* store skb to cleanup */ - itx_buf->skb = skb; - -- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - if (k & 0x1) - txd_pdma->txd2 |= TX_DMA_LS0; - else -@@ -1116,7 +1119,7 @@ static int mtk_tx_map(struct sk_buff *sk - */ - wmb(); - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || - !netdev_xmit_more()) - mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); -@@ -1130,13 +1133,13 @@ static int mtk_tx_map(struct sk_buff *sk - - err_dma: - do { -- tx_buf = mtk_desc_to_tx_buf(ring, itxd); -+ tx_buf = mtk_desc_to_tx_buf(ring, itxd, soc->txrx.txd_size); - - /* unmap dma */ - mtk_tx_unmap(eth, tx_buf, false); - - itxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; -- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) -+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) - itxd_pdma->txd2 = TX_DMA_DESP2_DEF; - - itxd = mtk_qdma_phys_to_virt(ring, itxd->txd2); -@@ -1450,7 +1453,8 @@ static int mtk_poll_tx_qdma(struct mtk_e - if ((desc->txd3 & TX_DMA_OWNER_CPU) == 0) - break; - -- tx_buf = mtk_desc_to_tx_buf(ring, desc); -+ tx_buf = mtk_desc_to_tx_buf(ring, desc, -+ eth->soc->txrx.txd_size); - if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) - mac = 1; - diff --git a/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch b/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch deleted file mode 100644 index 251d583f296..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-22-net-ethernet-mtk_eth_soc-rely-on-txd_size-in-txd_to_.patch +++ /dev/null @@ -1,39 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:31 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size in txd_to_idx - -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -906,9 +906,10 @@ static struct mtk_tx_dma *qdma_to_pdma(s - return ring->dma_pdma - ring->dma + dma; - } - --static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma) -+static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma, -+ u32 txd_size) - { -- return ((void *)dma - (void *)ring->dma) / sizeof(*dma); -+ return ((void *)dma - (void *)ring->dma) / txd_size; - } - - static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1124,8 +1125,10 @@ static int mtk_tx_map(struct sk_buff *sk - !netdev_xmit_more()) - mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); - } else { -- int next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd), -- ring->dma_size); -+ int next_idx; -+ -+ next_idx = NEXT_DESP_IDX(txd_to_idx(ring, txd, soc->txrx.txd_size), -+ ring->dma_size); - mtk_w32(eth, next_idx, MT7628_TX_CTX_IDX0); - } - diff --git a/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch b/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch deleted file mode 100644 index ec206f28d64..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-23-net-ethernet-mtk_eth_soc-add-rxd_size-to-mtk_soc_dat.patch +++ /dev/null @@ -1,102 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:32 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add rxd_size to mtk_soc_data - -Similar to tx counterpart, introduce rxd_size in mtk_soc_data data -structure. -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1776,7 +1776,7 @@ static int mtk_rx_alloc(struct mtk_eth * - } - - ring->dma = dma_alloc_coherent(eth->dma_dev, -- rx_dma_size * sizeof(*ring->dma), -+ rx_dma_size * eth->soc->txrx.rxd_size, - &ring->phys, GFP_KERNEL); - if (!ring->dma) - return -ENOMEM; -@@ -1834,9 +1834,8 @@ static void mtk_rx_clean(struct mtk_eth - - if (ring->dma) { - dma_free_coherent(eth->dma_dev, -- ring->dma_size * sizeof(*ring->dma), -- ring->dma, -- ring->phys); -+ ring->dma_size * eth->soc->txrx.rxd_size, -+ ring->dma, ring->phys); - ring->dma = NULL; - } - } -@@ -3406,6 +3405,7 @@ static const struct mtk_soc_data mt2701_ - .required_pctl = true, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - -@@ -3417,6 +3417,7 @@ static const struct mtk_soc_data mt7621_ - .offload_version = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - -@@ -3429,6 +3430,7 @@ static const struct mtk_soc_data mt7622_ - .offload_version = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - -@@ -3440,6 +3442,7 @@ static const struct mtk_soc_data mt7623_ - .offload_version = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - -@@ -3451,6 +3454,7 @@ static const struct mtk_soc_data mt7629_ - .required_pctl = false, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - -@@ -3461,6 +3465,7 @@ static const struct mtk_soc_data rt5350_ - .required_pctl = false, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), -+ .rxd_size = sizeof(struct mtk_rx_dma), - }, - }; - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -865,6 +865,7 @@ struct mtk_tx_dma_desc_info { - * @required_pctl A bool value to show whether the SoC requires - * the extra setup for those pins used by GMAC. - * @txd_size Tx DMA descriptor size. -+ * @rxd_size Rx DMA descriptor size. - */ - struct mtk_soc_data { - u32 ana_rgc3; -@@ -875,6 +876,7 @@ struct mtk_soc_data { - netdev_features_t hw_features; - struct { - u32 txd_size; -+ u32 rxd_size; - } txrx; - }; - diff --git a/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch deleted file mode 100644 index eb92b8c7a22..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-24-net-ethernet-mtk_eth_soc-rely-on-txd_size-field-in-m.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:33 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on txd_size field in - mtk_poll_tx/mtk_poll_rx - -This is a preliminary to ad mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1265,9 +1265,12 @@ static struct mtk_rx_ring *mtk_get_rx_ri - return ð->rx_ring[0]; - - for (i = 0; i < MTK_MAX_RX_RING_NUM; i++) { -+ struct mtk_rx_dma *rxd; -+ - ring = ð->rx_ring[i]; - idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); -- if (ring->dma[idx].rxd2 & RX_DMA_DONE) { -+ rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; -+ if (rxd->rxd2 & RX_DMA_DONE) { - ring->calc_idx_update = true; - return ring; - } -@@ -1318,7 +1321,7 @@ static int mtk_poll_rx(struct napi_struc - goto rx_done; - - idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); -- rxd = &ring->dma[idx]; -+ rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; - data = ring->data[idx]; - - if (!mtk_rx_get_desc(&trxd, rxd)) -@@ -1510,7 +1513,7 @@ static int mtk_poll_tx_pdma(struct mtk_e - - mtk_tx_unmap(eth, tx_buf, true); - -- desc = &ring->dma[cpu]; -+ desc = (void *)ring->dma + cpu * eth->soc->txrx.txd_size; - ring->last_free = desc; - atomic_inc(&ring->free_count); - diff --git a/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch b/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch deleted file mode 100644 index 456eec247c5..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-25-net-ethernet-mtk_eth_soc-rely-on-rxd_size-field-in-m.patch +++ /dev/null @@ -1,68 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:34 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on rxd_size field in - mtk_rx_alloc/mtk_rx_clean - -Remove mtk_rx_dma structure layout dependency in mtk_rx_alloc/mtk_rx_clean. -Initialize to 0 rxd3 and rxd4 in mtk_rx_alloc. -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1785,18 +1785,25 @@ static int mtk_rx_alloc(struct mtk_eth * - return -ENOMEM; - - for (i = 0; i < rx_dma_size; i++) { -+ struct mtk_rx_dma *rxd; -+ - dma_addr_t dma_addr = dma_map_single(eth->dma_dev, - ring->data[i] + NET_SKB_PAD + eth->ip_align, - ring->buf_size, - DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; -- ring->dma[i].rxd1 = (unsigned int)dma_addr; -+ -+ rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; -+ rxd->rxd1 = (unsigned int)dma_addr; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) -- ring->dma[i].rxd2 = RX_DMA_LSO; -+ rxd->rxd2 = RX_DMA_LSO; - else -- ring->dma[i].rxd2 = RX_DMA_PLEN0(ring->buf_size); -+ rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); -+ -+ rxd->rxd3 = 0; -+ rxd->rxd4 = 0; - } - ring->dma_size = rx_dma_size; - ring->calc_idx_update = false; -@@ -1821,14 +1828,17 @@ static void mtk_rx_clean(struct mtk_eth - - if (ring->data && ring->dma) { - for (i = 0; i < ring->dma_size; i++) { -+ struct mtk_rx_dma *rxd; -+ - if (!ring->data[i]) - continue; -- if (!ring->dma[i].rxd1) -+ -+ rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; -+ if (!rxd->rxd1) - continue; -- dma_unmap_single(eth->dma_dev, -- ring->dma[i].rxd1, -- ring->buf_size, -- DMA_FROM_DEVICE); -+ -+ dma_unmap_single(eth->dma_dev, rxd->rxd1, -+ ring->buf_size, DMA_FROM_DEVICE); - skb_free_frag(ring->data[i]); - } - kfree(ring->data); diff --git a/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch b/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch deleted file mode 100644 index 272f782877f..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-26-net-ethernet-mtk_eth_soc-introduce-device-register-m.patch +++ /dev/null @@ -1,814 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:35 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce device register map - -Introduce reg_map structure to add the capability to support different -register definitions. Move register definitions in mtk_regmap structure. -This is a preliminary patch to introduce mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -34,6 +34,59 @@ MODULE_PARM_DESC(msg_level, "Message lev - #define MTK_ETHTOOL_STAT(x) { #x, \ - offsetof(struct mtk_hw_stats, x) / sizeof(u64) } - -+static const struct mtk_reg_map mtk_reg_map = { -+ .tx_irq_mask = 0x1a1c, -+ .tx_irq_status = 0x1a18, -+ .pdma = { -+ .rx_ptr = 0x0900, -+ .rx_cnt_cfg = 0x0904, -+ .pcrx_ptr = 0x0908, -+ .glo_cfg = 0x0a04, -+ .rst_idx = 0x0a08, -+ .delay_irq = 0x0a0c, -+ .irq_status = 0x0a20, -+ .irq_mask = 0x0a28, -+ .int_grp = 0x0a50, -+ }, -+ .qdma = { -+ .qtx_cfg = 0x1800, -+ .rx_ptr = 0x1900, -+ .rx_cnt_cfg = 0x1904, -+ .qcrx_ptr = 0x1908, -+ .glo_cfg = 0x1a04, -+ .rst_idx = 0x1a08, -+ .delay_irq = 0x1a0c, -+ .fc_th = 0x1a10, -+ .int_grp = 0x1a20, -+ .hred = 0x1a44, -+ .ctx_ptr = 0x1b00, -+ .dtx_ptr = 0x1b04, -+ .crx_ptr = 0x1b10, -+ .drx_ptr = 0x1b14, -+ .fq_head = 0x1b20, -+ .fq_tail = 0x1b24, -+ .fq_count = 0x1b28, -+ .fq_blen = 0x1b2c, -+ }, -+ .gdm1_cnt = 0x2400, -+}; -+ -+static const struct mtk_reg_map mt7628_reg_map = { -+ .tx_irq_mask = 0x0a28, -+ .tx_irq_status = 0x0a20, -+ .pdma = { -+ .rx_ptr = 0x0900, -+ .rx_cnt_cfg = 0x0904, -+ .pcrx_ptr = 0x0908, -+ .glo_cfg = 0x0a04, -+ .rst_idx = 0x0a08, -+ .delay_irq = 0x0a0c, -+ .irq_status = 0x0a20, -+ .irq_mask = 0x0a28, -+ .int_grp = 0x0a50, -+ }, -+}; -+ - /* strings used by ethtool */ - static const struct mtk_ethtool_stats { - char str[ETH_GSTRING_LEN]; -@@ -619,8 +672,8 @@ static inline void mtk_tx_irq_disable(st - u32 val; - - spin_lock_irqsave(ð->tx_irq_lock, flags); -- val = mtk_r32(eth, eth->tx_int_mask_reg); -- mtk_w32(eth, val & ~mask, eth->tx_int_mask_reg); -+ val = mtk_r32(eth, eth->soc->reg_map->tx_irq_mask); -+ mtk_w32(eth, val & ~mask, eth->soc->reg_map->tx_irq_mask); - spin_unlock_irqrestore(ð->tx_irq_lock, flags); - } - -@@ -630,8 +683,8 @@ static inline void mtk_tx_irq_enable(str - u32 val; - - spin_lock_irqsave(ð->tx_irq_lock, flags); -- val = mtk_r32(eth, eth->tx_int_mask_reg); -- mtk_w32(eth, val | mask, eth->tx_int_mask_reg); -+ val = mtk_r32(eth, eth->soc->reg_map->tx_irq_mask); -+ mtk_w32(eth, val | mask, eth->soc->reg_map->tx_irq_mask); - spin_unlock_irqrestore(ð->tx_irq_lock, flags); - } - -@@ -641,8 +694,8 @@ static inline void mtk_rx_irq_disable(st - u32 val; - - spin_lock_irqsave(ð->rx_irq_lock, flags); -- val = mtk_r32(eth, MTK_PDMA_INT_MASK); -- mtk_w32(eth, val & ~mask, MTK_PDMA_INT_MASK); -+ val = mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask); -+ mtk_w32(eth, val & ~mask, eth->soc->reg_map->pdma.irq_mask); - spin_unlock_irqrestore(ð->rx_irq_lock, flags); - } - -@@ -652,8 +705,8 @@ static inline void mtk_rx_irq_enable(str - u32 val; - - spin_lock_irqsave(ð->rx_irq_lock, flags); -- val = mtk_r32(eth, MTK_PDMA_INT_MASK); -- mtk_w32(eth, val | mask, MTK_PDMA_INT_MASK); -+ val = mtk_r32(eth, eth->soc->reg_map->pdma.irq_mask); -+ mtk_w32(eth, val | mask, eth->soc->reg_map->pdma.irq_mask); - spin_unlock_irqrestore(ð->rx_irq_lock, flags); - } - -@@ -704,39 +757,39 @@ void mtk_stats_update_mac(struct mtk_mac - hw_stats->rx_checksum_errors += - mtk_r32(mac->hw, MT7628_SDM_CS_ERR); - } else { -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - unsigned int offs = hw_stats->reg_offset; - u64 stats; - -- hw_stats->rx_bytes += mtk_r32(mac->hw, -- MTK_GDM1_RX_GBCNT_L + offs); -- stats = mtk_r32(mac->hw, MTK_GDM1_RX_GBCNT_H + offs); -+ hw_stats->rx_bytes += mtk_r32(mac->hw, reg_map->gdm1_cnt + offs); -+ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x4 + offs); - if (stats) - hw_stats->rx_bytes += (stats << 32); - hw_stats->rx_packets += -- mtk_r32(mac->hw, MTK_GDM1_RX_GPCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x8 + offs); - hw_stats->rx_overflow += -- mtk_r32(mac->hw, MTK_GDM1_RX_OERCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x10 + offs); - hw_stats->rx_fcs_errors += -- mtk_r32(mac->hw, MTK_GDM1_RX_FERCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x14 + offs); - hw_stats->rx_short_errors += -- mtk_r32(mac->hw, MTK_GDM1_RX_SERCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x18 + offs); - hw_stats->rx_long_errors += -- mtk_r32(mac->hw, MTK_GDM1_RX_LENCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x1c + offs); - hw_stats->rx_checksum_errors += -- mtk_r32(mac->hw, MTK_GDM1_RX_CERCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x20 + offs); - hw_stats->rx_flow_control_packets += -- mtk_r32(mac->hw, MTK_GDM1_RX_FCCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x24 + offs); - hw_stats->tx_skip += -- mtk_r32(mac->hw, MTK_GDM1_TX_SKIPCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs); - hw_stats->tx_collisions += -- mtk_r32(mac->hw, MTK_GDM1_TX_COLCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs); - hw_stats->tx_bytes += -- mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_L + offs); -- stats = mtk_r32(mac->hw, MTK_GDM1_TX_GBCNT_H + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs); -+ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs); - if (stats) - hw_stats->tx_bytes += (stats << 32); - hw_stats->tx_packets += -- mtk_r32(mac->hw, MTK_GDM1_TX_GPCNT + offs); -+ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs); - } - - u64_stats_update_end(&hw_stats->syncp); -@@ -876,10 +929,10 @@ static int mtk_init_fq_dma(struct mtk_et - txd->txd4 = 0; - } - -- mtk_w32(eth, eth->phy_scratch_ring, MTK_QDMA_FQ_HEAD); -- mtk_w32(eth, phy_ring_tail, MTK_QDMA_FQ_TAIL); -- mtk_w32(eth, (cnt << 16) | cnt, MTK_QDMA_FQ_CNT); -- mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, MTK_QDMA_FQ_BLEN); -+ mtk_w32(eth, eth->phy_scratch_ring, soc->reg_map->qdma.fq_head); -+ mtk_w32(eth, phy_ring_tail, soc->reg_map->qdma.fq_tail); -+ mtk_w32(eth, (cnt << 16) | cnt, soc->reg_map->qdma.fq_count); -+ mtk_w32(eth, MTK_QDMA_PAGE_SIZE << 16, soc->reg_map->qdma.fq_blen); - - return 0; - } -@@ -1123,7 +1176,7 @@ static int mtk_tx_map(struct sk_buff *sk - if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) || - !netdev_xmit_more()) -- mtk_w32(eth, txd->txd2, MTK_QTX_CTX_PTR); -+ mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); - } else { - int next_idx; - -@@ -1440,6 +1493,7 @@ rx_done: - static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget, - unsigned int *done, unsigned int *bytes) - { -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - struct mtk_tx_ring *ring = ð->tx_ring; - struct mtk_tx_dma *desc; - struct sk_buff *skb; -@@ -1447,7 +1501,7 @@ static int mtk_poll_tx_qdma(struct mtk_e - u32 cpu, dma; - - cpu = ring->last_free_ptr; -- dma = mtk_r32(eth, MTK_QTX_DRX_PTR); -+ dma = mtk_r32(eth, reg_map->qdma.drx_ptr); - - desc = mtk_qdma_phys_to_virt(ring, cpu); - -@@ -1482,7 +1536,7 @@ static int mtk_poll_tx_qdma(struct mtk_e - } - - ring->last_free_ptr = cpu; -- mtk_w32(eth, cpu, MTK_QTX_CRX_PTR); -+ mtk_w32(eth, cpu, reg_map->qdma.crx_ptr); - - return budget; - } -@@ -1575,24 +1629,25 @@ static void mtk_handle_status_irq(struct - static int mtk_napi_tx(struct napi_struct *napi, int budget) - { - struct mtk_eth *eth = container_of(napi, struct mtk_eth, tx_napi); -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - int tx_done = 0; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) - mtk_handle_status_irq(eth); -- mtk_w32(eth, MTK_TX_DONE_INT, eth->tx_int_status_reg); -+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->tx_irq_status); - tx_done = mtk_poll_tx(eth, budget); - - if (unlikely(netif_msg_intr(eth))) { - dev_info(eth->dev, - "done tx %d, intr 0x%08x/0x%x\n", tx_done, -- mtk_r32(eth, eth->tx_int_status_reg), -- mtk_r32(eth, eth->tx_int_mask_reg)); -+ mtk_r32(eth, reg_map->tx_irq_status), -+ mtk_r32(eth, reg_map->tx_irq_mask)); - } - - if (tx_done == budget) - return budget; - -- if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT) -+ if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT) - return budget; - - if (napi_complete_done(napi, tx_done)) -@@ -1604,6 +1659,7 @@ static int mtk_napi_tx(struct napi_struc - static int mtk_napi_rx(struct napi_struct *napi, int budget) - { - struct mtk_eth *eth = container_of(napi, struct mtk_eth, rx_napi); -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - int rx_done_total = 0; - - mtk_handle_status_irq(eth); -@@ -1611,21 +1667,21 @@ static int mtk_napi_rx(struct napi_struc - do { - int rx_done; - -- mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_STATUS); -+ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.irq_status); - rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth); - rx_done_total += rx_done; - - if (unlikely(netif_msg_intr(eth))) { - dev_info(eth->dev, - "done rx %d, intr 0x%08x/0x%x\n", rx_done, -- mtk_r32(eth, MTK_PDMA_INT_STATUS), -- mtk_r32(eth, MTK_PDMA_INT_MASK)); -+ mtk_r32(eth, reg_map->pdma.irq_status), -+ mtk_r32(eth, reg_map->pdma.irq_mask)); - } - - if (rx_done_total == budget) - return budget; - -- } while (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT); -+ } while (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT); - - if (napi_complete_done(napi, rx_done_total)) - mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -@@ -1688,20 +1744,20 @@ static int mtk_tx_alloc(struct mtk_eth * - */ - wmb(); - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -- mtk_w32(eth, ring->phys, MTK_QTX_CTX_PTR); -- mtk_w32(eth, ring->phys, MTK_QTX_DTX_PTR); -+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { -+ mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); -+ mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); - mtk_w32(eth, - ring->phys + ((MTK_DMA_SIZE - 1) * sz), -- MTK_QTX_CRX_PTR); -- mtk_w32(eth, ring->last_free_ptr, MTK_QTX_DRX_PTR); -+ soc->reg_map->qdma.crx_ptr); -+ mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); - mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES, -- MTK_QTX_CFG(0)); -+ soc->reg_map->qdma.qtx_cfg); - } else { - mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); - mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0); - mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); -- mtk_w32(eth, MT7628_PST_DTX_IDX0, MTK_PDMA_RST_IDX); -+ mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx); - } - - return 0; -@@ -1740,6 +1796,7 @@ static void mtk_tx_clean(struct mtk_eth - - static int mtk_rx_alloc(struct mtk_eth *eth, int ring_no, int rx_flag) - { -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - struct mtk_rx_ring *ring; - int rx_data_len, rx_dma_size; - int i; -@@ -1808,16 +1865,18 @@ static int mtk_rx_alloc(struct mtk_eth * - ring->dma_size = rx_dma_size; - ring->calc_idx_update = false; - ring->calc_idx = rx_dma_size - 1; -- ring->crx_idx_reg = MTK_PRX_CRX_IDX_CFG(ring_no); -+ ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + ring_no * MTK_QRX_OFFSET; - /* make sure that all changes to the dma ring are flushed before we - * continue - */ - wmb(); - -- mtk_w32(eth, ring->phys, MTK_PRX_BASE_PTR_CFG(ring_no) + offset); -- mtk_w32(eth, rx_dma_size, MTK_PRX_MAX_CNT_CFG(ring_no) + offset); -+ mtk_w32(eth, ring->phys, -+ reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET + offset); -+ mtk_w32(eth, rx_dma_size, -+ reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET + offset); - mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); -- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), MTK_PDMA_RST_IDX + offset); -+ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), reg_map->pdma.rst_idx + offset); - - return 0; - } -@@ -2126,9 +2185,9 @@ static int mtk_dma_busy_wait(struct mtk_ - u32 val; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) -- reg = MTK_QDMA_GLO_CFG; -+ reg = eth->soc->reg_map->qdma.glo_cfg; - else -- reg = MTK_PDMA_GLO_CFG; -+ reg = eth->soc->reg_map->pdma.glo_cfg; - - ret = readx_poll_timeout_atomic(__raw_readl, eth->base + reg, val, - !(val & (MTK_RX_DMA_BUSY | MTK_TX_DMA_BUSY)), -@@ -2186,8 +2245,8 @@ static int mtk_dma_init(struct mtk_eth * - * automatically - */ - mtk_w32(eth, FC_THRES_DROP_MODE | FC_THRES_DROP_EN | -- FC_THRES_MIN, MTK_QDMA_FC_THRES); -- mtk_w32(eth, 0x0, MTK_QDMA_HRED2); -+ FC_THRES_MIN, eth->soc->reg_map->qdma.fc_th); -+ mtk_w32(eth, 0x0, eth->soc->reg_map->qdma.hred); - } - - return 0; -@@ -2261,13 +2320,14 @@ static irqreturn_t mtk_handle_irq_tx(int - static irqreturn_t mtk_handle_irq(int irq, void *_eth) - { - struct mtk_eth *eth = _eth; -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - -- if (mtk_r32(eth, MTK_PDMA_INT_MASK) & MTK_RX_DONE_INT) { -- if (mtk_r32(eth, MTK_PDMA_INT_STATUS) & MTK_RX_DONE_INT) -+ if (mtk_r32(eth, reg_map->pdma.irq_mask) & MTK_RX_DONE_INT) { -+ if (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT) - mtk_handle_irq_rx(irq, _eth); - } -- if (mtk_r32(eth, eth->tx_int_mask_reg) & MTK_TX_DONE_INT) { -- if (mtk_r32(eth, eth->tx_int_status_reg) & MTK_TX_DONE_INT) -+ if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) { -+ if (mtk_r32(eth, reg_map->tx_irq_status) & MTK_TX_DONE_INT) - mtk_handle_irq_tx(irq, _eth); - } - -@@ -2291,6 +2351,7 @@ static void mtk_poll_controller(struct n - static int mtk_start_dma(struct mtk_eth *eth) - { - u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - int err; - - err = mtk_dma_init(eth); -@@ -2305,16 +2366,15 @@ static int mtk_start_dma(struct mtk_eth - MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | - MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | - MTK_RX_BT_32DWORDS, -- MTK_QDMA_GLO_CFG); -- -+ reg_map->qdma.glo_cfg); - mtk_w32(eth, - MTK_RX_DMA_EN | rx_2b_offset | - MTK_RX_BT_32DWORDS | MTK_MULTI_EN, -- MTK_PDMA_GLO_CFG); -+ reg_map->pdma.glo_cfg); - } else { - mtk_w32(eth, MTK_TX_WB_DDONE | MTK_TX_DMA_EN | MTK_RX_DMA_EN | - MTK_MULTI_EN | MTK_PDMA_SIZE_8DWORDS, -- MTK_PDMA_GLO_CFG); -+ reg_map->pdma.glo_cfg); - } - - return 0; -@@ -2440,8 +2500,8 @@ static int mtk_stop(struct net_device *d - cancel_work_sync(ð->tx_dim.work); - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) -- mtk_stop_dma(eth, MTK_QDMA_GLO_CFG); -- mtk_stop_dma(eth, MTK_PDMA_GLO_CFG); -+ mtk_stop_dma(eth, eth->soc->reg_map->qdma.glo_cfg); -+ mtk_stop_dma(eth, eth->soc->reg_map->pdma.glo_cfg); - - mtk_dma_free(eth); - -@@ -2495,6 +2555,7 @@ static void mtk_dim_rx(struct work_struc - { - struct dim *dim = container_of(work, struct dim, work); - struct mtk_eth *eth = container_of(dim, struct mtk_eth, rx_dim); -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - struct dim_cq_moder cur_profile; - u32 val, cur; - -@@ -2502,7 +2563,7 @@ static void mtk_dim_rx(struct work_struc - dim->profile_ix); - spin_lock_bh(ð->dim_lock); - -- val = mtk_r32(eth, MTK_PDMA_DELAY_INT); -+ val = mtk_r32(eth, reg_map->pdma.delay_irq); - val &= MTK_PDMA_DELAY_TX_MASK; - val |= MTK_PDMA_DELAY_RX_EN; - -@@ -2512,9 +2573,9 @@ static void mtk_dim_rx(struct work_struc - cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); - val |= cur << MTK_PDMA_DELAY_RX_PINT_SHIFT; - -- mtk_w32(eth, val, MTK_PDMA_DELAY_INT); -+ mtk_w32(eth, val, reg_map->pdma.delay_irq); - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) -- mtk_w32(eth, val, MTK_QDMA_DELAY_INT); -+ mtk_w32(eth, val, reg_map->qdma.delay_irq); - - spin_unlock_bh(ð->dim_lock); - -@@ -2525,6 +2586,7 @@ static void mtk_dim_tx(struct work_struc - { - struct dim *dim = container_of(work, struct dim, work); - struct mtk_eth *eth = container_of(dim, struct mtk_eth, tx_dim); -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - struct dim_cq_moder cur_profile; - u32 val, cur; - -@@ -2532,7 +2594,7 @@ static void mtk_dim_tx(struct work_struc - dim->profile_ix); - spin_lock_bh(ð->dim_lock); - -- val = mtk_r32(eth, MTK_PDMA_DELAY_INT); -+ val = mtk_r32(eth, reg_map->pdma.delay_irq); - val &= MTK_PDMA_DELAY_RX_MASK; - val |= MTK_PDMA_DELAY_TX_EN; - -@@ -2542,9 +2604,9 @@ static void mtk_dim_tx(struct work_struc - cur = min_t(u32, cur_profile.pkts, MTK_PDMA_DELAY_PINT_MASK); - val |= cur << MTK_PDMA_DELAY_TX_PINT_SHIFT; - -- mtk_w32(eth, val, MTK_PDMA_DELAY_INT); -+ mtk_w32(eth, val, reg_map->pdma.delay_irq); - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) -- mtk_w32(eth, val, MTK_QDMA_DELAY_INT); -+ mtk_w32(eth, val, reg_map->qdma.delay_irq); - - spin_unlock_bh(ð->dim_lock); - -@@ -2555,6 +2617,7 @@ static int mtk_hw_init(struct mtk_eth *e - { - u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | - ETHSYS_DMA_AG_MAP_PPE; -+ const struct mtk_reg_map *reg_map = eth->soc->reg_map; - int i, val, ret; - - if (test_and_set_bit(MTK_HW_INIT, ð->state)) -@@ -2629,10 +2692,10 @@ static int mtk_hw_init(struct mtk_eth *e - mtk_rx_irq_disable(eth, ~0); - - /* FE int grouping */ -- mtk_w32(eth, MTK_TX_DONE_INT, MTK_PDMA_INT_GRP1); -- mtk_w32(eth, MTK_RX_DONE_INT, MTK_PDMA_INT_GRP2); -- mtk_w32(eth, MTK_TX_DONE_INT, MTK_QDMA_INT_GRP1); -- mtk_w32(eth, MTK_RX_DONE_INT, MTK_QDMA_INT_GRP2); -+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp); -+ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.int_grp + 4); -+ mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp); -+ mtk_w32(eth, MTK_RX_DONE_INT, reg_map->qdma.int_grp + 4); - mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); - - return 0; -@@ -3171,14 +3234,6 @@ static int mtk_probe(struct platform_dev - if (IS_ERR(eth->base)) - return PTR_ERR(eth->base); - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -- eth->tx_int_mask_reg = MTK_QDMA_INT_MASK; -- eth->tx_int_status_reg = MTK_QDMA_INT_STATUS; -- } else { -- eth->tx_int_mask_reg = MTK_PDMA_INT_MASK; -- eth->tx_int_status_reg = MTK_PDMA_INT_STATUS; -- } -- - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { - eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; - eth->ip_align = NET_IP_ALIGN; -@@ -3412,6 +3467,7 @@ static int mtk_remove(struct platform_de - } - - static const struct mtk_soc_data mt2701_data = { -+ .reg_map = &mtk_reg_map, - .caps = MT7623_CAPS | MTK_HWLRO, - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7623_CLKS_BITMAP, -@@ -3423,6 +3479,7 @@ static const struct mtk_soc_data mt2701_ - }; - - static const struct mtk_soc_data mt7621_data = { -+ .reg_map = &mtk_reg_map, - .caps = MT7621_CAPS, - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7621_CLKS_BITMAP, -@@ -3435,6 +3492,7 @@ static const struct mtk_soc_data mt7621_ - }; - - static const struct mtk_soc_data mt7622_data = { -+ .reg_map = &mtk_reg_map, - .ana_rgc3 = 0x2028, - .caps = MT7622_CAPS | MTK_HWLRO, - .hw_features = MTK_HW_FEATURES, -@@ -3448,6 +3506,7 @@ static const struct mtk_soc_data mt7622_ - }; - - static const struct mtk_soc_data mt7623_data = { -+ .reg_map = &mtk_reg_map, - .caps = MT7623_CAPS | MTK_HWLRO, - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7623_CLKS_BITMAP, -@@ -3460,6 +3519,7 @@ static const struct mtk_soc_data mt7623_ - }; - - static const struct mtk_soc_data mt7629_data = { -+ .reg_map = &mtk_reg_map, - .ana_rgc3 = 0x128, - .caps = MT7629_CAPS | MTK_HWLRO, - .hw_features = MTK_HW_FEATURES, -@@ -3472,6 +3532,7 @@ static const struct mtk_soc_data mt7629_ - }; - - static const struct mtk_soc_data rt5350_data = { -+ .reg_map = &mt7628_reg_map, - .caps = MT7628_CAPS, - .hw_features = MTK_HW_FEATURES_MT7628, - .required_clks = MT7628_CLKS_BITMAP, ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -48,6 +48,8 @@ - #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) - #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) - -+#define MTK_QRX_OFFSET 0x10 -+ - #define MTK_MAX_RX_RING_NUM 4 - #define MTK_HW_LRO_DMA_SIZE 8 - -@@ -100,18 +102,6 @@ - /* Unicast Filter MAC Address Register - High */ - #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) - --/* PDMA RX Base Pointer Register */ --#define MTK_PRX_BASE_PTR0 0x900 --#define MTK_PRX_BASE_PTR_CFG(x) (MTK_PRX_BASE_PTR0 + (x * 0x10)) -- --/* PDMA RX Maximum Count Register */ --#define MTK_PRX_MAX_CNT0 0x904 --#define MTK_PRX_MAX_CNT_CFG(x) (MTK_PRX_MAX_CNT0 + (x * 0x10)) -- --/* PDMA RX CPU Pointer Register */ --#define MTK_PRX_CRX_IDX0 0x908 --#define MTK_PRX_CRX_IDX_CFG(x) (MTK_PRX_CRX_IDX0 + (x * 0x10)) -- - /* PDMA HW LRO Control Registers */ - #define MTK_PDMA_LRO_CTRL_DW0 0x980 - #define MTK_LRO_EN BIT(0) -@@ -126,18 +116,19 @@ - #define MTK_ADMA_MODE BIT(15) - #define MTK_LRO_MIN_RXD_SDL (MTK_HW_LRO_SDL_REMAIN_ROOM << 16) - --/* PDMA Global Configuration Register */ --#define MTK_PDMA_GLO_CFG 0xa04 -+#define MTK_RX_DMA_LRO_EN BIT(8) - #define MTK_MULTI_EN BIT(10) - #define MTK_PDMA_SIZE_8DWORDS (1 << 4) - -+/* PDMA Global Configuration Register */ -+#define MTK_PDMA_LRO_SDL 0x3000 -+#define MTK_RX_CFG_SDL_OFFSET 16 -+ - /* PDMA Reset Index Register */ --#define MTK_PDMA_RST_IDX 0xa08 - #define MTK_PST_DRX_IDX0 BIT(16) - #define MTK_PST_DRX_IDX_CFG(x) (MTK_PST_DRX_IDX0 << (x)) - - /* PDMA Delay Interrupt Register */ --#define MTK_PDMA_DELAY_INT 0xa0c - #define MTK_PDMA_DELAY_RX_MASK GENMASK(15, 0) - #define MTK_PDMA_DELAY_RX_EN BIT(15) - #define MTK_PDMA_DELAY_RX_PINT_SHIFT 8 -@@ -151,19 +142,9 @@ - #define MTK_PDMA_DELAY_PINT_MASK 0x7f - #define MTK_PDMA_DELAY_PTIME_MASK 0xff - --/* PDMA Interrupt Status Register */ --#define MTK_PDMA_INT_STATUS 0xa20 -- --/* PDMA Interrupt Mask Register */ --#define MTK_PDMA_INT_MASK 0xa28 -- - /* PDMA HW LRO Alter Flow Delta Register */ - #define MTK_PDMA_LRO_ALT_SCORE_DELTA 0xa4c - --/* PDMA Interrupt grouping registers */ --#define MTK_PDMA_INT_GRP1 0xa50 --#define MTK_PDMA_INT_GRP2 0xa54 -- - /* PDMA HW LRO IP Setting Registers */ - #define MTK_LRO_RX_RING0_DIP_DW0 0xb04 - #define MTK_LRO_DIP_DW0_CFG(x) (MTK_LRO_RX_RING0_DIP_DW0 + (x * 0x40)) -@@ -185,26 +166,9 @@ - #define MTK_RING_MAX_AGG_CNT_H ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3) - - /* QDMA TX Queue Configuration Registers */ --#define MTK_QTX_CFG(x) (0x1800 + (x * 0x10)) - #define QDMA_RES_THRES 4 - --/* QDMA TX Queue Scheduler Registers */ --#define MTK_QTX_SCH(x) (0x1804 + (x * 0x10)) -- --/* QDMA RX Base Pointer Register */ --#define MTK_QRX_BASE_PTR0 0x1900 -- --/* QDMA RX Maximum Count Register */ --#define MTK_QRX_MAX_CNT0 0x1904 -- --/* QDMA RX CPU Pointer Register */ --#define MTK_QRX_CRX_IDX0 0x1908 -- --/* QDMA RX DMA Pointer Register */ --#define MTK_QRX_DRX_IDX0 0x190C -- - /* QDMA Global Configuration Register */ --#define MTK_QDMA_GLO_CFG 0x1A04 - #define MTK_RX_2B_OFFSET BIT(31) - #define MTK_RX_BT_32DWORDS (3 << 11) - #define MTK_NDP_CO_PRO BIT(10) -@@ -216,20 +180,12 @@ - #define MTK_TX_DMA_EN BIT(0) - #define MTK_DMA_BUSY_TIMEOUT_US 1000000 - --/* QDMA Reset Index Register */ --#define MTK_QDMA_RST_IDX 0x1A08 -- --/* QDMA Delay Interrupt Register */ --#define MTK_QDMA_DELAY_INT 0x1A0C -- - /* QDMA Flow Control Register */ --#define MTK_QDMA_FC_THRES 0x1A10 - #define FC_THRES_DROP_MODE BIT(20) - #define FC_THRES_DROP_EN (7 << 16) - #define FC_THRES_MIN 0x4444 - - /* QDMA Interrupt Status Register */ --#define MTK_QDMA_INT_STATUS 0x1A18 - #define MTK_RX_DONE_DLY BIT(30) - #define MTK_TX_DONE_DLY BIT(28) - #define MTK_RX_DONE_INT3 BIT(19) -@@ -244,55 +200,8 @@ - #define MTK_TX_DONE_INT MTK_TX_DONE_DLY - - /* QDMA Interrupt grouping registers */ --#define MTK_QDMA_INT_GRP1 0x1a20 --#define MTK_QDMA_INT_GRP2 0x1a24 - #define MTK_RLS_DONE_INT BIT(0) - --/* QDMA Interrupt Status Register */ --#define MTK_QDMA_INT_MASK 0x1A1C -- --/* QDMA Interrupt Mask Register */ --#define MTK_QDMA_HRED2 0x1A44 -- --/* QDMA TX Forward CPU Pointer Register */ --#define MTK_QTX_CTX_PTR 0x1B00 -- --/* QDMA TX Forward DMA Pointer Register */ --#define MTK_QTX_DTX_PTR 0x1B04 -- --/* QDMA TX Release CPU Pointer Register */ --#define MTK_QTX_CRX_PTR 0x1B10 -- --/* QDMA TX Release DMA Pointer Register */ --#define MTK_QTX_DRX_PTR 0x1B14 -- --/* QDMA FQ Head Pointer Register */ --#define MTK_QDMA_FQ_HEAD 0x1B20 -- --/* QDMA FQ Head Pointer Register */ --#define MTK_QDMA_FQ_TAIL 0x1B24 -- --/* QDMA FQ Free Page Counter Register */ --#define MTK_QDMA_FQ_CNT 0x1B28 -- --/* QDMA FQ Free Page Buffer Length Register */ --#define MTK_QDMA_FQ_BLEN 0x1B2C -- --/* GMA1 counter / statics register */ --#define MTK_GDM1_RX_GBCNT_L 0x2400 --#define MTK_GDM1_RX_GBCNT_H 0x2404 --#define MTK_GDM1_RX_GPCNT 0x2408 --#define MTK_GDM1_RX_OERCNT 0x2410 --#define MTK_GDM1_RX_FERCNT 0x2414 --#define MTK_GDM1_RX_SERCNT 0x2418 --#define MTK_GDM1_RX_LENCNT 0x241c --#define MTK_GDM1_RX_CERCNT 0x2420 --#define MTK_GDM1_RX_FCCNT 0x2424 --#define MTK_GDM1_TX_SKIPCNT 0x2428 --#define MTK_GDM1_TX_COLCNT 0x242c --#define MTK_GDM1_TX_GBCNT_L 0x2430 --#define MTK_GDM1_TX_GBCNT_H 0x2434 --#define MTK_GDM1_TX_GPCNT 0x2438 - #define MTK_STAT_OFFSET 0x40 - - #define MTK_WDMA0_BASE 0x2800 -@@ -854,8 +763,46 @@ struct mtk_tx_dma_desc_info { - u8 last:1; - }; - -+struct mtk_reg_map { -+ u32 tx_irq_mask; -+ u32 tx_irq_status; -+ struct { -+ u32 rx_ptr; /* rx base pointer */ -+ u32 rx_cnt_cfg; /* rx max count configuration */ -+ u32 pcrx_ptr; /* rx cpu pointer */ -+ u32 glo_cfg; /* global configuration */ -+ u32 rst_idx; /* reset index */ -+ u32 delay_irq; /* delay interrupt */ -+ u32 irq_status; /* interrupt status */ -+ u32 irq_mask; /* interrupt mask */ -+ u32 int_grp; -+ } pdma; -+ struct { -+ u32 qtx_cfg; /* tx queue configuration */ -+ u32 rx_ptr; /* rx base pointer */ -+ u32 rx_cnt_cfg; /* rx max count configuration */ -+ u32 qcrx_ptr; /* rx cpu pointer */ -+ u32 glo_cfg; /* global configuration */ -+ u32 rst_idx; /* reset index */ -+ u32 delay_irq; /* delay interrupt */ -+ u32 fc_th; /* flow control */ -+ u32 int_grp; -+ u32 hred; /* interrupt mask */ -+ u32 ctx_ptr; /* tx acquire cpu pointer */ -+ u32 dtx_ptr; /* tx acquire dma pointer */ -+ u32 crx_ptr; /* tx release cpu pointer */ -+ u32 drx_ptr; /* tx release dma pointer */ -+ u32 fq_head; /* fq head pointer */ -+ u32 fq_tail; /* fq tail pointer */ -+ u32 fq_count; /* fq free page count */ -+ u32 fq_blen; /* fq free page buffer length */ -+ } qdma; -+ u32 gdm1_cnt; -+}; -+ - /* struct mtk_eth_data - This is the structure holding all differences - * among various plaforms -+ * @reg_map Soc register map. - * @ana_rgc3: The offset for register ANA_RGC3 related to - * sgmiisys syscon - * @caps Flags shown the extra capability for the SoC -@@ -868,6 +815,7 @@ struct mtk_tx_dma_desc_info { - * @rxd_size Rx DMA descriptor size. - */ - struct mtk_soc_data { -+ const struct mtk_reg_map *reg_map; - u32 ana_rgc3; - u32 caps; - u32 required_clks; -@@ -995,8 +943,6 @@ struct mtk_eth { - u32 tx_bytes; - struct dim tx_dim; - -- u32 tx_int_mask_reg; -- u32 tx_int_status_reg; - u32 rx_dma_l4_valid; - int ip_align; - diff --git a/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch b/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch deleted file mode 100644 index 4d6c94b13b8..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-27-net-ethernet-mtk_eth_soc-introduce-MTK_NETSYS_V2-sup.patch +++ /dev/null @@ -1,917 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:36 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support - -Introduce MTK_NETSYS_V2 support. MTK_NETSYS_V2 defines 32B TX/RX DMA -descriptors. -This is a preliminary patch to add mt7986 ethernet support. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -863,8 +863,8 @@ static inline int mtk_max_buf_size(int f - return buf_size; - } - --static inline bool mtk_rx_get_desc(struct mtk_rx_dma *rxd, -- struct mtk_rx_dma *dma_rxd) -+static bool mtk_rx_get_desc(struct mtk_eth *eth, struct mtk_rx_dma_v2 *rxd, -+ struct mtk_rx_dma_v2 *dma_rxd) - { - rxd->rxd2 = READ_ONCE(dma_rxd->rxd2); - if (!(rxd->rxd2 & RX_DMA_DONE)) -@@ -873,6 +873,10 @@ static inline bool mtk_rx_get_desc(struc - rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); - rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); - rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ rxd->rxd5 = READ_ONCE(dma_rxd->rxd5); -+ rxd->rxd6 = READ_ONCE(dma_rxd->rxd6); -+ } - - return true; - } -@@ -917,7 +921,7 @@ static int mtk_init_fq_dma(struct mtk_et - phy_ring_tail = eth->phy_scratch_ring + soc->txrx.txd_size * (cnt - 1); - - for (i = 0; i < cnt; i++) { -- struct mtk_tx_dma *txd; -+ struct mtk_tx_dma_v2 *txd; - - txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; - txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; -@@ -927,6 +931,12 @@ static int mtk_init_fq_dma(struct mtk_et - - txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); - txd->txd4 = 0; -+ if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { -+ txd->txd5 = 0; -+ txd->txd6 = 0; -+ txd->txd7 = 0; -+ txd->txd8 = 0; -+ } - } - - mtk_w32(eth, eth->phy_scratch_ring, soc->reg_map->qdma.fq_head); -@@ -1030,10 +1040,12 @@ static void setup_tx_buf(struct mtk_eth - } - } - --static void mtk_tx_set_dma_desc(struct net_device *dev, struct mtk_tx_dma *desc, -- struct mtk_tx_dma_desc_info *info) -+static void mtk_tx_set_dma_desc_v1(struct net_device *dev, void *txd, -+ struct mtk_tx_dma_desc_info *info) - { - struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_eth *eth = mac->hw; -+ struct mtk_tx_dma *desc = txd; - u32 data; - - WRITE_ONCE(desc->txd1, info->addr); -@@ -1057,6 +1069,59 @@ static void mtk_tx_set_dma_desc(struct n - WRITE_ONCE(desc->txd4, data); - } - -+static void mtk_tx_set_dma_desc_v2(struct net_device *dev, void *txd, -+ struct mtk_tx_dma_desc_info *info) -+{ -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_tx_dma_v2 *desc = txd; -+ struct mtk_eth *eth = mac->hw; -+ u32 data; -+ -+ WRITE_ONCE(desc->txd1, info->addr); -+ -+ data = TX_DMA_PLEN0(info->size); -+ if (info->last) -+ data |= TX_DMA_LS0; -+ WRITE_ONCE(desc->txd3, data); -+ -+ if (!info->qid && mac->id) -+ info->qid = MTK_QDMA_GMAC2_QID; -+ -+ data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ -+ data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); -+ WRITE_ONCE(desc->txd4, data); -+ -+ data = 0; -+ if (info->first) { -+ if (info->gso) -+ data |= TX_DMA_TSO_V2; -+ /* tx checksum offload */ -+ if (info->csum) -+ data |= TX_DMA_CHKSUM_V2; -+ } -+ WRITE_ONCE(desc->txd5, data); -+ -+ data = 0; -+ if (info->first && info->vlan) -+ data |= TX_DMA_INS_VLAN_V2 | info->vlan_tci; -+ WRITE_ONCE(desc->txd6, data); -+ -+ WRITE_ONCE(desc->txd7, 0); -+ WRITE_ONCE(desc->txd8, 0); -+} -+ -+static void mtk_tx_set_dma_desc(struct net_device *dev, void *txd, -+ struct mtk_tx_dma_desc_info *info) -+{ -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_eth *eth = mac->hw; -+ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ mtk_tx_set_dma_desc_v2(dev, txd, info); -+ else -+ mtk_tx_set_dma_desc_v1(dev, txd, info); -+} -+ - static int mtk_tx_map(struct sk_buff *skb, struct net_device *dev, - int tx_num, struct mtk_tx_ring *ring, bool gso) - { -@@ -1065,6 +1130,7 @@ static int mtk_tx_map(struct sk_buff *sk - .gso = gso, - .csum = skb->ip_summed == CHECKSUM_PARTIAL, - .vlan = skb_vlan_tag_present(skb), -+ .qid = skb->mark & MTK_QDMA_TX_MASK, - .vlan_tci = skb_vlan_tag_get(skb), - .first = true, - .last = !skb_is_nonlinear(skb), -@@ -1124,7 +1190,9 @@ static int mtk_tx_map(struct sk_buff *sk - } - - memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); -- txd_info.size = min(frag_size, MTK_TX_DMA_BUF_LEN); -+ txd_info.size = min_t(unsigned int, frag_size, -+ soc->txrx.dma_max_len); -+ txd_info.qid = skb->mark & MTK_QDMA_TX_MASK; - txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && - !(frag_size - txd_info.size); - txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, -@@ -1205,17 +1273,16 @@ err_dma: - return -ENOMEM; - } - --static inline int mtk_cal_txd_req(struct sk_buff *skb) -+static int mtk_cal_txd_req(struct mtk_eth *eth, struct sk_buff *skb) - { -- int i, nfrags; -+ int i, nfrags = 1; - skb_frag_t *frag; - -- nfrags = 1; - if (skb_is_gso(skb)) { - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - frag = &skb_shinfo(skb)->frags[i]; - nfrags += DIV_ROUND_UP(skb_frag_size(frag), -- MTK_TX_DMA_BUF_LEN); -+ eth->soc->txrx.dma_max_len); - } - } else { - nfrags += skb_shinfo(skb)->nr_frags; -@@ -1267,7 +1334,7 @@ static netdev_tx_t mtk_start_xmit(struct - if (unlikely(test_bit(MTK_RESETTING, ð->state))) - goto drop; - -- tx_num = mtk_cal_txd_req(skb); -+ tx_num = mtk_cal_txd_req(eth, skb); - if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { - netif_stop_queue(dev); - netif_err(eth, tx_queued, dev, -@@ -1359,7 +1426,7 @@ static int mtk_poll_rx(struct napi_struc - int idx; - struct sk_buff *skb; - u8 *data, *new_data; -- struct mtk_rx_dma *rxd, trxd; -+ struct mtk_rx_dma_v2 *rxd, trxd; - int done = 0, bytes = 0; - - while (done < budget) { -@@ -1367,7 +1434,7 @@ static int mtk_poll_rx(struct napi_struc - unsigned int pktlen; - dma_addr_t dma_addr; - u32 hash, reason; -- int mac; -+ int mac = 0; - - ring = mtk_get_rx_ring(eth); - if (unlikely(!ring)) -@@ -1377,16 +1444,15 @@ static int mtk_poll_rx(struct napi_struc - rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; - data = ring->data[idx]; - -- if (!mtk_rx_get_desc(&trxd, rxd)) -+ if (!mtk_rx_get_desc(eth, &trxd, rxd)) - break; - - /* find out which mac the packet come from. values start at 1 */ -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) || -- (trxd.rxd4 & RX_DMA_SPECIAL_TAG)) -- mac = 0; -- else -- mac = ((trxd.rxd4 >> RX_DMA_FPORT_SHIFT) & -- RX_DMA_FPORT_MASK) - 1; -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1; -+ else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && -+ !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) -+ mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1; - - if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || - !eth->netdev[mac])) -@@ -1432,7 +1498,7 @@ static int mtk_poll_rx(struct napi_struc - pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); - skb->dev = netdev; - skb_put(skb, pktlen); -- if (trxd.rxd4 & eth->rx_dma_l4_valid) -+ if (trxd.rxd4 & eth->soc->txrx.rx_dma_l4_valid) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb_checksum_none_assert(skb); -@@ -1450,10 +1516,25 @@ static int mtk_poll_rx(struct napi_struc - mtk_ppe_check_skb(eth->ppe, skb, - trxd.rxd4 & MTK_RXD4_FOE_ENTRY); - -- if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX && -- (trxd.rxd2 & RX_DMA_VTAG)) -- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -- RX_DMA_VID(trxd.rxd3)); -+ if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ if (trxd.rxd3 & RX_DMA_VTAG_V2) -+ __vlan_hwaccel_put_tag(skb, -+ htons(RX_DMA_VPID(trxd.rxd4)), -+ RX_DMA_VID(trxd.rxd4)); -+ } else if (trxd.rxd2 & RX_DMA_VTAG) { -+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), -+ RX_DMA_VID(trxd.rxd3)); -+ } -+ -+ /* If the device is attached to a dsa switch, the special -+ * tag inserted in VLAN field by hw switch can * be offloaded -+ * by RX HW VLAN offload. Clear vlan info. -+ */ -+ if (netdev_uses_dsa(netdev)) -+ __vlan_hwaccel_clear_tag(skb); -+ } -+ - skb_record_rx_queue(skb, 0); - napi_gro_receive(napi, skb); - -@@ -1465,7 +1546,7 @@ release_desc: - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) - rxd->rxd2 = RX_DMA_LSO; - else -- rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); -+ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); - - ring->calc_idx = idx; - -@@ -1667,7 +1748,8 @@ static int mtk_napi_rx(struct napi_struc - do { - int rx_done; - -- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.irq_status); -+ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, -+ reg_map->pdma.irq_status); - rx_done = mtk_poll_rx(napi, budget - rx_done_total, eth); - rx_done_total += rx_done; - -@@ -1681,10 +1763,11 @@ static int mtk_napi_rx(struct napi_struc - if (rx_done_total == budget) - return budget; - -- } while (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT); -+ } while (mtk_r32(eth, reg_map->pdma.irq_status) & -+ eth->soc->txrx.rx_irq_done_mask); - - if (napi_complete_done(napi, rx_done_total)) -- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); - - return rx_done_total; - } -@@ -1694,7 +1777,7 @@ static int mtk_tx_alloc(struct mtk_eth * - const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_ring *ring = ð->tx_ring; - int i, sz = soc->txrx.txd_size; -- struct mtk_tx_dma *txd; -+ struct mtk_tx_dma_v2 *txd; - - ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf), - GFP_KERNEL); -@@ -1714,13 +1797,19 @@ static int mtk_tx_alloc(struct mtk_eth * - txd->txd2 = next_ptr; - txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; - txd->txd4 = 0; -+ if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { -+ txd->txd5 = 0; -+ txd->txd6 = 0; -+ txd->txd7 = 0; -+ txd->txd8 = 0; -+ } - } - - /* On MT7688 (PDMA only) this driver uses the ring->dma structs - * only as the framework. The real HW descriptors are the PDMA - * descriptors in ring->dma_pdma. - */ -- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz, - &ring->phys_pdma, GFP_KERNEL); - if (!ring->dma_pdma) -@@ -1800,13 +1889,11 @@ static int mtk_rx_alloc(struct mtk_eth * - struct mtk_rx_ring *ring; - int rx_data_len, rx_dma_size; - int i; -- u32 offset = 0; - - if (rx_flag == MTK_RX_FLAGS_QDMA) { - if (ring_no) - return -EINVAL; - ring = ð->rx_ring_qdma; -- offset = 0x1000; - } else { - ring = ð->rx_ring[ring_no]; - } -@@ -1842,7 +1929,7 @@ static int mtk_rx_alloc(struct mtk_eth * - return -ENOMEM; - - for (i = 0; i < rx_dma_size; i++) { -- struct mtk_rx_dma *rxd; -+ struct mtk_rx_dma_v2 *rxd; - - dma_addr_t dma_addr = dma_map_single(eth->dma_dev, - ring->data[i] + NET_SKB_PAD + eth->ip_align, -@@ -1857,26 +1944,47 @@ static int mtk_rx_alloc(struct mtk_eth * - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) - rxd->rxd2 = RX_DMA_LSO; - else -- rxd->rxd2 = RX_DMA_PLEN0(ring->buf_size); -+ rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); - - rxd->rxd3 = 0; - rxd->rxd4 = 0; -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ rxd->rxd5 = 0; -+ rxd->rxd6 = 0; -+ rxd->rxd7 = 0; -+ rxd->rxd8 = 0; -+ } - } - ring->dma_size = rx_dma_size; - ring->calc_idx_update = false; - ring->calc_idx = rx_dma_size - 1; -- ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + ring_no * MTK_QRX_OFFSET; -+ if (rx_flag == MTK_RX_FLAGS_QDMA) -+ ring->crx_idx_reg = reg_map->qdma.qcrx_ptr + -+ ring_no * MTK_QRX_OFFSET; -+ else -+ ring->crx_idx_reg = reg_map->pdma.pcrx_ptr + -+ ring_no * MTK_QRX_OFFSET; - /* make sure that all changes to the dma ring are flushed before we - * continue - */ - wmb(); - -- mtk_w32(eth, ring->phys, -- reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET + offset); -- mtk_w32(eth, rx_dma_size, -- reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET + offset); -- mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg + offset); -- mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), reg_map->pdma.rst_idx + offset); -+ if (rx_flag == MTK_RX_FLAGS_QDMA) { -+ mtk_w32(eth, ring->phys, -+ reg_map->qdma.rx_ptr + ring_no * MTK_QRX_OFFSET); -+ mtk_w32(eth, rx_dma_size, -+ reg_map->qdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET); -+ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), -+ reg_map->qdma.rst_idx); -+ } else { -+ mtk_w32(eth, ring->phys, -+ reg_map->pdma.rx_ptr + ring_no * MTK_QRX_OFFSET); -+ mtk_w32(eth, rx_dma_size, -+ reg_map->pdma.rx_cnt_cfg + ring_no * MTK_QRX_OFFSET); -+ mtk_w32(eth, MTK_PST_DRX_IDX_CFG(ring_no), -+ reg_map->pdma.rst_idx); -+ } -+ mtk_w32(eth, ring->calc_idx, ring->crx_idx_reg); - - return 0; - } -@@ -2298,7 +2406,7 @@ static irqreturn_t mtk_handle_irq_rx(int - eth->rx_events++; - if (likely(napi_schedule_prep(ð->rx_napi))) { - __napi_schedule(ð->rx_napi); -- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); - } - - return IRQ_HANDLED; -@@ -2322,8 +2430,10 @@ static irqreturn_t mtk_handle_irq(int ir - struct mtk_eth *eth = _eth; - const struct mtk_reg_map *reg_map = eth->soc->reg_map; - -- if (mtk_r32(eth, reg_map->pdma.irq_mask) & MTK_RX_DONE_INT) { -- if (mtk_r32(eth, reg_map->pdma.irq_status) & MTK_RX_DONE_INT) -+ if (mtk_r32(eth, reg_map->pdma.irq_mask) & -+ eth->soc->txrx.rx_irq_done_mask) { -+ if (mtk_r32(eth, reg_map->pdma.irq_status) & -+ eth->soc->txrx.rx_irq_done_mask) - mtk_handle_irq_rx(irq, _eth); - } - if (mtk_r32(eth, reg_map->tx_irq_mask) & MTK_TX_DONE_INT) { -@@ -2341,16 +2451,16 @@ static void mtk_poll_controller(struct n - struct mtk_eth *eth = mac->hw; - - mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); -- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); - mtk_handle_irq_rx(eth->irq[2], dev); - mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); -- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); - } - #endif - - static int mtk_start_dma(struct mtk_eth *eth) - { -- u32 rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; -+ u32 val, rx_2b_offset = (NET_IP_ALIGN == 2) ? MTK_RX_2B_OFFSET : 0; - const struct mtk_reg_map *reg_map = eth->soc->reg_map; - int err; - -@@ -2361,12 +2471,19 @@ static int mtk_start_dma(struct mtk_eth - } - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) { -- mtk_w32(eth, -- MTK_TX_WB_DDONE | MTK_TX_DMA_EN | -- MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | -- MTK_RX_DMA_EN | MTK_RX_2B_OFFSET | -- MTK_RX_BT_32DWORDS, -- reg_map->qdma.glo_cfg); -+ val = mtk_r32(eth, reg_map->qdma.glo_cfg); -+ val |= MTK_TX_DMA_EN | MTK_RX_DMA_EN | -+ MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | -+ MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; -+ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ val |= MTK_MUTLI_CNT | MTK_RESV_BUF | -+ MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | -+ MTK_CHK_DDONE_EN; -+ else -+ val |= MTK_RX_BT_32DWORDS; -+ mtk_w32(eth, val, reg_map->qdma.glo_cfg); -+ - mtk_w32(eth, - MTK_RX_DMA_EN | rx_2b_offset | - MTK_RX_BT_32DWORDS | MTK_MULTI_EN, -@@ -2440,7 +2557,7 @@ static int mtk_open(struct net_device *d - napi_enable(ð->tx_napi); - napi_enable(ð->rx_napi); - mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); -- mtk_rx_irq_enable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); - refcount_set(ð->dma_refcnt, 1); - } - else -@@ -2492,7 +2609,7 @@ static int mtk_stop(struct net_device *d - mtk_gdm_config(eth, MTK_GDMA_DROP_ALL); - - mtk_tx_irq_disable(eth, MTK_TX_DONE_INT); -- mtk_rx_irq_disable(eth, MTK_RX_DONE_INT); -+ mtk_rx_irq_disable(eth, eth->soc->txrx.rx_irq_done_mask); - napi_disable(ð->tx_napi); - napi_disable(ð->rx_napi); - -@@ -2652,9 +2769,25 @@ static int mtk_hw_init(struct mtk_eth *e - return 0; - } - -- /* Non-MT7628 handling... */ -- ethsys_reset(eth, RSTCTRL_FE); -- ethsys_reset(eth, RSTCTRL_PPE); -+ val = RSTCTRL_FE | RSTCTRL_PPE; -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); -+ -+ val |= RSTCTRL_ETH; -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) -+ val |= RSTCTRL_PPE1; -+ } -+ -+ ethsys_reset(eth, val); -+ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, -+ 0x3ffffff); -+ -+ /* Set FE to PDMAv2 if necessary */ -+ val = mtk_r32(eth, MTK_FE_GLO_MISC); -+ mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC); -+ } - - if (eth->pctl) { - /* Set GE2 driving and slew rate */ -@@ -2693,11 +2826,47 @@ static int mtk_hw_init(struct mtk_eth *e - - /* FE int grouping */ - mtk_w32(eth, MTK_TX_DONE_INT, reg_map->pdma.int_grp); -- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->pdma.int_grp + 4); -+ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->pdma.int_grp + 4); - mtk_w32(eth, MTK_TX_DONE_INT, reg_map->qdma.int_grp); -- mtk_w32(eth, MTK_RX_DONE_INT, reg_map->qdma.int_grp + 4); -+ mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4); - mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); - -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ /* PSE should not drop port8 and port9 packets */ -+ mtk_w32(eth, 0x00000300, PSE_DROP_CFG); -+ -+ /* PSE Free Queue Flow Control */ -+ mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); -+ -+ /* PSE config input queue threshold */ -+ mtk_w32(eth, 0x001a000e, PSE_IQ_REV(1)); -+ mtk_w32(eth, 0x01ff001a, PSE_IQ_REV(2)); -+ mtk_w32(eth, 0x000e01ff, PSE_IQ_REV(3)); -+ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(4)); -+ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(5)); -+ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(6)); -+ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(7)); -+ mtk_w32(eth, 0x000e000e, PSE_IQ_REV(8)); -+ -+ /* PSE config output queue threshold */ -+ mtk_w32(eth, 0x000f000a, PSE_OQ_TH(1)); -+ mtk_w32(eth, 0x001a000f, PSE_OQ_TH(2)); -+ mtk_w32(eth, 0x000f001a, PSE_OQ_TH(3)); -+ mtk_w32(eth, 0x01ff000f, PSE_OQ_TH(4)); -+ mtk_w32(eth, 0x000f000f, PSE_OQ_TH(5)); -+ mtk_w32(eth, 0x0006000f, PSE_OQ_TH(6)); -+ mtk_w32(eth, 0x00060006, PSE_OQ_TH(7)); -+ mtk_w32(eth, 0x00060006, PSE_OQ_TH(8)); -+ -+ /* GDM and CDM Threshold */ -+ mtk_w32(eth, 0x00000004, MTK_GDM2_THRES); -+ mtk_w32(eth, 0x00000004, MTK_CDMW0_THRES); -+ mtk_w32(eth, 0x00000004, MTK_CDMW1_THRES); -+ mtk_w32(eth, 0x00000004, MTK_CDME0_THRES); -+ mtk_w32(eth, 0x00000004, MTK_CDME1_THRES); -+ mtk_w32(eth, 0x00000004, MTK_CDMM_THRES); -+ } -+ - return 0; - - err_disable_pm: -@@ -3234,12 +3403,8 @@ static int mtk_probe(struct platform_dev - if (IS_ERR(eth->base)) - return PTR_ERR(eth->base); - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { -- eth->rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA; -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) - eth->ip_align = NET_IP_ALIGN; -- } else { -- eth->rx_dma_l4_valid = RX_DMA_L4_VALID; -- } - - spin_lock_init(ð->page_lock); - spin_lock_init(ð->tx_irq_lock); -@@ -3475,6 +3640,10 @@ static const struct mtk_soc_data mt2701_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - -@@ -3488,6 +3657,10 @@ static const struct mtk_soc_data mt7621_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - -@@ -3502,6 +3675,10 @@ static const struct mtk_soc_data mt7622_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - -@@ -3515,6 +3692,10 @@ static const struct mtk_soc_data mt7623_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - -@@ -3528,6 +3709,10 @@ static const struct mtk_soc_data mt7629_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - -@@ -3540,6 +3725,10 @@ static const struct mtk_soc_data rt5350_ - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -+ .rx_irq_done_mask = MTK_RX_DONE_INT, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN, -+ .dma_len_offset = 16, - }, - }; - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -23,6 +23,7 @@ - #define MTK_MAX_RX_LENGTH 1536 - #define MTK_MAX_RX_LENGTH_2K 2048 - #define MTK_TX_DMA_BUF_LEN 0x3fff -+#define MTK_TX_DMA_BUF_LEN_V2 0xffff - #define MTK_DMA_SIZE 512 - #define MTK_NAPI_WEIGHT 64 - #define MTK_MAC_COUNT 2 -@@ -83,6 +84,10 @@ - #define MTK_CDMQ_IG_CTRL 0x1400 - #define MTK_CDMQ_STAG_EN BIT(0) - -+/* CDMP Ingress Control Register */ -+#define MTK_CDMP_IG_CTRL 0x400 -+#define MTK_CDMP_STAG_EN BIT(0) -+ - /* CDMP Exgress Control Register */ - #define MTK_CDMP_EG_CTRL 0x404 - -@@ -102,13 +107,38 @@ - /* Unicast Filter MAC Address Register - High */ - #define MTK_GDMA_MAC_ADRH(x) (0x50C + (x * 0x1000)) - -+/* FE global misc reg*/ -+#define MTK_FE_GLO_MISC 0x124 -+ -+/* PSE Free Queue Flow Control */ -+#define PSE_FQFC_CFG1 0x100 -+#define PSE_FQFC_CFG2 0x104 -+#define PSE_DROP_CFG 0x108 -+ -+/* PSE Input Queue Reservation Register*/ -+#define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) -+ -+/* PSE Output Queue Threshold Register*/ -+#define PSE_OQ_TH(x) (0x160 + (((x) - 1) << 2)) -+ -+/* GDM and CDM Threshold */ -+#define MTK_GDM2_THRES 0x1530 -+#define MTK_CDMW0_THRES 0x164c -+#define MTK_CDMW1_THRES 0x1650 -+#define MTK_CDME0_THRES 0x1654 -+#define MTK_CDME1_THRES 0x1658 -+#define MTK_CDMM_THRES 0x165c -+ - /* PDMA HW LRO Control Registers */ - #define MTK_PDMA_LRO_CTRL_DW0 0x980 - #define MTK_LRO_EN BIT(0) - #define MTK_L3_CKS_UPD_EN BIT(7) -+#define MTK_L3_CKS_UPD_EN_V2 BIT(19) - #define MTK_LRO_ALT_PKT_CNT_MODE BIT(21) - #define MTK_LRO_RING_RELINQUISH_REQ (0x7 << 26) -+#define MTK_LRO_RING_RELINQUISH_REQ_V2 (0xf << 24) - #define MTK_LRO_RING_RELINQUISH_DONE (0x7 << 29) -+#define MTK_LRO_RING_RELINQUISH_DONE_V2 (0xf << 28) - - #define MTK_PDMA_LRO_CTRL_DW1 0x984 - #define MTK_PDMA_LRO_CTRL_DW2 0x988 -@@ -180,6 +210,13 @@ - #define MTK_TX_DMA_EN BIT(0) - #define MTK_DMA_BUSY_TIMEOUT_US 1000000 - -+/* QDMA V2 Global Configuration Register */ -+#define MTK_CHK_DDONE_EN BIT(28) -+#define MTK_DMAD_WR_WDONE BIT(26) -+#define MTK_WCOMP_EN BIT(24) -+#define MTK_RESV_BUF (0x40 << 16) -+#define MTK_MUTLI_CNT (0x4 << 12) -+ - /* QDMA Flow Control Register */ - #define FC_THRES_DROP_MODE BIT(20) - #define FC_THRES_DROP_EN (7 << 16) -@@ -199,11 +236,32 @@ - #define MTK_RX_DONE_INT MTK_RX_DONE_DLY - #define MTK_TX_DONE_INT MTK_TX_DONE_DLY - -+#define MTK_RX_DONE_INT_V2 BIT(14) -+ - /* QDMA Interrupt grouping registers */ - #define MTK_RLS_DONE_INT BIT(0) - - #define MTK_STAT_OFFSET 0x40 - -+/* QDMA TX NUM */ -+#define MTK_QDMA_TX_NUM 16 -+#define MTK_QDMA_TX_MASK (MTK_QDMA_TX_NUM - 1) -+#define QID_BITS_V2(x) (((x) & 0x3f) << 16) -+#define MTK_QDMA_GMAC2_QID 8 -+ -+#define MTK_TX_DMA_BUF_SHIFT 8 -+ -+/* QDMA V2 descriptor txd6 */ -+#define TX_DMA_INS_VLAN_V2 BIT(16) -+/* QDMA V2 descriptor txd5 */ -+#define TX_DMA_CHKSUM_V2 (0x7 << 28) -+#define TX_DMA_TSO_V2 BIT(31) -+ -+/* QDMA V2 descriptor txd4 */ -+#define TX_DMA_FPORT_SHIFT_V2 8 -+#define TX_DMA_FPORT_MASK_V2 0xf -+#define TX_DMA_SWC_V2 BIT(30) -+ - #define MTK_WDMA0_BASE 0x2800 - #define MTK_WDMA1_BASE 0x2c00 - -@@ -217,10 +275,9 @@ - /* QDMA descriptor txd3 */ - #define TX_DMA_OWNER_CPU BIT(31) - #define TX_DMA_LS0 BIT(30) --#define TX_DMA_PLEN0(_x) (((_x) & MTK_TX_DMA_BUF_LEN) << 16) --#define TX_DMA_PLEN1(_x) ((_x) & MTK_TX_DMA_BUF_LEN) -+#define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) -+#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len) - #define TX_DMA_SWC BIT(14) --#define TX_DMA_SDL(_x) (((_x) & 0x3fff) << 16) - - /* PDMA on MT7628 */ - #define TX_DMA_DONE BIT(31) -@@ -230,12 +287,14 @@ - /* QDMA descriptor rxd2 */ - #define RX_DMA_DONE BIT(31) - #define RX_DMA_LSO BIT(30) --#define RX_DMA_PLEN0(_x) (((_x) & 0x3fff) << 16) --#define RX_DMA_GET_PLEN0(_x) (((_x) >> 16) & 0x3fff) -+#define RX_DMA_PREP_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) -+#define RX_DMA_GET_PLEN0(x) (((x) >> eth->soc->txrx.dma_len_offset) & eth->soc->txrx.dma_max_len) - #define RX_DMA_VTAG BIT(15) - - /* QDMA descriptor rxd3 */ --#define RX_DMA_VID(_x) ((_x) & 0xfff) -+#define RX_DMA_VID(x) ((x) & VLAN_VID_MASK) -+#define RX_DMA_TCI(x) ((x) & (VLAN_PRIO_MASK | VLAN_VID_MASK)) -+#define RX_DMA_VPID(x) (((x) >> 16) & 0xffff) - - /* QDMA descriptor rxd4 */ - #define MTK_RXD4_FOE_ENTRY GENMASK(13, 0) -@@ -246,10 +305,15 @@ - /* QDMA descriptor rxd4 */ - #define RX_DMA_L4_VALID BIT(24) - #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ --#define RX_DMA_FPORT_SHIFT 19 --#define RX_DMA_FPORT_MASK 0x7 - #define RX_DMA_SPECIAL_TAG BIT(22) - -+#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) -+#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) -+ -+/* PDMA V2 descriptor rxd3 */ -+#define RX_DMA_VTAG_V2 BIT(0) -+#define RX_DMA_L4_VALID_V2 BIT(2) -+ - /* PHY Indirect Access Control registers */ - #define MTK_PHY_IAC 0x10004 - #define PHY_IAC_ACCESS BIT(31) -@@ -371,6 +435,16 @@ - #define ETHSYS_TRGMII_MT7621_DDR_PLL BIT(5) - - /* ethernet reset control register */ -+#define ETHSYS_RSTCTRL 0x34 -+#define RSTCTRL_FE BIT(6) -+#define RSTCTRL_PPE BIT(31) -+#define RSTCTRL_PPE1 BIT(30) -+#define RSTCTRL_ETH BIT(23) -+ -+/* ethernet reset check idle register */ -+#define ETHSYS_FE_RST_CHK_IDLE_EN 0x28 -+ -+/* ethernet reset control register */ - #define ETHSYS_RSTCTRL 0x34 - #define RSTCTRL_FE BIT(6) - #define RSTCTRL_PPE BIT(31) -@@ -454,6 +528,17 @@ struct mtk_rx_dma { - unsigned int rxd4; - } __packed __aligned(4); - -+struct mtk_rx_dma_v2 { -+ unsigned int rxd1; -+ unsigned int rxd2; -+ unsigned int rxd3; -+ unsigned int rxd4; -+ unsigned int rxd5; -+ unsigned int rxd6; -+ unsigned int rxd7; -+ unsigned int rxd8; -+} __packed __aligned(4); -+ - struct mtk_tx_dma { - unsigned int txd1; - unsigned int txd2; -@@ -461,6 +546,17 @@ struct mtk_tx_dma { - unsigned int txd4; - } __packed __aligned(4); - -+struct mtk_tx_dma_v2 { -+ unsigned int txd1; -+ unsigned int txd2; -+ unsigned int txd3; -+ unsigned int txd4; -+ unsigned int txd5; -+ unsigned int txd6; -+ unsigned int txd7; -+ unsigned int txd8; -+} __packed __aligned(4); -+ - struct mtk_eth; - struct mtk_mac; - -@@ -647,7 +743,9 @@ enum mkt_eth_capabilities { - MTK_SHARED_INT_BIT, - MTK_TRGMII_MT7621_CLK_BIT, - MTK_QDMA_BIT, -+ MTK_NETSYS_V2_BIT, - MTK_SOC_MT7628_BIT, -+ MTK_RSTCTRL_PPE1_BIT, - - /* MUX BITS*/ - MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, -@@ -679,7 +777,9 @@ enum mkt_eth_capabilities { - #define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT) - #define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) - #define MTK_QDMA BIT(MTK_QDMA_BIT) -+#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) - #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) -+#define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) - - #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ - BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) -@@ -756,6 +856,7 @@ struct mtk_tx_dma_desc_info { - dma_addr_t addr; - u32 size; - u16 vlan_tci; -+ u16 qid; - u8 gso:1; - u8 csum:1; - u8 vlan:1; -@@ -813,6 +914,10 @@ struct mtk_reg_map { - * the extra setup for those pins used by GMAC. - * @txd_size Tx DMA descriptor size. - * @rxd_size Rx DMA descriptor size. -+ * @rx_irq_done_mask Rx irq done register mask. -+ * @rx_dma_l4_valid Rx DMA valid register mask. -+ * @dma_max_len Max DMA tx/rx buffer length. -+ * @dma_len_offset Tx/Rx DMA length field offset. - */ - struct mtk_soc_data { - const struct mtk_reg_map *reg_map; -@@ -825,6 +930,10 @@ struct mtk_soc_data { - struct { - u32 txd_size; - u32 rxd_size; -+ u32 rx_irq_done_mask; -+ u32 rx_dma_l4_valid; -+ u32 dma_max_len; -+ u32 dma_len_offset; - } txrx; - }; - -@@ -943,7 +1052,6 @@ struct mtk_eth { - u32 tx_bytes; - struct dim tx_dim; - -- u32 rx_dma_l4_valid; - int ip_align; - - struct mtk_ppe *ppe; diff --git a/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch b/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch deleted file mode 100644 index 1ecb5e71b3a..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-28-net-ethernet-mtk_eth_soc-convert-ring-dma-pointer-to.patch +++ /dev/null @@ -1,135 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:37 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: convert ring dma pointer to void - -Simplify the code converting {tx,rx} ring dma pointer to void - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -947,18 +947,15 @@ static int mtk_init_fq_dma(struct mtk_et - return 0; - } - --static inline void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) -+static void *mtk_qdma_phys_to_virt(struct mtk_tx_ring *ring, u32 desc) - { -- void *ret = ring->dma; -- -- return ret + (desc - ring->phys); -+ return ring->dma + (desc - ring->phys); - } - - static struct mtk_tx_buf *mtk_desc_to_tx_buf(struct mtk_tx_ring *ring, -- struct mtk_tx_dma *txd, -- u32 txd_size) -+ void *txd, u32 txd_size) - { -- int idx = ((void *)txd - (void *)ring->dma) / txd_size; -+ int idx = (txd - ring->dma) / txd_size; - - return &ring->buf[idx]; - } -@@ -966,13 +963,12 @@ static struct mtk_tx_buf *mtk_desc_to_tx - static struct mtk_tx_dma *qdma_to_pdma(struct mtk_tx_ring *ring, - struct mtk_tx_dma *dma) - { -- return ring->dma_pdma - ring->dma + dma; -+ return ring->dma_pdma - (struct mtk_tx_dma *)ring->dma + dma; - } - --static int txd_to_idx(struct mtk_tx_ring *ring, struct mtk_tx_dma *dma, -- u32 txd_size) -+static int txd_to_idx(struct mtk_tx_ring *ring, void *dma, u32 txd_size) - { -- return ((void *)dma - (void *)ring->dma) / txd_size; -+ return (dma - ring->dma) / txd_size; - } - - static void mtk_tx_unmap(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1389,7 +1385,7 @@ static struct mtk_rx_ring *mtk_get_rx_ri - - ring = ð->rx_ring[i]; - idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); -- rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; -+ rxd = ring->dma + idx * eth->soc->txrx.rxd_size; - if (rxd->rxd2 & RX_DMA_DONE) { - ring->calc_idx_update = true; - return ring; -@@ -1441,7 +1437,7 @@ static int mtk_poll_rx(struct napi_struc - goto rx_done; - - idx = NEXT_DESP_IDX(ring->calc_idx, ring->dma_size); -- rxd = (void *)ring->dma + idx * eth->soc->txrx.rxd_size; -+ rxd = ring->dma + idx * eth->soc->txrx.rxd_size; - data = ring->data[idx]; - - if (!mtk_rx_get_desc(eth, &trxd, rxd)) -@@ -1648,7 +1644,7 @@ static int mtk_poll_tx_pdma(struct mtk_e - - mtk_tx_unmap(eth, tx_buf, true); - -- desc = (void *)ring->dma + cpu * eth->soc->txrx.txd_size; -+ desc = ring->dma + cpu * eth->soc->txrx.txd_size; - ring->last_free = desc; - atomic_inc(&ring->free_count); - -@@ -1793,7 +1789,7 @@ static int mtk_tx_alloc(struct mtk_eth * - int next = (i + 1) % MTK_DMA_SIZE; - u32 next_ptr = ring->phys + next * sz; - -- txd = (void *)ring->dma + i * sz; -+ txd = ring->dma + i * sz; - txd->txd2 = next_ptr; - txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; - txd->txd4 = 0; -@@ -1823,7 +1819,7 @@ static int mtk_tx_alloc(struct mtk_eth * - - ring->dma_size = MTK_DMA_SIZE; - atomic_set(&ring->free_count, MTK_DMA_SIZE - 2); -- ring->next_free = &ring->dma[0]; -+ ring->next_free = ring->dma; - ring->last_free = (void *)txd; - ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz)); - ring->thresh = MAX_SKB_FRAGS; -@@ -1938,7 +1934,7 @@ static int mtk_rx_alloc(struct mtk_eth * - if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) - return -ENOMEM; - -- rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; -+ rxd = ring->dma + i * eth->soc->txrx.rxd_size; - rxd->rxd1 = (unsigned int)dma_addr; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) -@@ -2000,7 +1996,7 @@ static void mtk_rx_clean(struct mtk_eth - if (!ring->data[i]) - continue; - -- rxd = (void *)ring->dma + i * eth->soc->txrx.rxd_size; -+ rxd = ring->dma + i * eth->soc->txrx.rxd_size; - if (!rxd->rxd1) - continue; - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -689,7 +689,7 @@ struct mtk_tx_buf { - * are present - */ - struct mtk_tx_ring { -- struct mtk_tx_dma *dma; -+ void *dma; - struct mtk_tx_buf *buf; - dma_addr_t phys; - struct mtk_tx_dma *next_free; -@@ -719,7 +719,7 @@ enum mtk_rx_flags { - * @calc_idx: The current head of ring - */ - struct mtk_rx_ring { -- struct mtk_rx_dma *dma; -+ void *dma; - u8 **data; - dma_addr_t phys; - u16 frag_size; diff --git a/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch b/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch deleted file mode 100644 index f7318e68bbd..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-29-net-ethernet-mtk_eth_soc-convert-scratch_ring-pointe.patch +++ /dev/null @@ -1,33 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:38 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: convert scratch_ring pointer to - void - -Simplify the code converting scratch_ring pointer to void - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -923,7 +923,7 @@ static int mtk_init_fq_dma(struct mtk_et - for (i = 0; i < cnt; i++) { - struct mtk_tx_dma_v2 *txd; - -- txd = (void *)eth->scratch_ring + i * soc->txrx.txd_size; -+ txd = eth->scratch_ring + i * soc->txrx.txd_size; - txd->txd1 = dma_addr + i * MTK_QDMA_PAGE_SIZE; - if (i < cnt - 1) - txd->txd2 = eth->phy_scratch_ring + ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1029,7 +1029,7 @@ struct mtk_eth { - struct mtk_rx_ring rx_ring_qdma; - struct napi_struct tx_napi; - struct napi_struct rx_napi; -- struct mtk_tx_dma *scratch_ring; -+ void *scratch_ring; - dma_addr_t phy_scratch_ring; - void *scratch_head; - struct clk *clks[MTK_CLK_MAX]; diff --git a/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch b/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch deleted file mode 100644 index a4698d7814d..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-30-net-ethernet-mtk_eth_soc-introduce-support-for-mt798.patch +++ /dev/null @@ -1,138 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 20 May 2022 20:11:39 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce support for mt7986 - chipset - -Add support for mt7986-eth driver available on mt7986 soc. - -Tested-by: Sam Shih -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -87,6 +87,43 @@ static const struct mtk_reg_map mt7628_r - }, - }; - -+static const struct mtk_reg_map mt7986_reg_map = { -+ .tx_irq_mask = 0x461c, -+ .tx_irq_status = 0x4618, -+ .pdma = { -+ .rx_ptr = 0x6100, -+ .rx_cnt_cfg = 0x6104, -+ .pcrx_ptr = 0x6108, -+ .glo_cfg = 0x6204, -+ .rst_idx = 0x6208, -+ .delay_irq = 0x620c, -+ .irq_status = 0x6220, -+ .irq_mask = 0x6228, -+ .int_grp = 0x6250, -+ }, -+ .qdma = { -+ .qtx_cfg = 0x4400, -+ .rx_ptr = 0x4500, -+ .rx_cnt_cfg = 0x4504, -+ .qcrx_ptr = 0x4508, -+ .glo_cfg = 0x4604, -+ .rst_idx = 0x4608, -+ .delay_irq = 0x460c, -+ .fc_th = 0x4610, -+ .int_grp = 0x4620, -+ .hred = 0x4644, -+ .ctx_ptr = 0x4700, -+ .dtx_ptr = 0x4704, -+ .crx_ptr = 0x4710, -+ .drx_ptr = 0x4714, -+ .fq_head = 0x4720, -+ .fq_tail = 0x4724, -+ .fq_count = 0x4728, -+ .fq_blen = 0x472c, -+ }, -+ .gdm1_cnt = 0x1c00, -+}; -+ - /* strings used by ethtool */ - static const struct mtk_ethtool_stats { - char str[ETH_GSTRING_LEN]; -@@ -110,7 +147,7 @@ static const char * const mtk_clks_sourc - "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", - "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", - "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", -- "sgmii_ck", "eth2pll", -+ "sgmii_ck", "eth2pll", "wocpu0", "wocpu1", "netsys0", "netsys1" - }; - - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) -@@ -3712,6 +3749,21 @@ static const struct mtk_soc_data mt7629_ - }, - }; - -+static const struct mtk_soc_data mt7986_data = { -+ .reg_map = &mt7986_reg_map, -+ .ana_rgc3 = 0x128, -+ .caps = MT7986_CAPS, -+ .required_clks = MT7986_CLKS_BITMAP, -+ .required_pctl = false, -+ .txrx = { -+ .txd_size = sizeof(struct mtk_tx_dma_v2), -+ .rxd_size = sizeof(struct mtk_rx_dma_v2), -+ .rx_irq_done_mask = MTK_RX_DONE_INT_V2, -+ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, -+ .dma_len_offset = 8, -+ }, -+}; -+ - static const struct mtk_soc_data rt5350_data = { - .reg_map = &mt7628_reg_map, - .caps = MT7628_CAPS, -@@ -3734,6 +3786,7 @@ const struct of_device_id of_mtk_match[] - { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, - { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, - { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, -+ { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, - { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, - {}, - }; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -624,6 +624,10 @@ enum mtk_clks_map { - MTK_CLK_SGMII2_CDR_FB, - MTK_CLK_SGMII_CK, - MTK_CLK_ETH2PLL, -+ MTK_CLK_WOCPU0, -+ MTK_CLK_WOCPU1, -+ MTK_CLK_NETSYS0, -+ MTK_CLK_NETSYS1, - MTK_CLK_MAX - }; - -@@ -654,6 +658,16 @@ enum mtk_clks_map { - BIT(MTK_CLK_SGMII2_CDR_FB) | \ - BIT(MTK_CLK_SGMII_CK) | \ - BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) -+#define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ -+ BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ -+ BIT(MTK_CLK_SGMII_TX_250M) | \ -+ BIT(MTK_CLK_SGMII_RX_250M) | \ -+ BIT(MTK_CLK_SGMII_CDR_REF) | \ -+ BIT(MTK_CLK_SGMII_CDR_FB) | \ -+ BIT(MTK_CLK_SGMII2_TX_250M) | \ -+ BIT(MTK_CLK_SGMII2_RX_250M) | \ -+ BIT(MTK_CLK_SGMII2_CDR_REF) | \ -+ BIT(MTK_CLK_SGMII2_CDR_FB)) - - enum mtk_dev_state { - MTK_HW_INIT, -@@ -852,6 +866,10 @@ enum mkt_eth_capabilities { - MTK_MUX_U3_GMAC2_TO_QPHY | \ - MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) - -+#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ -+ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ -+ MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) -+ - struct mtk_tx_dma_desc_info { - dma_addr_t addr; - u32 size; diff --git a/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch b/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch deleted file mode 100644 index e490333a9bb..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-31-net-ethernet-mtk_eth_soc-fix-error-code-in-mtk_flow_.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Dan Carpenter -Date: Thu, 19 May 2022 17:08:00 +0300 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix error code in - mtk_flow_offload_replace() - -Preserve the error code from mtk_foe_entry_commit(). Do not return -success. - -Fixes: c4f033d9e03e ("net: ethernet: mtk_eth_soc: rework hardware flow table management") -Signed-off-by: Dan Carpenter -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -434,7 +434,8 @@ mtk_flow_offload_replace(struct mtk_eth - memcpy(&entry->data, &foe, sizeof(entry->data)); - entry->wed_index = wed_index; - -- if (mtk_foe_entry_commit(eth->ppe, entry) < 0) -+ err = mtk_foe_entry_commit(eth->ppe, entry); -+ if (err < 0) - goto free; - - err = rhashtable_insert_fast(ð->flow_table, &entry->node, diff --git a/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch b/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch deleted file mode 100644 index d76df75dda8..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-33-net-ethernet-mtk_eth_soc-enable-rx-cksum-offload-for.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Lorenzo Bianconi -Date: Mon, 6 Jun 2022 21:49:00 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: enable rx cksum offload for - MTK_NETSYS_V2 - -Enable rx checksum offload for mt7986 chipset. - -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/c8699805c18f7fd38315fcb8da2787676d83a32c.1654544585.git.lorenzo@kernel.org -Signed-off-by: Jakub Kicinski ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1463,8 +1463,8 @@ static int mtk_poll_rx(struct napi_struc - int done = 0, bytes = 0; - - while (done < budget) { -+ unsigned int pktlen, *rxdcsum; - struct net_device *netdev; -- unsigned int pktlen; - dma_addr_t dma_addr; - u32 hash, reason; - int mac = 0; -@@ -1531,7 +1531,13 @@ static int mtk_poll_rx(struct napi_struc - pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); - skb->dev = netdev; - skb_put(skb, pktlen); -- if (trxd.rxd4 & eth->soc->txrx.rx_dma_l4_valid) -+ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ rxdcsum = &trxd.rxd3; -+ else -+ rxdcsum = &trxd.rxd4; -+ -+ if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) - skb->ip_summed = CHECKSUM_UNNECESSARY; - else - skb_checksum_none_assert(skb); -@@ -3759,6 +3765,7 @@ static const struct mtk_soc_data mt7986_ - .txd_size = sizeof(struct mtk_tx_dma_v2), - .rxd_size = sizeof(struct mtk_rx_dma_v2), - .rx_irq_done_mask = MTK_RX_DONE_INT_V2, -+ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2, - .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, - .dma_len_offset = 8, - }, diff --git a/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch b/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch deleted file mode 100644 index 5303ca48a7e..00000000000 --- a/target/linux/generic/backport-6.1/702-v5.19-34-eth-mtk_ppe-fix-up-after-merge.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Jakub Kicinski -Date: Thu, 19 May 2022 18:25:55 -0700 -Subject: [PATCH] eth: mtk_ppe: fix up after merge - -I missed this in the barrage of GCC 12 warnings. Commit cf2df74e202d -("net: fix dev_fill_forward_path with pppoe + bridge") changed -the pointer into an array. - -Fixes: d7e6f5836038 ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net") -Link: https://lore.kernel.org/r/20220520012555.2262461-1-kuba@kernel.org -Signed-off-by: Jakub Kicinski ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -90,10 +90,11 @@ mtk_flow_get_wdma_info(struct net_device - { - struct net_device_path_ctx ctx = { - .dev = dev, -- .daddr = addr, - }; - struct net_device_path path = {}; - -+ memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); -+ - if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) - return -1; - diff --git a/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch b/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch deleted file mode 100644 index 919da4d1ef1..00000000000 --- a/target/linux/generic/backport-6.1/703-00-v5.16-net-convert-users-of-bitmap_foo-to-linkmode_foo.patch +++ /dev/null @@ -1,948 +0,0 @@ -From 4973056cceacc70966396039fae99867dfafd796 Mon Sep 17 00:00:00 2001 -From: Sean Anderson -Date: Fri, 22 Oct 2021 18:41:04 -0400 -Subject: [PATCH] net: convert users of bitmap_foo() to linkmode_foo() - -This converts instances of - bitmap_foo(args..., __ETHTOOL_LINK_MODE_MASK_NBITS) -to - linkmode_foo(args...) - -I manually fixed up some lines to prevent them from being excessively -long. Otherwise, this change was generated with the following semantic -patch: - -// Generated with -// echo linux/linkmode.h > includes -// git grep -Flf includes include/ | cut -f 2- -d / | cat includes - \ -// | sort | uniq | tee new_includes | wc -l && mv new_includes includes -// and repeating until the number stopped going up -@i@ -@@ - -( - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -| - #include -) - -@depends on i@ -expression list args; -@@ - -( -- bitmap_zero(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_zero(args) -| -- bitmap_copy(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_copy(args) -| -- bitmap_and(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_and(args) -| -- bitmap_or(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_or(args) -| -- bitmap_empty(args, ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_empty(args) -| -- bitmap_andnot(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_andnot(args) -| -- bitmap_equal(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_equal(args) -| -- bitmap_intersects(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_intersects(args) -| -- bitmap_subset(args, __ETHTOOL_LINK_MODE_MASK_NBITS) -+ linkmode_subset(args) -) - -Add missing linux/mii.h include to mellanox. -DaveM - -Signed-off-by: Sean Anderson -Signed-off-by: David S. Miller ---- - drivers/net/dsa/b53/b53_common.c | 6 ++---- - drivers/net/dsa/bcm_sf2.c | 8 +++---- - drivers/net/dsa/hirschmann/hellcreek.c | 6 ++---- - drivers/net/dsa/lantiq_gswip.c | 14 ++++++------- - drivers/net/dsa/microchip/ksz8795.c | 8 +++---- - drivers/net/dsa/mv88e6xxx/chip.c | 5 ++--- - drivers/net/dsa/ocelot/felix_vsc9959.c | 8 +++---- - drivers/net/dsa/ocelot/seville_vsc9953.c | 8 +++---- - drivers/net/dsa/qca/ar9331.c | 10 ++++----- - drivers/net/dsa/sja1105/sja1105_main.c | 7 +++---- - drivers/net/dsa/xrs700x/xrs700x.c | 8 +++---- - drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c | 8 +++---- - drivers/net/ethernet/atheros/ag71xx.c | 8 +++---- - drivers/net/ethernet/cadence/macb_main.c | 11 +++++----- - .../net/ethernet/freescale/enetc/enetc_pf.c | 8 +++---- - .../net/ethernet/huawei/hinic/hinic_ethtool.c | 10 ++++----- - .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 5 ++--- - drivers/net/ethernet/marvell/mvneta.c | 10 ++++----- - .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 7 +++---- - .../marvell/octeontx2/nic/otx2_ethtool.c | 5 ++--- - drivers/net/ethernet/marvell/pxa168_eth.c | 3 +-- - .../net/ethernet/mellanox/mlx4/en_ethtool.c | 21 +++++++------------ - .../microchip/sparx5/sparx5_phylink.c | 7 +++---- - drivers/net/ethernet/mscc/ocelot_net.c | 7 +++---- - .../ethernet/pensando/ionic/ionic_ethtool.c | 3 +-- - .../net/ethernet/xilinx/xilinx_axienet_main.c | 8 +++---- - drivers/net/pcs/pcs-xpcs.c | 2 +- - drivers/net/phy/sfp-bus.c | 2 +- - net/ethtool/ioctl.c | 7 +++---- - 29 files changed, 87 insertions(+), 133 deletions(-) - ---- a/drivers/net/dsa/b53/b53_common.c -+++ b/drivers/net/dsa/b53/b53_common.c -@@ -1349,10 +1349,8 @@ void b53_phylink_validate(struct dsa_swi - phylink_set(mask, 100baseT_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - phylink_helper_basex_speed(state); - } ---- a/drivers/net/dsa/bcm_sf2.c -+++ b/drivers/net/dsa/bcm_sf2.c -@@ -686,7 +686,7 @@ static void bcm_sf2_sw_validate(struct d - state->interface != PHY_INTERFACE_MODE_GMII && - state->interface != PHY_INTERFACE_MODE_INTERNAL && - state->interface != PHY_INTERFACE_MODE_MOCA) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - if (port != core_readl(priv, CORE_IMP0_PRT_ID)) - dev_err(ds->dev, - "Unsupported interface: %d for port %d\n", -@@ -714,10 +714,8 @@ static void bcm_sf2_sw_validate(struct d - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, ---- a/drivers/net/dsa/hirschmann/hellcreek.c -+++ b/drivers/net/dsa/hirschmann/hellcreek.c -@@ -1476,10 +1476,8 @@ static void hellcreek_phylink_validate(s - else - phylink_set(mask, 1000baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static int ---- a/drivers/net/dsa/lantiq_gswip.c -+++ b/drivers/net/dsa/lantiq_gswip.c -@@ -1452,10 +1452,8 @@ static void gswip_phylink_set_capab(unsi - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void gswip_xrx200_phylink_validate(struct dsa_switch *ds, int port, -@@ -1483,7 +1481,7 @@ static void gswip_xrx200_phylink_validat - goto unsupported; - break; - default: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported port: %i\n", port); - return; - } -@@ -1493,7 +1491,7 @@ static void gswip_xrx200_phylink_validat - return; - - unsupported: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", - phy_modes(state->interface), port); - } -@@ -1523,7 +1521,7 @@ static void gswip_xrx300_phylink_validat - goto unsupported; - break; - default: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported port: %i\n", port); - return; - } -@@ -1533,7 +1531,7 @@ static void gswip_xrx300_phylink_validat - return; - - unsupported: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", - phy_modes(state->interface), port); - } ---- a/drivers/net/dsa/microchip/ksz8795.c -+++ b/drivers/net/dsa/microchip/ksz8795.c -@@ -1542,15 +1542,13 @@ static void ksz8_validate(struct dsa_swi - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - return; - - unsupported: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported interface: %s, port: %d\n", - phy_modes(state->interface), port); - } ---- a/drivers/net/dsa/mv88e6xxx/chip.c -+++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -683,9 +683,8 @@ static void mv88e6xxx_validate(struct ds - if (chip->info->ops->phylink_validate) - chip->info->ops->phylink_validate(chip, port, mask, state); - -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - /* We can only operate at 2500BaseX or 1000BaseX. If requested - * to advertise both, only report advertising at 2500BaseX. ---- a/drivers/net/dsa/ocelot/felix_vsc9959.c -+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c -@@ -944,7 +944,7 @@ static void vsc9959_phylink_validate(str - - if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != ocelot_port->phy_mode) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -966,10 +966,8 @@ static void vsc9959_phylink_validate(str - phylink_set(mask, 2500baseX_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port, ---- a/drivers/net/dsa/ocelot/seville_vsc9953.c -+++ b/drivers/net/dsa/ocelot/seville_vsc9953.c -@@ -1000,7 +1000,7 @@ static void vsc9953_phylink_validate(str - - if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != ocelot_port->phy_mode) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -1019,10 +1019,8 @@ static void vsc9953_phylink_validate(str - phylink_set(mask, 2500baseX_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static int vsc9953_prevalidate_phy_mode(struct ocelot *ocelot, int port, ---- a/drivers/net/dsa/qca/ar9331.c -+++ b/drivers/net/dsa/qca/ar9331.c -@@ -522,7 +522,7 @@ static void ar9331_sw_phylink_validate(s - goto unsupported; - break; - default: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported port: %i\n", port); - return; - } -@@ -536,15 +536,13 @@ static void ar9331_sw_phylink_validate(s - phylink_set(mask, 100baseT_Half); - phylink_set(mask, 100baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - return; - - unsupported: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported interface: %d, port: %d\n", - state->interface, port); - } ---- a/drivers/net/dsa/sja1105/sja1105_main.c -+++ b/drivers/net/dsa/sja1105/sja1105_main.c -@@ -1360,7 +1360,7 @@ static void sja1105_phylink_validate(str - */ - if (state->interface != PHY_INTERFACE_MODE_NA && - sja1105_phy_mode_mismatch(priv, port, state->interface)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -1380,9 +1380,8 @@ static void sja1105_phylink_validate(str - phylink_set(mask, 2500baseX_Full); - } - -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static int ---- a/drivers/net/dsa/xrs700x/xrs700x.c -+++ b/drivers/net/dsa/xrs700x/xrs700x.c -@@ -457,7 +457,7 @@ static void xrs700x_phylink_validate(str - phylink_set(mask, 1000baseT_Full); - break; - default: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - dev_err(ds->dev, "Unsupported port: %i\n", port); - return; - } -@@ -468,10 +468,8 @@ static void xrs700x_phylink_validate(str - phylink_set(mask, 10baseT_Full); - phylink_set(mask, 100baseT_Full); - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void xrs700x_mac_link_up(struct dsa_switch *ds, int port, ---- a/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c -+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ethtool.c -@@ -369,9 +369,8 @@ static int xgbe_set_link_ksettings(struc - __ETHTOOL_LINK_MODE_MASK_NBITS, cmd->link_modes.advertising, - __ETHTOOL_LINK_MODE_MASK_NBITS, lks->link_modes.supported); - -- bitmap_and(advertising, -- cmd->link_modes.advertising, lks->link_modes.supported, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(advertising, cmd->link_modes.advertising, -+ lks->link_modes.supported); - - if ((cmd->base.autoneg == AUTONEG_ENABLE) && - bitmap_empty(advertising, __ETHTOOL_LINK_MODE_MASK_NBITS)) { -@@ -384,8 +383,7 @@ static int xgbe_set_link_ksettings(struc - pdata->phy.autoneg = cmd->base.autoneg; - pdata->phy.speed = speed; - pdata->phy.duplex = cmd->base.duplex; -- bitmap_copy(lks->link_modes.advertising, advertising, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_copy(lks->link_modes.advertising, advertising); - - if (cmd->base.autoneg == AUTONEG_ENABLE) - XGBE_SET_ADV(lks, Autoneg); ---- a/drivers/net/ethernet/atheros/ag71xx.c -+++ b/drivers/net/ethernet/atheros/ag71xx.c -@@ -1082,14 +1082,12 @@ static void ag71xx_mac_validate(struct p - phylink_set(mask, 1000baseX_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - return; - unsupported: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - } - - static void ag71xx_mac_pcs_get_state(struct phylink_config *config, ---- a/drivers/net/ethernet/cadence/macb_main.c -+++ b/drivers/net/ethernet/cadence/macb_main.c -@@ -523,21 +523,21 @@ static void macb_validate(struct phylink - state->interface != PHY_INTERFACE_MODE_SGMII && - state->interface != PHY_INTERFACE_MODE_10GBASER && - !phy_interface_mode_is_rgmii(state->interface)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - - if (!macb_is_gem(bp) && - (state->interface == PHY_INTERFACE_MODE_GMII || - phy_interface_mode_is_rgmii(state->interface))) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - - if (state->interface == PHY_INTERFACE_MODE_10GBASER && - !(bp->caps & MACB_CAPS_HIGH_SPEED && - bp->caps & MACB_CAPS_PCS)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -576,9 +576,8 @@ static void macb_validate(struct phylink - phylink_set(mask, 1000baseT_Half); - } - out: -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void macb_usx_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, ---- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c -+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c -@@ -965,7 +965,7 @@ static void enetc_pl_mac_validate(struct - state->interface != PHY_INTERFACE_MODE_2500BASEX && - state->interface != PHY_INTERFACE_MODE_USXGMII && - !phy_interface_mode_is_rgmii(state->interface)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -988,10 +988,8 @@ static void enetc_pl_mac_validate(struct - phylink_set(mask, 2500baseX_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void enetc_pl_mac_config(struct phylink_config *config, ---- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c -+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c -@@ -322,12 +322,10 @@ static int hinic_get_link_ksettings(stru - } - } - -- bitmap_copy(link_ksettings->link_modes.supported, -- (unsigned long *)&settings.supported, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_copy(link_ksettings->link_modes.advertising, -- (unsigned long *)&settings.advertising, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_copy(link_ksettings->link_modes.supported, -+ (unsigned long *)&settings.supported); -+ linkmode_copy(link_ksettings->link_modes.advertising, -+ (unsigned long *)&settings.advertising); - - return 0; - } ---- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c -+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c -@@ -467,9 +467,8 @@ static int ixgbe_set_link_ksettings(stru - * this function does not support duplex forcing, but can - * limit the advertising of the adapter to the specified speed - */ -- if (!bitmap_subset(cmd->link_modes.advertising, -- cmd->link_modes.supported, -- __ETHTOOL_LINK_MODE_MASK_NBITS)) -+ if (!linkmode_subset(cmd->link_modes.advertising, -+ cmd->link_modes.supported)) - return -EINVAL; - - /* only allow one speed at a time if no autoneg */ ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -3835,14 +3835,14 @@ static void mvneta_validate(struct phyli - */ - if (phy_interface_mode_is_8023z(state->interface)) { - if (!phylink_test(state->advertising, Autoneg)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - } else if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != PHY_INTERFACE_MODE_QSGMII && - state->interface != PHY_INTERFACE_MODE_SGMII && - !phy_interface_mode_is_rgmii(state->interface)) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -3871,10 +3871,8 @@ static void mvneta_validate(struct phyli - phylink_set(mask, 100baseT_Full); - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - /* We can only operate at 2500BaseX or 1000BaseX. If requested - * to advertise both, only report advertising at 2500BaseX. ---- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c -+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c -@@ -6347,15 +6347,14 @@ static void mvpp2_phylink_validate(struc - goto empty_set; - } - -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - - phylink_helper_basex_speed(state); - return; - - empty_set: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - } - - static void mvpp2_xlg_config(struct mvpp2_port *port, unsigned int mode, ---- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c -+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c -@@ -1168,9 +1168,8 @@ static int otx2_set_link_ksettings(struc - otx2_get_link_ksettings(netdev, &cur_ks); - - /* Check requested modes against supported modes by hardware */ -- if (!bitmap_subset(cmd->link_modes.advertising, -- cur_ks.link_modes.supported, -- __ETHTOOL_LINK_MODE_MASK_NBITS)) -+ if (!linkmode_subset(cmd->link_modes.advertising, -+ cur_ks.link_modes.supported)) - return -EINVAL; - - mutex_lock(&mbox->lock); ---- a/drivers/net/ethernet/marvell/pxa168_eth.c -+++ b/drivers/net/ethernet/marvell/pxa168_eth.c -@@ -977,8 +977,7 @@ static int pxa168_init_phy(struct net_de - cmd.base.phy_address = pep->phy_addr; - cmd.base.speed = pep->phy_speed; - cmd.base.duplex = pep->phy_duplex; -- bitmap_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_copy(cmd.link_modes.advertising, PHY_BASIC_FEATURES); - cmd.base.autoneg = AUTONEG_ENABLE; - - if (cmd.base.speed != 0) ---- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c -+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - - #include "mlx4_en.h" - #include "en_port.h" -@@ -643,10 +644,8 @@ static unsigned long *ptys2ethtool_link_ - unsigned int i; \ - cfg = &ptys2ethtool_map[reg_]; \ - cfg->speed = speed_; \ -- bitmap_zero(cfg->supported, \ -- __ETHTOOL_LINK_MODE_MASK_NBITS); \ -- bitmap_zero(cfg->advertised, \ -- __ETHTOOL_LINK_MODE_MASK_NBITS); \ -+ linkmode_zero(cfg->supported); \ -+ linkmode_zero(cfg->advertised); \ - for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \ - __set_bit(modes[i], cfg->supported); \ - __set_bit(modes[i], cfg->advertised); \ -@@ -702,10 +701,8 @@ static void ptys2ethtool_update_link_mod - int i; - for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { - if (eth_proto & MLX4_PROT_MASK(i)) -- bitmap_or(link_modes, link_modes, -- ptys2ethtool_link_mode(&ptys2ethtool_map[i], -- report), -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_or(link_modes, link_modes, -+ ptys2ethtool_link_mode(&ptys2ethtool_map[i], report)); - } - } - -@@ -716,11 +713,9 @@ static u32 ethtool2ptys_link_modes(const - u32 ptys_modes = 0; - - for (i = 0; i < MLX4_LINK_MODES_SZ; i++) { -- if (bitmap_intersects( -- ptys2ethtool_link_mode(&ptys2ethtool_map[i], -- report), -- link_modes, -- __ETHTOOL_LINK_MODE_MASK_NBITS)) -+ ulong *map_mode = ptys2ethtool_link_mode(&ptys2ethtool_map[i], -+ report); -+ if (linkmode_intersects(map_mode, link_modes)) - ptys_modes |= 1 << i; - } - return ptys_modes; ---- a/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c -+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_phylink.c -@@ -92,12 +92,11 @@ static void sparx5_phylink_validate(stru - } - break; - default: -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void sparx5_phylink_mac_config(struct phylink_config *config, ---- a/drivers/net/ethernet/mscc/ocelot_net.c -+++ b/drivers/net/ethernet/mscc/ocelot_net.c -@@ -1509,7 +1509,7 @@ static void vsc7514_phylink_validate(str - - if (state->interface != PHY_INTERFACE_MODE_NA && - state->interface != ocelot_port->phy_mode) { -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - -@@ -1528,9 +1528,8 @@ static void vsc7514_phylink_validate(str - phylink_set(mask, 2500baseT_Full); - phylink_set(mask, 2500baseX_Full); - -- bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void vsc7514_phylink_mac_config(struct phylink_config *config, ---- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c -+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c -@@ -228,8 +228,7 @@ static int ionic_get_link_ksettings(stru - break; - } - -- bitmap_copy(ks->link_modes.advertising, ks->link_modes.supported, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_copy(ks->link_modes.advertising, ks->link_modes.supported); - - ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER); - ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS); ---- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c -@@ -1565,7 +1565,7 @@ static void axienet_validate(struct phyl - netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n", - phy_modes(state->interface), - phy_modes(lp->phy_mode)); -- bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(supported); - return; - } - } -@@ -1598,10 +1598,8 @@ static void axienet_validate(struct phyl - break; - } - -- bitmap_and(supported, supported, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -- bitmap_and(state->advertising, state->advertising, mask, -- __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); - } - - static void axienet_mac_pcs_get_state(struct phylink_config *config, ---- a/drivers/net/pcs/pcs-xpcs.c -+++ b/drivers/net/pcs/pcs-xpcs.c -@@ -637,7 +637,7 @@ void xpcs_validate(struct dw_xpcs *xpcs, - if (state->interface == PHY_INTERFACE_MODE_NA) - return; - -- bitmap_zero(xpcs_supported, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(xpcs_supported); - - compat = xpcs_find_compat(xpcs->id, state->interface); - ---- a/drivers/net/phy/sfp-bus.c -+++ b/drivers/net/phy/sfp-bus.c -@@ -379,7 +379,7 @@ void sfp_parse_support(struct sfp_bus *b - if (bus->sfp_quirk) - bus->sfp_quirk->modes(id, modes); - -- bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_or(support, support, modes); - - phylink_set(support, Autoneg); - phylink_set(support, Pause); ---- a/net/ethtool/ioctl.c -+++ b/net/ethtool/ioctl.c -@@ -335,7 +335,7 @@ EXPORT_SYMBOL(ethtool_intersect_link_mas - void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, - u32 legacy_u32) - { -- bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(dst); - dst[0] = legacy_u32; - } - EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode); -@@ -350,11 +350,10 @@ bool ethtool_convert_link_mode_to_legacy - if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(ext); - -- bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS); -+ linkmode_zero(ext); - bitmap_fill(ext, 32); - bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS); -- if (bitmap_intersects(ext, src, -- __ETHTOOL_LINK_MODE_MASK_NBITS)) { -+ if (linkmode_intersects(ext, src)) { - /* src mask goes beyond bit 31 */ - retval = false; - } diff --git a/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch b/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch deleted file mode 100644 index 885c2fcf252..00000000000 --- a/target/linux/generic/backport-6.1/703-01-v5.16-net-phylink-add-MAC-phy_interface_t-bitmap.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 38c310eb46f5f80213a92093af11af270c209a76 Mon Sep 17 00:00:00 2001 -From: Russell King -Date: Tue, 26 Oct 2021 11:06:06 +0100 -Subject: [PATCH] net: phylink: add MAC phy_interface_t bitmap - -Add a phy_interface_t bitmap so the MAC driver can specifiy which PHY -interface modes it supports. - -Signed-off-by: Russell King -Signed-off-by: David S. Miller ---- - include/linux/phylink.h | 1 + - 1 file changed, 1 insertion(+) - ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -78,6 +78,7 @@ struct phylink_config { - bool ovr_an_inband; - void (*get_fixed_state)(struct phylink_config *config, - struct phylink_link_state *state); -+ DECLARE_PHY_INTERFACE_MASK(supported_interfaces); - }; - - /** diff --git a/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch b/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch deleted file mode 100644 index 9800884f6e9..00000000000 --- a/target/linux/generic/backport-6.1/703-02-v5.16-net-phylink-use-supported_interfaces-for-phylink-val.patch +++ /dev/null @@ -1,98 +0,0 @@ -From d25f3a74f30aace819163dfa54f2a4b8ca1dc932 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 26 Oct 2021 11:06:11 +0100 -Subject: [PATCH] net: phylink: use supported_interfaces for phylink - validation - -If the network device supplies a supported interface bitmap, we can use -that during phylink's validation to simplify MAC drivers in two ways by -using the supported_interfaces bitmap to: - -1. reject unsupported interfaces before calling into the MAC driver. -2. generate the set of all supported link modes across all supported - interfaces (used mainly for SFP, but also some 10G PHYs.) - -Suggested-by: Sean Anderson -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/phy/phylink.c | 36 ++++++++++++++++++++++++++++++++++++ - include/linux/phylink.h | 12 ++++++++++-- - 2 files changed, 46 insertions(+), 2 deletions(-) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -155,9 +155,45 @@ static const char *phylink_an_mode_str(u - return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; - } - -+static int phylink_validate_any(struct phylink *pl, unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_adv) = { 0, }; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(all_s) = { 0, }; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(s); -+ struct phylink_link_state t; -+ int intf; -+ -+ for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) { -+ if (test_bit(intf, pl->config->supported_interfaces)) { -+ linkmode_copy(s, supported); -+ -+ t = *state; -+ t.interface = intf; -+ pl->mac_ops->validate(pl->config, s, &t); -+ linkmode_or(all_s, all_s, s); -+ linkmode_or(all_adv, all_adv, t.advertising); -+ } -+ } -+ -+ linkmode_copy(supported, all_s); -+ linkmode_copy(state->advertising, all_adv); -+ -+ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; -+} -+ - static int phylink_validate(struct phylink *pl, unsigned long *supported, - struct phylink_link_state *state) - { -+ if (!phy_interface_empty(pl->config->supported_interfaces)) { -+ if (state->interface == PHY_INTERFACE_MODE_NA) -+ return phylink_validate_any(pl, supported, state); -+ -+ if (!test_bit(state->interface, -+ pl->config->supported_interfaces)) -+ return -EINVAL; -+ } -+ - pl->mac_ops->validate(pl->config, supported, state); - - return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -68,6 +68,8 @@ enum phylink_op_type { - * @ovr_an_inband: if true, override PCS to MLO_AN_INBAND - * @get_fixed_state: callback to execute to determine the fixed link state, - * if MAC link is at %MLO_AN_FIXED mode. -+ * @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx -+ * are supported by the MAC/PCS. - */ - struct phylink_config { - struct device *dev; -@@ -136,8 +138,14 @@ struct phylink_mac_ops { - * based on @state->advertising and/or @state->speed and update - * @state->interface accordingly. See phylink_helper_basex_speed(). - * -- * When @state->interface is %PHY_INTERFACE_MODE_NA, phylink expects the -- * MAC driver to return all supported link modes. -+ * When @config->supported_interfaces has been set, phylink will iterate -+ * over the supported interfaces to determine the full capability of the -+ * MAC. The validation function must not print errors if @state->interface -+ * is set to an unexpected value. -+ * -+ * When @config->supported_interfaces is empty, phylink will call this -+ * function with @state->interface set to %PHY_INTERFACE_MODE_NA, and -+ * expects the MAC driver to return all supported link modes. - * - * If the @state->interface mode is not supported, then the @supported - * mask must be cleared. diff --git a/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch deleted file mode 100644 index b10e6da0e9a..00000000000 --- a/target/linux/generic/backport-6.1/703-03-v5.16-net-dsa-populate-supported_interfaces-member.patch +++ /dev/null @@ -1,63 +0,0 @@ -From c07c6e8eb4b38bae921f9e2f108d1e7f8e14226e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marek=20Beh=C3=BAn?= -Date: Thu, 28 Oct 2021 18:00:14 +0100 -Subject: [PATCH] net: dsa: populate supported_interfaces member -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add a new DSA switch operation, phylink_get_interfaces, which should -fill in which PHY_INTERFACE_MODE_* are supported by given port. - -Use this before phylink_create() to fill phylinks supported_interfaces -member, allowing phylink to determine which PHY_INTERFACE_MODEs are -supported. - -Signed-off-by: Marek Behún -[tweaked patch and description to add more complete support -- rmk] -Signed-off-by: Russell King -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 2 ++ - net/dsa/port.c | 4 ++++ - net/dsa/slave.c | 4 ++++ - 3 files changed, 10 insertions(+) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -626,6 +626,8 @@ struct dsa_switch_ops { - /* - * PHYLINK integration - */ -+ void (*phylink_get_interfaces)(struct dsa_switch *ds, int port, -+ unsigned long *supported_interfaces); - void (*phylink_validate)(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state); ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1188,6 +1188,10 @@ static int dsa_port_phylink_register(str - dp->pl_config.type = PHYLINK_DEV; - dp->pl_config.pcs_poll = ds->pcs_poll; - -+ if (ds->ops->phylink_get_interfaces) -+ ds->ops->phylink_get_interfaces(ds, dp->index, -+ dp->pl_config.supported_interfaces); -+ - dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), - mode, &dsa_port_phylink_mac_ops); - if (IS_ERR(dp->pl)) { ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -1837,6 +1837,10 @@ static int dsa_slave_phy_setup(struct ne - dp->pl_config.poll_fixed_state = true; - } - -+ if (ds->ops->phylink_get_interfaces) -+ ds->ops->phylink_get_interfaces(ds, dp->index, -+ dp->pl_config.supported_interfaces); -+ - dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, - &dsa_port_phylink_mac_ops); - if (IS_ERR(dp->pl)) { diff --git a/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch b/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch deleted file mode 100644 index 9b67a8a5185..00000000000 --- a/target/linux/generic/backport-6.1/703-04-v5.17-net-dsa-consolidate-phylink-creation.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 21bd64bd717dedac96f53b668144cbe37d3c12d4 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 30 Nov 2021 13:09:55 +0000 -Subject: [PATCH] net: dsa: consolidate phylink creation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The code in port.c and slave.c creating the phylink instance is very -similar - let's consolidate this into a single function. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Marek Behún -Reviewed-by: Andrew Lunn -Signed-off-by: Jakub Kicinski ---- - net/dsa/dsa_priv.h | 2 +- - net/dsa/port.c | 44 ++++++++++++++++++++++++++++---------------- - net/dsa/slave.c | 19 +++---------------- - 3 files changed, 32 insertions(+), 33 deletions(-) - ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -261,13 +261,13 @@ int dsa_port_mrp_add_ring_role(const str - const struct switchdev_obj_ring_role_mrp *mrp); - int dsa_port_mrp_del_ring_role(const struct dsa_port *dp, - const struct switchdev_obj_ring_role_mrp *mrp); -+int dsa_port_phylink_create(struct dsa_port *dp); - int dsa_port_link_register_of(struct dsa_port *dp); - void dsa_port_link_unregister_of(struct dsa_port *dp); - int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr); - void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr); - int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast); - void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast); --extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; - - static inline bool dsa_port_offloads_bridge_port(struct dsa_port *dp, - const struct net_device *dev) ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1092,7 +1092,7 @@ static void dsa_port_phylink_mac_link_up - speed, duplex, tx_pause, rx_pause); - } - --const struct phylink_mac_ops dsa_port_phylink_mac_ops = { -+static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { - .validate = dsa_port_phylink_validate, - .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, - .mac_config = dsa_port_phylink_mac_config, -@@ -1101,6 +1101,30 @@ const struct phylink_mac_ops dsa_port_ph - .mac_link_up = dsa_port_phylink_mac_link_up, - }; - -+int dsa_port_phylink_create(struct dsa_port *dp) -+{ -+ struct dsa_switch *ds = dp->ds; -+ phy_interface_t mode; -+ int err; -+ -+ err = of_get_phy_mode(dp->dn, &mode); -+ if (err) -+ mode = PHY_INTERFACE_MODE_NA; -+ -+ if (ds->ops->phylink_get_interfaces) -+ ds->ops->phylink_get_interfaces(ds, dp->index, -+ dp->pl_config.supported_interfaces); -+ -+ dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), -+ mode, &dsa_port_phylink_mac_ops); -+ if (IS_ERR(dp->pl)) { -+ pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); -+ return PTR_ERR(dp->pl); -+ } -+ -+ return 0; -+} -+ - static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable) - { - struct dsa_switch *ds = dp->ds; -@@ -1177,27 +1201,15 @@ static int dsa_port_phylink_register(str - { - struct dsa_switch *ds = dp->ds; - struct device_node *port_dn = dp->dn; -- phy_interface_t mode; - int err; - -- err = of_get_phy_mode(port_dn, &mode); -- if (err) -- mode = PHY_INTERFACE_MODE_NA; -- - dp->pl_config.dev = ds->dev; - dp->pl_config.type = PHYLINK_DEV; - dp->pl_config.pcs_poll = ds->pcs_poll; - -- if (ds->ops->phylink_get_interfaces) -- ds->ops->phylink_get_interfaces(ds, dp->index, -- dp->pl_config.supported_interfaces); -- -- dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), -- mode, &dsa_port_phylink_mac_ops); -- if (IS_ERR(dp->pl)) { -- pr_err("error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); -- return PTR_ERR(dp->pl); -- } -+ err = dsa_port_phylink_create(dp); -+ if (err) -+ return err; - - err = phylink_of_phy_connect(dp->pl, port_dn, 0); - if (err && err != -ENODEV) { ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -1817,14 +1817,9 @@ static int dsa_slave_phy_setup(struct ne - struct dsa_port *dp = dsa_slave_to_port(slave_dev); - struct device_node *port_dn = dp->dn; - struct dsa_switch *ds = dp->ds; -- phy_interface_t mode; - u32 phy_flags = 0; - int ret; - -- ret = of_get_phy_mode(port_dn, &mode); -- if (ret) -- mode = PHY_INTERFACE_MODE_NA; -- - dp->pl_config.dev = &slave_dev->dev; - dp->pl_config.type = PHYLINK_NETDEV; - -@@ -1837,17 +1832,9 @@ static int dsa_slave_phy_setup(struct ne - dp->pl_config.poll_fixed_state = true; - } - -- if (ds->ops->phylink_get_interfaces) -- ds->ops->phylink_get_interfaces(ds, dp->index, -- dp->pl_config.supported_interfaces); -- -- dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, -- &dsa_port_phylink_mac_ops); -- if (IS_ERR(dp->pl)) { -- netdev_err(slave_dev, -- "error creating PHYLINK: %ld\n", PTR_ERR(dp->pl)); -- return PTR_ERR(dp->pl); -- } -+ ret = dsa_port_phylink_create(dp); -+ if (ret) -+ return ret; - - if (ds->ops->get_phy_flags) - phy_flags = ds->ops->get_phy_flags(ds, dp->index); diff --git a/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch b/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch deleted file mode 100644 index d70b9aa6a47..00000000000 --- a/target/linux/generic/backport-6.1/703-05-v5.17-net-dsa-replace-phylink_get_interfaces-with-phylink_.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 072eea6c22b2af680c3949e64f9adde278c71e68 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 30 Nov 2021 13:10:01 +0000 -Subject: [PATCH] net: dsa: replace phylink_get_interfaces() with - phylink_get_caps() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Phylink needs slightly more information than phylink_get_interfaces() -allows us to get from the DSA drivers - we need the MAC capabilities. -Replace the phylink_get_interfaces() method with phylink_get_caps() to -allow DSA drivers to fill in the phylink_config MAC capabilities field -as well. - -Signed-off-by: Russell King (Oracle) -Reviewed-by: Marek Behún -Reviewed-by: Andrew Lunn -Signed-off-by: Jakub Kicinski ---- - include/net/dsa.h | 4 ++-- - net/dsa/port.c | 5 ++--- - 2 files changed, 4 insertions(+), 5 deletions(-) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -626,8 +626,8 @@ struct dsa_switch_ops { - /* - * PHYLINK integration - */ -- void (*phylink_get_interfaces)(struct dsa_switch *ds, int port, -- unsigned long *supported_interfaces); -+ void (*phylink_get_caps)(struct dsa_switch *ds, int port, -+ struct phylink_config *config); - void (*phylink_validate)(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state); ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1111,9 +1111,8 @@ int dsa_port_phylink_create(struct dsa_p - if (err) - mode = PHY_INTERFACE_MODE_NA; - -- if (ds->ops->phylink_get_interfaces) -- ds->ops->phylink_get_interfaces(ds, dp->index, -- dp->pl_config.supported_interfaces); -+ if (ds->ops->phylink_get_caps) -+ ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); - - dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn), - mode, &dsa_port_phylink_mac_ops); diff --git a/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch b/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch deleted file mode 100644 index 2af5cb9d9db..00000000000 --- a/target/linux/generic/backport-6.1/703-06-v5.18-net-dsa-add-support-for-phylink-mac_select_pcs.patch +++ /dev/null @@ -1,59 +0,0 @@ -From bde018222c6b084ac32933a9f933581dd83da18e Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Thu, 17 Feb 2022 18:30:35 +0000 -Subject: [PATCH] net: dsa: add support for phylink mac_select_pcs() - -Add DSA support for the phylink mac_select_pcs() method so DSA drivers -can return provide phylink with the appropriate PCS for the PHY -interface mode. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 3 +++ - net/dsa/port.c | 15 +++++++++++++++ - 2 files changed, 18 insertions(+) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -631,6 +631,9 @@ struct dsa_switch_ops { - void (*phylink_validate)(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state); -+ struct phylink_pcs *(*phylink_mac_select_pcs)(struct dsa_switch *ds, -+ int port, -+ phy_interface_t iface); - int (*phylink_mac_link_state)(struct dsa_switch *ds, int port, - struct phylink_link_state *state); - void (*phylink_mac_config)(struct dsa_switch *ds, int port, ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1028,6 +1028,20 @@ static void dsa_port_phylink_mac_pcs_get - } - } - -+static struct phylink_pcs * -+dsa_port_phylink_mac_select_pcs(struct phylink_config *config, -+ phy_interface_t interface) -+{ -+ struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); -+ struct dsa_switch *ds = dp->ds; -+ struct phylink_pcs *pcs = NULL; -+ -+ if (ds->ops->phylink_mac_select_pcs) -+ pcs = ds->ops->phylink_mac_select_pcs(ds, dp->index, interface); -+ -+ return pcs; -+} -+ - static void dsa_port_phylink_mac_config(struct phylink_config *config, - unsigned int mode, - const struct phylink_link_state *state) -@@ -1094,6 +1108,7 @@ static void dsa_port_phylink_mac_link_up - - static const struct phylink_mac_ops dsa_port_phylink_mac_ops = { - .validate = dsa_port_phylink_validate, -+ .mac_select_pcs = dsa_port_phylink_mac_select_pcs, - .mac_pcs_get_state = dsa_port_phylink_mac_pcs_get_state, - .mac_config = dsa_port_phylink_mac_config, - .mac_an_restart = dsa_port_phylink_mac_an_restart, diff --git a/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch b/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch deleted file mode 100644 index 1a7817b0f96..00000000000 --- a/target/linux/generic/backport-6.1/703-07-v5.16-net-phy-add-phy_interface_t-bitmap-support.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 8e20f591f204f8db7f1182918f8e2285d3f589e0 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 26 Oct 2021 11:06:01 +0100 -Subject: [PATCH] net: phy: add phy_interface_t bitmap support - -Add support for a bitmap for phy interface modes, which includes: -- a macro to declare the interface bitmap -- an inline helper to zero the interface bitmap -- an inline helper to detect an empty interface bitmap -- inline helpers to do a bitwise AND and OR operations on two interface - bitmaps - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - include/linux/phy.h | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - ---- a/include/linux/phy.h -+++ b/include/linux/phy.h -@@ -155,6 +155,40 @@ typedef enum { - PHY_INTERFACE_MODE_MAX, - } phy_interface_t; - -+/* PHY interface mode bitmap handling */ -+#define DECLARE_PHY_INTERFACE_MASK(name) \ -+ DECLARE_BITMAP(name, PHY_INTERFACE_MODE_MAX) -+ -+static inline void phy_interface_zero(unsigned long *intf) -+{ -+ bitmap_zero(intf, PHY_INTERFACE_MODE_MAX); -+} -+ -+static inline bool phy_interface_empty(const unsigned long *intf) -+{ -+ return bitmap_empty(intf, PHY_INTERFACE_MODE_MAX); -+} -+ -+static inline void phy_interface_and(unsigned long *dst, const unsigned long *a, -+ const unsigned long *b) -+{ -+ bitmap_and(dst, a, b, PHY_INTERFACE_MODE_MAX); -+} -+ -+static inline void phy_interface_or(unsigned long *dst, const unsigned long *a, -+ const unsigned long *b) -+{ -+ bitmap_or(dst, a, b, PHY_INTERFACE_MODE_MAX); -+} -+ -+static inline void phy_interface_set_rgmii(unsigned long *intf) -+{ -+ __set_bit(PHY_INTERFACE_MODE_RGMII, intf); -+ __set_bit(PHY_INTERFACE_MODE_RGMII_ID, intf); -+ __set_bit(PHY_INTERFACE_MODE_RGMII_RXID, intf); -+ __set_bit(PHY_INTERFACE_MODE_RGMII_TXID, intf); -+} -+ - /* - * phy_supported_speeds - return all speeds currently supported by a PHY device - */ diff --git a/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch b/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch deleted file mode 100644 index d826877e7dc..00000000000 --- a/target/linux/generic/backport-6.1/703-08-v5.17-net-phylink-add-mac_select_pcs-method-to-phylink_mac.patch +++ /dev/null @@ -1,197 +0,0 @@ -From d1e86325af377129adb7fc6f34eb044ca6068b47 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 15 Dec 2021 15:34:15 +0000 -Subject: [PATCH] net: phylink: add mac_select_pcs() method to phylink_mac_ops - -mac_select_pcs() allows us to have an explicit point to query which -PCS the MAC wishes to use for a particular PHY interface mode, thereby -allowing us to add support to validate the link settings with the PCS. - -Phylink will also use this to select the PCS to be used during a major -configuration event without the MAC driver needing to call -phylink_set_pcs(). - -Note that if mac_select_pcs() is present, the supported_interfaces -bitmap must be filled in; this avoids mac_select_pcs() being called -with PHY_INTERFACE_MODE_NA when we want to get support for all -interface types. Phylink will return an error in phylink_create() -unless this condition is satisfied. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/phy/phylink.c | 68 +++++++++++++++++++++++++++++++++------ - include/linux/phylink.h | 18 +++++++++++ - 2 files changed, 77 insertions(+), 9 deletions(-) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -155,6 +155,23 @@ static const char *phylink_an_mode_str(u - return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; - } - -+static int phylink_validate_mac_and_pcs(struct phylink *pl, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ struct phylink_pcs *pcs; -+ -+ if (pl->mac_ops->mac_select_pcs) { -+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); -+ if (IS_ERR(pcs)) -+ return PTR_ERR(pcs); -+ } -+ -+ pl->mac_ops->validate(pl->config, supported, state); -+ -+ return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; -+} -+ - static int phylink_validate_any(struct phylink *pl, unsigned long *supported, - struct phylink_link_state *state) - { -@@ -170,9 +187,10 @@ static int phylink_validate_any(struct p - - t = *state; - t.interface = intf; -- pl->mac_ops->validate(pl->config, s, &t); -- linkmode_or(all_s, all_s, s); -- linkmode_or(all_adv, all_adv, t.advertising); -+ if (!phylink_validate_mac_and_pcs(pl, s, &t)) { -+ linkmode_or(all_s, all_s, s); -+ linkmode_or(all_adv, all_adv, t.advertising); -+ } - } - } - -@@ -194,9 +212,7 @@ static int phylink_validate(struct phyli - return -EINVAL; - } - -- pl->mac_ops->validate(pl->config, supported, state); -- -- return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; -+ return phylink_validate_mac_and_pcs(pl, supported, state); - } - - static int phylink_parse_fixedlink(struct phylink *pl, -@@ -486,10 +502,21 @@ static void phylink_mac_pcs_an_restart(s - static void phylink_major_config(struct phylink *pl, bool restart, - const struct phylink_link_state *state) - { -+ struct phylink_pcs *pcs = NULL; - int err; - - phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); - -+ if (pl->mac_ops->mac_select_pcs) { -+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); -+ if (IS_ERR(pcs)) { -+ phylink_err(pl, -+ "mac_select_pcs unexpectedly failed: %pe\n", -+ pcs); -+ return; -+ } -+ } -+ - if (pl->mac_ops->mac_prepare) { - err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode, - state->interface); -@@ -500,6 +527,12 @@ static void phylink_major_config(struct - } - } - -+ /* If we have a new PCS, switch to the new PCS after preparing the MAC -+ * for the change. -+ */ -+ if (pcs) -+ phylink_set_pcs(pl, pcs); -+ - phylink_mac_config(pl, state); - - if (pl->pcs_ops) { -@@ -879,6 +912,14 @@ struct phylink *phylink_create(struct ph - struct phylink *pl; - int ret; - -+ /* Validate the supplied configuration */ -+ if (mac_ops->mac_select_pcs && -+ phy_interface_empty(config->supported_interfaces)) { -+ dev_err(config->dev, -+ "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); -+ return ERR_PTR(-EINVAL); -+ } -+ - pl = kzalloc(sizeof(*pl), GFP_KERNEL); - if (!pl) - return ERR_PTR(-ENOMEM); -@@ -946,9 +987,10 @@ EXPORT_SYMBOL_GPL(phylink_create); - * @pl: a pointer to a &struct phylink returned from phylink_create() - * @pcs: a pointer to the &struct phylink_pcs - * -- * Bind the MAC PCS to phylink. This may be called after phylink_create(), -- * in mac_prepare() or mac_config() methods if it is desired to dynamically -- * change the PCS. -+ * Bind the MAC PCS to phylink. This may be called after phylink_create(). -+ * If it is desired to dynamically change the PCS, then the preferred method -+ * is to use mac_select_pcs(), but it may also be called in mac_prepare() -+ * or mac_config(). - * - * Please note that there are behavioural changes with the mac_config() - * callback if a PCS is present (denoting a newer setup) so removing a PCS -@@ -959,6 +1001,14 @@ void phylink_set_pcs(struct phylink *pl, - { - pl->pcs = pcs; - pl->pcs_ops = pcs->ops; -+ -+ if (!pl->phylink_disable_state && -+ pl->cfg_link_an_mode == MLO_AN_INBAND) { -+ if (pl->config->pcs_poll || pcs->poll) -+ mod_timer(&pl->link_poll, jiffies + HZ); -+ else -+ del_timer(&pl->link_poll); -+ } - } - EXPORT_SYMBOL_GPL(phylink_set_pcs); - ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -86,6 +86,7 @@ struct phylink_config { - /** - * struct phylink_mac_ops - MAC operations structure. - * @validate: Validate and update the link configuration. -+ * @mac_select_pcs: Select a PCS for the interface mode. - * @mac_pcs_get_state: Read the current link state from the hardware. - * @mac_prepare: prepare for a major reconfiguration of the interface. - * @mac_config: configure the MAC for the selected mode and state. -@@ -100,6 +101,8 @@ struct phylink_mac_ops { - void (*validate)(struct phylink_config *config, - unsigned long *supported, - struct phylink_link_state *state); -+ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config, -+ phy_interface_t interface); - void (*mac_pcs_get_state)(struct phylink_config *config, - struct phylink_link_state *state); - int (*mac_prepare)(struct phylink_config *config, unsigned int mode, -@@ -152,6 +155,21 @@ struct phylink_mac_ops { - */ - void validate(struct phylink_config *config, unsigned long *supported, - struct phylink_link_state *state); -+/** -+ * mac_select_pcs: Select a PCS for the interface mode. -+ * @config: a pointer to a &struct phylink_config. -+ * @interface: PHY interface mode for PCS -+ * -+ * Return the &struct phylink_pcs for the specified interface mode, or -+ * NULL if none is required, or an error pointer on error. -+ * -+ * This must not modify any state. It is used to query which PCS should -+ * be used. Phylink will use this during validation to ensure that the -+ * configuration is valid, and when setting a configuration to internally -+ * set the PCS that will be used. -+ */ -+struct phylink_pcs *mac_select_pcs(struct phylink_config *config, -+ phy_interface_t interface); - - /** - * mac_pcs_get_state() - Read the current inband link state from the hardware diff --git a/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch b/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch deleted file mode 100644 index f30a566c81e..00000000000 --- a/target/linux/generic/backport-6.1/703-09-v5.17-net-phylink-add-generic-validate-implementation.patch +++ /dev/null @@ -1,341 +0,0 @@ -From 34ae2c09d46a2d0abd907e139b466f798e4095a8 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 15 Nov 2021 10:00:27 +0000 -Subject: [PATCH] net: phylink: add generic validate implementation - -Add a generic validate() implementation using the supported_interfaces -and a bitmask of MAC pause/speed/duplex capabilities. This allows us -to entirely eliminate many driver private validate() implementations. - -We expose the underlying phylink_get_linkmodes() function so that -drivers which have special needs can still benefit from conversion. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/phy/phylink.c | 252 ++++++++++++++++++++++++++++++++++++++ - include/linux/phylink.h | 31 +++++ - 2 files changed, 283 insertions(+) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -172,6 +172,258 @@ static int phylink_validate_mac_and_pcs( - return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; - } - -+static void phylink_caps_to_linkmodes(unsigned long *linkmodes, -+ unsigned long caps) -+{ -+ if (caps & MAC_SYM_PAUSE) -+ __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, linkmodes); -+ -+ if (caps & MAC_ASYM_PAUSE) -+ __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, linkmodes); -+ -+ if (caps & MAC_10HD) -+ __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, linkmodes); -+ -+ if (caps & MAC_10FD) -+ __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, linkmodes); -+ -+ if (caps & MAC_100HD) { -+ __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_100FD) { -+ __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_1000HD) -+ __set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, linkmodes); -+ -+ if (caps & MAC_1000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_2500FD) { -+ __set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_5000FD) -+ __set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT, linkmodes); -+ -+ if (caps & MAC_10000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_25000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_40000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_50000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_56000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_100000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_200000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, linkmodes); -+ } -+ -+ if (caps & MAC_400000FD) { -+ __set_bit(ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, -+ linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, linkmodes); -+ __set_bit(ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, linkmodes); -+ } -+} -+ -+/** -+ * phylink_get_linkmodes() - get acceptable link modes -+ * @linkmodes: ethtool linkmode mask (must be already initialised) -+ * @interface: phy interface mode defined by &typedef phy_interface_t -+ * @mac_capabilities: bitmask of MAC capabilities -+ * -+ * Set all possible pause, speed and duplex linkmodes in @linkmodes that -+ * are supported by the @interface mode and @mac_capabilities. @linkmodes -+ * must have been initialised previously. -+ */ -+void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, -+ unsigned long mac_capabilities) -+{ -+ unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE; -+ -+ switch (interface) { -+ case PHY_INTERFACE_MODE_USXGMII: -+ caps |= MAC_10000FD | MAC_5000FD | MAC_2500FD; -+ fallthrough; -+ -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_QSGMII: -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_GMII: -+ caps |= MAC_1000HD | MAC_1000FD; -+ fallthrough; -+ -+ case PHY_INTERFACE_MODE_REVRMII: -+ case PHY_INTERFACE_MODE_RMII: -+ case PHY_INTERFACE_MODE_REVMII: -+ case PHY_INTERFACE_MODE_MII: -+ caps |= MAC_10HD | MAC_10FD; -+ fallthrough; -+ -+ case PHY_INTERFACE_MODE_100BASEX: -+ caps |= MAC_100HD | MAC_100FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_TBI: -+ case PHY_INTERFACE_MODE_MOCA: -+ case PHY_INTERFACE_MODE_RTBI: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ caps |= MAC_1000HD; -+ fallthrough; -+ case PHY_INTERFACE_MODE_TRGMII: -+ caps |= MAC_1000FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_2500BASEX: -+ caps |= MAC_2500FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_5GBASER: -+ caps |= MAC_5000FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_XGMII: -+ case PHY_INTERFACE_MODE_RXAUI: -+ case PHY_INTERFACE_MODE_XAUI: -+ case PHY_INTERFACE_MODE_10GBASER: -+ case PHY_INTERFACE_MODE_10GKR: -+ caps |= MAC_10000FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_25GBASER: -+ caps |= MAC_25000FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_XLGMII: -+ caps |= MAC_40000FD; -+ break; -+ -+ case PHY_INTERFACE_MODE_INTERNAL: -+ caps |= ~0; -+ break; -+ -+ case PHY_INTERFACE_MODE_NA: -+ case PHY_INTERFACE_MODE_MAX: -+ case PHY_INTERFACE_MODE_SMII: -+ break; -+ } -+ -+ phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities); -+} -+EXPORT_SYMBOL_GPL(phylink_get_linkmodes); -+ -+/** -+ * phylink_generic_validate() - generic validate() callback implementation -+ * @config: a pointer to a &struct phylink_config. -+ * @supported: ethtool bitmask for supported link modes. -+ * @state: a pointer to a &struct phylink_link_state. -+ * -+ * Generic implementation of the validate() callback that MAC drivers can -+ * use when they pass the range of supported interfaces and MAC capabilities. -+ * This makes use of phylink_get_linkmodes(). -+ */ -+void phylink_generic_validate(struct phylink_config *config, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ phylink_set_port_modes(mask); -+ phylink_set(mask, Autoneg); -+ phylink_get_linkmodes(mask, state->interface, config->mac_capabilities); -+ -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+} -+EXPORT_SYMBOL_GPL(phylink_generic_validate); -+ - static int phylink_validate_any(struct phylink *pl, unsigned long *supported, - struct phylink_link_state *state) - { ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -20,6 +20,29 @@ enum { - MLO_AN_PHY = 0, /* Conventional PHY */ - MLO_AN_FIXED, /* Fixed-link mode */ - MLO_AN_INBAND, /* In-band protocol */ -+ -+ MAC_SYM_PAUSE = BIT(0), -+ MAC_ASYM_PAUSE = BIT(1), -+ MAC_10HD = BIT(2), -+ MAC_10FD = BIT(3), -+ MAC_10 = MAC_10HD | MAC_10FD, -+ MAC_100HD = BIT(4), -+ MAC_100FD = BIT(5), -+ MAC_100 = MAC_100HD | MAC_100FD, -+ MAC_1000HD = BIT(6), -+ MAC_1000FD = BIT(7), -+ MAC_1000 = MAC_1000HD | MAC_1000FD, -+ MAC_2500FD = BIT(8), -+ MAC_5000FD = BIT(9), -+ MAC_10000FD = BIT(10), -+ MAC_20000FD = BIT(11), -+ MAC_25000FD = BIT(12), -+ MAC_40000FD = BIT(13), -+ MAC_50000FD = BIT(14), -+ MAC_56000FD = BIT(15), -+ MAC_100000FD = BIT(16), -+ MAC_200000FD = BIT(17), -+ MAC_400000FD = BIT(18), - }; - - static inline bool phylink_autoneg_inband(unsigned int mode) -@@ -70,6 +93,7 @@ enum phylink_op_type { - * if MAC link is at %MLO_AN_FIXED mode. - * @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx - * are supported by the MAC/PCS. -+ * @mac_capabilities: MAC pause/speed/duplex capabilities. - */ - struct phylink_config { - struct device *dev; -@@ -81,6 +105,7 @@ struct phylink_config { - void (*get_fixed_state)(struct phylink_config *config, - struct phylink_link_state *state); - DECLARE_PHY_INTERFACE_MASK(supported_interfaces); -+ unsigned long mac_capabilities; - }; - - /** -@@ -462,6 +487,12 @@ void pcs_link_up(struct phylink_pcs *pcs - phy_interface_t interface, int speed, int duplex); - #endif - -+void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface, -+ unsigned long mac_capabilities); -+void phylink_generic_validate(struct phylink_config *config, -+ unsigned long *supported, -+ struct phylink_link_state *state); -+ - struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *, - phy_interface_t iface, - const struct phylink_mac_ops *mac_ops); diff --git a/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch b/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch deleted file mode 100644 index a55623519ce..00000000000 --- a/target/linux/generic/backport-6.1/703-10-v5.16-net-dsa-introduce-helpers-for-iterating-through-port.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 82b318983c515f29b8b3a0dad9f6a5fe8a68a7f4 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Wed, 20 Oct 2021 20:49:49 +0300 -Subject: [PATCH] net: dsa: introduce helpers for iterating through ports using - dp - -Since the DSA conversion from the ds->ports array into the dst->ports -list, the DSA API has encouraged driver writers, as well as the core -itself, to write inefficient code. - -Currently, code that wants to filter by a specific type of port when -iterating, like {!unused, user, cpu, dsa}, uses the dsa_is_*_port helper. -Under the hood, this uses dsa_to_port which iterates again through -dst->ports. But the driver iterates through the port list already, so -the complexity is quadratic for the typical case of a single-switch -tree. - -This patch introduces some iteration helpers where the iterator is -already a struct dsa_port *dp, so that the other variant of the -filtering functions, dsa_port_is_{unused,user,cpu_dsa}, can be used -directly on the iterator. This eliminates the second lookup. - -These functions can be used both by the core and by drivers. - -Signed-off-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -476,6 +476,34 @@ static inline bool dsa_is_user_port(stru - return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_USER; - } - -+#define dsa_tree_for_each_user_port(_dp, _dst) \ -+ list_for_each_entry((_dp), &(_dst)->ports, list) \ -+ if (dsa_port_is_user((_dp))) -+ -+#define dsa_switch_for_each_port(_dp, _ds) \ -+ list_for_each_entry((_dp), &(_ds)->dst->ports, list) \ -+ if ((_dp)->ds == (_ds)) -+ -+#define dsa_switch_for_each_port_safe(_dp, _next, _ds) \ -+ list_for_each_entry_safe((_dp), (_next), &(_ds)->dst->ports, list) \ -+ if ((_dp)->ds == (_ds)) -+ -+#define dsa_switch_for_each_port_continue_reverse(_dp, _ds) \ -+ list_for_each_entry_continue_reverse((_dp), &(_ds)->dst->ports, list) \ -+ if ((_dp)->ds == (_ds)) -+ -+#define dsa_switch_for_each_available_port(_dp, _ds) \ -+ dsa_switch_for_each_port((_dp), (_ds)) \ -+ if (!dsa_port_is_unused((_dp))) -+ -+#define dsa_switch_for_each_user_port(_dp, _ds) \ -+ dsa_switch_for_each_port((_dp), (_ds)) \ -+ if (dsa_port_is_user((_dp))) -+ -+#define dsa_switch_for_each_cpu_port(_dp, _ds) \ -+ dsa_switch_for_each_port((_dp), (_ds)) \ -+ if (dsa_port_is_cpu((_dp))) -+ - static inline u32 dsa_user_ports(struct dsa_switch *ds) - { - u32 mask = 0; diff --git a/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch b/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch deleted file mode 100644 index 524ce9bd926..00000000000 --- a/target/linux/generic/backport-6.1/703-11-v5.17-net-phylink-add-pcs_validate-method.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 0d22d4b626a4eaa3196019092eb6c1919e9f8caa Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 15 Dec 2021 15:34:20 +0000 -Subject: [PATCH] net: phylink: add pcs_validate() method - -Add a hook for PCS to validate the link parameters. This avoids MAC -drivers having to have knowledge of their PCS in their validate() -method, thereby allowing several MAC drivers to be simplfied. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/phy/phylink.c | 31 +++++++++++++++++++++++++++++++ - include/linux/phylink.h | 20 ++++++++++++++++++++ - 2 files changed, 51 insertions(+) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -160,13 +160,44 @@ static int phylink_validate_mac_and_pcs( - struct phylink_link_state *state) - { - struct phylink_pcs *pcs; -+ int ret; - -+ /* Get the PCS for this interface mode */ - if (pl->mac_ops->mac_select_pcs) { - pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); - if (IS_ERR(pcs)) - return PTR_ERR(pcs); -+ } else { -+ pcs = pl->pcs; - } - -+ if (pcs) { -+ /* The PCS, if present, must be setup before phylink_create() -+ * has been called. If the ops is not initialised, print an -+ * error and backtrace rather than oopsing the kernel. -+ */ -+ if (!pcs->ops) { -+ phylink_err(pl, "interface %s: uninitialised PCS\n", -+ phy_modes(state->interface)); -+ dump_stack(); -+ return -EINVAL; -+ } -+ -+ /* Validate the link parameters with the PCS */ -+ if (pcs->ops->pcs_validate) { -+ ret = pcs->ops->pcs_validate(pcs, supported, state); -+ if (ret < 0 || phylink_is_empty_linkmode(supported)) -+ return -EINVAL; -+ -+ /* Ensure the advertising mask is a subset of the -+ * supported mask. -+ */ -+ linkmode_and(state->advertising, state->advertising, -+ supported); -+ } -+ } -+ -+ /* Then validate the link parameters with the MAC */ - pl->mac_ops->validate(pl->config, supported, state); - - return phylink_is_empty_linkmode(supported) ? -EINVAL : 0; ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -398,6 +398,7 @@ struct phylink_pcs { - - /** - * struct phylink_pcs_ops - MAC PCS operations structure. -+ * @pcs_validate: validate the link configuration. - * @pcs_get_state: read the current MAC PCS link state from the hardware. - * @pcs_config: configure the MAC PCS for the selected mode and state. - * @pcs_an_restart: restart 802.3z BaseX autonegotiation. -@@ -405,6 +406,8 @@ struct phylink_pcs { - * (where necessary). - */ - struct phylink_pcs_ops { -+ int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported, -+ const struct phylink_link_state *state); - void (*pcs_get_state)(struct phylink_pcs *pcs, - struct phylink_link_state *state); - int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode, -@@ -418,6 +421,23 @@ struct phylink_pcs_ops { - - #if 0 /* For kernel-doc purposes only. */ - /** -+ * pcs_validate() - validate the link configuration. -+ * @pcs: a pointer to a &struct phylink_pcs. -+ * @supported: ethtool bitmask for supported link modes. -+ * @state: a const pointer to a &struct phylink_link_state. -+ * -+ * Validate the interface mode, and advertising's autoneg bit, removing any -+ * media ethtool link modes that would not be supportable from the supported -+ * mask. Phylink will propagate the changes to the advertising mask. See the -+ * &struct phylink_mac_ops validate() method. -+ * -+ * Returns -EINVAL if the interface mode/autoneg mode is not supported. -+ * Returns non-zero positive if the link state can be supported. -+ */ -+int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported, -+ const struct phylink_link_state *state); -+ -+/** - * pcs_get_state() - Read the current inband link state from the hardware - * @pcs: a pointer to a &struct phylink_pcs. - * @state: a pointer to a &struct phylink_link_state. diff --git a/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch b/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch deleted file mode 100644 index 16d5da9c70e..00000000000 --- a/target/linux/generic/backport-6.1/703-12-v5.17-net-phylink-add-legacy_pre_march2020-indicator.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 3e5b1feccea7db576353ffc302f78d522e4116e6 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Thu, 9 Dec 2021 13:11:32 +0000 -Subject: [PATCH] net: phylink: add legacy_pre_march2020 indicator - -Add a boolean to phylink_config to indicate whether a driver has not -been updated for the changes in commit 7cceb599d15d ("net: phylink: -avoid mac_config calls"), and thus are reliant on the old behaviour. - -We were currently keying the phylink behaviour on the presence of a -PCS, but this is sub-optimal for modern drivers that may not have a -PCS. - -This commit merely introduces the new flag, but does not add any use, -since we need all legacy drivers to set this flag before it can be -used. Once these legacy drivers have been updated, we can remove this -flag. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - include/linux/phylink.h | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -84,6 +84,8 @@ enum phylink_op_type { - * struct phylink_config - PHYLINK configuration structure - * @dev: a pointer to a struct device associated with the MAC - * @type: operation type of PHYLINK instance -+ * @legacy_pre_march2020: driver has not been updated for March 2020 updates -+ * (See commit 7cceb599d15d ("net: phylink: avoid mac_config calls") - * @pcs_poll: MAC PCS cannot provide link change interrupt - * @poll_fixed_state: if true, starts link_poll, - * if MAC link is at %MLO_AN_FIXED mode. -@@ -98,6 +100,7 @@ enum phylink_op_type { - struct phylink_config { - struct device *dev; - enum phylink_op_type type; -+ bool legacy_pre_march2020; - bool pcs_poll; - bool poll_fixed_state; - bool mac_managed_pm; diff --git a/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch b/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch deleted file mode 100644 index 849881942e1..00000000000 --- a/target/linux/generic/backport-6.1/703-13-v5.17-net-dsa-mark-DSA-phylink-as-legacy_pre_march2020.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 0a9f0794d9bd67e590a9488afe87fbb0419d9539 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Thu, 9 Dec 2021 13:11:38 +0000 -Subject: [PATCH] net: dsa: mark DSA phylink as legacy_pre_march2020 - -The majority of DSA drivers do not make use of the PCS support, and -thus operate in legacy mode. In order to preserve this behaviour in -future, we need to set the legacy_pre_march2020 flag so phylink knows -this may require the legacy calls. - -There are some DSA drivers that do make use of PCS support, and these -will continue operating as before - legacy_pre_march2020 will not -prevent split-PCS support enabling the newer phylink behaviour. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - net/dsa/port.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1126,6 +1126,13 @@ int dsa_port_phylink_create(struct dsa_p - if (err) - mode = PHY_INTERFACE_MODE_NA; - -+ /* Presence of phylink_mac_link_state or phylink_mac_an_restart is -+ * an indicator of a legacy phylink driver. -+ */ -+ if (ds->ops->phylink_mac_link_state || -+ ds->ops->phylink_mac_an_restart) -+ dp->pl_config.legacy_pre_march2020 = true; -+ - if (ds->ops->phylink_get_caps) - ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config); - diff --git a/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch b/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch deleted file mode 100644 index 73e53068b8a..00000000000 --- a/target/linux/generic/backport-6.1/703-14-v5.17-net-phylink-use-legacy_pre_march2020.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 001f4261fe4d5ae710cf1f445b6cae6d9d3ae26e Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Thu, 9 Dec 2021 13:11:48 +0000 -Subject: [PATCH] net: phylink: use legacy_pre_march2020 - -Use the legacy flag to indicate whether we should operate in legacy -mode. This allows us to stop using the presence of a PCS as an -indicator to the age of the phylink user, and make PCS presence -optional. - -Legacy mode involves: -1) calling mac_config() whenever the link comes up -2) calling mac_config() whenever the inband advertisement changes, - possibly followed by a call to mac_an_restart() -3) making use of mac_an_restart() -4) making use of mac_pcs_get_state() - -All the above functionality was moved to a seperate "PCS" block of -operations in March 2020. - -Update the documents to indicate that the differences that this flag -makes. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/phylink.c | 12 ++++++------ - include/linux/phylink.h | 17 +++++++++++++++++ - 2 files changed, 23 insertions(+), 6 deletions(-) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -777,7 +777,7 @@ static void phylink_mac_pcs_an_restart(s - phylink_autoneg_inband(pl->cur_link_an_mode)) { - if (pl->pcs_ops) - pl->pcs_ops->pcs_an_restart(pl->pcs); -- else -+ else if (pl->config->legacy_pre_march2020) - pl->mac_ops->mac_an_restart(pl->config); - } - } -@@ -855,7 +855,7 @@ static int phylink_change_inband_advert( - if (test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) - return 0; - -- if (!pl->pcs_ops) { -+ if (!pl->pcs_ops && pl->config->legacy_pre_march2020) { - /* Legacy method */ - phylink_mac_config(pl, &pl->link_config); - phylink_mac_pcs_an_restart(pl); -@@ -900,7 +900,8 @@ static void phylink_mac_pcs_get_state(st - - if (pl->pcs_ops) - pl->pcs_ops->pcs_get_state(pl->pcs, state); -- else if (pl->mac_ops->mac_pcs_get_state) -+ else if (pl->mac_ops->mac_pcs_get_state && -+ pl->config->legacy_pre_march2020) - pl->mac_ops->mac_pcs_get_state(pl->config, state); - else - state->link = 0; -@@ -1094,12 +1095,11 @@ static void phylink_resolve(struct work_ - } - phylink_major_config(pl, false, &link_state); - pl->link_config.interface = link_state.interface; -- } else if (!pl->pcs_ops) { -+ } else if (!pl->pcs_ops && pl->config->legacy_pre_march2020) { - /* The interface remains unchanged, only the speed, - * duplex or pause settings have changed. Call the - * old mac_config() method to configure the MAC/PCS -- * only if we do not have a PCS installed (an -- * unconverted user.) -+ * only if we do not have a legacy MAC driver. - */ - phylink_mac_config(pl, &link_state); - } ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -210,6 +210,10 @@ struct phylink_pcs *mac_select_pcs(struc - * negotiation completion state in @state->an_complete, and link up state - * in @state->link. If possible, @state->lp_advertising should also be - * populated. -+ * -+ * Note: This is a legacy method. This function will not be called unless -+ * legacy_pre_march2020 is set in &struct phylink_config and there is no -+ * PCS attached. - */ - void mac_pcs_get_state(struct phylink_config *config, - struct phylink_link_state *state); -@@ -250,6 +254,15 @@ int mac_prepare(struct phylink_config *c - * guaranteed to be correct, and so any mac_config() implementation must - * never reference these fields. - * -+ * Note: For legacy March 2020 drivers (drivers with legacy_pre_march2020 set -+ * in their &phylnk_config and which don't have a PCS), this function will be -+ * called on each link up event, and to also change the in-band advert. For -+ * non-legacy drivers, it will only be called to reconfigure the MAC for a -+ * "major" change in e.g. interface mode. It will not be called for changes -+ * in speed, duplex or pause modes or to change the in-band advertisement. -+ * In any case, it is strongly preferred that speed, duplex and pause settings -+ * are handled in the mac_link_up() method and not in this method. -+ * - * (this requires a rewrite - please refer to mac_link_up() for situations - * where the PCS and MAC are not tightly integrated.) - * -@@ -334,6 +347,10 @@ int mac_finish(struct phylink_config *co - /** - * mac_an_restart() - restart 802.3z BaseX autonegotiation - * @config: a pointer to a &struct phylink_config. -+ * -+ * Note: This is a legacy method. This function will not be called unless -+ * legacy_pre_march2020 is set in &struct phylink_config and there is no -+ * PCS attached. - */ - void mac_an_restart(struct phylink_config *config); - diff --git a/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch b/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch deleted file mode 100644 index 9e5061aaed8..00000000000 --- a/target/linux/generic/backport-6.1/703-15-v5.18-net-phy-phylink-fix-DSA-mac_select_pcs-introduction.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 1054457006d4a14de4ae4132030e33d7eedaeba1 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 21 Feb 2022 17:10:52 +0000 -Subject: [PATCH] net: phy: phylink: fix DSA mac_select_pcs() introduction - -Vladimir Oltean reports that probing on DSA drivers that aren't yet -populating supported_interfaces now fails. Fix this by allowing -phylink to detect whether DSA actually provides an underlying -mac_select_pcs() implementation. - -Reported-by: Vladimir Oltean -Fixes: bde018222c6b ("net: dsa: add support for phylink mac_select_pcs()") -Signed-off-by: Russell King (Oracle) -Tested-by: Vladimir Oltean -Link: https://lore.kernel.org/r/E1nMCD6-00A0wC-FG@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/phylink.c | 14 +++++++++++--- - net/dsa/port.c | 2 +- - 2 files changed, 12 insertions(+), 4 deletions(-) - ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -74,6 +74,7 @@ struct phylink { - struct work_struct resolve; - - bool mac_link_dropped; -+ bool using_mac_select_pcs; - - struct sfp_bus *sfp_bus; - bool sfp_may_have_phy; -@@ -163,7 +164,7 @@ static int phylink_validate_mac_and_pcs( - int ret; - - /* Get the PCS for this interface mode */ -- if (pl->mac_ops->mac_select_pcs) { -+ if (pl->using_mac_select_pcs) { - pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); - if (IS_ERR(pcs)) - return PTR_ERR(pcs); -@@ -790,7 +791,7 @@ static void phylink_major_config(struct - - phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); - -- if (pl->mac_ops->mac_select_pcs) { -+ if (pl->using_mac_select_pcs) { - pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface); - if (IS_ERR(pcs)) { - phylink_err(pl, -@@ -1192,11 +1193,17 @@ struct phylink *phylink_create(struct ph - phy_interface_t iface, - const struct phylink_mac_ops *mac_ops) - { -+ bool using_mac_select_pcs = false; - struct phylink *pl; - int ret; - -- /* Validate the supplied configuration */ - if (mac_ops->mac_select_pcs && -+ mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) != -+ ERR_PTR(-EOPNOTSUPP)) -+ using_mac_select_pcs = true; -+ -+ /* Validate the supplied configuration */ -+ if (using_mac_select_pcs && - phy_interface_empty(config->supported_interfaces)) { - dev_err(config->dev, - "phylink: error: empty supported_interfaces but mac_select_pcs() method present\n"); -@@ -1220,6 +1227,7 @@ struct phylink *phylink_create(struct ph - return ERR_PTR(-EINVAL); - } - -+ pl->using_mac_select_pcs = using_mac_select_pcs; - pl->phy_state.interface = iface; - pl->link_interface = iface; - if (iface == PHY_INTERFACE_MODE_MOCA) ---- a/net/dsa/port.c -+++ b/net/dsa/port.c -@@ -1033,8 +1033,8 @@ dsa_port_phylink_mac_select_pcs(struct p - phy_interface_t interface) - { - struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); -+ struct phylink_pcs *pcs = ERR_PTR(-EOPNOTSUPP); - struct dsa_switch *ds = dp->ds; -- struct phylink_pcs *pcs = NULL; - - if (ds->ops->phylink_mac_select_pcs) - pcs = ds->ops->phylink_mac_select_pcs(ds, dp->index, interface); diff --git a/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch deleted file mode 100644 index f21fa4b2778..00000000000 --- a/target/linux/generic/backport-6.1/703-16-v5.16-net-mvneta-populate-supported_interfaces-member.patch +++ /dev/null @@ -1,48 +0,0 @@ -From fdedb695e6a8657302341cda81d519ef04f9acaa Mon Sep 17 00:00:00 2001 -From: Russell King -Date: Wed, 27 Oct 2021 10:03:43 +0100 -Subject: [PATCH] net: mvneta: populate supported_interfaces member - -Populate the phy_interface_t bitmap for the Marvell mvneta driver with -interfaces modes supported by the MAC. - -Signed-off-by: Russell King -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/marvell/mvneta.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -5180,6 +5180,31 @@ static int mvneta_probe(struct platform_ - - pp->phylink_config.dev = &dev->dev; - pp->phylink_config.type = PHYLINK_NETDEV; -+ phy_interface_set_rgmii(pp->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_QSGMII, -+ pp->phylink_config.supported_interfaces); -+ if (comphy) { -+ /* If a COMPHY is present, we can support any of the serdes -+ * modes and switch between them. -+ */ -+ __set_bit(PHY_INTERFACE_MODE_SGMII, -+ pp->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, -+ pp->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, -+ pp->phylink_config.supported_interfaces); -+ } else if (phy_mode == PHY_INTERFACE_MODE_2500BASEX) { -+ /* No COMPHY, with only 2500BASE-X mode supported */ -+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, -+ pp->phylink_config.supported_interfaces); -+ } else if (phy_mode == PHY_INTERFACE_MODE_1000BASEX || -+ phy_mode == PHY_INTERFACE_MODE_SGMII) { -+ /* No COMPHY, we can switch between 1000BASE-X and SGMII */ -+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, -+ pp->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_SGMII, -+ pp->phylink_config.supported_interfaces); -+ } - - phylink = phylink_create(&pp->phylink_config, pdev->dev.fwnode, - phy_mode, &mvneta_phylink_ops); diff --git a/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch b/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch deleted file mode 100644 index e287e39d6a4..00000000000 --- a/target/linux/generic/backport-6.1/703-17-v5.16-net-mvneta-remove-interface-checks-in-mvneta_validat.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d9ca72807ecb236f679b960c70ef5b7d4a5f0222 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 27 Oct 2021 10:03:48 +0100 -Subject: [PATCH] net: mvneta: remove interface checks in mvneta_validate() - -As phylink checks the interface mode against the supported_interfaces -bitmap, we no longer need to validate the interface mode in the -validation function. Remove this to simplify it. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/marvell/mvneta.c | 11 ++--------- - 1 file changed, 2 insertions(+), 9 deletions(-) - ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -3833,15 +3833,8 @@ static void mvneta_validate(struct phyli - * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... - * When = 1 (1000BASE-X) this field must be set to 1." - */ -- if (phy_interface_mode_is_8023z(state->interface)) { -- if (!phylink_test(state->advertising, Autoneg)) { -- linkmode_zero(supported); -- return; -- } -- } else if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_QSGMII && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- !phy_interface_mode_is_rgmii(state->interface)) { -+ if (phy_interface_mode_is_8023z(state->interface) && -+ !phylink_test(state->advertising, Autoneg)) { - linkmode_zero(supported); - return; - } diff --git a/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch b/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch deleted file mode 100644 index 9121612bf82..00000000000 --- a/target/linux/generic/backport-6.1/703-18-v5.16-net-mvneta-drop-use-of-phylink_helper_basex_speed.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 099cbfa286ab937d8213c2dc5c0b401969b78042 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 27 Oct 2021 10:03:53 +0100 -Subject: [PATCH] net: mvneta: drop use of phylink_helper_basex_speed() - -Now that we have a better method to select SFP interface modes, we -no longer need to use phylink_helper_basex_speed() in a driver's -validation function, and we can also get rid of our hack to indicate -both 1000base-X and 2500base-X if the comphy is present to make that -work. Remove this hack and use of phylink_helper_basex_speed(). - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/marvell/mvneta.c | 12 +++--------- - 1 file changed, 3 insertions(+), 9 deletions(-) - ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -3824,8 +3824,6 @@ static void mvneta_validate(struct phyli - unsigned long *supported, - struct phylink_link_state *state) - { -- struct net_device *ndev = to_net_dev(config->dev); -- struct mvneta_port *pp = netdev_priv(ndev); - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - - /* We only support QSGMII, SGMII, 802.3z and RGMII modes. -@@ -3847,11 +3845,12 @@ static void mvneta_validate(struct phyli - phylink_set(mask, Pause); - - /* Half-duplex at speeds higher than 100Mbit is unsupported */ -- if (pp->comphy || state->interface != PHY_INTERFACE_MODE_2500BASEX) { -+ if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); - } -- if (pp->comphy || state->interface == PHY_INTERFACE_MODE_2500BASEX) { -+ -+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { - phylink_set(mask, 2500baseT_Full); - phylink_set(mask, 2500baseX_Full); - } -@@ -3866,11 +3865,6 @@ static void mvneta_validate(struct phyli - - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); -- -- /* We can only operate at 2500BaseX or 1000BaseX. If requested -- * to advertise both, only report advertising at 2500BaseX. -- */ -- phylink_helper_basex_speed(state); - } - - static void mvneta_mac_pcs_get_state(struct phylink_config *config, diff --git a/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch b/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch deleted file mode 100644 index 209dfbc0de9..00000000000 --- a/target/linux/generic/backport-6.1/703-19-v5.17-net-mvneta-use-phylink_generic_validate.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 02a0988b98930491db95966fb8086072e47dabb6 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 15 Nov 2021 10:00:32 +0000 -Subject: [PATCH] net: mvneta: use phylink_generic_validate() - -Convert mvneta to use phylink_generic_validate() for the bulk of its -validate() implementation. This network adapter has a restriction -that for 802.3z links, autonegotiation must be enabled. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/marvell/mvneta.c | 34 ++++----------------------- - 1 file changed, 4 insertions(+), 30 deletions(-) - ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -3824,8 +3824,6 @@ static void mvneta_validate(struct phyli - unsigned long *supported, - struct phylink_link_state *state) - { -- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- - /* We only support QSGMII, SGMII, 802.3z and RGMII modes. - * When in 802.3z mode, we must have AN enabled: - * "Bit 2 Field InBandAnEn In-band Auto-Negotiation enable. ... -@@ -3837,34 +3835,7 @@ static void mvneta_validate(struct phyli - return; - } - -- /* Allow all the expected bits */ -- phylink_set(mask, Autoneg); -- phylink_set_port_modes(mask); -- -- /* Asymmetric pause is unsupported */ -- phylink_set(mask, Pause); -- -- /* Half-duplex at speeds higher than 100Mbit is unsupported */ -- if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseX_Full); -- } -- -- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) { -- phylink_set(mask, 2500baseT_Full); -- phylink_set(mask, 2500baseX_Full); -- } -- -- if (!phy_interface_mode_is_8023z(state->interface)) { -- /* 10M and 100M are only supported in non-802.3z mode */ -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -- } -- -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); -+ phylink_generic_validate(config, supported, state); - } - - static void mvneta_mac_pcs_get_state(struct phylink_config *config, -@@ -5167,6 +5138,9 @@ static int mvneta_probe(struct platform_ - - pp->phylink_config.dev = &dev->dev; - pp->phylink_config.type = PHYLINK_NETDEV; -+ pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | -+ MAC_100 | MAC_1000FD | MAC_2500FD; -+ - phy_interface_set_rgmii(pp->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_QSGMII, - pp->phylink_config.supported_interfaces); diff --git a/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch b/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch deleted file mode 100644 index 31717565bf1..00000000000 --- a/target/linux/generic/backport-6.1/703-20-v5.17-net-mvneta-mark-as-a-legacy_pre_march2020-driver.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 2106be4fdf3223d9c5bd485e6ef094139e3197ba Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Sun, 12 Dec 2021 13:01:21 +0000 -Subject: [PATCH] net: mvneta: mark as a legacy_pre_march2020 driver -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -mvneta provides mac_an_restart and mac_pcs_get_state methods, so needs -to be marked as a legacy driver. Marek spotted that mvneta had stopped -working in 2500base-X mode - thanks for reporting. - -Reported-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/marvell/mvneta.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/ethernet/marvell/mvneta.c -+++ b/drivers/net/ethernet/marvell/mvneta.c -@@ -5138,6 +5138,7 @@ static int mvneta_probe(struct platform_ - - pp->phylink_config.dev = &dev->dev; - pp->phylink_config.type = PHYLINK_NETDEV; -+ pp->phylink_config.legacy_pre_march2020 = true; - pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 | - MAC_100 | MAC_1000FD | MAC_2500FD; - diff --git a/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch b/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch deleted file mode 100644 index b6fe0dad4c8..00000000000 --- a/target/linux/generic/backport-6.1/704-01-v5.17-net-mtk_eth_soc-populate-supported_interfaces-member.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 83800d29f0c578e82554e7d4c6bfdbdf9b6cf428 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 16 Nov 2021 10:06:43 +0000 -Subject: [PATCH] net: mtk_eth_soc: populate supported_interfaces member - -Populate the phy interface mode bitmap for the Mediatek driver with -interfaces modes supported by the MAC. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3355,6 +3355,26 @@ static int mtk_add_mac(struct mtk_eth *e - - mac->phylink_config.dev = ð->netdev[id]->dev; - mac->phylink_config.type = PHYLINK_NETDEV; -+ __set_bit(PHY_INTERFACE_MODE_MII, -+ mac->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_GMII, -+ mac->phylink_config.supported_interfaces); -+ -+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) -+ phy_interface_set_rgmii(mac->phylink_config.supported_interfaces); -+ -+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && !mac->id) -+ __set_bit(PHY_INTERFACE_MODE_TRGMII, -+ mac->phylink_config.supported_interfaces); -+ -+ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { -+ __set_bit(PHY_INTERFACE_MODE_SGMII, -+ mac->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, -+ mac->phylink_config.supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, -+ mac->phylink_config.supported_interfaces); -+ } - - phylink = phylink_create(&mac->phylink_config, - of_fwnode_handle(mac->of_node), diff --git a/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch b/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch deleted file mode 100644 index 0a33ab00934..00000000000 --- a/target/linux/generic/backport-6.1/704-02-v5.17-net-mtk_eth_soc-remove-interface-checks-in-mtk_valid.patch +++ /dev/null @@ -1,75 +0,0 @@ -From db81ca153814475d7e07365d46a4d1134bd122e2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 16 Nov 2021 10:06:48 +0000 -Subject: [PATCH] net: mtk_eth_soc: remove interface checks in mtk_validate() - -As phylink checks the interface mode against the supported_interfaces -bitmap, we no longer need to validate the interface mode, nor handle -PHY_INTERFACE_MODE_NA in the validation function. Remove these to -simplify the implementation. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 --------------------- - 1 file changed, 34 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -568,24 +568,8 @@ static void mtk_validate(struct phylink_ - unsigned long *supported, - struct phylink_link_state *state) - { -- struct mtk_mac *mac = container_of(config, struct mtk_mac, -- phylink_config); - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_MII && -- state->interface != PHY_INTERFACE_MODE_GMII && -- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII) && -- phy_interface_mode_is_rgmii(state->interface)) && -- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_TRGMII) && -- !mac->id && state->interface == PHY_INTERFACE_MODE_TRGMII) && -- !(MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII) && -- (state->interface == PHY_INTERFACE_MODE_SGMII || -- phy_interface_mode_is_8023z(state->interface)))) { -- linkmode_zero(supported); -- return; -- } -- - phylink_set_port_modes(mask); - phylink_set(mask, Autoneg); - -@@ -612,7 +596,6 @@ static void mtk_validate(struct phylink_ - case PHY_INTERFACE_MODE_MII: - case PHY_INTERFACE_MODE_RMII: - case PHY_INTERFACE_MODE_REVMII: -- case PHY_INTERFACE_MODE_NA: - default: - phylink_set(mask, 10baseT_Half); - phylink_set(mask, 10baseT_Full); -@@ -621,23 +604,6 @@ static void mtk_validate(struct phylink_ - break; - } - -- if (state->interface == PHY_INTERFACE_MODE_NA) { -- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) { -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseX_Full); -- phylink_set(mask, 2500baseX_Full); -- } -- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_RGMII)) { -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseT_Half); -- phylink_set(mask, 1000baseX_Full); -- } -- if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_GEPHY)) { -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseT_Half); -- } -- } -- - phylink_set(mask, Pause); - phylink_set(mask, Asym_Pause); - diff --git a/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch b/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch deleted file mode 100644 index f8cc8105a4c..00000000000 --- a/target/linux/generic/backport-6.1/704-03-v5.17-net-mtk_eth_soc-drop-use-of-phylink_helper_basex_spe.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 71d927494463c4f016d828e1134da26b7e961af5 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 16 Nov 2021 10:06:53 +0000 -Subject: [PATCH] net: mtk_eth_soc: drop use of phylink_helper_basex_speed() - -Now that we have a better method to select SFP interface modes, we -no longer need to use phylink_helper_basex_speed() in a driver's -validation function, and we can also get rid of our hack to indicate -both 1000base-X and 2500base-X if the comphy is present to make that -work. Remove this hack and use of phylink_helper_basex_speed(). - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -578,8 +578,9 @@ static void mtk_validate(struct phylink_ - phylink_set(mask, 1000baseT_Full); - break; - case PHY_INTERFACE_MODE_1000BASEX: -- case PHY_INTERFACE_MODE_2500BASEX: - phylink_set(mask, 1000baseX_Full); -+ break; -+ case PHY_INTERFACE_MODE_2500BASEX: - phylink_set(mask, 2500baseX_Full); - break; - case PHY_INTERFACE_MODE_GMII: -@@ -609,11 +610,6 @@ static void mtk_validate(struct phylink_ - - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); -- -- /* We can only operate at 2500BaseX or 1000BaseX. If requested -- * to advertise both, only report advertising at 2500BaseX. -- */ -- phylink_helper_basex_speed(state); - } - - static const struct phylink_mac_ops mtk_phylink_ops = { diff --git a/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch b/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch deleted file mode 100644 index f695991ec1f..00000000000 --- a/target/linux/generic/backport-6.1/704-04-v5.17-net-mtk_eth_soc-use-phylink_generic_validate.patch +++ /dev/null @@ -1,84 +0,0 @@ -From a4238f6ce151afa331375d74a5033b76da637644 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 16 Nov 2021 10:06:58 +0000 -Subject: [PATCH] net: mtk_eth_soc: use phylink_generic_validate() - -mtk_eth_soc has no special behaviour in its validation implementation, -so can be switched to phylink_generic_validate(). - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 53 ++------------------- - 1 file changed, 4 insertions(+), 49 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -564,56 +564,8 @@ static void mtk_mac_link_up(struct phyli - mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); - } - --static void mtk_validate(struct phylink_config *config, -- unsigned long *supported, -- struct phylink_link_state *state) --{ -- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- -- phylink_set_port_modes(mask); -- phylink_set(mask, Autoneg); -- -- switch (state->interface) { -- case PHY_INTERFACE_MODE_TRGMII: -- phylink_set(mask, 1000baseT_Full); -- break; -- case PHY_INTERFACE_MODE_1000BASEX: -- phylink_set(mask, 1000baseX_Full); -- break; -- case PHY_INTERFACE_MODE_2500BASEX: -- phylink_set(mask, 2500baseX_Full); -- break; -- case PHY_INTERFACE_MODE_GMII: -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- phylink_set(mask, 1000baseT_Half); -- fallthrough; -- case PHY_INTERFACE_MODE_SGMII: -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseX_Full); -- fallthrough; -- case PHY_INTERFACE_MODE_MII: -- case PHY_INTERFACE_MODE_RMII: -- case PHY_INTERFACE_MODE_REVMII: -- default: -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -- break; -- } -- -- phylink_set(mask, Pause); -- phylink_set(mask, Asym_Pause); -- -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); --} -- - static const struct phylink_mac_ops mtk_phylink_ops = { -- .validate = mtk_validate, -+ .validate = phylink_generic_validate, - .mac_pcs_get_state = mtk_mac_pcs_get_state, - .mac_an_restart = mtk_mac_an_restart, - .mac_config = mtk_mac_config, -@@ -3317,6 +3269,9 @@ static int mtk_add_mac(struct mtk_eth *e - - mac->phylink_config.dev = ð->netdev[id]->dev; - mac->phylink_config.type = PHYLINK_NETDEV; -+ mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | -+ MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; -+ - __set_bit(PHY_INTERFACE_MODE_MII, - mac->phylink_config.supported_interfaces); - __set_bit(PHY_INTERFACE_MODE_GMII, diff --git a/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch b/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch deleted file mode 100644 index cbff1bfbbc4..00000000000 --- a/target/linux/generic/backport-6.1/704-05-v5.17-net-mtk_eth_soc-mark-as-a-legacy_pre_march2020-drive.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b06515367facfadcf5e70cf6f39db749cf4eb5e3 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Thu, 9 Dec 2021 13:11:43 +0000 -Subject: [PATCH] net: mtk_eth_soc: mark as a legacy_pre_march2020 driver - -mtk_eth_soc has not been updated for commit 7cceb599d15d ("net: phylink: -avoid mac_config calls"), and makes use of state->speed and -state->duplex in contravention of the phylink documentation. This makes -reliant on the legacy behaviours, so mark it as a legacy driver. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3269,6 +3269,10 @@ static int mtk_add_mac(struct mtk_eth *e - - mac->phylink_config.dev = ð->netdev[id]->dev; - mac->phylink_config.type = PHYLINK_NETDEV; -+ /* This driver makes use of state->speed/state->duplex in -+ * mac_config -+ */ -+ mac->phylink_config.legacy_pre_march2020 = true; - mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; - diff --git a/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch b/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch deleted file mode 100644 index c0b4a61cb6e..00000000000 --- a/target/linux/generic/backport-6.1/704-06-v5.19-eth-mtk_eth_soc-remove-a-copy-of-the-NAPI_POLL_WEIGH.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 889e3691b9d6573de133da1f5e78f590e52152cd Mon Sep 17 00:00:00 2001 -From: Jakub Kicinski -Date: Thu, 28 Apr 2022 14:23:13 -0700 -Subject: [PATCH] eth: mtk_eth_soc: remove a copy of the NAPI_POLL_WEIGHT - define - -Defining local versions of NAPI_POLL_WEIGHT with the same -values in the drivers just makes refactoring harder. - -Signed-off-by: Jakub Kicinski -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++-- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 - - 2 files changed, 2 insertions(+), 3 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3568,9 +3568,9 @@ static int mtk_probe(struct platform_dev - */ - init_dummy_netdev(ð->dummy_dev); - netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, -- MTK_NAPI_WEIGHT); -+ NAPI_POLL_WEIGHT); - netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, -- MTK_NAPI_WEIGHT); -+ NAPI_POLL_WEIGHT); - - platform_set_drvdata(pdev, eth); - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -25,7 +25,6 @@ - #define MTK_TX_DMA_BUF_LEN 0x3fff - #define MTK_TX_DMA_BUF_LEN_V2 0xffff - #define MTK_DMA_SIZE 512 --#define MTK_NAPI_WEIGHT 64 - #define MTK_MAC_COUNT 2 - #define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN) - #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) diff --git a/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch b/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch deleted file mode 100644 index 5940ac27df9..00000000000 --- a/target/linux/generic/backport-6.1/704-07-v5.19-mtk_eth_soc-remove-unused-mac-mode.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 0600bdde1fae75fb9bad72033d28edddc72b44b2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:54:31 +0100 -Subject: [PATCH 01/12] net: mtk_eth_soc: remove unused mac->mode - -mac->mode is only ever written to in one location, and is thus -superflous. Remove it. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 - - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 - - 2 files changed, 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3264,7 +3264,6 @@ static int mtk_add_mac(struct mtk_eth *e - - /* mac config is not set */ - mac->interface = PHY_INTERFACE_MODE_NA; -- mac->mode = MLO_AN_PHY; - mac->speed = SPEED_UNKNOWN; - - mac->phylink_config.dev = ð->netdev[id]->dev; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1086,7 +1086,6 @@ struct mtk_eth { - struct mtk_mac { - int id; - phy_interface_t interface; -- unsigned int mode; - int speed; - struct device_node *of_node; - struct phylink *phylink; diff --git a/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch b/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch deleted file mode 100644 index a15914bd553..00000000000 --- a/target/linux/generic/backport-6.1/704-08-v5.19-net-mtk_eth_soc-remove-unused-sgmii-flags.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 5a7a2f4b29d7546244da7d8bbc1962fce5b230f2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:54:36 +0100 -Subject: [PATCH 02/12] net: mtk_eth_soc: remove unused sgmii flags - -The "flags" member of struct mtk_sgmii appears to be unused, as are -the MTK_SGMII_PHYSPEED_* and MTK_HAS_FLAGS() macros. Remove them. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 -------- - 1 file changed, 8 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -957,23 +957,15 @@ struct mtk_soc_data { - /* currently no SoC has more than 2 macs */ - #define MTK_MAX_DEVS 2 - --#define MTK_SGMII_PHYSPEED_AN BIT(31) --#define MTK_SGMII_PHYSPEED_MASK GENMASK(2, 0) --#define MTK_SGMII_PHYSPEED_1000 BIT(0) --#define MTK_SGMII_PHYSPEED_2500 BIT(1) --#define MTK_HAS_FLAGS(flags, _x) (((flags) & (_x)) == (_x)) -- - /* struct mtk_sgmii - This is the structure holding sgmii regmap and its - * characteristics - * @regmap: The register map pointing at the range used to setup - * SGMII modes -- * @flags: The enum refers to which mode the sgmii wants to run on - * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap - */ - - struct mtk_sgmii { - struct regmap *regmap[MTK_MAX_DEVS]; -- u32 flags[MTK_MAX_DEVS]; - u32 ana_rgc3; - }; - diff --git a/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch b/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch deleted file mode 100644 index e16bc875e52..00000000000 --- a/target/linux/generic/backport-6.1/704-09-v5.19-net-mtk_eth_soc-add-mask-and-update-PCS-speed-defini.patch +++ /dev/null @@ -1,40 +0,0 @@ -From bc5e93e0cd22e360eda23859b939280205567580 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:54:42 +0100 -Subject: [PATCH 03/12] net: mtk_eth_soc: add mask and update PCS speed - definitions - -The PCS speed setting is a two bit field, but it is defined as two -separate bits. Add a bitfield mask for the speed definitions, an - use the FIELD_PREP() macro to define each PCS speed. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -17,6 +17,7 @@ - #include - #include - #include -+#include - #include "mtk_ppe.h" - - #define MTK_QDMA_PAGE_SIZE 2048 -@@ -474,9 +475,10 @@ - #define SGMSYS_SGMII_MODE 0x20 - #define SGMII_IF_MODE_BIT0 BIT(0) - #define SGMII_SPEED_DUPLEX_AN BIT(1) --#define SGMII_SPEED_10 0x0 --#define SGMII_SPEED_100 BIT(2) --#define SGMII_SPEED_1000 BIT(3) -+#define SGMII_SPEED_MASK GENMASK(3, 2) -+#define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) -+#define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) -+#define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) - #define SGMII_DUPLEX_FULL BIT(4) - #define SGMII_IF_MODE_BIT5 BIT(5) - #define SGMII_REMOTE_FAULT_DIS BIT(8) diff --git a/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch b/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch deleted file mode 100644 index fb1ee4e310e..00000000000 --- a/target/linux/generic/backport-6.1/704-10-v5.19-net-mtk_eth_soc-correct-802.3z-speed-setting.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 7da3f901f8ecb425105fad39a0f5de73306abe52 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:54:47 +0100 -Subject: [PATCH 04/12] net: mtk_eth_soc: correct 802.3z speed setting - -Phylink does not guarantee that state->speed will be set correctly in -the mac_config() call, so it's a bug that the driver makes use of it. -Moreover, it is making use of it in a function that is only ever called -for 1000BASE-X and 2500BASE-X which operate at a fixed speed which -happens to be the same setting irrespective of the interface mode. We -can simply remove the switch statement and just set the SGMII interface -speed. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 18 +++++------------- - 1 file changed, 5 insertions(+), 13 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -34,6 +34,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, - return 0; - } - -+/* For SGMII interface mode */ - int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) - { - unsigned int val; -@@ -60,6 +61,9 @@ int mtk_sgmii_setup_mode_an(struct mtk_s - return 0; - } - -+/* For 1000BASE-X and 2500BASE-X interface modes, which operate at a -+ * fixed speed. -+ */ - int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, - const struct phylink_link_state *state) - { -@@ -82,19 +86,7 @@ int mtk_sgmii_setup_mode_force(struct mt - /* SGMII force mode setting */ - regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); - val &= ~SGMII_IF_MODE_MASK; -- -- switch (state->speed) { -- case SPEED_10: -- val |= SGMII_SPEED_10; -- break; -- case SPEED_100: -- val |= SGMII_SPEED_100; -- break; -- case SPEED_2500: -- case SPEED_1000: -- val |= SGMII_SPEED_1000; -- break; -- } -+ val |= SGMII_SPEED_1000; - - if (state->duplex == DUPLEX_FULL) - val |= SGMII_DUPLEX_FULL; diff --git a/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch b/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch deleted file mode 100644 index 78444903a8c..00000000000 --- a/target/linux/generic/backport-6.1/704-11-v5.19-net-mtk_eth_soc-correct-802.3z-duplex-setting.patch +++ /dev/null @@ -1,101 +0,0 @@ -From a459187390bb221827f9c07866c3a5ffbdf9622b Mon Sep 17 00:00:00 2001 -From: Russell King -Date: Wed, 18 May 2022 15:54:52 +0100 -Subject: [PATCH 05/12] net: mtk_eth_soc: correct 802.3z duplex setting - -Phylink does not guarantee that state->duplex will be set correctly in -the mac_config() call, so it's a bug that the driver makes use of it. - -Move the 802.3z PCS duplex configuration to mac_link_up(). - -Signed-off-by: Russell King -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 +++++++++++---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + - drivers/net/ethernet/mediatek/mtk_sgmii.c | 22 +++++++++++++++------ - 3 files changed, 29 insertions(+), 10 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -533,8 +533,18 @@ static void mtk_mac_link_up(struct phyli - { - struct mtk_mac *mac = container_of(config, struct mtk_mac, - phylink_config); -- u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); -+ u32 mcr; - -+ if (phy_interface_mode_is_8023z(interface)) { -+ struct mtk_eth *eth = mac->hw; -+ -+ /* Decide how GMAC and SGMIISYS be mapped */ -+ int sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? -+ 0 : mac->id; -+ mtk_sgmii_link_up(eth->sgmii, sid, speed, duplex); -+ } -+ -+ mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | - MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | - MAC_MCR_FORCE_RX_FC); -@@ -3268,9 +3278,7 @@ static int mtk_add_mac(struct mtk_eth *e - - mac->phylink_config.dev = ð->netdev[id]->dev; - mac->phylink_config.type = PHYLINK_NETDEV; -- /* This driver makes use of state->speed/state->duplex in -- * mac_config -- */ -+ /* This driver makes use of state->speed in mac_config */ - mac->phylink_config.legacy_pre_march2020 = true; - mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000 | MAC_2500FD; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1104,6 +1104,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, - int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); - int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, - const struct phylink_link_state *state); -+void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); - void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); - - int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -83,14 +83,10 @@ int mtk_sgmii_setup_mode_force(struct mt - val &= ~SGMII_AN_ENABLE; - regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); - -- /* SGMII force mode setting */ -+ /* Set the speed etc but leave the duplex unchanged */ - regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -- val &= ~SGMII_IF_MODE_MASK; -+ val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; - val |= SGMII_SPEED_1000; -- -- if (state->duplex == DUPLEX_FULL) -- val |= SGMII_DUPLEX_FULL; -- - regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); - - /* Release PHYA power down state */ -@@ -101,6 +97,20 @@ int mtk_sgmii_setup_mode_force(struct mt - return 0; - } - -+/* For 1000BASE-X and 2500BASE-X interface modes */ -+void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) -+{ -+ unsigned int val; -+ -+ /* SGMII force duplex setting */ -+ regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -+ val &= ~SGMII_DUPLEX_FULL; -+ if (duplex == DUPLEX_FULL) -+ val |= SGMII_DUPLEX_FULL; -+ -+ regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+} -+ - void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) - { - struct mtk_sgmii *ss = eth->sgmii; diff --git a/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch b/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch deleted file mode 100644 index 6556bb7d07d..00000000000 --- a/target/linux/generic/backport-6.1/704-12-v5.19-net-mtk_eth_soc-stop-passing-phylink-state-to-sgmii-.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 4ce5a0bd3958ed248f0325bfcb95339f7c74feb2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:54:57 +0100 -Subject: [PATCH 06/12] net: mtk_eth_soc: stop passing phylink state to sgmii - setup - -Now that mtk_sgmii_setup_mode_force() only uses the interface mode -from the phylink state, pass just the interface mode into this -function. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 4 ++-- - 3 files changed, 4 insertions(+), 4 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -437,7 +437,7 @@ static void mtk_mac_config(struct phylin - /* Setup SGMIISYS with the determined property */ - if (state->interface != PHY_INTERFACE_MODE_SGMII) - err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, -- state); -+ state->interface); - else if (phylink_autoneg_inband(mode)) - err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1103,7 +1103,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, - u32 ana_rgc3); - int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); - int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -- const struct phylink_link_state *state); -+ phy_interface_t interface); - void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); - void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -65,7 +65,7 @@ int mtk_sgmii_setup_mode_an(struct mtk_s - * fixed speed. - */ - int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -- const struct phylink_link_state *state) -+ phy_interface_t interface) - { - unsigned int val; - -@@ -74,7 +74,7 @@ int mtk_sgmii_setup_mode_force(struct mt - - regmap_read(ss->regmap[id], ss->ana_rgc3, &val); - val &= ~RG_PHY_SPEED_MASK; -- if (state->interface == PHY_INTERFACE_MODE_2500BASEX) -+ if (interface == PHY_INTERFACE_MODE_2500BASEX) - val |= RG_PHY_SPEED_3_125G; - regmap_write(ss->regmap[id], ss->ana_rgc3, val); - diff --git a/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch b/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch deleted file mode 100644 index 0e22c7fd674..00000000000 --- a/target/linux/generic/backport-6.1/704-13-v5.19-net-mtk_eth_soc-provide-mtk_sgmii_config.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 1ec619ee4a052fb9ac48b57554ac2722a0bfe73c Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:02 +0100 -Subject: [PATCH 07/12] net: mtk_eth_soc: provide mtk_sgmii_config() - -Provide mtk_sgmii_config() to wrap up the decisions about which SGMII -configuration will be called. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 7 +------ - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 ++--- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 20 +++++++++++++++++--- - 3 files changed, 20 insertions(+), 12 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -435,12 +435,7 @@ static void mtk_mac_config(struct phylin - 0 : mac->id; - - /* Setup SGMIISYS with the determined property */ -- if (state->interface != PHY_INTERFACE_MODE_SGMII) -- err = mtk_sgmii_setup_mode_force(eth->sgmii, sid, -- state->interface); -- else if (phylink_autoneg_inband(mode)) -- err = mtk_sgmii_setup_mode_an(eth->sgmii, sid); -- -+ err = mtk_sgmii_config(eth->sgmii, sid, mode, state->interface); - if (err) - goto init_err; - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1101,9 +1101,8 @@ u32 mtk_r32(struct mtk_eth *eth, unsigne - - int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, - u32 ana_rgc3); --int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id); --int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -- phy_interface_t interface); -+int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, -+ phy_interface_t interface); - void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); - void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); - ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -35,7 +35,7 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, - } - - /* For SGMII interface mode */ --int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) -+static int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) - { - unsigned int val; - -@@ -64,8 +64,8 @@ int mtk_sgmii_setup_mode_an(struct mtk_s - /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a - * fixed speed. - */ --int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -- phy_interface_t interface) -+static int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -+ phy_interface_t interface) - { - unsigned int val; - -@@ -97,6 +97,20 @@ int mtk_sgmii_setup_mode_force(struct mt - return 0; - } - -+int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, -+ phy_interface_t interface) -+{ -+ int err = 0; -+ -+ /* Setup SGMIISYS with the determined property */ -+ if (interface != PHY_INTERFACE_MODE_SGMII) -+ err = mtk_sgmii_setup_mode_force(ss, id, interface); -+ else if (phylink_autoneg_inband(mode)) -+ err = mtk_sgmii_setup_mode_an(ss, id); -+ -+ return err; -+} -+ - /* For 1000BASE-X and 2500BASE-X interface modes */ - void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) - { diff --git a/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch b/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch deleted file mode 100644 index 8080a2ca441..00000000000 --- a/target/linux/generic/backport-6.1/704-14-v5.19-net-mtk_eth_soc-add-fixme-comment-for-state-speed-us.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 650a49bc65df6b0e0051a8f62d7c22d95a8f350d Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:07 +0100 -Subject: [PATCH 08/12] net: mtk_eth_soc: add fixme comment for state->speed - use - -Add a fixme comment for the last remaining incorrect usage of -state->speed in the mac_config() method, which is strangely in a code -path which is only run when the PHY interface mode changes. - -This means if we are in RGMII mode, changes in state->speed will not -cause the INTF_MODE, TRGMII_RCK_CTRL and TRGMII_TCK_CTRL registers to -be set according to the speed, nor will the TRGPLL clock be set to the -correct value. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -374,6 +374,14 @@ static void mtk_mac_config(struct phylin - state->interface)) - goto err_phy; - } else { -+ /* FIXME: this is incorrect. Not only does it -+ * use state->speed (which is not guaranteed -+ * to be correct) but it also makes use of it -+ * in a code path that will only be reachable -+ * when the PHY interface mode changes, not -+ * when the speed changes. Consequently, RGMII -+ * is probably broken. -+ */ - mtk_gmac0_rgmii_adjust(mac->hw, - state->interface, - state->speed); diff --git a/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch b/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch deleted file mode 100644 index 337c6112d66..00000000000 --- a/target/linux/generic/backport-6.1/704-15-v5.19-net-mtk_eth_soc-move-MAC_MCR-setting-to-mac_finish.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 0e37ad71b2ff772009595002da2860999e98e14e Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:12 +0100 -Subject: [PATCH 09/12] net: mtk_eth_soc: move MAC_MCR setting to mac_finish() - -Move the setting of the MTK_MAC_MCR register from the end of mac_config -into the phylink mac_finish() method, to keep it as the very last write -that is done during configuration. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 33 ++++++++++++++------- - 1 file changed, 22 insertions(+), 11 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -316,8 +316,8 @@ static void mtk_mac_config(struct phylin - struct mtk_mac *mac = container_of(config, struct mtk_mac, - phylink_config); - struct mtk_eth *eth = mac->hw; -- u32 mcr_cur, mcr_new, sid, i; - int val, ge_mode, err = 0; -+ u32 sid, i; - - /* MT76x8 has no hardware settings between for the MAC */ - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && -@@ -455,6 +455,25 @@ static void mtk_mac_config(struct phylin - return; - } - -+ return; -+ -+err_phy: -+ dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, -+ mac->id, phy_modes(state->interface)); -+ return; -+ -+init_err: -+ dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, -+ mac->id, phy_modes(state->interface), err); -+} -+ -+static int mtk_mac_finish(struct phylink_config *config, unsigned int mode, -+ phy_interface_t interface) -+{ -+ struct mtk_mac *mac = container_of(config, struct mtk_mac, -+ phylink_config); -+ u32 mcr_cur, mcr_new; -+ - /* Setup gmac */ - mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr_new = mcr_cur; -@@ -466,16 +485,7 @@ static void mtk_mac_config(struct phylin - if (mcr_new != mcr_cur) - mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); - -- return; -- --err_phy: -- dev_err(eth->dev, "%s: GMAC%d mode %s not supported!\n", __func__, -- mac->id, phy_modes(state->interface)); -- return; -- --init_err: -- dev_err(eth->dev, "%s: GMAC%d mode %s err: %d!\n", __func__, -- mac->id, phy_modes(state->interface), err); -+ return 0; - } - - static void mtk_mac_pcs_get_state(struct phylink_config *config, -@@ -582,6 +592,7 @@ static const struct phylink_mac_ops mtk_ - .mac_pcs_get_state = mtk_mac_pcs_get_state, - .mac_an_restart = mtk_mac_an_restart, - .mac_config = mtk_mac_config, -+ .mac_finish = mtk_mac_finish, - .mac_link_down = mtk_mac_link_down, - .mac_link_up = mtk_mac_link_up, - }; diff --git a/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch b/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch deleted file mode 100644 index b03ef436bdb..00000000000 --- a/target/linux/generic/backport-6.1/704-16-v5.19-net-mtk_eth_soc-move-restoration-of-SYSCFG0-to-mac_f.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 21089867278deb2a110b685e3cd33f64f9ce41e2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:17 +0100 -Subject: [PATCH 10/12] net: mtk_eth_soc: move restoration of SYSCFG0 to - mac_finish() - -The SGMIISYS configuration is performed while ETHSYS_SYSCFG0 is in a -disabled state. In order to preserve this when we switch to phylink_pcs -we need to move the restoration of this register to the mac_finish() -callback. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +++++++++-- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 + - 2 files changed, 10 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -447,8 +447,8 @@ static void mtk_mac_config(struct phylin - if (err) - goto init_err; - -- regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -- SYSCFG0_SGMII_MASK, val); -+ /* Save the syscfg0 value for mac_finish */ -+ mac->syscfg0 = val; - } else if (phylink_autoneg_inband(mode)) { - dev_err(eth->dev, - "In-band mode not supported in non SGMII mode!\n"); -@@ -472,8 +472,15 @@ static int mtk_mac_finish(struct phylink - { - struct mtk_mac *mac = container_of(config, struct mtk_mac, - phylink_config); -+ struct mtk_eth *eth = mac->hw; - u32 mcr_cur, mcr_new; - -+ /* Enable SGMII */ -+ if (interface == PHY_INTERFACE_MODE_SGMII || -+ phy_interface_mode_is_8023z(interface)) -+ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, -+ SYSCFG0_SGMII_MASK, mac->syscfg0); -+ - /* Setup gmac */ - mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr_new = mcr_cur; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1088,6 +1088,7 @@ struct mtk_mac { - struct mtk_hw_stats *hw_stats; - __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; - int hwlro_ip_cnt; -+ unsigned int syscfg0; - }; - - /* the struct describing the SoC. these are declared in the soc_xyz.c files */ diff --git a/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch b/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch deleted file mode 100644 index 4c84703cd94..00000000000 --- a/target/linux/generic/backport-6.1/704-17-v5.19-net-mtk_eth_soc-convert-code-structure-to-suit-split.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 901f3fbe13c3e56f0742e02717ccbfabbc95c463 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:22 +0100 -Subject: [PATCH 11/12] net: mtk_eth_soc: convert code structure to suit split - PCS support - -Provide a mtk_pcs structure which encapsulates everything that the PCS -functions need (the regmap and ana_rgc3 offset), and use this in the -PCS functions. Provide shim functions to convert from the existing -"mtk_sgmii_*" interface to the converted PCS functions. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 15 ++- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 123 +++++++++++--------- - 2 files changed, 79 insertions(+), 59 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -959,16 +959,23 @@ struct mtk_soc_data { - /* currently no SoC has more than 2 macs */ - #define MTK_MAX_DEVS 2 - --/* struct mtk_sgmii - This is the structure holding sgmii regmap and its -- * characteristics -+/* struct mtk_pcs - This structure holds each sgmii regmap and associated -+ * data - * @regmap: The register map pointing at the range used to setup - * SGMII modes - * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap - */ -+struct mtk_pcs { -+ struct regmap *regmap; -+ u32 ana_rgc3; -+}; - -+/* struct mtk_sgmii - This is the structure holding sgmii regmap and its -+ * characteristics -+ * @pcs Array of individual PCS structures -+ */ - struct mtk_sgmii { -- struct regmap *regmap[MTK_MAX_DEVS]; -- u32 ana_rgc3; -+ struct mtk_pcs pcs[MTK_MAX_DEVS]; - }; - - /* struct mtk_eth - This is the main datasructure for holding the state ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -9,90 +9,71 @@ - - #include - #include -+#include - #include - - #include "mtk_eth_soc.h" - --int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) --{ -- struct device_node *np; -- int i; -- -- ss->ana_rgc3 = ana_rgc3; -- -- for (i = 0; i < MTK_MAX_DEVS; i++) { -- np = of_parse_phandle(r, "mediatek,sgmiisys", i); -- if (!np) -- break; -- -- ss->regmap[i] = syscon_node_to_regmap(np); -- of_node_put(np); -- if (IS_ERR(ss->regmap[i])) -- return PTR_ERR(ss->regmap[i]); -- } -- -- return 0; --} -- - /* For SGMII interface mode */ --static int mtk_sgmii_setup_mode_an(struct mtk_sgmii *ss, int id) -+static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) - { - unsigned int val; - -- if (!ss->regmap[id]) -+ if (!mpcs->regmap) - return -EINVAL; - - /* Setup the link timer and QPHY power up inside SGMIISYS */ -- regmap_write(ss->regmap[id], SGMSYS_PCS_LINK_TIMER, -+ regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, - SGMII_LINK_TIMER_DEFAULT); - -- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -+ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); - val |= SGMII_REMOTE_FAULT_DIS; -- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - -- regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); -+ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); - val |= SGMII_AN_RESTART; -- regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); -+ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - -- regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); -+ regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); - val &= ~SGMII_PHYA_PWD; -- regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); -+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); - - return 0; -+ - } - - /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a - * fixed speed. - */ --static int mtk_sgmii_setup_mode_force(struct mtk_sgmii *ss, int id, -- phy_interface_t interface) -+static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs, -+ phy_interface_t interface) - { - unsigned int val; - -- if (!ss->regmap[id]) -+ if (!mpcs->regmap) - return -EINVAL; - -- regmap_read(ss->regmap[id], ss->ana_rgc3, &val); -+ regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); - val &= ~RG_PHY_SPEED_MASK; - if (interface == PHY_INTERFACE_MODE_2500BASEX) - val |= RG_PHY_SPEED_3_125G; -- regmap_write(ss->regmap[id], ss->ana_rgc3, val); -+ regmap_write(mpcs->regmap, mpcs->ana_rgc3, val); - - /* Disable SGMII AN */ -- regmap_read(ss->regmap[id], SGMSYS_PCS_CONTROL_1, &val); -+ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); - val &= ~SGMII_AN_ENABLE; -- regmap_write(ss->regmap[id], SGMSYS_PCS_CONTROL_1, val); -+ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - - /* Set the speed etc but leave the duplex unchanged */ -- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -+ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); - val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK; - val |= SGMII_SPEED_1000; -- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - - /* Release PHYA power down state */ -- regmap_read(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, &val); -+ regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val); - val &= ~SGMII_PHYA_PWD; -- regmap_write(ss->regmap[id], SGMSYS_QPHY_PWR_STATE_CTRL, val); -+ regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val); - - return 0; - } -@@ -100,44 +81,76 @@ static int mtk_sgmii_setup_mode_force(st - int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, - phy_interface_t interface) - { -+ struct mtk_pcs *mpcs = &ss->pcs[id]; - int err = 0; - - /* Setup SGMIISYS with the determined property */ - if (interface != PHY_INTERFACE_MODE_SGMII) -- err = mtk_sgmii_setup_mode_force(ss, id, interface); -+ err = mtk_pcs_setup_mode_force(mpcs, interface); - else if (phylink_autoneg_inband(mode)) -- err = mtk_sgmii_setup_mode_an(ss, id); -+ err = mtk_pcs_setup_mode_an(mpcs); - - return err; - } - --/* For 1000BASE-X and 2500BASE-X interface modes */ --void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) -+static void mtk_pcs_restart_an(struct mtk_pcs *mpcs) -+{ -+ unsigned int val; -+ -+ if (!mpcs->regmap) -+ return; -+ -+ regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); -+ val |= SGMII_AN_RESTART; -+ regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); -+} -+ -+static void mtk_pcs_link_up(struct mtk_pcs *mpcs, int speed, int duplex) - { - unsigned int val; - - /* SGMII force duplex setting */ -- regmap_read(ss->regmap[id], SGMSYS_SGMII_MODE, &val); -+ regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); - val &= ~SGMII_DUPLEX_FULL; - if (duplex == DUPLEX_FULL) - val |= SGMII_DUPLEX_FULL; - -- regmap_write(ss->regmap[id], SGMSYS_SGMII_MODE, val); -+ regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); -+} -+ -+/* For 1000BASE-X and 2500BASE-X interface modes */ -+void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) -+{ -+ mtk_pcs_link_up(&ss->pcs[id], speed, duplex); -+} -+ -+int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) -+{ -+ struct device_node *np; -+ int i; -+ -+ for (i = 0; i < MTK_MAX_DEVS; i++) { -+ np = of_parse_phandle(r, "mediatek,sgmiisys", i); -+ if (!np) -+ break; -+ -+ ss->pcs[i].ana_rgc3 = ana_rgc3; -+ ss->pcs[i].regmap = syscon_node_to_regmap(np); -+ of_node_put(np); -+ if (IS_ERR(ss->pcs[i].regmap)) -+ return PTR_ERR(ss->pcs[i].regmap); -+ } -+ -+ return 0; - } - - void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) - { -- struct mtk_sgmii *ss = eth->sgmii; -- unsigned int val, sid; -+ unsigned int sid; - - /* Decide how GMAC and SGMIISYS be mapped */ - sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? - 0 : mac_id; - -- if (!ss->regmap[sid]) -- return; -- -- regmap_read(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, &val); -- val |= SGMII_AN_RESTART; -- regmap_write(ss->regmap[sid], SGMSYS_PCS_CONTROL_1, val); -+ mtk_pcs_restart_an(ð->sgmii->pcs[sid]); - } diff --git a/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch deleted file mode 100644 index b585867935e..00000000000 --- a/target/linux/generic/backport-6.1/704-18-v5.19-net-mtk_eth_soc-partially-convert-to-phylink_pcs.patch +++ /dev/null @@ -1,262 +0,0 @@ -From 14a44ab0330d290fade1403a920e299cc56d7300 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Wed, 18 May 2022 15:55:28 +0100 -Subject: [PATCH 12/12] net: mtk_eth_soc: partially convert to phylink_pcs - -Partially convert mtk_eth_soc to phylink_pcs, moving the configuration, -link up and AN restart over. However, it seems mac_pcs_get_state() -doesn't actually get the state from the PCS, so we can't convert that -over without a better understanding of the hardware. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 49 ++++++++---------- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 ++- - drivers/net/ethernet/mediatek/mtk_sgmii.c | 55 +++++++++++---------- - 3 files changed, 53 insertions(+), 58 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -310,6 +310,25 @@ static void mtk_gmac0_rgmii_adjust(struc - mtk_w32(eth, val, TRGMII_TCK_CTRL); - } - -+static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, -+ phy_interface_t interface) -+{ -+ struct mtk_mac *mac = container_of(config, struct mtk_mac, -+ phylink_config); -+ struct mtk_eth *eth = mac->hw; -+ unsigned int sid; -+ -+ if (interface == PHY_INTERFACE_MODE_SGMII || -+ phy_interface_mode_is_8023z(interface)) { -+ sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? -+ 0 : mac->id; -+ -+ return mtk_sgmii_select_pcs(eth->sgmii, sid); -+ } -+ -+ return NULL; -+} -+ - static void mtk_mac_config(struct phylink_config *config, unsigned int mode, - const struct phylink_link_state *state) - { -@@ -317,7 +336,7 @@ static void mtk_mac_config(struct phylin - phylink_config); - struct mtk_eth *eth = mac->hw; - int val, ge_mode, err = 0; -- u32 sid, i; -+ u32 i; - - /* MT76x8 has no hardware settings between for the MAC */ - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && -@@ -438,15 +457,6 @@ static void mtk_mac_config(struct phylin - SYSCFG0_SGMII_MASK, - ~(u32)SYSCFG0_SGMII_MASK); - -- /* Decide how GMAC and SGMIISYS be mapped */ -- sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? -- 0 : mac->id; -- -- /* Setup SGMIISYS with the determined property */ -- err = mtk_sgmii_config(eth->sgmii, sid, mode, state->interface); -- if (err) -- goto init_err; -- - /* Save the syscfg0 value for mac_finish */ - mac->syscfg0 = val; - } else if (phylink_autoneg_inband(mode)) { -@@ -527,14 +537,6 @@ static void mtk_mac_pcs_get_state(struct - state->pause |= MLO_PAUSE_TX; - } - --static void mtk_mac_an_restart(struct phylink_config *config) --{ -- struct mtk_mac *mac = container_of(config, struct mtk_mac, -- phylink_config); -- -- mtk_sgmii_restart_an(mac->hw, mac->id); --} -- - static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, - phy_interface_t interface) - { -@@ -555,15 +557,6 @@ static void mtk_mac_link_up(struct phyli - phylink_config); - u32 mcr; - -- if (phy_interface_mode_is_8023z(interface)) { -- struct mtk_eth *eth = mac->hw; -- -- /* Decide how GMAC and SGMIISYS be mapped */ -- int sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? -- 0 : mac->id; -- mtk_sgmii_link_up(eth->sgmii, sid, speed, duplex); -- } -- - mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr &= ~(MAC_MCR_SPEED_100 | MAC_MCR_SPEED_1000 | - MAC_MCR_FORCE_DPX | MAC_MCR_FORCE_TX_FC | -@@ -596,8 +589,8 @@ static void mtk_mac_link_up(struct phyli - - static const struct phylink_mac_ops mtk_phylink_ops = { - .validate = phylink_generic_validate, -+ .mac_select_pcs = mtk_mac_select_pcs, - .mac_pcs_get_state = mtk_mac_pcs_get_state, -- .mac_an_restart = mtk_mac_an_restart, - .mac_config = mtk_mac_config, - .mac_finish = mtk_mac_finish, - .mac_link_down = mtk_mac_link_down, ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -964,10 +964,12 @@ struct mtk_soc_data { - * @regmap: The register map pointing at the range used to setup - * SGMII modes - * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap -+ * @pcs: Phylink PCS structure - */ - struct mtk_pcs { - struct regmap *regmap; - u32 ana_rgc3; -+ struct phylink_pcs pcs; - }; - - /* struct mtk_sgmii - This is the structure holding sgmii regmap and its -@@ -1107,12 +1109,9 @@ void mtk_stats_update_mac(struct mtk_mac - void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); - u32 mtk_r32(struct mtk_eth *eth, unsigned reg); - -+struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id); - int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *np, - u32 ana_rgc3); --int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, -- phy_interface_t interface); --void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex); --void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id); - - int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); - int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); ---- a/drivers/net/ethernet/mediatek/mtk_sgmii.c -+++ b/drivers/net/ethernet/mediatek/mtk_sgmii.c -@@ -14,14 +14,16 @@ - - #include "mtk_eth_soc.h" - -+static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs) -+{ -+ return container_of(pcs, struct mtk_pcs, pcs); -+} -+ - /* For SGMII interface mode */ - static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs) - { - unsigned int val; - -- if (!mpcs->regmap) -- return -EINVAL; -- - /* Setup the link timer and QPHY power up inside SGMIISYS */ - regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER, - SGMII_LINK_TIMER_DEFAULT); -@@ -50,9 +52,6 @@ static int mtk_pcs_setup_mode_force(stru - { - unsigned int val; - -- if (!mpcs->regmap) -- return -EINVAL; -- - regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val); - val &= ~RG_PHY_SPEED_MASK; - if (interface == PHY_INTERFACE_MODE_2500BASEX) -@@ -78,10 +77,12 @@ static int mtk_pcs_setup_mode_force(stru - return 0; - } - --int mtk_sgmii_config(struct mtk_sgmii *ss, int id, unsigned int mode, -- phy_interface_t interface) -+static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode, -+ phy_interface_t interface, -+ const unsigned long *advertising, -+ bool permit_pause_to_mac) - { -- struct mtk_pcs *mpcs = &ss->pcs[id]; -+ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); - int err = 0; - - /* Setup SGMIISYS with the determined property */ -@@ -93,22 +94,25 @@ int mtk_sgmii_config(struct mtk_sgmii *s - return err; - } - --static void mtk_pcs_restart_an(struct mtk_pcs *mpcs) -+static void mtk_pcs_restart_an(struct phylink_pcs *pcs) - { -+ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); - unsigned int val; - -- if (!mpcs->regmap) -- return; -- - regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val); - val |= SGMII_AN_RESTART; - regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val); - } - --static void mtk_pcs_link_up(struct mtk_pcs *mpcs, int speed, int duplex) -+static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, -+ phy_interface_t interface, int speed, int duplex) - { -+ struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs); - unsigned int val; - -+ if (!phy_interface_mode_is_8023z(interface)) -+ return; -+ - /* SGMII force duplex setting */ - regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val); - val &= ~SGMII_DUPLEX_FULL; -@@ -118,11 +122,11 @@ static void mtk_pcs_link_up(struct mtk_p - regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val); - } - --/* For 1000BASE-X and 2500BASE-X interface modes */ --void mtk_sgmii_link_up(struct mtk_sgmii *ss, int id, int speed, int duplex) --{ -- mtk_pcs_link_up(&ss->pcs[id], speed, duplex); --} -+static const struct phylink_pcs_ops mtk_pcs_ops = { -+ .pcs_config = mtk_pcs_config, -+ .pcs_an_restart = mtk_pcs_restart_an, -+ .pcs_link_up = mtk_pcs_link_up, -+}; - - int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3) - { -@@ -139,18 +143,17 @@ int mtk_sgmii_init(struct mtk_sgmii *ss, - of_node_put(np); - if (IS_ERR(ss->pcs[i].regmap)) - return PTR_ERR(ss->pcs[i].regmap); -+ -+ ss->pcs[i].pcs.ops = &mtk_pcs_ops; - } - - return 0; - } - --void mtk_sgmii_restart_an(struct mtk_eth *eth, int mac_id) -+struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id) - { -- unsigned int sid; -- -- /* Decide how GMAC and SGMIISYS be mapped */ -- sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? -- 0 : mac_id; -+ if (!ss->pcs[id].regmap) -+ return NULL; - -- mtk_pcs_restart_an(ð->sgmii->pcs[sid]); -+ return &ss->pcs[id].pcs; - } diff --git a/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch b/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch deleted file mode 100644 index 4142fd1d508..00000000000 --- a/target/linux/generic/backport-6.1/705-01-v5.17-net-dsa-mt7530-iterate-using-dsa_switch_for_each_use.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 505560028b6deb9b4385cf6100f05ca6f4aacaf8 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Mon, 6 Dec 2021 18:57:49 +0200 -Subject: [PATCH 01/13] net: dsa: mt7530: iterate using - dsa_switch_for_each_user_port in bridging ops - -Avoid repeated calls to dsa_to_port() (some hidden behind dsa_is_user_port -and some in plain sight) by keeping two struct dsa_port references: one -to the port passed as argument, and another to the other ports of the -switch that we're iterating over. - -dsa_to_port(ds, i) gets replaced by other_dp, i gets replaced by -other_port which is derived from other_dp->index, dsa_is_user_port is -handled by the DSA iterator. - -Signed-off-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/mt7530.c | 52 +++++++++++++++++++++++----------------- - 1 file changed, 30 insertions(+), 22 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -1190,27 +1190,31 @@ static int - mt7530_port_bridge_join(struct dsa_switch *ds, int port, - struct net_device *bridge) - { -- struct mt7530_priv *priv = ds->priv; -+ struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; - u32 port_bitmap = BIT(MT7530_CPU_PORT); -- int i; -+ struct mt7530_priv *priv = ds->priv; - - mutex_lock(&priv->reg_mutex); - -- for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ dsa_switch_for_each_user_port(other_dp, ds) { -+ int other_port = other_dp->index; -+ -+ if (dp == other_dp) -+ continue; -+ - /* Add this port to the port matrix of the other ports in the - * same bridge. If the port is disabled, port matrix is kept - * and not being setup until the port becomes enabled. - */ -- if (dsa_is_user_port(ds, i) && i != port) { -- if (dsa_to_port(ds, i)->bridge_dev != bridge) -- continue; -- if (priv->ports[i].enable) -- mt7530_set(priv, MT7530_PCR_P(i), -- PCR_MATRIX(BIT(port))); -- priv->ports[i].pm |= PCR_MATRIX(BIT(port)); -+ if (other_dp->bridge_dev != bridge) -+ continue; - -- port_bitmap |= BIT(i); -- } -+ if (priv->ports[other_port].enable) -+ mt7530_set(priv, MT7530_PCR_P(other_port), -+ PCR_MATRIX(BIT(port))); -+ priv->ports[other_port].pm |= PCR_MATRIX(BIT(port)); -+ -+ port_bitmap |= BIT(other_port); - } - - /* Add the all other ports to this port matrix. */ -@@ -1315,24 +1319,28 @@ static void - mt7530_port_bridge_leave(struct dsa_switch *ds, int port, - struct net_device *bridge) - { -+ struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; - struct mt7530_priv *priv = ds->priv; -- int i; - - mutex_lock(&priv->reg_mutex); - -- for (i = 0; i < MT7530_NUM_PORTS; i++) { -+ dsa_switch_for_each_user_port(other_dp, ds) { -+ int other_port = other_dp->index; -+ -+ if (dp == other_dp) -+ continue; -+ - /* Remove this port from the port matrix of the other ports - * in the same bridge. If the port is disabled, port matrix - * is kept and not being setup until the port becomes enabled. - */ -- if (dsa_is_user_port(ds, i) && i != port) { -- if (dsa_to_port(ds, i)->bridge_dev != bridge) -- continue; -- if (priv->ports[i].enable) -- mt7530_clear(priv, MT7530_PCR_P(i), -- PCR_MATRIX(BIT(port))); -- priv->ports[i].pm &= ~PCR_MATRIX(BIT(port)); -- } -+ if (other_dp->bridge_dev != bridge) -+ continue; -+ -+ if (priv->ports[other_port].enable) -+ mt7530_clear(priv, MT7530_PCR_P(other_port), -+ PCR_MATRIX(BIT(port))); -+ priv->ports[other_port].pm &= ~PCR_MATRIX(BIT(port)); - } - - /* Set the cpu port to be the only one in the port matrix of diff --git a/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch b/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch deleted file mode 100644 index 435f282845f..00000000000 --- a/target/linux/generic/backport-6.1/705-02-v5.19-net-dsa-mt7530-populate-supported_interfaces-and-mac.patch +++ /dev/null @@ -1,166 +0,0 @@ -From a1da54bcd664fc27169386db966575675ac3ccb0 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:01 +0100 -Subject: [PATCH 02/13] net: dsa: mt7530: populate supported_interfaces and - mac_capabilities -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Populate the supported interfaces and MAC capabilities for mt7530, -mt7531 and mt7621 DSA switches. Filling this in will enable phylink -to pre-check the PHY interface mode against the the supported -interfaces bitmap prior to calling the validate function, and will -eventually allow us to convert to using the generic validation. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 74 ++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/mt7530.h | 2 ++ - 2 files changed, 76 insertions(+) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2412,6 +2412,32 @@ mt7531_setup(struct dsa_switch *ds) - return 0; - } - -+static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, -+ struct phylink_config *config) -+{ -+ switch (port) { -+ case 0 ... 4: /* Internal phy */ -+ __set_bit(PHY_INTERFACE_MODE_GMII, -+ config->supported_interfaces); -+ break; -+ -+ case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ -+ phy_interface_set_rgmii(config->supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_MII, -+ config->supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_GMII, -+ config->supported_interfaces); -+ break; -+ -+ case 6: /* 1st cpu port */ -+ __set_bit(PHY_INTERFACE_MODE_RGMII, -+ config->supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_TRGMII, -+ config->supported_interfaces); -+ break; -+ } -+} -+ - static bool - mt7530_phy_mode_supported(struct dsa_switch *ds, int port, - const struct phylink_link_state *state) -@@ -2448,6 +2474,37 @@ static bool mt7531_is_rgmii_port(struct - return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); - } - -+static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, -+ struct phylink_config *config) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ switch (port) { -+ case 0 ... 4: /* Internal phy */ -+ __set_bit(PHY_INTERFACE_MODE_GMII, -+ config->supported_interfaces); -+ break; -+ -+ case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ -+ if (mt7531_is_rgmii_port(priv, port)) { -+ phy_interface_set_rgmii(config->supported_interfaces); -+ break; -+ } -+ fallthrough; -+ -+ case 6: /* 1st cpu port supports sgmii/8023z only */ -+ __set_bit(PHY_INTERFACE_MODE_SGMII, -+ config->supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, -+ config->supported_interfaces); -+ __set_bit(PHY_INTERFACE_MODE_2500BASEX, -+ config->supported_interfaces); -+ -+ config->mac_capabilities |= MAC_2500FD; -+ break; -+ } -+} -+ - static bool - mt7531_phy_mode_supported(struct dsa_switch *ds, int port, - const struct phylink_link_state *state) -@@ -2924,6 +2981,18 @@ mt7531_cpu_port_config(struct dsa_switch - return 0; - } - -+static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, -+ struct phylink_config *config) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ /* This switch only supports full-duplex at 1Gbps */ -+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | -+ MAC_10 | MAC_100 | MAC_1000FD; -+ -+ priv->info->mac_port_get_caps(ds, port, config); -+} -+ - static void - mt7530_mac_port_validate(struct dsa_switch *ds, int port, - unsigned long *supported) -@@ -3159,6 +3228,7 @@ static const struct dsa_switch_ops mt753 - .port_vlan_del = mt7530_port_vlan_del, - .port_mirror_add = mt753x_port_mirror_add, - .port_mirror_del = mt753x_port_mirror_del, -+ .phylink_get_caps = mt753x_phylink_get_caps, - .phylink_validate = mt753x_phylink_validate, - .phylink_mac_link_state = mt753x_phylink_mac_link_state, - .phylink_mac_config = mt753x_phylink_mac_config, -@@ -3176,6 +3246,7 @@ static const struct mt753x_info mt753x_t - .phy_read = mt7530_phy_read, - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, -+ .mac_port_get_caps = mt7530_mac_port_get_caps, - .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, -@@ -3187,6 +3258,7 @@ static const struct mt753x_info mt753x_t - .phy_read = mt7530_phy_read, - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, -+ .mac_port_get_caps = mt7530_mac_port_get_caps, - .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, -@@ -3199,6 +3271,7 @@ static const struct mt753x_info mt753x_t - .phy_write = mt7531_ind_phy_write, - .pad_setup = mt7531_pad_setup, - .cpu_port_config = mt7531_cpu_port_config, -+ .mac_port_get_caps = mt7531_mac_port_get_caps, - .phy_mode_supported = mt7531_phy_mode_supported, - .mac_port_validate = mt7531_mac_port_validate, - .mac_port_get_state = mt7531_phylink_mac_link_state, -@@ -3261,6 +3334,7 @@ mt7530_probe(struct mdio_device *mdiodev - */ - if (!priv->info->sw_setup || !priv->info->pad_setup || - !priv->info->phy_read || !priv->info->phy_write || -+ !priv->info->mac_port_get_caps || - !priv->info->phy_mode_supported || - !priv->info->mac_port_validate || - !priv->info->mac_port_get_state || !priv->info->mac_port_config) ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -769,6 +769,8 @@ struct mt753x_info { - int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val); - int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface); - int (*cpu_port_config)(struct dsa_switch *ds, int port); -+ void (*mac_port_get_caps)(struct dsa_switch *ds, int port, -+ struct phylink_config *config); - bool (*phy_mode_supported)(struct dsa_switch *ds, int port, - const struct phylink_link_state *state); - void (*mac_port_validate)(struct dsa_switch *ds, int port, diff --git a/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch b/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch deleted file mode 100644 index 38a24dc46b0..00000000000 --- a/target/linux/generic/backport-6.1/705-03-v5.19-net-dsa-mt7530-remove-interface-checks.patch +++ /dev/null @@ -1,172 +0,0 @@ -From e3f6719e2269868ca129b05da50cd55786848954 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:06 +0100 -Subject: [PATCH 03/13] net: dsa: mt7530: remove interface checks -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -As phylink checks the interface mode against the supported_interfaces -bitmap, we no longer need to validate the interface mode, nor handle -PHY_INTERFACE_MODE_NA in the validation function. Remove these to -simplify the implementation. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 82 ---------------------------------------- - drivers/net/dsa/mt7530.h | 2 - - 2 files changed, 84 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2438,37 +2438,6 @@ static void mt7530_mac_port_get_caps(str - } - } - --static bool --mt7530_phy_mode_supported(struct dsa_switch *ds, int port, -- const struct phylink_link_state *state) --{ -- struct mt7530_priv *priv = ds->priv; -- -- switch (port) { -- case 0 ... 4: /* Internal phy */ -- if (state->interface != PHY_INTERFACE_MODE_GMII) -- return false; -- break; -- case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ -- if (!phy_interface_mode_is_rgmii(state->interface) && -- state->interface != PHY_INTERFACE_MODE_MII && -- state->interface != PHY_INTERFACE_MODE_GMII) -- return false; -- break; -- case 6: /* 1st cpu port */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_TRGMII) -- return false; -- break; -- default: -- dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, -- port); -- return false; -- } -- -- return true; --} -- - static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) - { - return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); -@@ -2505,44 +2474,6 @@ static void mt7531_mac_port_get_caps(str - } - } - --static bool --mt7531_phy_mode_supported(struct dsa_switch *ds, int port, -- const struct phylink_link_state *state) --{ -- struct mt7530_priv *priv = ds->priv; -- -- switch (port) { -- case 0 ... 4: /* Internal phy */ -- if (state->interface != PHY_INTERFACE_MODE_GMII) -- return false; -- break; -- case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ -- if (mt7531_is_rgmii_port(priv, port)) -- return phy_interface_mode_is_rgmii(state->interface); -- fallthrough; -- case 6: /* 1st cpu port supports sgmii/8023z only */ -- if (state->interface != PHY_INTERFACE_MODE_SGMII && -- !phy_interface_mode_is_8023z(state->interface)) -- return false; -- break; -- default: -- dev_err(priv->dev, "%s: unsupported port: %i\n", __func__, -- port); -- return false; -- } -- -- return true; --} -- --static bool --mt753x_phy_mode_supported(struct dsa_switch *ds, int port, -- const struct phylink_link_state *state) --{ -- struct mt7530_priv *priv = ds->priv; -- -- return priv->info->phy_mode_supported(ds, port, state); --} -- - static int - mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) - { -@@ -2797,9 +2728,6 @@ mt753x_phylink_mac_config(struct dsa_swi - struct mt7530_priv *priv = ds->priv; - u32 mcr_cur, mcr_new; - -- if (!mt753x_phy_mode_supported(ds, port, state)) -- goto unsupported; -- - switch (port) { - case 0 ... 4: /* Internal phy */ - if (state->interface != PHY_INTERFACE_MODE_GMII) -@@ -3015,12 +2943,6 @@ mt753x_phylink_validate(struct dsa_switc - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; - struct mt7530_priv *priv = ds->priv; - -- if (state->interface != PHY_INTERFACE_MODE_NA && -- !mt753x_phy_mode_supported(ds, port, state)) { -- linkmode_zero(supported); -- return; -- } -- - phylink_set_port_modes(mask); - - if (state->interface != PHY_INTERFACE_MODE_TRGMII && -@@ -3247,7 +3169,6 @@ static const struct mt753x_info mt753x_t - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, -@@ -3259,7 +3180,6 @@ static const struct mt753x_info mt753x_t - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .phy_mode_supported = mt7530_phy_mode_supported, - .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, -@@ -3272,7 +3192,6 @@ static const struct mt753x_info mt753x_t - .pad_setup = mt7531_pad_setup, - .cpu_port_config = mt7531_cpu_port_config, - .mac_port_get_caps = mt7531_mac_port_get_caps, -- .phy_mode_supported = mt7531_phy_mode_supported, - .mac_port_validate = mt7531_mac_port_validate, - .mac_port_get_state = mt7531_phylink_mac_link_state, - .mac_port_config = mt7531_mac_config, -@@ -3335,7 +3254,6 @@ mt7530_probe(struct mdio_device *mdiodev - if (!priv->info->sw_setup || !priv->info->pad_setup || - !priv->info->phy_read || !priv->info->phy_write || - !priv->info->mac_port_get_caps || -- !priv->info->phy_mode_supported || - !priv->info->mac_port_validate || - !priv->info->mac_port_get_state || !priv->info->mac_port_config) - return -EINVAL; ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -771,8 +771,6 @@ struct mt753x_info { - int (*cpu_port_config)(struct dsa_switch *ds, int port); - void (*mac_port_get_caps)(struct dsa_switch *ds, int port, - struct phylink_config *config); -- bool (*phy_mode_supported)(struct dsa_switch *ds, int port, -- const struct phylink_link_state *state); - void (*mac_port_validate)(struct dsa_switch *ds, int port, - unsigned long *supported); - int (*mac_port_get_state)(struct dsa_switch *ds, int port, diff --git a/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch b/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch deleted file mode 100644 index e607a3c7d2c..00000000000 --- a/target/linux/generic/backport-6.1/705-04-v5.19-net-dsa-mt7530-drop-use-of-phylink_helper_basex_spee.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 58344a3b85f1bd5ffddfc2c11f6f2bf688b5f990 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:12 +0100 -Subject: [PATCH 04/13] net: dsa: mt7530: drop use of - phylink_helper_basex_speed() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Now that we have a better method to select SFP interface modes, we -no longer need to use phylink_helper_basex_speed() in a driver's -validation function. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 5 ----- - 1 file changed, 5 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2967,11 +2967,6 @@ mt753x_phylink_validate(struct dsa_switc - - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); -- -- /* We can only operate at 2500BaseX or 1000BaseX. If requested -- * to advertise both, only report advertising at 2500BaseX. -- */ -- phylink_helper_basex_speed(state); - } - - static int diff --git a/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch b/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch deleted file mode 100644 index 63a33176303..00000000000 --- a/target/linux/generic/backport-6.1/705-05-v5.19-net-dsa-mt7530-only-indicate-linkmodes-that-can-be-s.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 3c1d788a62dc648d1846049b66119ebb69dedd52 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:17 +0100 -Subject: [PATCH 05/13] net: dsa: mt7530: only indicate linkmodes that can be - supported -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Now that mt7530 is not using the basex helper, it becomes unnecessary to -indicate support for both 1000baseX and 2500baseX when one of the 803.3z -PHY interface modes is being selected. Ensure that the driver indicates -only those linkmodes that can actually be supported by the PHY interface -mode. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 12 ++++++++---- - drivers/net/dsa/mt7530.h | 1 + - 2 files changed, 9 insertions(+), 4 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2545,12 +2545,13 @@ static int mt7531_rgmii_setup(struct mt7 - } - - static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, -+ phy_interface_t interface, - unsigned long *supported) - { - /* Port5 supports ethier RGMII or SGMII. - * Port6 supports SGMII only. - */ -- if (port == 6) { -+ if (port == 6 && interface == PHY_INTERFACE_MODE_2500BASEX) { - phylink_set(supported, 2500baseX_Full); - phylink_set(supported, 2500baseT_Full); - } -@@ -2923,16 +2924,18 @@ static void mt753x_phylink_get_caps(stru - - static void - mt7530_mac_port_validate(struct dsa_switch *ds, int port, -+ phy_interface_t interface, - unsigned long *supported) - { - } - - static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, -+ phy_interface_t interface, - unsigned long *supported) - { - struct mt7530_priv *priv = ds->priv; - -- mt7531_sgmii_validate(priv, port, supported); -+ mt7531_sgmii_validate(priv, port, interface, supported); - } - - static void -@@ -2955,12 +2958,13 @@ mt753x_phylink_validate(struct dsa_switc - } - - /* This switch only supports 1G full-duplex. */ -- if (state->interface != PHY_INTERFACE_MODE_MII) { -+ if (state->interface != PHY_INTERFACE_MODE_MII && -+ state->interface != PHY_INTERFACE_MODE_2500BASEX) { - phylink_set(mask, 1000baseT_Full); - phylink_set(mask, 1000baseX_Full); - } - -- priv->info->mac_port_validate(ds, port, mask); -+ priv->info->mac_port_validate(ds, port, state->interface, mask); - - phylink_set(mask, Pause); - phylink_set(mask, Asym_Pause); ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -772,6 +772,7 @@ struct mt753x_info { - void (*mac_port_get_caps)(struct dsa_switch *ds, int port, - struct phylink_config *config); - void (*mac_port_validate)(struct dsa_switch *ds, int port, -+ phy_interface_t interface, - unsigned long *supported); - int (*mac_port_get_state)(struct dsa_switch *ds, int port, - struct phylink_link_state *state); diff --git a/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch b/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch deleted file mode 100644 index 97699d4c5e3..00000000000 --- a/target/linux/generic/backport-6.1/705-06-v5.19-net-dsa-mt7530-switch-to-use-phylink_get_linkmodes.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 1c2211cb15dd3957fb26c0e1615eceb5db851ad6 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:22 +0100 -Subject: [PATCH 06/13] net: dsa: mt7530: switch to use phylink_get_linkmodes() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Switch mt7530 to use phylink_get_linkmodes() to generate the ethtool -linkmodes that can be supported. We are unable to use the generic -helper for this as pause modes are dependent on the interface as -the Autoneg bit depends on the interface mode. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 57 ++++------------------------------------ - 1 file changed, 5 insertions(+), 52 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2544,19 +2544,6 @@ static int mt7531_rgmii_setup(struct mt7 - return 0; - } - --static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port, -- phy_interface_t interface, -- unsigned long *supported) --{ -- /* Port5 supports ethier RGMII or SGMII. -- * Port6 supports SGMII only. -- */ -- if (port == 6 && interface == PHY_INTERFACE_MODE_2500BASEX) { -- phylink_set(supported, 2500baseX_Full); -- phylink_set(supported, 2500baseT_Full); -- } --} -- - static void - mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, - unsigned int mode, phy_interface_t interface, -@@ -2923,51 +2910,21 @@ static void mt753x_phylink_get_caps(stru - } - - static void --mt7530_mac_port_validate(struct dsa_switch *ds, int port, -- phy_interface_t interface, -- unsigned long *supported) --{ --} -- --static void mt7531_mac_port_validate(struct dsa_switch *ds, int port, -- phy_interface_t interface, -- unsigned long *supported) --{ -- struct mt7530_priv *priv = ds->priv; -- -- mt7531_sgmii_validate(priv, port, interface, supported); --} -- --static void - mt753x_phylink_validate(struct dsa_switch *ds, int port, - unsigned long *supported, - struct phylink_link_state *state) - { - __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- struct mt7530_priv *priv = ds->priv; -+ u32 caps; -+ -+ caps = dsa_to_port(ds, port)->pl_config.mac_capabilities; - - phylink_set_port_modes(mask); -+ phylink_get_linkmodes(mask, state->interface, caps); - - if (state->interface != PHY_INTERFACE_MODE_TRGMII && -- !phy_interface_mode_is_8023z(state->interface)) { -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -+ !phy_interface_mode_is_8023z(state->interface)) - phylink_set(mask, Autoneg); -- } -- -- /* This switch only supports 1G full-duplex. */ -- if (state->interface != PHY_INTERFACE_MODE_MII && -- state->interface != PHY_INTERFACE_MODE_2500BASEX) { -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 1000baseX_Full); -- } -- -- priv->info->mac_port_validate(ds, port, state->interface, mask); -- -- phylink_set(mask, Pause); -- phylink_set(mask, Asym_Pause); - - linkmode_and(supported, supported, mask); - linkmode_and(state->advertising, state->advertising, mask); -@@ -3168,7 +3125,6 @@ static const struct mt753x_info mt753x_t - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, - }, -@@ -3179,7 +3135,6 @@ static const struct mt753x_info mt753x_t - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .mac_port_validate = mt7530_mac_port_validate, - .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, - }, -@@ -3191,7 +3146,6 @@ static const struct mt753x_info mt753x_t - .pad_setup = mt7531_pad_setup, - .cpu_port_config = mt7531_cpu_port_config, - .mac_port_get_caps = mt7531_mac_port_get_caps, -- .mac_port_validate = mt7531_mac_port_validate, - .mac_port_get_state = mt7531_phylink_mac_link_state, - .mac_port_config = mt7531_mac_config, - .mac_pcs_an_restart = mt7531_sgmii_restart_an, -@@ -3253,7 +3207,6 @@ mt7530_probe(struct mdio_device *mdiodev - if (!priv->info->sw_setup || !priv->info->pad_setup || - !priv->info->phy_read || !priv->info->phy_write || - !priv->info->mac_port_get_caps || -- !priv->info->mac_port_validate || - !priv->info->mac_port_get_state || !priv->info->mac_port_config) - return -EINVAL; - diff --git a/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch b/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch deleted file mode 100644 index b9b74833d22..00000000000 --- a/target/linux/generic/backport-6.1/705-07-v5.19-net-dsa-mt7530-partially-convert-to-phylink_pcs.patch +++ /dev/null @@ -1,385 +0,0 @@ -From fd993fd59d96d5e2d5972ec4ca1f9651025c987b Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:27 +0100 -Subject: [PATCH 07/13] net: dsa: mt7530: partially convert to phylink_pcs -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Partially convert the mt7530 driver to use phylink's PCS support. This -is a partial implementation as we don't move anything into the -pcs_config method yet - this driver supports SGMII or 1000BASE-X -without in-band. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 144 +++++++++++++++++++++++---------------- - drivers/net/dsa/mt7530.h | 21 +++--- - 2 files changed, 95 insertions(+), 70 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -24,6 +24,11 @@ - - #include "mt7530.h" - -+static struct mt753x_pcs *pcs_to_mt753x_pcs(struct phylink_pcs *pcs) -+{ -+ return container_of(pcs, struct mt753x_pcs, pcs); -+} -+ - /* String, offset, and register size in bytes if different from 4 bytes */ - static const struct mt7530_mib_desc mt7530_mib[] = { - MIB_DESC(1, 0x00, "TxDrop"), -@@ -2544,12 +2549,11 @@ static int mt7531_rgmii_setup(struct mt7 - return 0; - } - --static void --mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port, -- unsigned int mode, phy_interface_t interface, -- int speed, int duplex) -+static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode, -+ phy_interface_t interface, int speed, int duplex) - { -- struct mt7530_priv *priv = ds->priv; -+ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -+ int port = pcs_to_mt753x_pcs(pcs)->port; - unsigned int val; - - /* For adjusting speed and duplex of SGMII force mode. */ -@@ -2575,6 +2579,9 @@ mt7531_sgmii_link_up_force(struct dsa_sw - - /* MT7531 SGMII 1G force mode can only work in full duplex mode, - * no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not. -+ * -+ * The speed check is unnecessary as the MAC capabilities apply -+ * this restriction. --rmk - */ - if ((speed == SPEED_10 || speed == SPEED_100) && - duplex != DUPLEX_FULL) -@@ -2650,9 +2657,10 @@ static int mt7531_sgmii_setup_mode_an(st - return 0; - } - --static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port) -+static void mt7531_pcs_an_restart(struct phylink_pcs *pcs) - { -- struct mt7530_priv *priv = ds->priv; -+ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -+ int port = pcs_to_mt753x_pcs(pcs)->port; - u32 val; - - /* Only restart AN when AN is enabled */ -@@ -2709,6 +2717,24 @@ mt753x_mac_config(struct dsa_switch *ds, - return priv->info->mac_port_config(ds, port, mode, state->interface); - } - -+static struct phylink_pcs * -+mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port, -+ phy_interface_t interface) -+{ -+ struct mt7530_priv *priv = ds->priv; -+ -+ switch (interface) { -+ case PHY_INTERFACE_MODE_TRGMII: -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ case PHY_INTERFACE_MODE_2500BASEX: -+ return &priv->pcs[port].pcs; -+ -+ default: -+ return NULL; -+ } -+} -+ - static void - mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, - const struct phylink_link_state *state) -@@ -2770,17 +2796,6 @@ unsupported: - mt7530_write(priv, MT7530_PMCR_P(port), mcr_new); - } - --static void --mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port) --{ -- struct mt7530_priv *priv = ds->priv; -- -- if (!priv->info->mac_pcs_an_restart) -- return; -- -- priv->info->mac_pcs_an_restart(ds, port); --} -- - static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port, - unsigned int mode, - phy_interface_t interface) -@@ -2790,16 +2805,13 @@ static void mt753x_phylink_mac_link_down - mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK); - } - --static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port, -- unsigned int mode, phy_interface_t interface, -- int speed, int duplex) -+static void mt753x_phylink_pcs_link_up(struct phylink_pcs *pcs, -+ unsigned int mode, -+ phy_interface_t interface, -+ int speed, int duplex) - { -- struct mt7530_priv *priv = ds->priv; -- -- if (!priv->info->mac_pcs_link_up) -- return; -- -- priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex); -+ if (pcs->ops->pcs_link_up) -+ pcs->ops->pcs_link_up(pcs, mode, interface, speed, duplex); - } - - static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port, -@@ -2812,8 +2824,6 @@ static void mt753x_phylink_mac_link_up(s - struct mt7530_priv *priv = ds->priv; - u32 mcr; - -- mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex); -- - mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK; - - /* MT753x MAC works in 1G full duplex mode for all up-clocked -@@ -2891,6 +2901,8 @@ mt7531_cpu_port_config(struct dsa_switch - return ret; - mt7530_write(priv, MT7530_PMCR_P(port), - PMCR_CPU_PORT_SETTING(priv->id)); -+ mt753x_phylink_pcs_link_up(&priv->pcs[port].pcs, MLO_AN_FIXED, -+ interface, speed, DUPLEX_FULL); - mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL, - speed, DUPLEX_FULL, true, true); - -@@ -2930,16 +2942,13 @@ mt753x_phylink_validate(struct dsa_switc - linkmode_and(state->advertising, state->advertising, mask); - } - --static int --mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port, -- struct phylink_link_state *state) -+static void mt7530_pcs_get_state(struct phylink_pcs *pcs, -+ struct phylink_link_state *state) - { -- struct mt7530_priv *priv = ds->priv; -+ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -+ int port = pcs_to_mt753x_pcs(pcs)->port; - u32 pmsr; - -- if (port < 0 || port >= MT7530_NUM_PORTS) -- return -EINVAL; -- - pmsr = mt7530_read(priv, MT7530_PMSR_P(port)); - - state->link = (pmsr & PMSR_LINK); -@@ -2966,8 +2975,6 @@ mt7530_phylink_mac_link_state(struct dsa - state->pause |= MLO_PAUSE_RX; - if (pmsr & PMSR_TX_FC) - state->pause |= MLO_PAUSE_TX; -- -- return 1; - } - - static int -@@ -3009,32 +3016,49 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 - return 0; - } - --static int --mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port, -- struct phylink_link_state *state) -+static void mt7531_pcs_get_state(struct phylink_pcs *pcs, -+ struct phylink_link_state *state) - { -- struct mt7530_priv *priv = ds->priv; -+ struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; -+ int port = pcs_to_mt753x_pcs(pcs)->port; - - if (state->interface == PHY_INTERFACE_MODE_SGMII) -- return mt7531_sgmii_pcs_get_state_an(priv, port, state); -- -- return -EOPNOTSUPP; -+ mt7531_sgmii_pcs_get_state_an(priv, port, state); -+ else -+ state->link = false; - } - --static int --mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port, -- struct phylink_link_state *state) -+static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, -+ phy_interface_t interface, -+ const unsigned long *advertising, -+ bool permit_pause_to_mac) - { -- struct mt7530_priv *priv = ds->priv; -+ return 0; -+} - -- return priv->info->mac_port_get_state(ds, port, state); -+static void mt7530_pcs_an_restart(struct phylink_pcs *pcs) -+{ - } - -+static const struct phylink_pcs_ops mt7530_pcs_ops = { -+ .pcs_get_state = mt7530_pcs_get_state, -+ .pcs_config = mt753x_pcs_config, -+ .pcs_an_restart = mt7530_pcs_an_restart, -+}; -+ -+static const struct phylink_pcs_ops mt7531_pcs_ops = { -+ .pcs_get_state = mt7531_pcs_get_state, -+ .pcs_config = mt753x_pcs_config, -+ .pcs_an_restart = mt7531_pcs_an_restart, -+ .pcs_link_up = mt7531_pcs_link_up, -+}; -+ - static int - mt753x_setup(struct dsa_switch *ds) - { - struct mt7530_priv *priv = ds->priv; - int ret = priv->info->sw_setup(ds); -+ int i; - - if (ret) - return ret; -@@ -3047,6 +3071,13 @@ mt753x_setup(struct dsa_switch *ds) - if (ret && priv->irq) - mt7530_free_irq_common(priv); - -+ /* Initialise the PCS devices */ -+ for (i = 0; i < priv->ds->num_ports; i++) { -+ priv->pcs[i].pcs.ops = priv->info->pcs_ops; -+ priv->pcs[i].priv = priv; -+ priv->pcs[i].port = i; -+ } -+ - return ret; - } - -@@ -3108,9 +3139,8 @@ static const struct dsa_switch_ops mt753 - .port_mirror_del = mt753x_port_mirror_del, - .phylink_get_caps = mt753x_phylink_get_caps, - .phylink_validate = mt753x_phylink_validate, -- .phylink_mac_link_state = mt753x_phylink_mac_link_state, -+ .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs, - .phylink_mac_config = mt753x_phylink_mac_config, -- .phylink_mac_an_restart = mt753x_phylink_mac_an_restart, - .phylink_mac_link_down = mt753x_phylink_mac_link_down, - .phylink_mac_link_up = mt753x_phylink_mac_link_up, - .get_mac_eee = mt753x_get_mac_eee, -@@ -3120,36 +3150,34 @@ static const struct dsa_switch_ops mt753 - static const struct mt753x_info mt753x_table[] = { - [ID_MT7621] = { - .id = ID_MT7621, -+ .pcs_ops = &mt7530_pcs_ops, - .sw_setup = mt7530_setup, - .phy_read = mt7530_phy_read, - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, - }, - [ID_MT7530] = { - .id = ID_MT7530, -+ .pcs_ops = &mt7530_pcs_ops, - .sw_setup = mt7530_setup, - .phy_read = mt7530_phy_read, - .phy_write = mt7530_phy_write, - .pad_setup = mt7530_pad_clk_setup, - .mac_port_get_caps = mt7530_mac_port_get_caps, -- .mac_port_get_state = mt7530_phylink_mac_link_state, - .mac_port_config = mt7530_mac_config, - }, - [ID_MT7531] = { - .id = ID_MT7531, -+ .pcs_ops = &mt7531_pcs_ops, - .sw_setup = mt7531_setup, - .phy_read = mt7531_ind_phy_read, - .phy_write = mt7531_ind_phy_write, - .pad_setup = mt7531_pad_setup, - .cpu_port_config = mt7531_cpu_port_config, - .mac_port_get_caps = mt7531_mac_port_get_caps, -- .mac_port_get_state = mt7531_phylink_mac_link_state, - .mac_port_config = mt7531_mac_config, -- .mac_pcs_an_restart = mt7531_sgmii_restart_an, -- .mac_pcs_link_up = mt7531_sgmii_link_up_force, - }, - }; - -@@ -3207,7 +3235,7 @@ mt7530_probe(struct mdio_device *mdiodev - if (!priv->info->sw_setup || !priv->info->pad_setup || - !priv->info->phy_read || !priv->info->phy_write || - !priv->info->mac_port_get_caps || -- !priv->info->mac_port_get_state || !priv->info->mac_port_config) -+ !priv->info->mac_port_config) - return -EINVAL; - - priv->id = priv->info->id; ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -741,6 +741,12 @@ static const char *p5_intf_modes(unsigne - - struct mt7530_priv; - -+struct mt753x_pcs { -+ struct phylink_pcs pcs; -+ struct mt7530_priv *priv; -+ int port; -+}; -+ - /* struct mt753x_info - This is the main data structure for holding the specific - * part for each supported device - * @sw_setup: Holding the handler to a device initialization -@@ -752,18 +758,14 @@ struct mt7530_priv; - * port - * @mac_port_validate: Holding the way to set addition validate type for a - * certan MAC port -- * @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain -- * MAC port - * @mac_port_config: Holding the way setting up the PHY attribute to a - * certain MAC port -- * @mac_pcs_an_restart Holding the way restarting PCS autonegotiation for a -- * certain MAC port -- * @mac_pcs_link_up: Holding the way setting up the PHY attribute to the pcs -- * of the certain MAC port - */ - struct mt753x_info { - enum mt753x_id id; - -+ const struct phylink_pcs_ops *pcs_ops; -+ - int (*sw_setup)(struct dsa_switch *ds); - int (*phy_read)(struct mt7530_priv *priv, int port, int regnum); - int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val); -@@ -774,15 +776,9 @@ struct mt753x_info { - void (*mac_port_validate)(struct dsa_switch *ds, int port, - phy_interface_t interface, - unsigned long *supported); -- int (*mac_port_get_state)(struct dsa_switch *ds, int port, -- struct phylink_link_state *state); - int (*mac_port_config)(struct dsa_switch *ds, int port, - unsigned int mode, - phy_interface_t interface); -- void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port); -- void (*mac_pcs_link_up)(struct dsa_switch *ds, int port, -- unsigned int mode, phy_interface_t interface, -- int speed, int duplex); - }; - - /* struct mt7530_priv - This is the main data structure for holding the state -@@ -824,6 +820,7 @@ struct mt7530_priv { - u8 mirror_tx; - - struct mt7530_port ports[MT7530_NUM_PORTS]; -+ struct mt753x_pcs pcs[MT7530_NUM_PORTS]; - /* protect among processes for registers access*/ - struct mutex reg_mutex; - int irq; diff --git a/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch b/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch deleted file mode 100644 index 4aa013aad79..00000000000 --- a/target/linux/generic/backport-6.1/705-08-v5.19-net-dsa-mt7530-move-autoneg-handling-to-PCS-validati.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 2b0ee6768f3ac09072e5fd60b36580924e1cfa1c Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:32 +0100 -Subject: [PATCH 08/13] net: dsa: mt7530: move autoneg handling to PCS - validation -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Move the autoneg bit handling to the PCS validation, which allows us to -get rid of mt753x_phylink_validate() and rely on the default -phylink_generic_validate() implementation for the MAC side. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 28 ++++++++++------------------ - 1 file changed, 10 insertions(+), 18 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2921,25 +2921,16 @@ static void mt753x_phylink_get_caps(stru - priv->info->mac_port_get_caps(ds, port, config); - } - --static void --mt753x_phylink_validate(struct dsa_switch *ds, int port, -- unsigned long *supported, -- struct phylink_link_state *state) --{ -- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- u32 caps; -- -- caps = dsa_to_port(ds, port)->pl_config.mac_capabilities; -- -- phylink_set_port_modes(mask); -- phylink_get_linkmodes(mask, state->interface, caps); -+static int mt753x_pcs_validate(struct phylink_pcs *pcs, -+ unsigned long *supported, -+ const struct phylink_link_state *state) -+{ -+ /* Autonegotiation is not supported in TRGMII nor 802.3z modes */ -+ if (state->interface == PHY_INTERFACE_MODE_TRGMII || -+ phy_interface_mode_is_8023z(state->interface)) -+ phylink_clear(supported, Autoneg); - -- if (state->interface != PHY_INTERFACE_MODE_TRGMII && -- !phy_interface_mode_is_8023z(state->interface)) -- phylink_set(mask, Autoneg); -- -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); -+ return 0; - } - - static void mt7530_pcs_get_state(struct phylink_pcs *pcs, -@@ -3041,12 +3032,14 @@ static void mt7530_pcs_an_restart(struct - } - - static const struct phylink_pcs_ops mt7530_pcs_ops = { -+ .pcs_validate = mt753x_pcs_validate, - .pcs_get_state = mt7530_pcs_get_state, - .pcs_config = mt753x_pcs_config, - .pcs_an_restart = mt7530_pcs_an_restart, - }; - - static const struct phylink_pcs_ops mt7531_pcs_ops = { -+ .pcs_validate = mt753x_pcs_validate, - .pcs_get_state = mt7531_pcs_get_state, - .pcs_config = mt753x_pcs_config, - .pcs_an_restart = mt7531_pcs_an_restart, -@@ -3138,7 +3131,6 @@ static const struct dsa_switch_ops mt753 - .port_mirror_add = mt753x_port_mirror_add, - .port_mirror_del = mt753x_port_mirror_del, - .phylink_get_caps = mt753x_phylink_get_caps, -- .phylink_validate = mt753x_phylink_validate, - .phylink_mac_select_pcs = mt753x_phylink_mac_select_pcs, - .phylink_mac_config = mt753x_phylink_mac_config, - .phylink_mac_link_down = mt753x_phylink_mac_link_down, diff --git a/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch b/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch deleted file mode 100644 index d921d78733d..00000000000 --- a/target/linux/generic/backport-6.1/705-09-v5.19-net-dsa-mt7530-mark-as-non-legacy.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 5bc26de9bfaa6bb5539c09d4435dced98f429cfc Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 11 Apr 2022 10:46:37 +0100 -Subject: [PATCH 09/13] net: dsa: mt7530: mark as non-legacy -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The mt7530 driver does not make use of the speed, duplex, pause or -advertisement in its phylink_mac_config() implementation, so it can be -marked as a non-legacy driver. - -Tested-by: Marek Behún -Signed-off-by: Russell King (Oracle) -Signed-off-by: Paolo Abeni ---- - drivers/net/dsa/mt7530.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2918,6 +2918,12 @@ static void mt753x_phylink_get_caps(stru - config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000FD; - -+ /* This driver does not make use of the speed, duplex, pause or the -+ * advertisement in its mac_config, so it is safe to mark this driver -+ * as non-legacy. -+ */ -+ config->legacy_pre_march2020 = false; -+ - priv->info->mac_port_get_caps(ds, port, config); - } - diff --git a/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch b/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch deleted file mode 100644 index e797b1ecb42..00000000000 --- a/target/linux/generic/backport-6.1/705-10-v5.19-net-dsa-mt753x-fix-pcs-conversion-regression.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 1f15b5e8733115cee65342bcaafeaf0368809fae Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Mon, 25 Apr 2022 22:28:02 +0100 -Subject: [PATCH 10/13] net: dsa: mt753x: fix pcs conversion regression - -Daniel Golle reports that the conversion of mt753x to phylink PCS caused -an oops as below. - -The problem is with the placement of the PCS initialisation, which -occurs after mt7531_setup() has been called. However, burited in this -function is a call to setup the CPU port, which requires the PCS -structure to be already setup. - -Fix this by changing the initialisation order. - -Unable to handle kernel NULL pointer dereference at virtual address 0000000000000020 -Mem abort info: - ESR = 0x96000005 - EC = 0x25: DABT (current EL), IL = 32 bits - SET = 0, FnV = 0 - EA = 0, S1PTW = 0 - FSC = 0x05: level 1 translation fault -Data abort info: - ISV = 0, ISS = 0x00000005 - CM = 0, WnR = 0 -user pgtable: 4k pages, 39-bit VAs, pgdp=0000000046057000 -[0000000000000020] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 -Internal error: Oops: 96000005 [#1] SMP -Modules linked in: -CPU: 0 PID: 32 Comm: kworker/u4:1 Tainted: G S 5.18.0-rc3-next-20220422+ #0 -Hardware name: Bananapi BPI-R64 (DT) -Workqueue: events_unbound deferred_probe_work_func -pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) -pc : mt7531_cpu_port_config+0xcc/0x1b0 -lr : mt7531_cpu_port_config+0xc0/0x1b0 -sp : ffffffc008d5b980 -x29: ffffffc008d5b990 x28: ffffff80060562c8 x27: 00000000f805633b -x26: ffffff80001a8880 x25: 00000000000009c4 x24: 0000000000000016 -x23: ffffff8005eb6470 x22: 0000000000003600 x21: ffffff8006948080 -x20: 0000000000000000 x19: 0000000000000006 x18: 0000000000000000 -x17: 0000000000000001 x16: 0000000000000001 x15: 02963607fcee069e -x14: 0000000000000000 x13: 0000000000000030 x12: 0101010101010101 -x11: ffffffc037302000 x10: 0000000000000870 x9 : ffffffc008d5b800 -x8 : ffffff800028f950 x7 : 0000000000000001 x6 : 00000000662b3000 -x5 : 00000000000002f0 x4 : 0000000000000000 x3 : ffffff800028f080 -x2 : 0000000000000000 x1 : ffffff800028f080 x0 : 0000000000000000 -Call trace: - mt7531_cpu_port_config+0xcc/0x1b0 - mt753x_cpu_port_enable+0x24/0x1f0 - mt7531_setup+0x49c/0x5c0 - mt753x_setup+0x20/0x31c - dsa_register_switch+0x8bc/0x1020 - mt7530_probe+0x118/0x200 - mdio_probe+0x30/0x64 - really_probe.part.0+0x98/0x280 - __driver_probe_device+0x94/0x140 - driver_probe_device+0x40/0x114 - __device_attach_driver+0xb0/0x10c - bus_for_each_drv+0x64/0xa0 - __device_attach+0xa8/0x16c - device_initial_probe+0x10/0x20 - bus_probe_device+0x94/0x9c - deferred_probe_work_func+0x80/0xb4 - process_one_work+0x200/0x3a0 - worker_thread+0x260/0x4c0 - kthread+0xd4/0xe0 - ret_from_fork+0x10/0x20 -Code: 9409e911 937b7e60 8b0002a0 f9405800 (f9401005) ----[ end trace 0000000000000000 ]--- - -Reported-by: Daniel Golle -Tested-by: Daniel Golle -Fixes: cbd1f243bc41 ("net: dsa: mt7530: partially convert to phylink_pcs") -Signed-off-by: Russell King (Oracle) -Reviewed-by: Florian Fainelli -Link: https://lore.kernel.org/r/E1nj6FW-007WZB-5Y@rmk-PC.armlinux.org.uk -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/mt7530.c | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -3056,9 +3056,16 @@ static int - mt753x_setup(struct dsa_switch *ds) - { - struct mt7530_priv *priv = ds->priv; -- int ret = priv->info->sw_setup(ds); -- int i; -+ int i, ret; - -+ /* Initialise the PCS devices */ -+ for (i = 0; i < priv->ds->num_ports; i++) { -+ priv->pcs[i].pcs.ops = priv->info->pcs_ops; -+ priv->pcs[i].priv = priv; -+ priv->pcs[i].port = i; -+ } -+ -+ ret = priv->info->sw_setup(ds); - if (ret) - return ret; - -@@ -3070,13 +3077,6 @@ mt753x_setup(struct dsa_switch *ds) - if (ret && priv->irq) - mt7530_free_irq_common(priv); - -- /* Initialise the PCS devices */ -- for (i = 0; i < priv->ds->num_ports; i++) { -- priv->pcs[i].pcs.ops = priv->info->pcs_ops; -- priv->pcs[i].priv = priv; -- priv->pcs[i].port = i; -- } -- - return ret; - } - diff --git a/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch b/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch deleted file mode 100644 index 26d207ca6ab..00000000000 --- a/target/linux/generic/backport-6.1/705-11-v6.0-net-dsa-mt7530-rework-mt7530_hw_vlan_-add-del.patch +++ /dev/null @@ -1,87 +0,0 @@ -From e26be16262e1fc1e9f1798c12762663bd9c265c6 Mon Sep 17 00:00:00 2001 -From: Frank Wunderlich -Date: Fri, 10 Jun 2022 19:05:37 +0200 -Subject: [PATCH 11/13] net: dsa: mt7530: rework mt7530_hw_vlan_{add,del} - -Rework vlan_add/vlan_del functions in preparation for dynamic cpu port. - -Currently BIT(MT7530_CPU_PORT) is added to new_members, even though -mt7530_port_vlan_add() will be called on the CPU port too. - -Let DSA core decide when to call port_vlan_add for the CPU port, rather -than doing it implicitly. - -We can do autonomous forwarding in a certain VLAN, but not add br0 to that -VLAN and avoid flooding the CPU with those packets, if software knows it -doesn't need to process them. - -Suggested-by: Vladimir Oltean -Signed-off-by: Frank Wunderlich -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/mt7530.c | 30 ++++++++++++------------------ - 1 file changed, 12 insertions(+), 18 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -1536,11 +1536,11 @@ static void - mt7530_hw_vlan_add(struct mt7530_priv *priv, - struct mt7530_hw_vlan_entry *entry) - { -+ struct dsa_port *dp = dsa_to_port(priv->ds, entry->port); - u8 new_members; - u32 val; - -- new_members = entry->old_members | BIT(entry->port) | -- BIT(MT7530_CPU_PORT); -+ new_members = entry->old_members | BIT(entry->port); - - /* Validate the entry with independent learning, create egress tag per - * VLAN and joining the port as one of the port members. -@@ -1551,22 +1551,20 @@ mt7530_hw_vlan_add(struct mt7530_priv *p - - /* Decide whether adding tag or not for those outgoing packets from the - * port inside the VLAN. -- */ -- val = entry->untagged ? MT7530_VLAN_EGRESS_UNTAG : -- MT7530_VLAN_EGRESS_TAG; -- mt7530_rmw(priv, MT7530_VAWD2, -- ETAG_CTRL_P_MASK(entry->port), -- ETAG_CTRL_P(entry->port, val)); -- -- /* CPU port is always taken as a tagged port for serving more than one -+ * CPU port is always taken as a tagged port for serving more than one - * VLANs across and also being applied with egress type stack mode for - * that VLAN tags would be appended after hardware special tag used as - * DSA tag. - */ -+ if (dsa_port_is_cpu(dp)) -+ val = MT7530_VLAN_EGRESS_STACK; -+ else if (entry->untagged) -+ val = MT7530_VLAN_EGRESS_UNTAG; -+ else -+ val = MT7530_VLAN_EGRESS_TAG; - mt7530_rmw(priv, MT7530_VAWD2, -- ETAG_CTRL_P_MASK(MT7530_CPU_PORT), -- ETAG_CTRL_P(MT7530_CPU_PORT, -- MT7530_VLAN_EGRESS_STACK)); -+ ETAG_CTRL_P_MASK(entry->port), -+ ETAG_CTRL_P(entry->port, val)); - } - - static void -@@ -1585,11 +1583,7 @@ mt7530_hw_vlan_del(struct mt7530_priv *p - return; - } - -- /* If certain member apart from CPU port is still alive in the VLAN, -- * the entry would be kept valid. Otherwise, the entry is got to be -- * disabled. -- */ -- if (new_members && new_members != BIT(MT7530_CPU_PORT)) { -+ if (new_members) { - val = IVL_MAC | VTAG_EN | PORT_MEM(new_members) | - VLAN_VALID; - mt7530_write(priv, MT7530_VAWD1, val); diff --git a/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch b/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch deleted file mode 100644 index b02705cc701..00000000000 --- a/target/linux/generic/backport-6.1/705-12-v6.0-net-dsa-mt7530-rework-mt753-01-_setup.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 1f0dfd443eea7fc3e818e96f7c8264913ba41859 Mon Sep 17 00:00:00 2001 -From: Frank Wunderlich -Date: Fri, 10 Jun 2022 19:05:38 +0200 -Subject: [PATCH 12/13] net: dsa: mt7530: rework mt753[01]_setup - -Enumerate available cpu-ports instead of using hardcoded constant. - -Suggested-by: Vladimir Oltean -Signed-off-by: Frank Wunderlich -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/mt7530.c | 25 +++++++++++++++++++++---- - 1 file changed, 21 insertions(+), 4 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2101,11 +2101,12 @@ static int - mt7530_setup(struct dsa_switch *ds) - { - struct mt7530_priv *priv = ds->priv; -+ struct device_node *dn = NULL; - struct device_node *phy_node; - struct device_node *mac_np; - struct mt7530_dummy_poll p; - phy_interface_t interface; -- struct device_node *dn; -+ struct dsa_port *cpu_dp; - u32 id, val; - int ret, i; - -@@ -2113,7 +2114,19 @@ mt7530_setup(struct dsa_switch *ds) - * controller also is the container for two GMACs nodes representing - * as two netdev instances. - */ -- dn = dsa_to_port(ds, MT7530_CPU_PORT)->master->dev.of_node->parent; -+ dsa_switch_for_each_cpu_port(cpu_dp, ds) { -+ dn = cpu_dp->master->dev.of_node->parent; -+ /* It doesn't matter which CPU port is found first, -+ * their masters should share the same parent OF node -+ */ -+ break; -+ } -+ -+ if (!dn) { -+ dev_err(ds->dev, "parent OF node of DSA master not found"); -+ return -EINVAL; -+ } -+ - ds->assisted_learning_on_cpu_port = true; - ds->mtu_enforcement_ingress = true; - -@@ -2286,6 +2299,7 @@ mt7531_setup(struct dsa_switch *ds) - { - struct mt7530_priv *priv = ds->priv; - struct mt7530_dummy_poll p; -+ struct dsa_port *cpu_dp; - u32 val, id; - int ret, i; - -@@ -2360,8 +2374,11 @@ mt7531_setup(struct dsa_switch *ds) - CORE_PLL_GROUP4, val); - - /* BPDU to CPU port */ -- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, -- BIT(MT7530_CPU_PORT)); -+ dsa_switch_for_each_cpu_port(cpu_dp, ds) { -+ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, -+ BIT(cpu_dp->index)); -+ break; -+ } - mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, - MT753X_BPDU_CPU_ONLY); - diff --git a/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch b/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch deleted file mode 100644 index 2bfa1ef438e..00000000000 --- a/target/linux/generic/backport-6.1/705-13-v6.0-net-dsa-mt7530-get-cpu-port-via-dp-cpu_dp-instead-of.patch +++ /dev/null @@ -1,117 +0,0 @@ -From ad2606f6fafae3a7d41c4f2af5554c8f6adecbc7 Mon Sep 17 00:00:00 2001 -From: Frank Wunderlich -Date: Fri, 10 Jun 2022 19:05:39 +0200 -Subject: [PATCH 13/13] net: dsa: mt7530: get cpu-port via dp->cpu_dp instead - of constant - -Replace last occurences of hardcoded cpu-port by cpu_dp member of -dsa_port struct. - -Now the constant can be dropped. - -Suggested-by: Vladimir Oltean -Signed-off-by: Frank Wunderlich -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/mt7530.c | 27 ++++++++++++++++++++------- - drivers/net/dsa/mt7530.h | 1 - - 2 files changed, 20 insertions(+), 8 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -1040,6 +1040,7 @@ static int - mt7530_port_enable(struct dsa_switch *ds, int port, - struct phy_device *phy) - { -+ struct dsa_port *dp = dsa_to_port(ds, port); - struct mt7530_priv *priv = ds->priv; - - mutex_lock(&priv->reg_mutex); -@@ -1048,7 +1049,11 @@ mt7530_port_enable(struct dsa_switch *ds - * restore the port matrix if the port is the member of a certain - * bridge. - */ -- priv->ports[port].pm |= PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ if (dsa_port_is_user(dp)) { -+ struct dsa_port *cpu_dp = dp->cpu_dp; -+ -+ priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index)); -+ } - priv->ports[port].enable = true; - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, - priv->ports[port].pm); -@@ -1196,7 +1201,8 @@ mt7530_port_bridge_join(struct dsa_switc - struct net_device *bridge) - { - struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; -- u32 port_bitmap = BIT(MT7530_CPU_PORT); -+ struct dsa_port *cpu_dp = dp->cpu_dp; -+ u32 port_bitmap = BIT(cpu_dp->index); - struct mt7530_priv *priv = ds->priv; - - mutex_lock(&priv->reg_mutex); -@@ -1273,9 +1279,12 @@ mt7530_port_set_vlan_unaware(struct dsa_ - * the CPU port get out of VLAN filtering mode. - */ - if (all_user_ports_removed) { -- mt7530_write(priv, MT7530_PCR_P(MT7530_CPU_PORT), -+ struct dsa_port *dp = dsa_to_port(ds, port); -+ struct dsa_port *cpu_dp = dp->cpu_dp; -+ -+ mt7530_write(priv, MT7530_PCR_P(cpu_dp->index), - PCR_MATRIX(dsa_user_ports(priv->ds))); -- mt7530_write(priv, MT7530_PVC_P(MT7530_CPU_PORT), PORT_SPEC_TAG -+ mt7530_write(priv, MT7530_PVC_P(cpu_dp->index), PORT_SPEC_TAG - | PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); - } - } -@@ -1325,6 +1334,7 @@ mt7530_port_bridge_leave(struct dsa_swit - struct net_device *bridge) - { - struct dsa_port *dp = dsa_to_port(ds, port), *other_dp; -+ struct dsa_port *cpu_dp = dp->cpu_dp; - struct mt7530_priv *priv = ds->priv; - - mutex_lock(&priv->reg_mutex); -@@ -1353,8 +1363,8 @@ mt7530_port_bridge_leave(struct dsa_swit - */ - if (priv->ports[port].enable) - mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK, -- PCR_MATRIX(BIT(MT7530_CPU_PORT))); -- priv->ports[port].pm = PCR_MATRIX(BIT(MT7530_CPU_PORT)); -+ PCR_MATRIX(BIT(cpu_dp->index))); -+ priv->ports[port].pm = PCR_MATRIX(BIT(cpu_dp->index)); - - /* When a port is removed from the bridge, the port would be set up - * back to the default as is at initial boot which is a VLAN-unaware -@@ -1517,6 +1527,9 @@ static int - mt7530_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack) - { -+ struct dsa_port *dp = dsa_to_port(ds, port); -+ struct dsa_port *cpu_dp = dp->cpu_dp; -+ - if (vlan_filtering) { - /* The port is being kept as VLAN-unaware port when bridge is - * set up with vlan_filtering not being set, Otherwise, the -@@ -1524,7 +1537,7 @@ mt7530_port_vlan_filtering(struct dsa_sw - * for becoming a VLAN-aware port. - */ - mt7530_port_set_vlan_aware(ds, port); -- mt7530_port_set_vlan_aware(ds, MT7530_CPU_PORT); -+ mt7530_port_set_vlan_aware(ds, cpu_dp->index); - } else { - mt7530_port_set_vlan_unaware(ds, port); - } ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -8,7 +8,6 @@ - - #define MT7530_NUM_PORTS 7 - #define MT7530_NUM_PHYS 5 --#define MT7530_CPU_PORT 6 - #define MT7530_NUM_FDB_RECORDS 2048 - #define MT7530_ALL_MEMBERS 0xff - diff --git a/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch b/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch deleted file mode 100644 index c5501fb0402..00000000000 --- a/target/linux/generic/backport-6.1/706-00-v6.0-net-ethernet-mtk_eth_soc-rely-on-page_pool-for-singl.patch +++ /dev/null @@ -1,330 +0,0 @@ -From 23233e577ef973c2c5d0dd757a0a4605e34ecb57 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:19:36 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: rely on page_pool for single page - buffers - -Rely on page_pool allocator for single page buffers in order to keep -them dma mapped and add skb recycling support. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/Kconfig | 1 + - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 185 +++++++++++++++----- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++ - 3 files changed, 156 insertions(+), 40 deletions(-) - ---- a/drivers/net/ethernet/mediatek/Kconfig -+++ b/drivers/net/ethernet/mediatek/Kconfig -@@ -16,6 +16,7 @@ config NET_MEDIATEK_SOC - depends on NET_DSA || !NET_DSA - select PHYLINK - select DIMLIB -+ select PAGE_POOL - help - This driver supports the gigabit ethernet MACs in the - MediaTek SoC family. ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1389,6 +1389,68 @@ static void mtk_update_rx_cpu_idx(struct - } - } - -+static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, -+ struct xdp_rxq_info *xdp_q, -+ int id, int size) -+{ -+ struct page_pool_params pp_params = { -+ .order = 0, -+ .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, -+ .pool_size = size, -+ .nid = NUMA_NO_NODE, -+ .dev = eth->dma_dev, -+ .dma_dir = DMA_FROM_DEVICE, -+ .offset = MTK_PP_HEADROOM, -+ .max_len = MTK_PP_MAX_BUF_SIZE, -+ }; -+ struct page_pool *pp; -+ int err; -+ -+ pp = page_pool_create(&pp_params); -+ if (IS_ERR(pp)) -+ return pp; -+ -+ err = xdp_rxq_info_reg(xdp_q, ð->dummy_dev, id, -+ eth->rx_napi.napi_id); -+ if (err < 0) -+ goto err_free_pp; -+ -+ err = xdp_rxq_info_reg_mem_model(xdp_q, MEM_TYPE_PAGE_POOL, pp); -+ if (err) -+ goto err_unregister_rxq; -+ -+ return pp; -+ -+err_unregister_rxq: -+ xdp_rxq_info_unreg(xdp_q); -+err_free_pp: -+ page_pool_destroy(pp); -+ -+ return ERR_PTR(err); -+} -+ -+static void *mtk_page_pool_get_buff(struct page_pool *pp, dma_addr_t *dma_addr, -+ gfp_t gfp_mask) -+{ -+ struct page *page; -+ -+ page = page_pool_alloc_pages(pp, gfp_mask | __GFP_NOWARN); -+ if (!page) -+ return NULL; -+ -+ *dma_addr = page_pool_get_dma_addr(page) + MTK_PP_HEADROOM; -+ return page_address(page); -+} -+ -+static void mtk_rx_put_buff(struct mtk_rx_ring *ring, void *data, bool napi) -+{ -+ if (ring->page_pool) -+ page_pool_put_full_page(ring->page_pool, -+ virt_to_head_page(data), napi); -+ else -+ skb_free_frag(data); -+} -+ - static int mtk_poll_rx(struct napi_struct *napi, int budget, - struct mtk_eth *eth) - { -@@ -1402,9 +1464,9 @@ static int mtk_poll_rx(struct napi_struc - - while (done < budget) { - unsigned int pktlen, *rxdcsum; -+ u32 hash, reason, reserve_len; - struct net_device *netdev; - dma_addr_t dma_addr; -- u32 hash, reason; - int mac = 0; - - ring = mtk_get_rx_ring(eth); -@@ -1435,36 +1497,54 @@ static int mtk_poll_rx(struct napi_struc - goto release_desc; - - /* alloc new buffer */ -- if (ring->frag_size <= PAGE_SIZE) -- new_data = napi_alloc_frag(ring->frag_size); -- else -- new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); -- if (unlikely(!new_data)) { -- netdev->stats.rx_dropped++; -- goto release_desc; -- } -- dma_addr = dma_map_single(eth->dma_dev, -- new_data + NET_SKB_PAD + -- eth->ip_align, -- ring->buf_size, -- DMA_FROM_DEVICE); -- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) { -- skb_free_frag(new_data); -- netdev->stats.rx_dropped++; -- goto release_desc; -- } -+ if (ring->page_pool) { -+ new_data = mtk_page_pool_get_buff(ring->page_pool, -+ &dma_addr, -+ GFP_ATOMIC); -+ if (unlikely(!new_data)) { -+ netdev->stats.rx_dropped++; -+ goto release_desc; -+ } -+ } else { -+ if (ring->frag_size <= PAGE_SIZE) -+ new_data = napi_alloc_frag(ring->frag_size); -+ else -+ new_data = mtk_max_lro_buf_alloc(GFP_ATOMIC); -+ -+ if (unlikely(!new_data)) { -+ netdev->stats.rx_dropped++; -+ goto release_desc; -+ } - -- dma_unmap_single(eth->dma_dev, trxd.rxd1, -- ring->buf_size, DMA_FROM_DEVICE); -+ dma_addr = dma_map_single(eth->dma_dev, -+ new_data + NET_SKB_PAD + eth->ip_align, -+ ring->buf_size, DMA_FROM_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, -+ dma_addr))) { -+ skb_free_frag(new_data); -+ netdev->stats.rx_dropped++; -+ goto release_desc; -+ } -+ -+ dma_unmap_single(eth->dma_dev, trxd.rxd1, -+ ring->buf_size, DMA_FROM_DEVICE); -+ } - - /* receive data */ - skb = build_skb(data, ring->frag_size); - if (unlikely(!skb)) { -- skb_free_frag(data); -+ mtk_rx_put_buff(ring, data, true); - netdev->stats.rx_dropped++; - goto skip_rx; - } -- skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); -+ -+ if (ring->page_pool) { -+ reserve_len = MTK_PP_HEADROOM; -+ skb_mark_for_recycle(skb); -+ } else { -+ reserve_len = NET_SKB_PAD + NET_IP_ALIGN; -+ } -+ skb_reserve(skb, reserve_len); - - pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); - skb->dev = netdev; -@@ -1518,7 +1598,6 @@ static int mtk_poll_rx(struct napi_struc - skip_rx: - ring->data[idx] = new_data; - rxd->rxd1 = (unsigned int)dma_addr; -- - release_desc: - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) - rxd->rxd2 = RX_DMA_LSO; -@@ -1526,7 +1605,6 @@ release_desc: - rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); - - ring->calc_idx = idx; -- - done++; - } - -@@ -1890,13 +1968,15 @@ static int mtk_rx_alloc(struct mtk_eth * - if (!ring->data) - return -ENOMEM; - -- for (i = 0; i < rx_dma_size; i++) { -- if (ring->frag_size <= PAGE_SIZE) -- ring->data[i] = netdev_alloc_frag(ring->frag_size); -- else -- ring->data[i] = mtk_max_lro_buf_alloc(GFP_KERNEL); -- if (!ring->data[i]) -- return -ENOMEM; -+ if (!eth->hwlro) { -+ struct page_pool *pp; -+ -+ pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, -+ rx_dma_size); -+ if (IS_ERR(pp)) -+ return PTR_ERR(pp); -+ -+ ring->page_pool = pp; - } - - ring->dma = dma_alloc_coherent(eth->dma_dev, -@@ -1907,16 +1987,33 @@ static int mtk_rx_alloc(struct mtk_eth * - - for (i = 0; i < rx_dma_size; i++) { - struct mtk_rx_dma_v2 *rxd; -- -- dma_addr_t dma_addr = dma_map_single(eth->dma_dev, -- ring->data[i] + NET_SKB_PAD + eth->ip_align, -- ring->buf_size, -- DMA_FROM_DEVICE); -- if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) -- return -ENOMEM; -+ dma_addr_t dma_addr; -+ void *data; - - rxd = ring->dma + i * eth->soc->txrx.rxd_size; -+ if (ring->page_pool) { -+ data = mtk_page_pool_get_buff(ring->page_pool, -+ &dma_addr, GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ } else { -+ if (ring->frag_size <= PAGE_SIZE) -+ data = netdev_alloc_frag(ring->frag_size); -+ else -+ data = mtk_max_lro_buf_alloc(GFP_KERNEL); -+ -+ if (!data) -+ return -ENOMEM; -+ -+ dma_addr = dma_map_single(eth->dma_dev, -+ data + NET_SKB_PAD + eth->ip_align, -+ ring->buf_size, DMA_FROM_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, -+ dma_addr))) -+ return -ENOMEM; -+ } - rxd->rxd1 = (unsigned int)dma_addr; -+ ring->data[i] = data; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) - rxd->rxd2 = RX_DMA_LSO; -@@ -1932,6 +2029,7 @@ static int mtk_rx_alloc(struct mtk_eth * - rxd->rxd8 = 0; - } - } -+ - ring->dma_size = rx_dma_size; - ring->calc_idx_update = false; - ring->calc_idx = rx_dma_size - 1; -@@ -1983,7 +2081,7 @@ static void mtk_rx_clean(struct mtk_eth - - dma_unmap_single(eth->dma_dev, rxd->rxd1, - ring->buf_size, DMA_FROM_DEVICE); -- skb_free_frag(ring->data[i]); -+ mtk_rx_put_buff(ring, ring->data[i], false); - } - kfree(ring->data); - ring->data = NULL; -@@ -1995,6 +2093,13 @@ static void mtk_rx_clean(struct mtk_eth - ring->dma, ring->phys); - ring->dma = NULL; - } -+ -+ if (ring->page_pool) { -+ if (xdp_rxq_info_is_reg(&ring->xdp_q)) -+ xdp_rxq_info_unreg(&ring->xdp_q); -+ page_pool_destroy(ring->page_pool); -+ ring->page_pool = NULL; -+ } - } - - static int mtk_hwlro_rx_init(struct mtk_eth *eth) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -18,6 +18,8 @@ - #include - #include - #include -+#include -+#include - #include "mtk_ppe.h" - - #define MTK_QDMA_PAGE_SIZE 2048 -@@ -49,6 +51,11 @@ - #define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM) - #define NEXT_DESP_IDX(X, Y) (((X) + 1) & ((Y) - 1)) - -+#define MTK_PP_HEADROOM XDP_PACKET_HEADROOM -+#define MTK_PP_PAD (MTK_PP_HEADROOM + \ -+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) -+#define MTK_PP_MAX_BUF_SIZE (PAGE_SIZE - MTK_PP_PAD) -+ - #define MTK_QRX_OFFSET 0x10 - - #define MTK_MAX_RX_RING_NUM 4 -@@ -743,6 +750,9 @@ struct mtk_rx_ring { - bool calc_idx_update; - u16 calc_idx; - u32 crx_idx_reg; -+ /* page_pool */ -+ struct page_pool *page_pool; -+ struct xdp_rxq_info xdp_q; - }; - - enum mkt_eth_capabilities { diff --git a/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch b/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch deleted file mode 100644 index d94bdabd714..00000000000 --- a/target/linux/generic/backport-6.1/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch +++ /dev/null @@ -1,291 +0,0 @@ -From 7c26c20da5d420cde55618263be4aa2f6de53056 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:19:37 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add basic XDP support - -Introduce basic XDP support to mtk_eth_soc driver. -Supported XDP verdicts: -- XDP_PASS -- XDP_DROP -- XDP_REDIRECT - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 162 +++++++++++++++++--- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + - 2 files changed, 145 insertions(+), 19 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1389,6 +1389,11 @@ static void mtk_update_rx_cpu_idx(struct - } - } - -+static bool mtk_page_pool_enabled(struct mtk_eth *eth) -+{ -+ return !eth->hwlro; -+} -+ - static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, - struct xdp_rxq_info *xdp_q, - int id, int size) -@@ -1451,11 +1456,52 @@ static void mtk_rx_put_buff(struct mtk_r - skb_free_frag(data); - } - -+static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, -+ struct xdp_buff *xdp, struct net_device *dev) -+{ -+ struct bpf_prog *prog; -+ u32 act = XDP_PASS; -+ -+ rcu_read_lock(); -+ -+ prog = rcu_dereference(eth->prog); -+ if (!prog) -+ goto out; -+ -+ act = bpf_prog_run_xdp(prog, xdp); -+ switch (act) { -+ case XDP_PASS: -+ goto out; -+ case XDP_REDIRECT: -+ if (unlikely(xdp_do_redirect(dev, xdp, prog))) { -+ act = XDP_DROP; -+ break; -+ } -+ goto out; -+ default: -+ bpf_warn_invalid_xdp_action(act); -+ fallthrough; -+ case XDP_ABORTED: -+ trace_xdp_exception(dev, prog, act); -+ fallthrough; -+ case XDP_DROP: -+ break; -+ } -+ -+ page_pool_put_full_page(ring->page_pool, -+ virt_to_head_page(xdp->data), true); -+out: -+ rcu_read_unlock(); -+ -+ return act; -+} -+ - static int mtk_poll_rx(struct napi_struct *napi, int budget, - struct mtk_eth *eth) - { - struct dim_sample dim_sample = {}; - struct mtk_rx_ring *ring; -+ bool xdp_flush = false; - int idx; - struct sk_buff *skb; - u8 *data, *new_data; -@@ -1464,9 +1510,9 @@ static int mtk_poll_rx(struct napi_struc - - while (done < budget) { - unsigned int pktlen, *rxdcsum; -- u32 hash, reason, reserve_len; - struct net_device *netdev; - dma_addr_t dma_addr; -+ u32 hash, reason; - int mac = 0; - - ring = mtk_get_rx_ring(eth); -@@ -1496,8 +1542,14 @@ static int mtk_poll_rx(struct napi_struc - if (unlikely(test_bit(MTK_RESETTING, ð->state))) - goto release_desc; - -+ pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); -+ - /* alloc new buffer */ - if (ring->page_pool) { -+ struct page *page = virt_to_head_page(data); -+ struct xdp_buff xdp; -+ u32 ret; -+ - new_data = mtk_page_pool_get_buff(ring->page_pool, - &dma_addr, - GFP_ATOMIC); -@@ -1505,6 +1557,34 @@ static int mtk_poll_rx(struct napi_struc - netdev->stats.rx_dropped++; - goto release_desc; - } -+ -+ dma_sync_single_for_cpu(eth->dma_dev, -+ page_pool_get_dma_addr(page) + MTK_PP_HEADROOM, -+ pktlen, page_pool_get_dma_dir(ring->page_pool)); -+ -+ xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q); -+ xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen, -+ false); -+ xdp_buff_clear_frags_flag(&xdp); -+ -+ ret = mtk_xdp_run(eth, ring, &xdp, netdev); -+ if (ret == XDP_REDIRECT) -+ xdp_flush = true; -+ -+ if (ret != XDP_PASS) -+ goto skip_rx; -+ -+ skb = build_skb(data, PAGE_SIZE); -+ if (unlikely(!skb)) { -+ page_pool_put_full_page(ring->page_pool, -+ page, true); -+ netdev->stats.rx_dropped++; -+ goto skip_rx; -+ } -+ -+ skb_reserve(skb, xdp.data - xdp.data_hard_start); -+ skb_put(skb, xdp.data_end - xdp.data); -+ skb_mark_for_recycle(skb); - } else { - if (ring->frag_size <= PAGE_SIZE) - new_data = napi_alloc_frag(ring->frag_size); -@@ -1528,27 +1608,20 @@ static int mtk_poll_rx(struct napi_struc - - dma_unmap_single(eth->dma_dev, trxd.rxd1, - ring->buf_size, DMA_FROM_DEVICE); -- } - -- /* receive data */ -- skb = build_skb(data, ring->frag_size); -- if (unlikely(!skb)) { -- mtk_rx_put_buff(ring, data, true); -- netdev->stats.rx_dropped++; -- goto skip_rx; -- } -+ skb = build_skb(data, ring->frag_size); -+ if (unlikely(!skb)) { -+ netdev->stats.rx_dropped++; -+ skb_free_frag(data); -+ goto skip_rx; -+ } - -- if (ring->page_pool) { -- reserve_len = MTK_PP_HEADROOM; -- skb_mark_for_recycle(skb); -- } else { -- reserve_len = NET_SKB_PAD + NET_IP_ALIGN; -+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); -+ skb_put(skb, pktlen); - } -- skb_reserve(skb, reserve_len); - -- pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); - skb->dev = netdev; -- skb_put(skb, pktlen); -+ bytes += skb->len; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) - rxdcsum = &trxd.rxd3; -@@ -1560,7 +1633,6 @@ static int mtk_poll_rx(struct napi_struc - else - skb_checksum_none_assert(skb); - skb->protocol = eth_type_trans(skb, netdev); -- bytes += pktlen; - - hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; - if (hash != MTK_RXD4_FOE_ENTRY) { -@@ -1623,6 +1695,9 @@ rx_done: - &dim_sample); - net_dim(ð->rx_dim, dim_sample); - -+ if (xdp_flush) -+ xdp_do_flush_map(); -+ - return done; - } - -@@ -1968,7 +2043,7 @@ static int mtk_rx_alloc(struct mtk_eth * - if (!ring->data) - return -ENOMEM; - -- if (!eth->hwlro) { -+ if (mtk_page_pool_enabled(eth)) { - struct page_pool *pp; - - pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, -@@ -2710,6 +2785,48 @@ static int mtk_stop(struct net_device *d - return 0; - } - -+static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog, -+ struct netlink_ext_ack *extack) -+{ -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_eth *eth = mac->hw; -+ struct bpf_prog *old_prog; -+ bool need_update; -+ -+ if (eth->hwlro) { -+ NL_SET_ERR_MSG_MOD(extack, "XDP not supported with HWLRO"); -+ return -EOPNOTSUPP; -+ } -+ -+ if (dev->mtu > MTK_PP_MAX_BUF_SIZE) { -+ NL_SET_ERR_MSG_MOD(extack, "MTU too large for XDP"); -+ return -EOPNOTSUPP; -+ } -+ -+ need_update = !!eth->prog != !!prog; -+ if (netif_running(dev) && need_update) -+ mtk_stop(dev); -+ -+ old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held()); -+ if (old_prog) -+ bpf_prog_put(old_prog); -+ -+ if (netif_running(dev) && need_update) -+ return mtk_open(dev); -+ -+ return 0; -+} -+ -+static int mtk_xdp(struct net_device *dev, struct netdev_bpf *xdp) -+{ -+ switch (xdp->command) { -+ case XDP_SETUP_PROG: -+ return mtk_xdp_setup(dev, xdp->prog, xdp->extack); -+ default: -+ return -EINVAL; -+ } -+} -+ - static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) - { - regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, -@@ -3005,6 +3122,12 @@ static int mtk_change_mtu(struct net_dev - struct mtk_eth *eth = mac->hw; - u32 mcr_cur, mcr_new; - -+ if (rcu_access_pointer(eth->prog) && -+ length > MTK_PP_MAX_BUF_SIZE) { -+ netdev_err(dev, "Invalid MTU for XDP mode\n"); -+ return -EINVAL; -+ } -+ - if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { - mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); - mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; -@@ -3332,6 +3455,7 @@ static const struct net_device_ops mtk_n - .ndo_poll_controller = mtk_poll_controller, - #endif - .ndo_setup_tc = mtk_eth_setup_tc, -+ .ndo_bpf = mtk_xdp, - }; - - static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1086,6 +1086,8 @@ struct mtk_eth { - - struct mtk_ppe *ppe; - struct rhashtable flow_table; -+ -+ struct bpf_prog __rcu *prog; - }; - - /* struct mtk_mac - the structure that holds the info about the MACs of the diff --git a/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch b/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch deleted file mode 100644 index cf4d658684b..00000000000 --- a/target/linux/generic/backport-6.1/706-02-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-ethtool-count.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 916a6ee836d6b7b8ef1ed5f0515e256ca60e9968 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:19:38 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp ethtool counters - -Report xdp stats through ethtool - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 26 +++++++++++++++++++-- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 12 ++++++++++ - 2 files changed, 36 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -34,6 +34,10 @@ MODULE_PARM_DESC(msg_level, "Message lev - #define MTK_ETHTOOL_STAT(x) { #x, \ - offsetof(struct mtk_hw_stats, x) / sizeof(u64) } - -+#define MTK_ETHTOOL_XDP_STAT(x) { #x, \ -+ offsetof(struct mtk_hw_stats, xdp_stats.x) / \ -+ sizeof(u64) } -+ - static const struct mtk_reg_map mtk_reg_map = { - .tx_irq_mask = 0x1a1c, - .tx_irq_status = 0x1a18, -@@ -141,6 +145,13 @@ static const struct mtk_ethtool_stats { - MTK_ETHTOOL_STAT(rx_long_errors), - MTK_ETHTOOL_STAT(rx_checksum_errors), - MTK_ETHTOOL_STAT(rx_flow_control_packets), -+ MTK_ETHTOOL_XDP_STAT(rx_xdp_redirect), -+ MTK_ETHTOOL_XDP_STAT(rx_xdp_pass), -+ MTK_ETHTOOL_XDP_STAT(rx_xdp_drop), -+ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx), -+ MTK_ETHTOOL_XDP_STAT(rx_xdp_tx_errors), -+ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit), -+ MTK_ETHTOOL_XDP_STAT(tx_xdp_xmit_errors), - }; - - static const char * const mtk_clks_source_name[] = { -@@ -1459,6 +1470,9 @@ static void mtk_rx_put_buff(struct mtk_r - static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, - struct xdp_buff *xdp, struct net_device *dev) - { -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_hw_stats *hw_stats = mac->hw_stats; -+ u64 *count = &hw_stats->xdp_stats.rx_xdp_drop; - struct bpf_prog *prog; - u32 act = XDP_PASS; - -@@ -1471,13 +1485,16 @@ static u32 mtk_xdp_run(struct mtk_eth *e - act = bpf_prog_run_xdp(prog, xdp); - switch (act) { - case XDP_PASS: -- goto out; -+ count = &hw_stats->xdp_stats.rx_xdp_pass; -+ goto update_stats; - case XDP_REDIRECT: - if (unlikely(xdp_do_redirect(dev, xdp, prog))) { - act = XDP_DROP; - break; - } -- goto out; -+ -+ count = &hw_stats->xdp_stats.rx_xdp_redirect; -+ goto update_stats; - default: - bpf_warn_invalid_xdp_action(act); - fallthrough; -@@ -1490,6 +1507,11 @@ static u32 mtk_xdp_run(struct mtk_eth *e - - page_pool_put_full_page(ring->page_pool, - virt_to_head_page(xdp->data), true); -+ -+update_stats: -+ u64_stats_update_begin(&hw_stats->syncp); -+ *count = *count + 1; -+ u64_stats_update_end(&hw_stats->syncp); - out: - rcu_read_unlock(); - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -568,6 +568,16 @@ struct mtk_tx_dma_v2 { - struct mtk_eth; - struct mtk_mac; - -+struct mtk_xdp_stats { -+ u64 rx_xdp_redirect; -+ u64 rx_xdp_pass; -+ u64 rx_xdp_drop; -+ u64 rx_xdp_tx; -+ u64 rx_xdp_tx_errors; -+ u64 tx_xdp_xmit; -+ u64 tx_xdp_xmit_errors; -+}; -+ - /* struct mtk_hw_stats - the structure that holds the traffic statistics. - * @stats_lock: make sure that stats operations are atomic - * @reg_offset: the status register offset of the SoC -@@ -591,6 +601,8 @@ struct mtk_hw_stats { - u64 rx_checksum_errors; - u64 rx_flow_control_packets; - -+ struct mtk_xdp_stats xdp_stats; -+ - spinlock_t stats_lock; - u32 reg_offset; - struct u64_stats_sync syncp; diff --git a/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch b/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch deleted file mode 100644 index 58b49f28a25..00000000000 --- a/target/linux/generic/backport-6.1/706-03-v6.0-net-ethernet-mtk_eth_soc-add-xmit-XDP-support.patch +++ /dev/null @@ -1,340 +0,0 @@ -From 5886d26fd25bbe26130e3e5f7474b9b3e98a3469 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:19:39 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add xmit XDP support - -Introduce XDP support for XDP_TX verdict and ndo_xdp_xmit function -pointer. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 192 +++++++++++++++++--- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 +- - 2 files changed, 180 insertions(+), 22 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -988,15 +988,26 @@ static void mtk_tx_unmap(struct mtk_eth - } - } - -- tx_buf->flags = 0; -- if (tx_buf->skb && -- (tx_buf->skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC)) { -- if (napi) -- napi_consume_skb(tx_buf->skb, napi); -+ if (tx_buf->type == MTK_TYPE_SKB) { -+ if (tx_buf->data && -+ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ struct sk_buff *skb = tx_buf->data; -+ -+ if (napi) -+ napi_consume_skb(skb, napi); -+ else -+ dev_kfree_skb_any(skb); -+ } -+ } else if (tx_buf->data) { -+ struct xdp_frame *xdpf = tx_buf->data; -+ -+ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) -+ xdp_return_frame_rx_napi(xdpf); - else -- dev_kfree_skb_any(tx_buf->skb); -+ xdp_return_frame(xdpf); - } -- tx_buf->skb = NULL; -+ tx_buf->flags = 0; -+ tx_buf->data = NULL; - } - - static void setup_tx_buf(struct mtk_eth *eth, struct mtk_tx_buf *tx_buf, -@@ -1013,7 +1024,7 @@ static void setup_tx_buf(struct mtk_eth - dma_unmap_addr_set(tx_buf, dma_addr1, mapped_addr); - dma_unmap_len_set(tx_buf, dma_len1, size); - } else { -- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; -+ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; - txd->txd1 = mapped_addr; - txd->txd2 = TX_DMA_PLEN0(size); - dma_unmap_addr_set(tx_buf, dma_addr0, mapped_addr); -@@ -1189,7 +1200,7 @@ static int mtk_tx_map(struct sk_buff *sk - soc->txrx.txd_size); - if (new_desc) - memset(tx_buf, 0, sizeof(*tx_buf)); -- tx_buf->skb = (struct sk_buff *)MTK_DMA_DUMMY_DESC; -+ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; - tx_buf->flags |= MTK_TX_FLAGS_PAGE0; - tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : - MTK_TX_FLAGS_FPORT1; -@@ -1203,7 +1214,8 @@ static int mtk_tx_map(struct sk_buff *sk - } - - /* store skb to cleanup */ -- itx_buf->skb = skb; -+ itx_buf->type = MTK_TYPE_SKB; -+ itx_buf->data = skb; - - if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - if (k & 0x1) -@@ -1415,13 +1427,14 @@ static struct page_pool *mtk_create_page - .pool_size = size, - .nid = NUMA_NO_NODE, - .dev = eth->dma_dev, -- .dma_dir = DMA_FROM_DEVICE, - .offset = MTK_PP_HEADROOM, - .max_len = MTK_PP_MAX_BUF_SIZE, - }; - struct page_pool *pp; - int err; - -+ pp_params.dma_dir = rcu_access_pointer(eth->prog) ? DMA_BIDIRECTIONAL -+ : DMA_FROM_DEVICE; - pp = page_pool_create(&pp_params); - if (IS_ERR(pp)) - return pp; -@@ -1467,6 +1480,122 @@ static void mtk_rx_put_buff(struct mtk_r - skb_free_frag(data); - } - -+static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, -+ struct net_device *dev, bool dma_map) -+{ -+ const struct mtk_soc_data *soc = eth->soc; -+ struct mtk_tx_ring *ring = ð->tx_ring; -+ struct mtk_tx_dma_desc_info txd_info = { -+ .size = xdpf->len, -+ .first = true, -+ .last = true, -+ }; -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_tx_dma *txd, *txd_pdma; -+ int err = 0, index = 0, n_desc = 1; -+ struct mtk_tx_buf *tx_buf; -+ -+ if (unlikely(test_bit(MTK_RESETTING, ð->state))) -+ return -EBUSY; -+ -+ if (unlikely(atomic_read(&ring->free_count) <= 1)) -+ return -EBUSY; -+ -+ spin_lock(ð->page_lock); -+ -+ txd = ring->next_free; -+ if (txd == ring->last_free) { -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); -+ memset(tx_buf, 0, sizeof(*tx_buf)); -+ -+ if (dma_map) { /* ndo_xdp_xmit */ -+ txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, -+ txd_info.size, DMA_TO_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { -+ err = -ENOMEM; -+ goto out; -+ } -+ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; -+ } else { -+ struct page *page = virt_to_head_page(xdpf->data); -+ -+ txd_info.addr = page_pool_get_dma_addr(page) + -+ sizeof(*xdpf) + xdpf->headroom; -+ dma_sync_single_for_device(eth->dma_dev, txd_info.addr, -+ txd_info.size, -+ DMA_BIDIRECTIONAL); -+ } -+ mtk_tx_set_dma_desc(dev, txd, &txd_info); -+ -+ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; -+ -+ txd_pdma = qdma_to_pdma(ring, txd); -+ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, -+ index++); -+ -+ /* store xdpf for cleanup */ -+ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; -+ tx_buf->data = xdpf; -+ -+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { -+ if (index & 1) -+ txd_pdma->txd2 |= TX_DMA_LS0; -+ else -+ txd_pdma->txd2 |= TX_DMA_LS1; -+ } -+ -+ ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); -+ atomic_sub(n_desc, &ring->free_count); -+ -+ /* make sure that all changes to the dma ring are flushed before we -+ * continue -+ */ -+ wmb(); -+ -+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { -+ mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); -+ } else { -+ int idx; -+ -+ idx = txd_to_idx(ring, txd, soc->txrx.txd_size); -+ mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), -+ MT7628_TX_CTX_IDX0); -+ } -+out: -+ spin_unlock(ð->page_lock); -+ -+ return err; -+} -+ -+static int mtk_xdp_xmit(struct net_device *dev, int num_frame, -+ struct xdp_frame **frames, u32 flags) -+{ -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_hw_stats *hw_stats = mac->hw_stats; -+ struct mtk_eth *eth = mac->hw; -+ int i, nxmit = 0; -+ -+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) -+ return -EINVAL; -+ -+ for (i = 0; i < num_frame; i++) { -+ if (mtk_xdp_submit_frame(eth, frames[i], dev, true)) -+ break; -+ nxmit++; -+ } -+ -+ u64_stats_update_begin(&hw_stats->syncp); -+ hw_stats->xdp_stats.tx_xdp_xmit += nxmit; -+ hw_stats->xdp_stats.tx_xdp_xmit_errors += num_frame - nxmit; -+ u64_stats_update_end(&hw_stats->syncp); -+ -+ return nxmit; -+} -+ - static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, - struct xdp_buff *xdp, struct net_device *dev) - { -@@ -1495,6 +1624,18 @@ static u32 mtk_xdp_run(struct mtk_eth *e - - count = &hw_stats->xdp_stats.rx_xdp_redirect; - goto update_stats; -+ case XDP_TX: { -+ struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); -+ -+ if (mtk_xdp_submit_frame(eth, xdpf, dev, false)) { -+ count = &hw_stats->xdp_stats.rx_xdp_tx_errors; -+ act = XDP_DROP; -+ break; -+ } -+ -+ count = &hw_stats->xdp_stats.rx_xdp_tx; -+ goto update_stats; -+ } - default: - bpf_warn_invalid_xdp_action(act); - fallthrough; -@@ -1728,9 +1869,8 @@ static int mtk_poll_tx_qdma(struct mtk_e - { - const struct mtk_reg_map *reg_map = eth->soc->reg_map; - struct mtk_tx_ring *ring = ð->tx_ring; -- struct mtk_tx_dma *desc; -- struct sk_buff *skb; - struct mtk_tx_buf *tx_buf; -+ struct mtk_tx_dma *desc; - u32 cpu, dma; - - cpu = ring->last_free_ptr; -@@ -1751,15 +1891,21 @@ static int mtk_poll_tx_qdma(struct mtk_e - if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) - mac = 1; - -- skb = tx_buf->skb; -- if (!skb) -+ if (!tx_buf->data) - break; - -- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->type == MTK_TYPE_SKB && -+ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ struct sk_buff *skb = tx_buf->data; -+ - bytes[mac] += skb->len; - done[mac]++; - budget--; -+ } else if (tx_buf->type == MTK_TYPE_XDP_TX || -+ tx_buf->type == MTK_TYPE_XDP_NDO) { -+ budget--; - } -+ - mtk_tx_unmap(eth, tx_buf, true); - - ring->last_free = desc; -@@ -1778,9 +1924,8 @@ static int mtk_poll_tx_pdma(struct mtk_e - unsigned int *done, unsigned int *bytes) - { - struct mtk_tx_ring *ring = ð->tx_ring; -- struct mtk_tx_dma *desc; -- struct sk_buff *skb; - struct mtk_tx_buf *tx_buf; -+ struct mtk_tx_dma *desc; - u32 cpu, dma; - - cpu = ring->cpu_idx; -@@ -1788,14 +1933,18 @@ static int mtk_poll_tx_pdma(struct mtk_e - - while ((cpu != dma) && budget) { - tx_buf = &ring->buf[cpu]; -- skb = tx_buf->skb; -- if (!skb) -+ if (!tx_buf->data) - break; - -- if (skb != (struct sk_buff *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->type == MTK_TYPE_SKB && -+ tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ struct sk_buff *skb = tx_buf->data; - bytes[0] += skb->len; - done[0]++; - budget--; -+ } else if (tx_buf->type == MTK_TYPE_XDP_TX || -+ tx_buf->type == MTK_TYPE_XDP_NDO) { -+ budget--; - } - - mtk_tx_unmap(eth, tx_buf, true); -@@ -3478,6 +3627,7 @@ static const struct net_device_ops mtk_n - #endif - .ndo_setup_tc = mtk_eth_setup_tc, - .ndo_bpf = mtk_xdp, -+ .ndo_xdp_xmit = mtk_xdp_xmit, - }; - - static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -694,6 +694,12 @@ enum mtk_dev_state { - MTK_RESETTING - }; - -+enum mtk_tx_buf_type { -+ MTK_TYPE_SKB, -+ MTK_TYPE_XDP_TX, -+ MTK_TYPE_XDP_NDO, -+}; -+ - /* struct mtk_tx_buf - This struct holds the pointers to the memory pointed at - * by the TX descriptor s - * @skb: The SKB pointer of the packet being sent -@@ -703,7 +709,9 @@ enum mtk_dev_state { - * @dma_len1: The length of the second segment - */ - struct mtk_tx_buf { -- struct sk_buff *skb; -+ enum mtk_tx_buf_type type; -+ void *data; -+ - u32 flags; - DEFINE_DMA_UNMAP_ADDR(dma_addr0); - DEFINE_DMA_UNMAP_LEN(dma_len0); diff --git a/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch b/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch deleted file mode 100644 index e93e0df544a..00000000000 --- a/target/linux/generic/backport-6.1/706-04-v6.0-net-ethernet-mtk_eth_soc-add-support-for-page_pool_g.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 84b9cd389036d4a262d8cee794d56c04095358a7 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:19:40 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for - page_pool_get_stats - -Introduce support for the page_pool stats API into mtk_eth_soc driver. -Report page_pool stats through ethtool. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/Kconfig | 1 + - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 37 +++++++++++++++++++-- - 2 files changed, 35 insertions(+), 3 deletions(-) - ---- a/drivers/net/ethernet/mediatek/Kconfig -+++ b/drivers/net/ethernet/mediatek/Kconfig -@@ -17,6 +17,7 @@ config NET_MEDIATEK_SOC - select PHYLINK - select DIMLIB - select PAGE_POOL -+ select PAGE_POOL_STATS - help - This driver supports the gigabit ethernet MACs in the - MediaTek SoC family. ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3488,11 +3488,18 @@ static void mtk_get_strings(struct net_d - int i; - - switch (stringset) { -- case ETH_SS_STATS: -+ case ETH_SS_STATS: { -+ struct mtk_mac *mac = netdev_priv(dev); -+ - for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) { - memcpy(data, mtk_ethtool_stats[i].str, ETH_GSTRING_LEN); - data += ETH_GSTRING_LEN; - } -+ if (mtk_page_pool_enabled(mac->hw)) -+ page_pool_ethtool_stats_get_strings(data); -+ break; -+ } -+ default: - break; - } - } -@@ -3500,13 +3507,35 @@ static void mtk_get_strings(struct net_d - static int mtk_get_sset_count(struct net_device *dev, int sset) - { - switch (sset) { -- case ETH_SS_STATS: -- return ARRAY_SIZE(mtk_ethtool_stats); -+ case ETH_SS_STATS: { -+ int count = ARRAY_SIZE(mtk_ethtool_stats); -+ struct mtk_mac *mac = netdev_priv(dev); -+ -+ if (mtk_page_pool_enabled(mac->hw)) -+ count += page_pool_ethtool_stats_get_count(); -+ return count; -+ } - default: - return -EOPNOTSUPP; - } - } - -+static void mtk_ethtool_pp_stats(struct mtk_eth *eth, u64 *data) -+{ -+ struct page_pool_stats stats = {}; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(eth->rx_ring); i++) { -+ struct mtk_rx_ring *ring = ð->rx_ring[i]; -+ -+ if (!ring->page_pool) -+ continue; -+ -+ page_pool_get_stats(ring->page_pool, &stats); -+ } -+ page_pool_ethtool_stats_get(data, &stats); -+} -+ - static void mtk_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) - { -@@ -3534,6 +3563,8 @@ static void mtk_get_ethtool_stats(struct - - for (i = 0; i < ARRAY_SIZE(mtk_ethtool_stats); i++) - *data_dst++ = *(data_src + mtk_ethtool_stats[i].offset); -+ if (mtk_page_pool_enabled(mac->hw)) -+ mtk_ethtool_pp_stats(mac->hw, data_dst); - } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start)); - } - diff --git a/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch b/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch deleted file mode 100644 index 8e6895fe97f..00000000000 --- a/target/linux/generic/backport-6.1/706-05-v6.0-net-ethernet-mtk_eth_soc-introduce-mtk_xdp_frame_map.patch +++ /dev/null @@ -1,113 +0,0 @@ -From b16fe6d82b71fa0dd5c957bc22d66a694976d6eb Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Wed, 27 Jul 2022 23:20:50 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce mtk_xdp_frame_map - utility routine - -This is a preliminary patch to add xdp multi-frag support to mtk_eth_soc -driver - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 68 +++++++++++++-------- - 1 file changed, 42 insertions(+), 26 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1480,6 +1480,41 @@ static void mtk_rx_put_buff(struct mtk_r - skb_free_frag(data); - } - -+static int mtk_xdp_frame_map(struct mtk_eth *eth, struct net_device *dev, -+ struct mtk_tx_dma_desc_info *txd_info, -+ struct mtk_tx_dma *txd, struct mtk_tx_buf *tx_buf, -+ void *data, u16 headroom, int index, bool dma_map) -+{ -+ struct mtk_tx_ring *ring = ð->tx_ring; -+ struct mtk_mac *mac = netdev_priv(dev); -+ struct mtk_tx_dma *txd_pdma; -+ -+ if (dma_map) { /* ndo_xdp_xmit */ -+ txd_info->addr = dma_map_single(eth->dma_dev, data, -+ txd_info->size, DMA_TO_DEVICE); -+ if (unlikely(dma_mapping_error(eth->dma_dev, txd_info->addr))) -+ return -ENOMEM; -+ -+ tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; -+ } else { -+ struct page *page = virt_to_head_page(data); -+ -+ txd_info->addr = page_pool_get_dma_addr(page) + -+ sizeof(struct xdp_frame) + headroom; -+ dma_sync_single_for_device(eth->dma_dev, txd_info->addr, -+ txd_info->size, DMA_BIDIRECTIONAL); -+ } -+ mtk_tx_set_dma_desc(dev, txd, txd_info); -+ -+ tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; -+ -+ txd_pdma = qdma_to_pdma(ring, txd); -+ setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, -+ index); -+ -+ return 0; -+} -+ - static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, - struct net_device *dev, bool dma_map) - { -@@ -1490,9 +1525,8 @@ static int mtk_xdp_submit_frame(struct m - .first = true, - .last = true, - }; -- struct mtk_mac *mac = netdev_priv(dev); -- struct mtk_tx_dma *txd, *txd_pdma; - int err = 0, index = 0, n_desc = 1; -+ struct mtk_tx_dma *txd, *txd_pdma; - struct mtk_tx_buf *tx_buf; - - if (unlikely(test_bit(MTK_RESETTING, ð->state))) -@@ -1512,36 +1546,18 @@ static int mtk_xdp_submit_frame(struct m - tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); - memset(tx_buf, 0, sizeof(*tx_buf)); - -- if (dma_map) { /* ndo_xdp_xmit */ -- txd_info.addr = dma_map_single(eth->dma_dev, xdpf->data, -- txd_info.size, DMA_TO_DEVICE); -- if (unlikely(dma_mapping_error(eth->dma_dev, txd_info.addr))) { -- err = -ENOMEM; -- goto out; -- } -- tx_buf->flags |= MTK_TX_FLAGS_SINGLE0; -- } else { -- struct page *page = virt_to_head_page(xdpf->data); -- -- txd_info.addr = page_pool_get_dma_addr(page) + -- sizeof(*xdpf) + xdpf->headroom; -- dma_sync_single_for_device(eth->dma_dev, txd_info.addr, -- txd_info.size, -- DMA_BIDIRECTIONAL); -- } -- mtk_tx_set_dma_desc(dev, txd, &txd_info); -- -- tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; -- -- txd_pdma = qdma_to_pdma(ring, txd); -- setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, txd_info.size, -- index++); -+ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, -+ xdpf->data, xdpf->headroom, index, -+ dma_map); -+ if (err < 0) -+ goto out; - - /* store xdpf for cleanup */ - tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; - tx_buf->data = xdpf; - - if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { -+ txd_pdma = qdma_to_pdma(ring, txd); - if (index & 1) - txd_pdma->txd2 |= TX_DMA_LS0; - else diff --git a/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch b/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch deleted file mode 100644 index 23e4a4dfcbf..00000000000 --- a/target/linux/generic/backport-6.1/706-06-v6.0-net-ethernet-mtk_eth_soc-introduce-xdp-multi-frag-su.patch +++ /dev/null @@ -1,218 +0,0 @@ -From 155738a4f319538a09f734ce1f5a2eac3ada1de2 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Wed, 27 Jul 2022 23:20:51 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: introduce xdp multi-frag support - -Add the capability to map non-linear xdp frames in XDP_TX and -ndo_xdp_xmit callback. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 125 +++++++++++++------- - 1 file changed, 82 insertions(+), 43 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -988,23 +988,22 @@ static void mtk_tx_unmap(struct mtk_eth - } - } - -- if (tx_buf->type == MTK_TYPE_SKB) { -- if (tx_buf->data && -- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->data && tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->type == MTK_TYPE_SKB) { - struct sk_buff *skb = tx_buf->data; - - if (napi) - napi_consume_skb(skb, napi); - else - dev_kfree_skb_any(skb); -- } -- } else if (tx_buf->data) { -- struct xdp_frame *xdpf = tx_buf->data; -+ } else { -+ struct xdp_frame *xdpf = tx_buf->data; - -- if (napi && tx_buf->type == MTK_TYPE_XDP_TX) -- xdp_return_frame_rx_napi(xdpf); -- else -- xdp_return_frame(xdpf); -+ if (napi && tx_buf->type == MTK_TYPE_XDP_TX) -+ xdp_return_frame_rx_napi(xdpf); -+ else -+ xdp_return_frame(xdpf); -+ } - } - tx_buf->flags = 0; - tx_buf->data = NULL; -@@ -1507,6 +1506,8 @@ static int mtk_xdp_frame_map(struct mtk_ - mtk_tx_set_dma_desc(dev, txd, txd_info); - - tx_buf->flags |= !mac->id ? MTK_TX_FLAGS_FPORT0 : MTK_TX_FLAGS_FPORT1; -+ tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; -+ tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; - - txd_pdma = qdma_to_pdma(ring, txd); - setup_tx_buf(eth, tx_buf, txd_pdma, txd_info->addr, txd_info->size, -@@ -1518,43 +1519,69 @@ static int mtk_xdp_frame_map(struct mtk_ - static int mtk_xdp_submit_frame(struct mtk_eth *eth, struct xdp_frame *xdpf, - struct net_device *dev, bool dma_map) - { -+ struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); - const struct mtk_soc_data *soc = eth->soc; - struct mtk_tx_ring *ring = ð->tx_ring; - struct mtk_tx_dma_desc_info txd_info = { - .size = xdpf->len, - .first = true, -- .last = true, -+ .last = !xdp_frame_has_frags(xdpf), - }; -- int err = 0, index = 0, n_desc = 1; -- struct mtk_tx_dma *txd, *txd_pdma; -- struct mtk_tx_buf *tx_buf; -+ int err, index = 0, n_desc = 1, nr_frags; -+ struct mtk_tx_dma *htxd, *txd, *txd_pdma; -+ struct mtk_tx_buf *htx_buf, *tx_buf; -+ void *data = xdpf->data; - - if (unlikely(test_bit(MTK_RESETTING, ð->state))) - return -EBUSY; - -- if (unlikely(atomic_read(&ring->free_count) <= 1)) -+ nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0; -+ if (unlikely(atomic_read(&ring->free_count) <= 1 + nr_frags)) - return -EBUSY; - - spin_lock(ð->page_lock); - - txd = ring->next_free; - if (txd == ring->last_free) { -- err = -ENOMEM; -- goto out; -+ spin_unlock(ð->page_lock); -+ return -ENOMEM; - } -+ htxd = txd; - - tx_buf = mtk_desc_to_tx_buf(ring, txd, soc->txrx.txd_size); - memset(tx_buf, 0, sizeof(*tx_buf)); -+ htx_buf = tx_buf; - -- err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, -- xdpf->data, xdpf->headroom, index, -- dma_map); -- if (err < 0) -- goto out; -+ for (;;) { -+ err = mtk_xdp_frame_map(eth, dev, &txd_info, txd, tx_buf, -+ data, xdpf->headroom, index, dma_map); -+ if (err < 0) -+ goto unmap; -+ -+ if (txd_info.last) -+ break; - -+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA) || (index & 0x1)) { -+ txd = mtk_qdma_phys_to_virt(ring, txd->txd2); -+ txd_pdma = qdma_to_pdma(ring, txd); -+ if (txd == ring->last_free) -+ goto unmap; -+ -+ tx_buf = mtk_desc_to_tx_buf(ring, txd, -+ soc->txrx.txd_size); -+ memset(tx_buf, 0, sizeof(*tx_buf)); -+ n_desc++; -+ } -+ -+ memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); -+ txd_info.size = skb_frag_size(&sinfo->frags[index]); -+ txd_info.last = index + 1 == nr_frags; -+ data = skb_frag_address(&sinfo->frags[index]); -+ -+ index++; -+ } - /* store xdpf for cleanup */ -- tx_buf->type = dma_map ? MTK_TYPE_XDP_NDO : MTK_TYPE_XDP_TX; -- tx_buf->data = xdpf; -+ htx_buf->data = xdpf; - - if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { - txd_pdma = qdma_to_pdma(ring, txd); -@@ -1581,7 +1608,24 @@ static int mtk_xdp_submit_frame(struct m - mtk_w32(eth, NEXT_DESP_IDX(idx, ring->dma_size), - MT7628_TX_CTX_IDX0); - } --out: -+ -+ spin_unlock(ð->page_lock); -+ -+ return 0; -+ -+unmap: -+ while (htxd != txd) { -+ txd_pdma = qdma_to_pdma(ring, htxd); -+ tx_buf = mtk_desc_to_tx_buf(ring, htxd, soc->txrx.txd_size); -+ mtk_tx_unmap(eth, tx_buf, false); -+ -+ htxd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; -+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) -+ txd_pdma->txd2 = TX_DMA_DESP2_DEF; -+ -+ htxd = mtk_qdma_phys_to_virt(ring, htxd->txd2); -+ } -+ - spin_unlock(ð->page_lock); - - return err; -@@ -1910,18 +1954,15 @@ static int mtk_poll_tx_qdma(struct mtk_e - if (!tx_buf->data) - break; - -- if (tx_buf->type == MTK_TYPE_SKB && -- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -- struct sk_buff *skb = tx_buf->data; -+ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->type == MTK_TYPE_SKB) { -+ struct sk_buff *skb = tx_buf->data; - -- bytes[mac] += skb->len; -- done[mac]++; -- budget--; -- } else if (tx_buf->type == MTK_TYPE_XDP_TX || -- tx_buf->type == MTK_TYPE_XDP_NDO) { -+ bytes[mac] += skb->len; -+ done[mac]++; -+ } - budget--; - } -- - mtk_tx_unmap(eth, tx_buf, true); - - ring->last_free = desc; -@@ -1952,17 +1993,15 @@ static int mtk_poll_tx_pdma(struct mtk_e - if (!tx_buf->data) - break; - -- if (tx_buf->type == MTK_TYPE_SKB && -- tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -- struct sk_buff *skb = tx_buf->data; -- bytes[0] += skb->len; -- done[0]++; -- budget--; -- } else if (tx_buf->type == MTK_TYPE_XDP_TX || -- tx_buf->type == MTK_TYPE_XDP_NDO) { -+ if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { -+ if (tx_buf->type == MTK_TYPE_SKB) { -+ struct sk_buff *skb = tx_buf->data; -+ -+ bytes[0] += skb->len; -+ done[0]++; -+ } - budget--; - } -- - mtk_tx_unmap(eth, tx_buf, true); - - desc = ring->dma + cpu * eth->soc->txrx.txd_size; diff --git a/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch b/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch deleted file mode 100644 index 817b3e10fdf..00000000000 --- a/target/linux/generic/backport-6.1/710-v6.0-net-ethernet-mtk_eth_soc-fix-hw-hash-reporting-for-M.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0cf731f9ebb5bf6f252055bebf4463a5c0bd490b Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Tue, 23 Aug 2022 14:24:07 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix hw hash reporting for - MTK_NETSYS_V2 - -Properly report hw rx hash for mt7986 chipset accroding to the new dma -descriptor layout. - -Fixes: 197c9e9b17b11 ("net: ethernet: mtk_eth_soc: introduce support for mt7986 chipset") -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/091394ea4e705fbb35f828011d98d0ba33808f69.1661257293.git.lorenzo@kernel.org -Signed-off-by: Paolo Abeni ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 +++++++++++---------- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 5 +++++ - 2 files changed, 17 insertions(+), 10 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1846,10 +1846,19 @@ static int mtk_poll_rx(struct napi_struc - skb->dev = netdev; - bytes += skb->len; - -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; -+ if (hash != MTK_RXD5_FOE_ENTRY) -+ skb_set_hash(skb, jhash_1word(hash, 0), -+ PKT_HASH_TYPE_L4); - rxdcsum = &trxd.rxd3; -- else -+ } else { -+ hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; -+ if (hash != MTK_RXD4_FOE_ENTRY) -+ skb_set_hash(skb, jhash_1word(hash, 0), -+ PKT_HASH_TYPE_L4); - rxdcsum = &trxd.rxd4; -+ } - - if (*rxdcsum & eth->soc->txrx.rx_dma_l4_valid) - skb->ip_summed = CHECKSUM_UNNECESSARY; -@@ -1857,16 +1866,9 @@ static int mtk_poll_rx(struct napi_struc - skb_checksum_none_assert(skb); - skb->protocol = eth_type_trans(skb, netdev); - -- hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; -- if (hash != MTK_RXD4_FOE_ENTRY) { -- hash = jhash_1word(hash, 0); -- skb_set_hash(skb, hash, PKT_HASH_TYPE_L4); -- } -- - reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); - if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) -- mtk_ppe_check_skb(eth->ppe, skb, -- trxd.rxd4 & MTK_RXD4_FOE_ENTRY); -+ mtk_ppe_check_skb(eth->ppe, skb, hash); - - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -314,6 +314,11 @@ - #define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */ - #define RX_DMA_SPECIAL_TAG BIT(22) - -+/* PDMA descriptor rxd5 */ -+#define MTK_RXD5_FOE_ENTRY GENMASK(14, 0) -+#define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18) -+#define MTK_RXD5_SRC_PORT GENMASK(29, 26) -+ - #define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) - #define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) - diff --git a/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch b/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch deleted file mode 100644 index 0de8ab4376c..00000000000 --- a/target/linux/generic/backport-6.1/711-v6.0-01-net-ethernet-mtk_eth_soc-fix-off-by-one-check-of-ARR.patch +++ /dev/null @@ -1,31 +0,0 @@ -From: Tom Rix -Date: Sat, 16 Jul 2022 17:46:54 -0400 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix off by one check of - ARRAY_SIZE - -In mtk_wed_tx_ring_setup(.., int idx, ..), idx is used as an index here - struct mtk_wed_ring *ring = &dev->tx_ring[idx]; - -The bounds of idx are checked here - BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); - -If idx is the size of the array, it will pass this check and overflow. -So change the check to >= . - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Signed-off-by: Tom Rix -Link: https://lore.kernel.org/r/20220716214654.1540240-1-trix@redhat.com -Signed-off-by: Jakub Kicinski ---- - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -651,7 +651,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev - * WDMA RX. - */ - -- BUG_ON(idx > ARRAY_SIZE(dev->tx_ring)); -+ BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); - - if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) - return -ENOMEM; diff --git a/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch b/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch deleted file mode 100644 index fc6e2464688..00000000000 --- a/target/linux/generic/backport-6.1/711-v6.0-02-net-ethernet-mtk_ppe-fix-possible-NULL-pointer-deref.patch +++ /dev/null @@ -1,27 +0,0 @@ -From: Lorenzo Bianconi -Date: Mon, 18 Jul 2022 11:51:53 +0200 -Subject: [PATCH] net: ethernet: mtk_ppe: fix possible NULL pointer dereference - in mtk_flow_get_wdma_info - -odev pointer can be NULL in mtk_flow_offload_replace routine according -to the flower action rules. Fix possible NULL pointer dereference in -mtk_flow_get_wdma_info. - -Fixes: a333215e10cb5 ("net: ethernet: mtk_eth_soc: implement flow offloading to WED devices") -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/4e1685bc4976e21e364055f6bee86261f8f9ee93.1658137753.git.lorenzo@kernel.org -Signed-off-by: Jakub Kicinski ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -93,6 +93,9 @@ mtk_flow_get_wdma_info(struct net_device - }; - struct net_device_path path = {}; - -+ if (!ctx.dev) -+ return -ENODEV; -+ - memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); - - if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) diff --git a/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch b/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch deleted file mode 100644 index c0720152d65..00000000000 --- a/target/linux/generic/backport-6.1/711-v6.0-03-net-ethernet-mtk-ppe-fix-traffic-offload-with-bridge.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Lorenzo Bianconi -Date: Fri, 22 Jul 2022 09:06:19 +0200 -Subject: [PATCH] net: ethernet: mtk-ppe: fix traffic offload with bridged wlan - -A typical flow offload scenario for OpenWrt users is routed traffic -received by the wan interface that is redirected to a wlan device -belonging to the lan bridge. Current implementation fails to -fill wdma offload info in mtk_flow_get_wdma_info() since odev device is -the local bridge. Fix the issue running dev_fill_forward_path routine in -mtk_flow_get_wdma_info in order to identify the wlan device. - -Tested-by: Paolo Valerio -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -88,32 +88,28 @@ mtk_flow_offload_mangle_eth(const struct - static int - mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info) - { -- struct net_device_path_ctx ctx = { -- .dev = dev, -- }; -- struct net_device_path path = {}; -+ struct net_device_path_stack stack; -+ struct net_device_path *path; -+ int err; - -- if (!ctx.dev) -+ if (!dev) - return -ENODEV; - -- memcpy(ctx.daddr, addr, sizeof(ctx.daddr)); -- - if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)) - return -1; - -- if (!dev->netdev_ops->ndo_fill_forward_path) -- return -1; -- -- if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path)) -- return -1; -+ err = dev_fill_forward_path(dev, addr, &stack); -+ if (err) -+ return err; - -- if (path.type != DEV_PATH_MTK_WDMA) -+ path = &stack.path[stack.num_paths - 1]; -+ if (path->type != DEV_PATH_MTK_WDMA) - return -1; - -- info->wdma_idx = path.mtk_wdma.wdma_idx; -- info->queue = path.mtk_wdma.queue; -- info->bss = path.mtk_wdma.bss; -- info->wcid = path.mtk_wdma.wcid; -+ info->wdma_idx = path->mtk_wdma.wdma_idx; -+ info->queue = path->mtk_wdma.queue; -+ info->bss = path->mtk_wdma.bss; -+ info->wcid = path->mtk_wdma.wcid; - - return 0; - } diff --git a/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch b/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch deleted file mode 100644 index 3c28e835518..00000000000 --- a/target/linux/generic/backport-6.1/711-v6.0-04-net-ethernet-mtk_eth_soc-remove-mtk_foe_entry_timest.patch +++ /dev/null @@ -1,33 +0,0 @@ -From c9daab322313087afde8c46f41df3c628410ae20 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Mon, 5 Sep 2022 14:46:01 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: remove mtk_foe_entry_timestamp - -Get rid of mtk_foe_entry_timestamp routine since it is no longer used. - -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_ppe.h | 11 ----------- - 1 file changed, 11 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -302,17 +302,6 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s - __mtk_ppe_check_skb(ppe, skb, hash); - } - --static inline int --mtk_foe_entry_timestamp(struct mtk_ppe *ppe, u16 hash) --{ -- u32 ib1 = READ_ONCE(ppe->foe_table[hash].ib1); -- -- if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) -- return -1; -- -- return FIELD_GET(MTK_FOE_IB1_BIND_TIMESTAMP, ib1); --} -- - int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, - u8 pse_port, u8 *src_mac, u8 *dest_mac); - int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port); diff --git a/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch b/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch deleted file mode 100644 index f6fc7340794..00000000000 --- a/target/linux/generic/backport-6.1/712-v6.0-net-ethernet-mtk_eth_soc-enable-XDP-support-just-for.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 5e69163d3b9931098922b3fc2f8e786af8c1f37e Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Tue, 13 Sep 2022 15:03:05 +0200 -Subject: [PATCH] net: ethernet: mtk_eth_soc: enable XDP support just for - MT7986 SoC -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Disable page_pool/XDP support for MT7621 SoC in order fix a regression -introduce adding XDP for MT7986 SoC. There is no a real use case for XDP -on MT7621 since it is a low-end cpu. Moreover this patch reduces the -memory footprint. - -Tested-by: Sergio Paracuellos -Tested-by: Arınç ÜNAL -Fixes: 23233e577ef9 ("net: ethernet: mtk_eth_soc: rely on page_pool for single page buffers") -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/2bf31e27b888c43228b0d84dd2ef5033338269e2.1663074002.git.lorenzo@kernel.org -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1413,7 +1413,7 @@ static void mtk_update_rx_cpu_idx(struct - - static bool mtk_page_pool_enabled(struct mtk_eth *eth) - { -- return !eth->hwlro; -+ return MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2); - } - - static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, diff --git a/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch b/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch deleted file mode 100644 index f8bbea6c858..00000000000 --- a/target/linux/generic/backport-6.1/713-v6.0-net-ethernet-mtk_eth_soc-move-gdma_to_ppe-and-ppe_ba.patch +++ /dev/null @@ -1,127 +0,0 @@ -From patchwork Thu Sep 8 19:33:38 2022 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Lorenzo Bianconi -X-Patchwork-Id: 12970556 -X-Patchwork-Delegate: kuba@kernel.org -From: Lorenzo Bianconi -To: netdev@vger.kernel.org -Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, - Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, - kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, - linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, - Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, - ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, - devicetree@vger.kernel.org, robh@kernel.org -Subject: [PATCH net-next 03/12] net: ethernet: mtk_eth_soc: move gdma_to_ppe - and ppe_base definitions in mtk register map -Date: Thu, 8 Sep 2022 21:33:37 +0200 -Message-Id: - <95938fc9cbe0223714be2658a49ca58e9baace00.1662661555.git.lorenzo@kernel.org> -X-Mailer: git-send-email 2.37.3 -In-Reply-To: -References: -MIME-Version: 1.0 -Precedence: bulk -List-ID: -X-Mailing-List: netdev@vger.kernel.org -X-Patchwork-Delegate: kuba@kernel.org - -This is a preliminary patch to introduce mt7986 hw packet engine. - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 15 +++++++++++---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 ++- - drivers/net/ethernet/mediatek/mtk_ppe.h | 2 -- - 3 files changed, 13 insertions(+), 7 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -73,6 +73,8 @@ static const struct mtk_reg_map mtk_reg_ - .fq_blen = 0x1b2c, - }, - .gdm1_cnt = 0x2400, -+ .gdma_to_ppe0 = 0x4444, -+ .ppe_base = 0x0c00, - }; - - static const struct mtk_reg_map mt7628_reg_map = { -@@ -126,6 +128,8 @@ static const struct mtk_reg_map mt7986_r - .fq_blen = 0x472c, - }, - .gdm1_cnt = 0x1c00, -+ .gdma_to_ppe0 = 0x3333, -+ .ppe_base = 0x2000, - }; - - /* strings used by ethtool */ -@@ -2925,6 +2929,7 @@ static int mtk_open(struct net_device *d - - /* we run 2 netdevs on the same dma ring so we only bring it up once */ - if (!refcount_read(ð->dma_refcnt)) { -+ const struct mtk_soc_data *soc = eth->soc; - u32 gdm_config = MTK_GDMA_TO_PDMA; - int err; - -@@ -2934,15 +2939,15 @@ static int mtk_open(struct net_device *d - return err; - } - -- if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0) -- gdm_config = MTK_GDMA_TO_PPE; -+ if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) -+ gdm_config = soc->reg_map->gdma_to_ppe0; - - mtk_gdm_config(eth, gdm_config); - - napi_enable(ð->tx_napi); - napi_enable(ð->rx_napi); - mtk_tx_irq_enable(eth, MTK_TX_DONE_INT); -- mtk_rx_irq_enable(eth, eth->soc->txrx.rx_irq_done_mask); -+ mtk_rx_irq_enable(eth, soc->txrx.rx_irq_done_mask); - refcount_set(ð->dma_refcnt, 1); - } - else -@@ -4048,7 +4053,9 @@ static int mtk_probe(struct platform_dev - } - - if (eth->soc->offload_version) { -- eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2); -+ u32 ppe_addr = eth->soc->reg_map->ppe_base; -+ -+ eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); - if (!eth->ppe) { - err = -ENOMEM; - goto err_free_dev; ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -105,7 +105,6 @@ - #define MTK_GDMA_TCS_EN BIT(21) - #define MTK_GDMA_UCS_EN BIT(20) - #define MTK_GDMA_TO_PDMA 0x0 --#define MTK_GDMA_TO_PPE 0x4444 - #define MTK_GDMA_DROP_ALL 0x7777 - - /* Unicast Filter MAC Address Register - Low */ -@@ -953,6 +952,8 @@ struct mtk_reg_map { - u32 fq_blen; /* fq free page buffer length */ - } qdma; - u32 gdm1_cnt; -+ u32 gdma_to_ppe0; -+ u32 ppe_base; - }; - - /* struct mtk_eth_data - This is the structure holding all differences ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -8,8 +8,6 @@ - #include - #include - --#define MTK_ETH_PPE_BASE 0xc00 -- - #define MTK_PPE_ENTRIES_SHIFT 3 - #define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT) - #define MTK_PPE_HASH_MASK (MTK_PPE_ENTRIES - 1) diff --git a/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch b/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch deleted file mode 100644 index 7bed2785c99..00000000000 --- a/target/linux/generic/backport-6.1/714-v6.0-net-ethernet-mtk_eth_soc-move-ppe-table-hash-offset-.patch +++ /dev/null @@ -1,199 +0,0 @@ -From patchwork Thu Sep 8 19:33:38 2022 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Lorenzo Bianconi -X-Patchwork-Id: 12970557 -X-Patchwork-Delegate: kuba@kernel.org -From: Lorenzo Bianconi -To: netdev@vger.kernel.org -Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, - Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, - kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, - linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, - Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, - ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, - devicetree@vger.kernel.org, robh@kernel.org -Subject: [PATCH net-next 04/12] net: ethernet: mtk_eth_soc: move ppe table - hash offset to mtk_soc_data structure -Date: Thu, 8 Sep 2022 21:33:38 +0200 -Message-Id: - -X-Mailer: git-send-email 2.37.3 -In-Reply-To: -References: -MIME-Version: 1.0 -Precedence: bulk -List-ID: -X-Mailing-List: netdev@vger.kernel.org -X-Patchwork-Delegate: kuba@kernel.org - -This is a preliminary patch to introduce mt7986 hw packet engine. - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 4 ++++ - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++ - drivers/net/ethernet/mediatek/mtk_ppe.c | 24 +++++++++++++++------ - drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- - 4 files changed, 25 insertions(+), 7 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4151,6 +4151,7 @@ static const struct mtk_soc_data mt7621_ - .required_clks = MT7621_CLKS_BITMAP, - .required_pctl = false, - .offload_version = 2, -+ .hash_offset = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4169,6 +4170,7 @@ static const struct mtk_soc_data mt7622_ - .required_clks = MT7622_CLKS_BITMAP, - .required_pctl = false, - .offload_version = 2, -+ .hash_offset = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4186,6 +4188,7 @@ static const struct mtk_soc_data mt7623_ - .required_clks = MT7623_CLKS_BITMAP, - .required_pctl = true, - .offload_version = 2, -+ .hash_offset = 2, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4219,6 +4222,7 @@ static const struct mtk_soc_data mt7986_ - .caps = MT7986_CAPS, - .required_clks = MT7986_CLKS_BITMAP, - .required_pctl = false, -+ .hash_offset = 4, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma_v2), - .rxd_size = sizeof(struct mtk_rx_dma_v2), ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -967,6 +967,7 @@ struct mtk_reg_map { - * the target SoC - * @required_pctl A bool value to show whether the SoC requires - * the extra setup for those pins used by GMAC. -+ * @hash_offset Flow table hash offset. - * @txd_size Tx DMA descriptor size. - * @rxd_size Rx DMA descriptor size. - * @rx_irq_done_mask Rx irq done register mask. -@@ -981,6 +982,7 @@ struct mtk_soc_data { - u32 required_clks; - bool required_pctl; - u8 offload_version; -+ u8 hash_offset; - netdev_features_t hw_features; - struct { - u32 txd_size; ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -88,7 +88,7 @@ static void mtk_ppe_cache_enable(struct - enable * MTK_PPE_CACHE_CTL_EN); - } - --static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e) -+static u32 mtk_ppe_hash_entry(struct mtk_eth *eth, struct mtk_foe_entry *e) - { - u32 hv1, hv2, hv3; - u32 hash; -@@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk - hash = (hash >> 24) | ((hash & 0xffffff) << 8); - hash ^= hv1 ^ hv2 ^ hv3; - hash ^= hash >> 16; -- hash <<= 1; -+ hash <<= (ffs(eth->soc->hash_offset) - 1); - hash &= MTK_PPE_ENTRIES - 1; - - return hash; -@@ -540,15 +540,16 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { - int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); -+ const struct mtk_soc_data *soc = ppe->eth->soc; - u32 hash; - - if (type == MTK_PPE_PKT_TYPE_BRIDGE) - return mtk_foe_entry_commit_l2(ppe, entry); - -- hash = mtk_ppe_hash_entry(&entry->data); -+ hash = mtk_ppe_hash_entry(ppe->eth, &entry->data); - entry->hash = 0xffff; - spin_lock_bh(&ppe_lock); -- hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]); -+ hlist_add_head(&entry->list, &ppe->foe_flow[hash / soc->hash_offset]); - spin_unlock_bh(&ppe_lock); - - return 0; -@@ -558,6 +559,7 @@ static void - mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry, - u16 hash) - { -+ const struct mtk_soc_data *soc = ppe->eth->soc; - struct mtk_flow_entry *flow_info; - struct mtk_foe_entry foe, *hwe; - struct mtk_foe_mac_info *l2; -@@ -572,7 +574,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ - flow_info->l2_data.base_flow = entry; - flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW; - flow_info->hash = hash; -- hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]); -+ hlist_add_head(&flow_info->list, -+ &ppe->foe_flow[hash / soc->hash_offset]); - hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); - - hwe = &ppe->foe_table[hash]; -@@ -596,7 +599,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ - - void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) - { -- struct hlist_head *head = &ppe->foe_flow[hash / 2]; -+ const struct mtk_soc_data *soc = ppe->eth->soc; -+ struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; - struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; - struct mtk_flow_entry *entry; - struct mtk_foe_bridge key = {}; -@@ -680,9 +684,11 @@ int mtk_foe_entry_idle_time(struct mtk_p - struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, - int version) - { -+ const struct mtk_soc_data *soc = eth->soc; - struct device *dev = eth->dev; - struct mtk_foe_entry *foe; - struct mtk_ppe *ppe; -+ u32 foe_flow_size; - - ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); - if (!ppe) -@@ -705,6 +711,12 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - - ppe->foe_table = foe; - -+ foe_flow_size = (MTK_PPE_ENTRIES / soc->hash_offset) * -+ sizeof(*ppe->foe_flow); -+ ppe->foe_flow = devm_kzalloc(dev, foe_flow_size, GFP_KERNEL); -+ if (!ppe->foe_flow) -+ return NULL; -+ - mtk_ppe_debugfs_init(ppe); - - return ppe; ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -270,7 +270,7 @@ struct mtk_ppe { - dma_addr_t foe_phys; - - u16 foe_check_time[MTK_PPE_ENTRIES]; -- struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2]; -+ struct hlist_head *foe_flow; - - struct rhashtable l2_flows; - diff --git a/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch b/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch deleted file mode 100644 index 93860e41457..00000000000 --- a/target/linux/generic/backport-6.1/715-v6.0-net-ethernet-mtk_eth_soc-add-the-capability-to-run-m.patch +++ /dev/null @@ -1,318 +0,0 @@ -From patchwork Thu Sep 8 19:33:39 2022 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Lorenzo Bianconi -X-Patchwork-Id: 12970559 -X-Patchwork-Delegate: kuba@kernel.org -Return-Path: -From: Lorenzo Bianconi -To: netdev@vger.kernel.org -Cc: nbd@nbd.name, john@phrozen.org, sean.wang@mediatek.com, - Mark-MC.Lee@mediatek.com, davem@davemloft.net, edumazet@google.com, - kuba@kernel.org, pabeni@redhat.com, matthias.bgg@gmail.com, - linux-mediatek@lists.infradead.org, lorenzo.bianconi@redhat.com, - Bo.Jiao@mediatek.com, sujuan.chen@mediatek.com, - ryder.Lee@mediatek.com, evelyn.tsai@mediatek.com, - devicetree@vger.kernel.org, robh@kernel.org -Subject: [PATCH net-next 05/12] net: ethernet: mtk_eth_soc: add the capability - to run multiple ppe -Date: Thu, 8 Sep 2022 21:33:39 +0200 -Message-Id: - -X-Mailer: git-send-email 2.37.3 -In-Reply-To: -References: -MIME-Version: 1.0 -Precedence: bulk -List-ID: -X-Mailing-List: netdev@vger.kernel.org -X-Patchwork-Delegate: kuba@kernel.org - -mt7986 chipset support multiple packet engines for wlan <-> eth -packet forwarding. - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 35 ++++++++++++------- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 +- - drivers/net/ethernet/mediatek/mtk_ppe.c | 14 +++++--- - drivers/net/ethernet/mediatek/mtk_ppe.h | 9 +++-- - .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 8 ++--- - .../net/ethernet/mediatek/mtk_ppe_offload.c | 13 +++---- - 6 files changed, 48 insertions(+), 33 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1872,7 +1872,7 @@ static int mtk_poll_rx(struct napi_struc - - reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); - if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) -- mtk_ppe_check_skb(eth->ppe, skb, hash); -+ mtk_ppe_check_skb(eth->ppe[0], skb, hash); - - if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -@@ -2930,7 +2930,8 @@ static int mtk_open(struct net_device *d - /* we run 2 netdevs on the same dma ring so we only bring it up once */ - if (!refcount_read(ð->dma_refcnt)) { - const struct mtk_soc_data *soc = eth->soc; -- u32 gdm_config = MTK_GDMA_TO_PDMA; -+ u32 gdm_config; -+ int i; - int err; - - err = mtk_start_dma(eth); -@@ -2939,8 +2940,11 @@ static int mtk_open(struct net_device *d - return err; - } - -- if (soc->offload_version && mtk_ppe_start(eth->ppe) == 0) -- gdm_config = soc->reg_map->gdma_to_ppe0; -+ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) -+ mtk_ppe_start(eth->ppe[i]); -+ -+ gdm_config = soc->offload_version ? soc->reg_map->gdma_to_ppe0 -+ : MTK_GDMA_TO_PDMA; - - mtk_gdm_config(eth, gdm_config); - -@@ -2985,6 +2989,7 @@ static int mtk_stop(struct net_device *d - { - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; -+ int i; - - phylink_stop(mac->phylink); - -@@ -3012,8 +3017,8 @@ static int mtk_stop(struct net_device *d - - mtk_dma_free(eth); - -- if (eth->soc->offload_version) -- mtk_ppe_stop(eth->ppe); -+ for (i = 0; i < ARRAY_SIZE(eth->ppe); i++) -+ mtk_ppe_stop(eth->ppe[i]); - - return 0; - } -@@ -4053,12 +4058,19 @@ static int mtk_probe(struct platform_dev - } - - if (eth->soc->offload_version) { -- u32 ppe_addr = eth->soc->reg_map->ppe_base; -+ u32 num_ppe; - -- eth->ppe = mtk_ppe_init(eth, eth->base + ppe_addr, 2); -- if (!eth->ppe) { -- err = -ENOMEM; -- goto err_free_dev; -+ num_ppe = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; -+ num_ppe = min_t(u32, ARRAY_SIZE(eth->ppe), num_ppe); -+ for (i = 0; i < num_ppe; i++) { -+ u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; -+ -+ eth->ppe[i] = mtk_ppe_init(eth, eth->base + ppe_addr, -+ eth->soc->offload_version, i); -+ if (!eth->ppe[i]) { -+ err = -ENOMEM; -+ goto err_free_dev; -+ } - } - - err = mtk_eth_offload_init(eth); ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1112,7 +1112,7 @@ struct mtk_eth { - - int ip_align; - -- struct mtk_ppe *ppe; -+ struct mtk_ppe *ppe[2]; - struct rhashtable flow_table; - - struct bpf_prog __rcu *prog; ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -682,7 +682,7 @@ int mtk_foe_entry_idle_time(struct mtk_p - } - - struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, -- int version) -+ int version, int index) - { - const struct mtk_soc_data *soc = eth->soc; - struct device *dev = eth->dev; -@@ -717,7 +717,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - if (!ppe->foe_flow) - return NULL; - -- mtk_ppe_debugfs_init(ppe); -+ mtk_ppe_debugfs_init(ppe, index); - - return ppe; - } -@@ -738,10 +738,13 @@ static void mtk_ppe_init_foe_table(struc - ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; - } - --int mtk_ppe_start(struct mtk_ppe *ppe) -+void mtk_ppe_start(struct mtk_ppe *ppe) - { - u32 val; - -+ if (!ppe) -+ return; -+ - mtk_ppe_init_foe_table(ppe); - ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys); - -@@ -809,8 +812,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe) - ppe_w32(ppe, MTK_PPE_GLO_CFG, val); - - ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); -- -- return 0; - } - - int mtk_ppe_stop(struct mtk_ppe *ppe) -@@ -818,6 +819,9 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) - u32 val; - int i; - -+ if (!ppe) -+ return 0; -+ - for (i = 0; i < MTK_PPE_ENTRIES; i++) - ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, - MTK_FOE_STATE_INVALID); ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -247,6 +247,7 @@ struct mtk_flow_entry { - }; - u8 type; - s8 wed_index; -+ u8 ppe_index; - u16 hash; - union { - struct mtk_foe_entry data; -@@ -265,6 +266,7 @@ struct mtk_ppe { - struct device *dev; - void __iomem *base; - int version; -+ char dirname[5]; - - struct mtk_foe_entry *foe_table; - dma_addr_t foe_phys; -@@ -277,8 +279,9 @@ struct mtk_ppe { - void *acct_table; - }; - --struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version); --int mtk_ppe_start(struct mtk_ppe *ppe); -+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, -+ int version, int index); -+void mtk_ppe_start(struct mtk_ppe *ppe); - int mtk_ppe_stop(struct mtk_ppe *ppe); - - void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); -@@ -317,6 +320,6 @@ int mtk_foe_entry_set_wdma(struct mtk_fo - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); - void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); - int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); --int mtk_ppe_debugfs_init(struct mtk_ppe *ppe); -+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); - - #endif ---- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -@@ -187,7 +187,7 @@ mtk_ppe_debugfs_foe_open_bind(struct ino - inode->i_private); - } - --int mtk_ppe_debugfs_init(struct mtk_ppe *ppe) -+int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index) - { - static const struct file_operations fops_all = { - .open = mtk_ppe_debugfs_foe_open_all, -@@ -195,17 +195,17 @@ int mtk_ppe_debugfs_init(struct mtk_ppe - .llseek = seq_lseek, - .release = single_release, - }; -- - static const struct file_operations fops_bind = { - .open = mtk_ppe_debugfs_foe_open_bind, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - }; -- - struct dentry *root; - -- root = debugfs_create_dir("mtk_ppe", NULL); -+ snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index); -+ -+ root = debugfs_create_dir(ppe->dirname, NULL); - if (!root) - return -ENOMEM; - ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -434,7 +434,7 @@ mtk_flow_offload_replace(struct mtk_eth - memcpy(&entry->data, &foe, sizeof(entry->data)); - entry->wed_index = wed_index; - -- err = mtk_foe_entry_commit(eth->ppe, entry); -+ err = mtk_foe_entry_commit(eth->ppe[entry->ppe_index], entry); - if (err < 0) - goto free; - -@@ -446,7 +446,7 @@ mtk_flow_offload_replace(struct mtk_eth - return 0; - - clear: -- mtk_foe_entry_clear(eth->ppe, entry); -+ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); - free: - kfree(entry); - if (wed_index >= 0) -@@ -464,7 +464,7 @@ mtk_flow_offload_destroy(struct mtk_eth - if (!entry) - return -ENOENT; - -- mtk_foe_entry_clear(eth->ppe, entry); -+ mtk_foe_entry_clear(eth->ppe[entry->ppe_index], entry); - rhashtable_remove_fast(ð->flow_table, &entry->node, - mtk_flow_ht_params); - if (entry->wed_index >= 0) -@@ -485,7 +485,7 @@ mtk_flow_offload_stats(struct mtk_eth *e - if (!entry) - return -ENOENT; - -- idle = mtk_foe_entry_idle_time(eth->ppe, entry); -+ idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry); - f->stats.lastused = jiffies - idle * HZ; - - return 0; -@@ -537,7 +537,7 @@ mtk_eth_setup_tc_block(struct net_device - struct flow_block_cb *block_cb; - flow_setup_cb_t *cb; - -- if (!eth->ppe || !eth->ppe->foe_table) -+ if (!eth->soc->offload_version) - return -EOPNOTSUPP; - - if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) -@@ -590,8 +590,5 @@ int mtk_eth_setup_tc(struct net_device * - - int mtk_eth_offload_init(struct mtk_eth *eth) - { -- if (!eth->ppe || !eth->ppe->foe_table) -- return 0; -- - return rhashtable_init(ð->flow_table, &mtk_flow_ht_params); - } diff --git a/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch b/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch deleted file mode 100644 index a4b285632e1..00000000000 --- a/target/linux/generic/backport-6.1/716-v6.0-net-ethernet-mtk_eth_soc-move-wdma_base-definitions-.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0dcbe607cec32ccae23b02a641b8bd6191a328ae Mon Sep 17 00:00:00 2001 -Message-Id: <0dcbe607cec32ccae23b02a641b8bd6191a328ae.1662243796.git.lorenzo@kernel.org> -In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> -References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Tue, 23 Aug 2022 23:09:05 +0200 -Subject: [PATCH net-next 2/4] net: ethernet: mtk_eth_soc: move wdma_base - definitions in mtk register map - -This is a preliminary patch to introduce mt7986 wed support. - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 16 ++++++++++------ - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 +--- - 2 files changed, 11 insertions(+), 9 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -75,6 +75,10 @@ static const struct mtk_reg_map mtk_reg_ - .gdm1_cnt = 0x2400, - .gdma_to_ppe0 = 0x4444, - .ppe_base = 0x0c00, -+ .wdma_base = { -+ [0] = 0x2800, -+ [1] = 0x2c00, -+ }, - }; - - static const struct mtk_reg_map mt7628_reg_map = { -@@ -130,6 +134,10 @@ static const struct mtk_reg_map mt7986_r - .gdm1_cnt = 0x1c00, - .gdma_to_ppe0 = 0x3333, - .ppe_base = 0x2000, -+ .wdma_base = { -+ [0] = 0x4800, -+ [1] = 0x4c00, -+ }, - }; - - /* strings used by ethtool */ -@@ -3970,16 +3978,12 @@ static int mtk_probe(struct platform_dev - for (i = 0;; i++) { - struct device_node *np = of_parse_phandle(pdev->dev.of_node, - "mediatek,wed", i); -- static const u32 wdma_regs[] = { -- MTK_WDMA0_BASE, -- MTK_WDMA1_BASE -- }; - void __iomem *wdma; - -- if (!np || i >= ARRAY_SIZE(wdma_regs)) -+ if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) - break; - -- wdma = eth->base + wdma_regs[i]; -+ wdma = eth->base + eth->soc->reg_map->wdma_base[i]; - mtk_wed_add_hw(np, eth, wdma, i); - } - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -268,9 +268,6 @@ - #define TX_DMA_FPORT_MASK_V2 0xf - #define TX_DMA_SWC_V2 BIT(30) - --#define MTK_WDMA0_BASE 0x2800 --#define MTK_WDMA1_BASE 0x2c00 -- - /* QDMA descriptor txd4 */ - #define TX_DMA_CHKSUM (0x7 << 29) - #define TX_DMA_TSO BIT(28) -@@ -954,6 +951,7 @@ struct mtk_reg_map { - u32 gdm1_cnt; - u32 gdma_to_ppe0; - u32 ppe_base; -+ u32 wdma_base[2]; - }; - - /* struct mtk_eth_data - This is the structure holding all differences diff --git a/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch b/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch deleted file mode 100644 index 2bce63c4c01..00000000000 --- a/target/linux/generic/backport-6.1/717-v6.0-net-ethernet-mtk_eth_soc-add-foe_entry_size-to-mtk_e.patch +++ /dev/null @@ -1,251 +0,0 @@ -From e3c27d869fccc1f2b8d0b4cde4763ab223874e8c Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> -References: <43a21841ce0175d29f23c34a65ceaaf9dd7eb8b7.1662243796.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Sun, 21 Aug 2022 17:51:17 +0200 -Subject: [PATCH net-next 3/4] net: ethernet: mtk_eth_soc: add foe_entry_size - to mtk_eth_soc - -Introduce foe_entry_size to mtk_eth_soc data structure since mt7986 -relies on a bigger mtk_foe_entry data structure. - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 + - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 10 ++++ - drivers/net/ethernet/mediatek/mtk_ppe.c | 55 +++++++++++-------- - drivers/net/ethernet/mediatek/mtk_ppe.h | 2 +- - .../net/ethernet/mediatek/mtk_ppe_debugfs.c | 2 +- - 5 files changed, 48 insertions(+), 24 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4168,6 +4168,7 @@ static const struct mtk_soc_data mt7621_ - .required_pctl = false, - .offload_version = 2, - .hash_offset = 2, -+ .foe_entry_size = sizeof(struct mtk_foe_entry), - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4187,6 +4188,7 @@ static const struct mtk_soc_data mt7622_ - .required_pctl = false, - .offload_version = 2, - .hash_offset = 2, -+ .foe_entry_size = sizeof(struct mtk_foe_entry), - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4205,6 +4207,7 @@ static const struct mtk_soc_data mt7623_ - .required_pctl = true, - .offload_version = 2, - .hash_offset = 2, -+ .foe_entry_size = sizeof(struct mtk_foe_entry), - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -966,6 +966,7 @@ struct mtk_reg_map { - * @required_pctl A bool value to show whether the SoC requires - * the extra setup for those pins used by GMAC. - * @hash_offset Flow table hash offset. -+ * @foe_entry_size Foe table entry size. - * @txd_size Tx DMA descriptor size. - * @rxd_size Rx DMA descriptor size. - * @rx_irq_done_mask Rx irq done register mask. -@@ -981,6 +982,7 @@ struct mtk_soc_data { - bool required_pctl; - u8 offload_version; - u8 hash_offset; -+ u16 foe_entry_size; - netdev_features_t hw_features; - struct { - u32 txd_size; -@@ -1141,6 +1143,14 @@ struct mtk_mac { - /* the struct describing the SoC. these are declared in the soc_xyz.c files */ - extern const struct of_device_id of_mtk_match[]; - -+static inline struct mtk_foe_entry * -+mtk_foe_get_entry(struct mtk_ppe *ppe, u16 hash) -+{ -+ const struct mtk_soc_data *soc = ppe->eth->soc; -+ -+ return ppe->foe_table + hash * soc->foe_entry_size; -+} -+ - /* read the hardware status register */ - void mtk_stats_update_mac(struct mtk_mac *mac); - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -410,9 +410,10 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - - hlist_del_init(&entry->list); - if (entry->hash != 0xffff) { -- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE; -- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, -- MTK_FOE_STATE_BIND); -+ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); -+ -+ hwe->ib1 &= ~MTK_FOE_IB1_STATE; -+ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); - dma_wmb(); - } - entry->hash = 0xffff; -@@ -451,7 +452,7 @@ mtk_flow_entry_update_l2(struct mtk_ppe - int cur_idle; - u32 ib1; - -- hwe = &ppe->foe_table[cur->hash]; -+ hwe = mtk_foe_get_entry(ppe, cur->hash); - ib1 = READ_ONCE(hwe->ib1); - - if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) { -@@ -473,8 +474,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe - static void - mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { -+ struct mtk_foe_entry foe = {}; - struct mtk_foe_entry *hwe; -- struct mtk_foe_entry foe; - - spin_lock_bh(&ppe_lock); - -@@ -486,8 +487,8 @@ mtk_flow_entry_update(struct mtk_ppe *pp - if (entry->hash == 0xffff) - goto out; - -- hwe = &ppe->foe_table[entry->hash]; -- memcpy(&foe, hwe, sizeof(foe)); -+ hwe = mtk_foe_get_entry(ppe, entry->hash); -+ memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); - if (!mtk_flow_entry_match(entry, &foe)) { - entry->hash = 0xffff; - goto out; -@@ -511,8 +512,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p - entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; - entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); - -- hwe = &ppe->foe_table[hash]; -- memcpy(&hwe->data, &entry->data, sizeof(hwe->data)); -+ hwe = mtk_foe_get_entry(ppe, hash); -+ memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); - wmb(); - hwe->ib1 = entry->ib1; - -@@ -561,7 +562,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ - { - const struct mtk_soc_data *soc = ppe->eth->soc; - struct mtk_flow_entry *flow_info; -- struct mtk_foe_entry foe, *hwe; -+ struct mtk_foe_entry foe = {}, *hwe; - struct mtk_foe_mac_info *l2; - u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; - int type; -@@ -578,8 +579,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ - &ppe->foe_flow[hash / soc->hash_offset]); - hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows); - -- hwe = &ppe->foe_table[hash]; -- memcpy(&foe, hwe, sizeof(foe)); -+ hwe = mtk_foe_get_entry(ppe, hash); -+ memcpy(&foe, hwe, soc->foe_entry_size); - foe.ib1 &= ib1_mask; - foe.ib1 |= entry->data.ib1 & ~ib1_mask; - -@@ -601,7 +602,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe - { - const struct mtk_soc_data *soc = ppe->eth->soc; - struct hlist_head *head = &ppe->foe_flow[hash / soc->hash_offset]; -- struct mtk_foe_entry *hwe = &ppe->foe_table[hash]; -+ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); - struct mtk_flow_entry *entry; - struct mtk_foe_bridge key = {}; - struct hlist_node *n; -@@ -686,9 +687,9 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - { - const struct mtk_soc_data *soc = eth->soc; - struct device *dev = eth->dev; -- struct mtk_foe_entry *foe; - struct mtk_ppe *ppe; - u32 foe_flow_size; -+ void *foe; - - ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL); - if (!ppe) -@@ -704,7 +705,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - ppe->dev = dev; - ppe->version = version; - -- foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe), -+ foe = dmam_alloc_coherent(ppe->dev, -+ MTK_PPE_ENTRIES * soc->foe_entry_size, - &ppe->foe_phys, GFP_KERNEL); - if (!foe) - return NULL; -@@ -727,15 +729,21 @@ static void mtk_ppe_init_foe_table(struc - static const u8 skip[] = { 12, 25, 38, 51, 76, 89, 102 }; - int i, k; - -- memset(ppe->foe_table, 0, MTK_PPE_ENTRIES * sizeof(*ppe->foe_table)); -+ memset(ppe->foe_table, 0, -+ MTK_PPE_ENTRIES * ppe->eth->soc->foe_entry_size); - - if (!IS_ENABLED(CONFIG_SOC_MT7621)) - return; - - /* skip all entries that cross the 1024 byte boundary */ -- for (i = 0; i < MTK_PPE_ENTRIES; i += 128) -- for (k = 0; k < ARRAY_SIZE(skip); k++) -- ppe->foe_table[i + skip[k]].ib1 |= MTK_FOE_IB1_STATIC; -+ for (i = 0; i < MTK_PPE_ENTRIES; i += 128) { -+ for (k = 0; k < ARRAY_SIZE(skip); k++) { -+ struct mtk_foe_entry *hwe; -+ -+ hwe = mtk_foe_get_entry(ppe, i + skip[k]); -+ hwe->ib1 |= MTK_FOE_IB1_STATIC; -+ } -+ } - } - - void mtk_ppe_start(struct mtk_ppe *ppe) -@@ -822,9 +830,12 @@ int mtk_ppe_stop(struct mtk_ppe *ppe) - if (!ppe) - return 0; - -- for (i = 0; i < MTK_PPE_ENTRIES; i++) -- ppe->foe_table[i].ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, -- MTK_FOE_STATE_INVALID); -+ for (i = 0; i < MTK_PPE_ENTRIES; i++) { -+ struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, i); -+ -+ hwe->ib1 = FIELD_PREP(MTK_FOE_IB1_STATE, -+ MTK_FOE_STATE_INVALID); -+ } - - mtk_ppe_cache_enable(ppe, false); - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -268,7 +268,7 @@ struct mtk_ppe { - int version; - char dirname[5]; - -- struct mtk_foe_entry *foe_table; -+ void *foe_table; - dma_addr_t foe_phys; - - u16 foe_check_time[MTK_PPE_ENTRIES]; ---- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c -@@ -79,7 +79,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file - int i; - - for (i = 0; i < MTK_PPE_ENTRIES; i++) { -- struct mtk_foe_entry *entry = &ppe->foe_table[i]; -+ struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, i); - struct mtk_foe_mac_info *l2; - struct mtk_flow_addr_info ai = {}; - unsigned char h_source[ETH_ALEN]; diff --git a/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch b/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch deleted file mode 100644 index 77daf6c8bfe..00000000000 --- a/target/linux/generic/backport-6.1/718-v6.0-net-ethernet-mtk_eth_soc-fix-typo-in-__mtk_foe_entry.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 12ff69304c83c679ca01ef3db963ab0db9de19fb Mon Sep 17 00:00:00 2001 -Message-Id: <12ff69304c83c679ca01ef3db963ab0db9de19fb.1662332102.git.lorenzo@kernel.org> -In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> -References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Mon, 5 Sep 2022 00:43:43 +0200 -Subject: [PATCH net-next 2/6] net: ethernet: mtk_eth_soc: fix typo in - __mtk_foe_entry_clear - -Set ib1 state to MTK_FOE_STATE_UNBIND in __mtk_foe_entry_clear routine. - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -413,7 +413,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); - - hwe->ib1 &= ~MTK_FOE_IB1_STATE; -- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND); -+ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_UNBIND); - dma_wmb(); - } - entry->hash = 0xffff; diff --git a/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch b/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch deleted file mode 100644 index 7ab6d486b22..00000000000 --- a/target/linux/generic/backport-6.1/719-v6.0-net-ethernet-mtk_eth_soc-check-max-allowed-value-in-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 4253e6e2b795a18ab534adcd5c313d3fc4150975 Mon Sep 17 00:00:00 2001 -Message-Id: <4253e6e2b795a18ab534adcd5c313d3fc4150975.1662332102.git.lorenzo@kernel.org> -In-Reply-To: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> -References: <2a60545635c2705312299384f4e9fec2f2a3acd6.1662332102.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Mon, 5 Sep 2022 00:48:52 +0200 -Subject: [PATCH net-next 3/6] net: ethernet: mtk_eth_soc: check max allowed - value in mtk_ppe_check_skb - -Check theoretical OOB accesses in mtk_ppe_check_skb routine - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_ppe.h | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -294,6 +294,9 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s - if (!ppe) - return; - -+ if (hash > MTK_PPE_HASH_MASK) -+ return; -+ - now = (u16)jiffies; - diff = now - ppe->foe_check_time[hash]; - if (diff < HZ / 10) diff --git a/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch b/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch deleted file mode 100644 index a8c88daf1ff..00000000000 --- a/target/linux/generic/backport-6.1/720-v6.0-net-ethernet-mtk_eth_wed-add-mtk_wed_configure_irq-a.patch +++ /dev/null @@ -1,189 +0,0 @@ -From e5ecb4f619197b93fa682d722452dc8412864cdb Mon Sep 17 00:00:00 2001 -Message-Id: -From: Lorenzo Bianconi -Date: Fri, 26 Aug 2022 01:12:57 +0200 -Subject: [PATCH net-next 1/5] net: ethernet: mtk_eth_wed: add - mtk_wed_configure_irq and mtk_wed_dma_{enable/disable} - -Introduce mtk_wed_configure_irq, mtk_wed_dma_enable and mtk_wed_dma_disable -utility routines. -This is a preliminary patch to introduce mt7986 wed support. - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_wed.c | 87 +++++++++++++------- - drivers/net/ethernet/mediatek/mtk_wed_regs.h | 6 +- - 2 files changed, 64 insertions(+), 29 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -237,9 +237,30 @@ mtk_wed_set_ext_int(struct mtk_wed_devic - } - - static void --mtk_wed_stop(struct mtk_wed_device *dev) -+mtk_wed_dma_disable(struct mtk_wed_device *dev) - { -+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); -+ -+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); -+ -+ wed_clr(dev, MTK_WED_GLO_CFG, -+ MTK_WED_GLO_CFG_TX_DMA_EN | -+ MTK_WED_GLO_CFG_RX_DMA_EN); -+ - regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); -+ wdma_m32(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_TX_DMA_EN | -+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); -+} -+ -+static void -+mtk_wed_stop(struct mtk_wed_device *dev) -+{ -+ mtk_wed_dma_disable(dev); - mtk_wed_set_ext_int(dev, false); - - wed_clr(dev, MTK_WED_CTRL, -@@ -252,15 +273,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) - wdma_w32(dev, MTK_WDMA_INT_MASK, 0); - wdma_w32(dev, MTK_WDMA_INT_GRP2, 0); - wed_w32(dev, MTK_WED_WPDMA_INT_MASK, 0); -- -- wed_clr(dev, MTK_WED_GLO_CFG, -- MTK_WED_GLO_CFG_TX_DMA_EN | -- MTK_WED_GLO_CFG_RX_DMA_EN); -- wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -- MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN | -- MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN); -- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, -- MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); - } - - static void -@@ -313,7 +325,10 @@ mtk_wed_hw_init_early(struct mtk_wed_dev - MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; - wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); - -- wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO_PRERES); -+ wdma_set(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); - - offset = dev->hw->index ? 0x04000400 : 0; - wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); -@@ -520,43 +535,38 @@ mtk_wed_wdma_ring_setup(struct mtk_wed_d - } - - static void --mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) -+mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) - { -- u32 wdma_mask; -- u32 val; -- int i; -- -- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) -- if (!dev->tx_wdma[i].desc) -- mtk_wed_wdma_ring_setup(dev, i, 16); -- -- wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); -- -- mtk_wed_hw_init(dev); -+ u32 wdma_mask = FIELD_PREP(MTK_WDMA_INT_MASK_RX_DONE, GENMASK(1, 0)); - -+ /* wed control cr set */ - wed_set(dev, MTK_WED_CTRL, - MTK_WED_CTRL_WDMA_INT_AGENT_EN | - MTK_WED_CTRL_WPDMA_INT_AGENT_EN | - MTK_WED_CTRL_WED_TX_BM_EN | - MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); - -- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, MTK_WED_PCIE_INT_TRIGGER_STATUS); -+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, -+ MTK_WED_PCIE_INT_TRIGGER_STATUS); - - wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, - MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | - MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); - -- wed_set(dev, MTK_WED_WPDMA_INT_CTRL, -- MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); -- -+ /* initail wdma interrupt agent */ - wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); - wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); - - wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); - wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); -- - wed_w32(dev, MTK_WED_WPDMA_INT_MASK, irq_mask); - wed_w32(dev, MTK_WED_INT_MASK, irq_mask); -+} -+ -+static void -+mtk_wed_dma_enable(struct mtk_wed_device *dev) -+{ -+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV); - - wed_set(dev, MTK_WED_GLO_CFG, - MTK_WED_GLO_CFG_TX_DMA_EN | -@@ -567,6 +577,26 @@ mtk_wed_start(struct mtk_wed_device *dev - wed_set(dev, MTK_WED_WDMA_GLO_CFG, - MTK_WED_WDMA_GLO_CFG_RX_DRV_EN); - -+ wdma_set(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_TX_DMA_EN | -+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); -+} -+ -+static void -+mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) -+{ -+ u32 val; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) -+ if (!dev->tx_wdma[i].desc) -+ mtk_wed_wdma_ring_setup(dev, i, 16); -+ -+ mtk_wed_hw_init(dev); -+ mtk_wed_configure_irq(dev, irq_mask); -+ - mtk_wed_set_ext_int(dev, true); - val = dev->wlan.wpdma_phys | - MTK_PCIE_MIRROR_MAP_EN | -@@ -577,6 +607,7 @@ mtk_wed_start(struct mtk_wed_device *dev - val |= BIT(0); - regmap_write(dev->hw->mirror, dev->hw->index * 4, val); - -+ mtk_wed_dma_enable(dev); - dev->running = true; - } - ---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h -+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h -@@ -224,7 +224,11 @@ struct mtk_wdma_desc { - #define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) - - #define MTK_WDMA_GLO_CFG 0x204 --#define MTK_WDMA_GLO_CFG_RX_INFO_PRERES GENMASK(28, 26) -+#define MTK_WDMA_GLO_CFG_TX_DMA_EN BIT(0) -+#define MTK_WDMA_GLO_CFG_RX_DMA_EN BIT(2) -+#define MTK_WDMA_GLO_CFG_RX_INFO3_PRERES BIT(26) -+#define MTK_WDMA_GLO_CFG_RX_INFO2_PRERES BIT(27) -+#define MTK_WDMA_GLO_CFG_RX_INFO1_PRERES BIT(28) - - #define MTK_WDMA_RESET_IDX 0x208 - #define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) diff --git a/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch b/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch deleted file mode 100644 index bfca7b20e45..00000000000 --- a/target/linux/generic/backport-6.1/721-v6.0-net-ethernet-mtk_eth_wed-add-wed-support-for-mt7986-.patch +++ /dev/null @@ -1,942 +0,0 @@ -From 463a71af080fbc77339bee2037fb1e081e3824f7 Mon Sep 17 00:00:00 2001 -Message-Id: <463a71af080fbc77339bee2037fb1e081e3824f7.1662886034.git.lorenzo@kernel.org> -In-Reply-To: -References: -From: Lorenzo Bianconi -Date: Sat, 27 Aug 2022 16:15:14 +0200 -Subject: [PATCH net-next 2/5] net: ethernet: mtk_eth_wed: add wed support for - mt7986 chipset - -Introduce Wireless Etherne Dispatcher support on transmission side -for mt7986 chipset - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 +- - drivers/net/ethernet/mediatek/mtk_wed.c | 371 ++++++++++++++---- - drivers/net/ethernet/mediatek/mtk_wed.h | 8 +- - .../net/ethernet/mediatek/mtk_wed_debugfs.c | 3 + - drivers/net/ethernet/mediatek/mtk_wed_regs.h | 81 +++- - include/linux/soc/mediatek/mtk_wed.h | 8 + - 6 files changed, 408 insertions(+), 97 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3895,6 +3895,7 @@ void mtk_eth_set_dma_device(struct mtk_e - - static int mtk_probe(struct platform_device *pdev) - { -+ struct resource *res = NULL; - struct device_node *mac_np; - struct mtk_eth *eth; - int err, i; -@@ -3975,16 +3976,31 @@ static int mtk_probe(struct platform_dev - } - } - -- for (i = 0;; i++) { -- struct device_node *np = of_parse_phandle(pdev->dev.of_node, -- "mediatek,wed", i); -- void __iomem *wdma; -- -- if (!np || i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) -- break; -- -- wdma = eth->base + eth->soc->reg_map->wdma_base[i]; -- mtk_wed_add_hw(np, eth, wdma, i); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -EINVAL; -+ } -+ -+ if (eth->soc->offload_version) { -+ for (i = 0;; i++) { -+ struct device_node *np; -+ phys_addr_t wdma_phy; -+ u32 wdma_base; -+ -+ if (i >= ARRAY_SIZE(eth->soc->reg_map->wdma_base)) -+ break; -+ -+ np = of_parse_phandle(pdev->dev.of_node, -+ "mediatek,wed", i); -+ if (!np) -+ break; -+ -+ wdma_base = eth->soc->reg_map->wdma_base[i]; -+ wdma_phy = res ? res->start + wdma_base : 0; -+ mtk_wed_add_hw(np, eth, eth->base + wdma_base, -+ wdma_phy, i); -+ } - } - - for (i = 0; i < 3; i++) { ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -25,6 +25,11 @@ - - #define MTK_WED_TX_RING_SIZE 2048 - #define MTK_WED_WDMA_RING_SIZE 1024 -+#define MTK_WED_MAX_GROUP_SIZE 0x100 -+#define MTK_WED_VLD_GROUP_SIZE 0x40 -+#define MTK_WED_PER_GROUP_PKT 128 -+ -+#define MTK_WED_FBUF_SIZE 128 - - static struct mtk_wed_hw *hw_list[2]; - static DEFINE_MUTEX(hw_lock); -@@ -150,10 +155,17 @@ mtk_wed_buffer_alloc(struct mtk_wed_devi - - desc->buf0 = cpu_to_le32(buf_phys); - desc->buf1 = cpu_to_le32(buf_phys + txd_size); -- ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | -- FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, -- MTK_WED_BUF_SIZE - txd_size) | -- MTK_WDMA_DESC_CTRL_LAST_SEG1; -+ -+ if (dev->hw->version == 1) -+ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | -+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1, -+ MTK_WED_BUF_SIZE - txd_size) | -+ MTK_WDMA_DESC_CTRL_LAST_SEG1; -+ else -+ ctrl = FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN0, txd_size) | -+ FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2, -+ MTK_WED_BUF_SIZE - txd_size) | -+ MTK_WDMA_DESC_CTRL_LAST_SEG0; - desc->ctrl = cpu_to_le32(ctrl); - desc->info = 0; - desc++; -@@ -209,7 +221,7 @@ mtk_wed_free_ring(struct mtk_wed_device - if (!ring->desc) - return; - -- dma_free_coherent(dev->hw->dev, ring->size * sizeof(*ring->desc), -+ dma_free_coherent(dev->hw->dev, ring->size * ring->desc_size, - ring->desc, ring->desc_phys); - } - -@@ -229,6 +241,14 @@ mtk_wed_set_ext_int(struct mtk_wed_devic - { - u32 mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; - -+ if (dev->hw->version == 1) -+ mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; -+ else -+ mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | -+ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | -+ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | -+ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; -+ - if (!dev->hw->num_flows) - mask &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; - -@@ -237,6 +257,20 @@ mtk_wed_set_ext_int(struct mtk_wed_devic - } - - static void -+mtk_wed_set_512_support(struct mtk_wed_device *dev, bool enable) -+{ -+ if (enable) { -+ wed_w32(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); -+ wed_w32(dev, MTK_WED_TXP_DW1, -+ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0103)); -+ } else { -+ wed_w32(dev, MTK_WED_TXP_DW1, -+ FIELD_PREP(MTK_WED_WPDMA_WRITE_TXP, 0x0100)); -+ wed_clr(dev, MTK_WED_TXDP_CTRL, MTK_WED_TXDP_DW9_OVERWR); -+ } -+} -+ -+static void - mtk_wed_dma_disable(struct mtk_wed_device *dev) - { - wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -@@ -249,12 +283,22 @@ mtk_wed_dma_disable(struct mtk_wed_devic - MTK_WED_GLO_CFG_TX_DMA_EN | - MTK_WED_GLO_CFG_RX_DMA_EN); - -- regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); - wdma_m32(dev, MTK_WDMA_GLO_CFG, - MTK_WDMA_GLO_CFG_TX_DMA_EN | - MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES, 0); -+ -+ if (dev->hw->version == 1) { -+ regmap_write(dev->hw->mirror, dev->hw->index * 4, 0); -+ wdma_m32(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES, 0); -+ } else { -+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); -+ -+ mtk_wed_set_512_support(dev, false); -+ } - } - - static void -@@ -293,7 +337,7 @@ mtk_wed_detach(struct mtk_wed_device *de - mtk_wed_free_buffer(dev); - mtk_wed_free_tx_rings(dev); - -- if (of_dma_is_coherent(wlan_node)) -+ if (of_dma_is_coherent(wlan_node) && hw->hifsys) - regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, - BIT(hw->index), BIT(hw->index)); - -@@ -308,14 +352,69 @@ mtk_wed_detach(struct mtk_wed_device *de - mutex_unlock(&hw_lock); - } - -+#define PCIE_BASE_ADDR0 0x11280000 -+static void -+mtk_wed_bus_init(struct mtk_wed_device *dev) -+{ -+ struct device_node *np = dev->hw->eth->dev->of_node; -+ struct regmap *regs; -+ u32 val; -+ -+ regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); -+ if (IS_ERR(regs)) -+ return; -+ -+ regmap_update_bits(regs, 0, BIT(0), BIT(0)); -+ -+ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, -+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); -+ -+ /* pcie interrupt control: pola/source selection */ -+ wed_set(dev, MTK_WED_PCIE_INT_CTRL, -+ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | -+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); -+ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -+ -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -+ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); -+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); -+ -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -+ -+ /* pcie interrupt status trigger register */ -+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); -+ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); -+ -+ /* pola setting */ -+ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -+ wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); -+} -+ -+static void -+mtk_wed_set_wpdma(struct mtk_wed_device *dev) -+{ -+ if (dev->hw->version == 1) { -+ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); -+ } else { -+ mtk_wed_bus_init(dev); -+ -+ wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_int); -+ wed_w32(dev, MTK_WED_WPDMA_CFG_INT_MASK, dev->wlan.wpdma_mask); -+ wed_w32(dev, MTK_WED_WPDMA_CFG_TX, dev->wlan.wpdma_tx); -+ wed_w32(dev, MTK_WED_WPDMA_CFG_TX_FREE, dev->wlan.wpdma_txfree); -+ } -+} -+ - static void - mtk_wed_hw_init_early(struct mtk_wed_device *dev) - { - u32 mask, set; -- u32 offset; - - mtk_wed_stop(dev); - mtk_wed_reset(dev, MTK_WED_RESET_WED); -+ mtk_wed_set_wpdma(dev); - - mask = MTK_WED_WDMA_GLO_CFG_BT_SIZE | - MTK_WED_WDMA_GLO_CFG_DYNAMIC_DMAD_RECYCLE | -@@ -325,17 +424,33 @@ mtk_wed_hw_init_early(struct mtk_wed_dev - MTK_WED_WDMA_GLO_CFG_IDLE_DMAD_SUPPLY; - wed_m32(dev, MTK_WED_WDMA_GLO_CFG, mask, set); - -- wdma_set(dev, MTK_WDMA_GLO_CFG, -- MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); -- -- offset = dev->hw->index ? 0x04000400 : 0; -- wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); -- wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); -+ if (dev->hw->version == 1) { -+ u32 offset = dev->hw->index ? 0x04000400 : 0; - -- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, MTK_PCIE_BASE(dev->hw->index)); -- wed_w32(dev, MTK_WED_WPDMA_CFG_BASE, dev->wlan.wpdma_phys); -+ wdma_set(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); -+ -+ wed_w32(dev, MTK_WED_WDMA_OFFSET0, 0x2a042a20 + offset); -+ wed_w32(dev, MTK_WED_WDMA_OFFSET1, 0x29002800 + offset); -+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, -+ MTK_PCIE_BASE(dev->hw->index)); -+ } else { -+ wed_w32(dev, MTK_WED_WDMA_CFG_BASE, dev->hw->wdma_phy); -+ wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_ETH_DMAD_FMT); -+ wed_w32(dev, MTK_WED_WDMA_OFFSET0, -+ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_INTS, -+ MTK_WDMA_INT_STATUS) | -+ FIELD_PREP(MTK_WED_WDMA_OFST0_GLO_CFG, -+ MTK_WDMA_GLO_CFG)); -+ -+ wed_w32(dev, MTK_WED_WDMA_OFFSET1, -+ FIELD_PREP(MTK_WED_WDMA_OFST1_TX_CTRL, -+ MTK_WDMA_RING_TX(0)) | -+ FIELD_PREP(MTK_WED_WDMA_OFST1_RX_CTRL, -+ MTK_WDMA_RING_RX(0))); -+ } - } - - static void -@@ -355,37 +470,65 @@ mtk_wed_hw_init(struct mtk_wed_device *d - - wed_w32(dev, MTK_WED_TX_BM_BASE, dev->buf_ring.desc_phys); - -- wed_w32(dev, MTK_WED_TX_BM_TKID, -- FIELD_PREP(MTK_WED_TX_BM_TKID_START, -- dev->wlan.token_start) | -- FIELD_PREP(MTK_WED_TX_BM_TKID_END, -- dev->wlan.token_start + dev->wlan.nbuf - 1)); -- - wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); - -- wed_w32(dev, MTK_WED_TX_BM_DYN_THR, -- FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | -- MTK_WED_TX_BM_DYN_THR_HI); -+ if (dev->hw->version == 1) { -+ wed_w32(dev, MTK_WED_TX_BM_TKID, -+ FIELD_PREP(MTK_WED_TX_BM_TKID_START, -+ dev->wlan.token_start) | -+ FIELD_PREP(MTK_WED_TX_BM_TKID_END, -+ dev->wlan.token_start + -+ dev->wlan.nbuf - 1)); -+ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, -+ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO, 1) | -+ MTK_WED_TX_BM_DYN_THR_HI); -+ } else { -+ wed_w32(dev, MTK_WED_TX_BM_TKID_V2, -+ FIELD_PREP(MTK_WED_TX_BM_TKID_START, -+ dev->wlan.token_start) | -+ FIELD_PREP(MTK_WED_TX_BM_TKID_END, -+ dev->wlan.token_start + -+ dev->wlan.nbuf - 1)); -+ wed_w32(dev, MTK_WED_TX_BM_DYN_THR, -+ FIELD_PREP(MTK_WED_TX_BM_DYN_THR_LO_V2, 0) | -+ MTK_WED_TX_BM_DYN_THR_HI_V2); -+ wed_w32(dev, MTK_WED_TX_TKID_CTRL, -+ MTK_WED_TX_TKID_CTRL_PAUSE | -+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM, -+ dev->buf_ring.size / 128) | -+ FIELD_PREP(MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM, -+ dev->buf_ring.size / 128)); -+ wed_w32(dev, MTK_WED_TX_TKID_DYN_THR, -+ FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) | -+ MTK_WED_TX_TKID_DYN_THR_HI); -+ } - - mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); - -- wed_set(dev, MTK_WED_CTRL, -- MTK_WED_CTRL_WED_TX_BM_EN | -- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); -+ if (dev->hw->version == 1) -+ wed_set(dev, MTK_WED_CTRL, -+ MTK_WED_CTRL_WED_TX_BM_EN | -+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); -+ else -+ wed_clr(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE); - - wed_clr(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE); - } - - static void --mtk_wed_ring_reset(struct mtk_wdma_desc *desc, int size) -+mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size) - { -+ void *head = (void *)ring->desc; - int i; - - for (i = 0; i < size; i++) { -- desc[i].buf0 = 0; -- desc[i].ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); -- desc[i].buf1 = 0; -- desc[i].info = 0; -+ struct mtk_wdma_desc *desc; -+ -+ desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size); -+ desc->buf0 = 0; -+ desc->ctrl = cpu_to_le32(MTK_WDMA_DESC_CTRL_DMA_DONE); -+ desc->buf1 = 0; -+ desc->info = 0; - } - } - -@@ -436,12 +579,10 @@ mtk_wed_reset_dma(struct mtk_wed_device - int i; - - for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++) { -- struct mtk_wdma_desc *desc = dev->tx_ring[i].desc; -- -- if (!desc) -+ if (!dev->tx_ring[i].desc) - continue; - -- mtk_wed_ring_reset(desc, MTK_WED_TX_RING_SIZE); -+ mtk_wed_ring_reset(&dev->tx_ring[i], MTK_WED_TX_RING_SIZE); - } - - if (mtk_wed_poll_busy(dev)) -@@ -498,16 +639,16 @@ mtk_wed_reset_dma(struct mtk_wed_device - - static int - mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring, -- int size) -+ int size, u32 desc_size) - { -- ring->desc = dma_alloc_coherent(dev->hw->dev, -- size * sizeof(*ring->desc), -+ ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size, - &ring->desc_phys, GFP_KERNEL); - if (!ring->desc) - return -ENOMEM; - -+ ring->desc_size = desc_size; - ring->size = size; -- mtk_wed_ring_reset(ring->desc, size); -+ mtk_wed_ring_reset(ring, size); - - return 0; - } -@@ -515,9 +656,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device - static int - mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size) - { -+ u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; - struct mtk_wed_ring *wdma = &dev->tx_wdma[idx]; - -- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE)) -+ if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) - return -ENOMEM; - - wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, -@@ -546,16 +688,41 @@ mtk_wed_configure_irq(struct mtk_wed_dev - MTK_WED_CTRL_WED_TX_BM_EN | - MTK_WED_CTRL_WED_TX_FREE_AGENT_EN); - -- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, -- MTK_WED_PCIE_INT_TRIGGER_STATUS); -+ if (dev->hw->version == 1) { -+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, -+ MTK_WED_PCIE_INT_TRIGGER_STATUS); -+ -+ wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, -+ MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | -+ MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); - -- wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, -- MTK_WED_WPDMA_INT_TRIGGER_RX_DONE | -- MTK_WED_WPDMA_INT_TRIGGER_TX_DONE); -+ wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); -+ } else { -+ /* initail tx interrupt trigger */ -+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, -+ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | -+ MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR | -+ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN | -+ MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR | -+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG, -+ dev->wlan.tx_tbit[0]) | -+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG, -+ dev->wlan.tx_tbit[1])); -+ -+ /* initail txfree interrupt trigger */ -+ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX_FREE, -+ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN | -+ MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR | -+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG, -+ dev->wlan.txfree_tbit)); -+ -+ wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask); -+ wed_set(dev, MTK_WED_WDMA_INT_CTRL, -+ FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL, -+ dev->wdma_idx)); -+ } - -- /* initail wdma interrupt agent */ - wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, wdma_mask); -- wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); - - wdma_w32(dev, MTK_WDMA_INT_MASK, wdma_mask); - wdma_w32(dev, MTK_WDMA_INT_GRP2, wdma_mask); -@@ -580,14 +747,28 @@ mtk_wed_dma_enable(struct mtk_wed_device - wdma_set(dev, MTK_WDMA_GLO_CFG, - MTK_WDMA_GLO_CFG_TX_DMA_EN | - MTK_WDMA_GLO_CFG_RX_INFO1_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO2_PRERES | -- MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); -+ MTK_WDMA_GLO_CFG_RX_INFO2_PRERES); -+ -+ if (dev->hw->version == 1) { -+ wdma_set(dev, MTK_WDMA_GLO_CFG, -+ MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); -+ } else { -+ wed_set(dev, MTK_WED_WPDMA_CTRL, -+ MTK_WED_WPDMA_CTRL_SDL1_FIXED); -+ -+ wed_set(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | -+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); -+ -+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, -+ MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP | -+ MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV); -+ } - } - - static void - mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) - { -- u32 val; - int i; - - for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) -@@ -598,14 +779,17 @@ mtk_wed_start(struct mtk_wed_device *dev - mtk_wed_configure_irq(dev, irq_mask); - - mtk_wed_set_ext_int(dev, true); -- val = dev->wlan.wpdma_phys | -- MTK_PCIE_MIRROR_MAP_EN | -- FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index); -- -- if (dev->hw->index) -- val |= BIT(1); -- val |= BIT(0); -- regmap_write(dev->hw->mirror, dev->hw->index * 4, val); -+ -+ if (dev->hw->version == 1) { -+ u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN | -+ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, -+ dev->hw->index); -+ -+ val |= BIT(0) | (BIT(1) * !!dev->hw->index); -+ regmap_write(dev->hw->mirror, dev->hw->index * 4, val); -+ } else { -+ mtk_wed_set_512_support(dev, true); -+ } - - mtk_wed_dma_enable(dev); - dev->running = true; -@@ -639,7 +823,9 @@ mtk_wed_attach(struct mtk_wed_device *de - goto out; - } - -- dev_info(&dev->wlan.pci_dev->dev, "attaching wed device %d\n", hw->index); -+ dev_info(&dev->wlan.pci_dev->dev, -+ "attaching wed device %d version %d\n", -+ hw->index, hw->version); - - dev->hw = hw; - dev->dev = hw->dev; -@@ -657,7 +843,9 @@ mtk_wed_attach(struct mtk_wed_device *de - } - - mtk_wed_hw_init_early(dev); -- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, BIT(hw->index), 0); -+ if (hw->hifsys) -+ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, -+ BIT(hw->index), 0); - - out: - mutex_unlock(&hw_lock); -@@ -684,7 +872,8 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev - - BUG_ON(idx >= ARRAY_SIZE(dev->tx_ring)); - -- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE)) -+ if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE, -+ sizeof(*ring->desc))) - return -ENOMEM; - - if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) -@@ -711,21 +900,21 @@ static int - mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs) - { - struct mtk_wed_ring *ring = &dev->txfree_ring; -- int i; -+ int i, index = dev->hw->version == 1; - - /* - * For txfree event handling, the same DMA ring is shared between WED - * and WLAN. The WLAN driver accesses the ring index registers through - * WED - */ -- ring->reg_base = MTK_WED_RING_RX(1); -+ ring->reg_base = MTK_WED_RING_RX(index); - ring->wpdma = regs; - - for (i = 0; i < 12; i += 4) { - u32 val = readl(regs + i); - -- wed_w32(dev, MTK_WED_RING_RX(1) + i, val); -- wed_w32(dev, MTK_WED_WPDMA_RING_RX(1) + i, val); -+ wed_w32(dev, MTK_WED_RING_RX(index) + i, val); -+ wed_w32(dev, MTK_WED_WPDMA_RING_RX(index) + i, val); - } - - return 0; -@@ -734,11 +923,19 @@ mtk_wed_txfree_ring_setup(struct mtk_wed - static u32 - mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) - { -- u32 val; -+ u32 val, ext_mask = MTK_WED_EXT_INT_STATUS_ERROR_MASK; -+ -+ if (dev->hw->version == 1) -+ ext_mask |= MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR; -+ else -+ ext_mask |= MTK_WED_EXT_INT_STATUS_RX_FBUF_LO_TH | -+ MTK_WED_EXT_INT_STATUS_RX_FBUF_HI_TH | -+ MTK_WED_EXT_INT_STATUS_RX_DRV_COHERENT | -+ MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR; - - val = wed_r32(dev, MTK_WED_EXT_INT_STATUS); - wed_w32(dev, MTK_WED_EXT_INT_STATUS, val); -- val &= MTK_WED_EXT_INT_STATUS_ERROR_MASK; -+ val &= ext_mask; - if (!dev->hw->num_flows) - val &= ~MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD; - if (val && net_ratelimit()) -@@ -813,7 +1010,8 @@ out: - } - - void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -- void __iomem *wdma, int index) -+ void __iomem *wdma, phys_addr_t wdma_phy, -+ int index) - { - static const struct mtk_wed_ops wed_ops = { - .attach = mtk_wed_attach, -@@ -860,26 +1058,33 @@ void mtk_wed_add_hw(struct device_node * - hw = kzalloc(sizeof(*hw), GFP_KERNEL); - if (!hw) - goto unlock; -+ - hw->node = np; - hw->regs = regs; - hw->eth = eth; - hw->dev = &pdev->dev; -+ hw->wdma_phy = wdma_phy; - hw->wdma = wdma; - hw->index = index; - hw->irq = irq; -- hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, -- "mediatek,pcie-mirror"); -- hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, -- "mediatek,hifsys"); -- if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { -- kfree(hw); -- goto unlock; -- } -+ hw->version = MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) ? 2 : 1; - -- if (!index) { -- regmap_write(hw->mirror, 0, 0); -- regmap_write(hw->mirror, 4, 0); -+ if (hw->version == 1) { -+ hw->mirror = syscon_regmap_lookup_by_phandle(eth_np, -+ "mediatek,pcie-mirror"); -+ hw->hifsys = syscon_regmap_lookup_by_phandle(eth_np, -+ "mediatek,hifsys"); -+ if (IS_ERR(hw->mirror) || IS_ERR(hw->hifsys)) { -+ kfree(hw); -+ goto unlock; -+ } -+ -+ if (!index) { -+ regmap_write(hw->mirror, 0, 0); -+ regmap_write(hw->mirror, 4, 0); -+ } - } -+ - mtk_wed_hw_add_debugfs(hw); - - hw_list[index] = hw; ---- a/drivers/net/ethernet/mediatek/mtk_wed.h -+++ b/drivers/net/ethernet/mediatek/mtk_wed.h -@@ -18,11 +18,13 @@ struct mtk_wed_hw { - struct regmap *hifsys; - struct device *dev; - void __iomem *wdma; -+ phys_addr_t wdma_phy; - struct regmap *mirror; - struct dentry *debugfs_dir; - struct mtk_wed_device *wed_dev; - u32 debugfs_reg; - u32 num_flows; -+ u8 version; - char dirname[5]; - int irq; - int index; -@@ -101,14 +103,16 @@ wpdma_txfree_w32(struct mtk_wed_device * - } - - void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -- void __iomem *wdma, int index); -+ void __iomem *wdma, phys_addr_t wdma_phy, -+ int index); - void mtk_wed_exit(void); - int mtk_wed_flow_add(int index); - void mtk_wed_flow_remove(int index); - #else - static inline void - mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, -- void __iomem *wdma, int index) -+ void __iomem *wdma, phys_addr_t wdma_phy, -+ int index) - { - } - static inline void ---- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c -@@ -116,6 +116,9 @@ wed_txinfo_show(struct seq_file *s, void - DUMP_WDMA(WDMA_GLO_CFG), - DUMP_WDMA_RING(WDMA_RING_RX(0)), - DUMP_WDMA_RING(WDMA_RING_RX(1)), -+ -+ DUMP_STR("TX FREE"), -+ DUMP_WED(WED_RX_MIB(0)), - }; - struct mtk_wed_hw *hw = s->private; - struct mtk_wed_device *dev = hw->wed_dev; ---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h -+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h -@@ -5,6 +5,7 @@ - #define __MTK_WED_REGS_H - - #define MTK_WDMA_DESC_CTRL_LEN1 GENMASK(14, 0) -+#define MTK_WDMA_DESC_CTRL_LEN1_V2 GENMASK(13, 0) - #define MTK_WDMA_DESC_CTRL_LAST_SEG1 BIT(15) - #define MTK_WDMA_DESC_CTRL_BURST BIT(16) - #define MTK_WDMA_DESC_CTRL_LEN0 GENMASK(29, 16) -@@ -41,6 +42,7 @@ struct mtk_wdma_desc { - #define MTK_WED_CTRL_RESERVE_EN BIT(12) - #define MTK_WED_CTRL_RESERVE_BUSY BIT(13) - #define MTK_WED_CTRL_FINAL_DIDX_READ BIT(24) -+#define MTK_WED_CTRL_ETH_DMAD_FMT BIT(25) - #define MTK_WED_CTRL_MIB_READ_CLEAR BIT(28) - - #define MTK_WED_EXT_INT_STATUS 0x020 -@@ -57,7 +59,8 @@ struct mtk_wdma_desc { - #define MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN BIT(19) - #define MTK_WED_EXT_INT_STATUS_RX_DRV_BM_DMAD_COHERENT BIT(20) - #define MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR BIT(21) --#define MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR BIT(22) -+#define MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR BIT(22) -+#define MTK_WED_EXT_INT_STATUS_TX_DMA_W_RESP_ERR BIT(23) - #define MTK_WED_EXT_INT_STATUS_RX_DRV_DMA_RECYCLE BIT(24) - #define MTK_WED_EXT_INT_STATUS_ERROR_MASK (MTK_WED_EXT_INT_STATUS_TF_LEN_ERR | \ - MTK_WED_EXT_INT_STATUS_TKID_WO_PYLD | \ -@@ -65,8 +68,7 @@ struct mtk_wdma_desc { - MTK_WED_EXT_INT_STATUS_RX_DRV_R_RESP_ERR | \ - MTK_WED_EXT_INT_STATUS_RX_DRV_W_RESP_ERR | \ - MTK_WED_EXT_INT_STATUS_RX_DRV_INIT_WDMA_EN | \ -- MTK_WED_EXT_INT_STATUS_TX_DRV_R_RESP_ERR | \ -- MTK_WED_EXT_INT_STATUS_TX_DRV_W_RESP_ERR) -+ MTK_WED_EXT_INT_STATUS_TX_DMA_R_RESP_ERR) - - #define MTK_WED_EXT_INT_MASK 0x028 - -@@ -81,6 +83,7 @@ struct mtk_wdma_desc { - #define MTK_WED_TX_BM_BASE 0x084 - - #define MTK_WED_TX_BM_TKID 0x088 -+#define MTK_WED_TX_BM_TKID_V2 0x0c8 - #define MTK_WED_TX_BM_TKID_START GENMASK(15, 0) - #define MTK_WED_TX_BM_TKID_END GENMASK(31, 16) - -@@ -94,7 +97,25 @@ struct mtk_wdma_desc { - - #define MTK_WED_TX_BM_DYN_THR 0x0a0 - #define MTK_WED_TX_BM_DYN_THR_LO GENMASK(6, 0) -+#define MTK_WED_TX_BM_DYN_THR_LO_V2 GENMASK(8, 0) - #define MTK_WED_TX_BM_DYN_THR_HI GENMASK(22, 16) -+#define MTK_WED_TX_BM_DYN_THR_HI_V2 GENMASK(24, 16) -+ -+#define MTK_WED_TX_TKID_CTRL 0x0c0 -+#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM GENMASK(6, 0) -+#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM GENMASK(22, 16) -+#define MTK_WED_TX_TKID_CTRL_PAUSE BIT(28) -+ -+#define MTK_WED_TX_TKID_DYN_THR 0x0e0 -+#define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0) -+#define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16) -+ -+#define MTK_WED_TXP_DW0 0x120 -+#define MTK_WED_TXP_DW1 0x124 -+#define MTK_WED_WPDMA_WRITE_TXP GENMASK(31, 16) -+#define MTK_WED_TXDP_CTRL 0x130 -+#define MTK_WED_TXDP_DW9_OVERWR BIT(9) -+#define MTK_WED_RX_BM_TKID_MIB 0x1cc - - #define MTK_WED_INT_STATUS 0x200 - #define MTK_WED_INT_MASK 0x204 -@@ -125,6 +146,7 @@ struct mtk_wdma_desc { - #define MTK_WED_RESET_IDX_RX GENMASK(17, 16) - - #define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4) -+#define MTK_WED_RX_MIB(_n) (0x2e0 + (_n) * 4) - - #define MTK_WED_RING_TX(_n) (0x300 + (_n) * 0x10) - -@@ -155,21 +177,62 @@ struct mtk_wdma_desc { - #define MTK_WED_WPDMA_GLO_CFG_BYTE_SWAP BIT(29) - #define MTK_WED_WPDMA_GLO_CFG_RX_2B_OFFSET BIT(31) - -+/* CONFIG_MEDIATEK_NETSYS_V2 */ -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC BIT(4) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_PKT_PROC BIT(5) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC BIT(6) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_R1_CRX_SYNC BIT(7) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_EVENT_PKT_FMT_VER GENMASK(18, 16) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UNSUPPORT_FMT BIT(19) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DRV_UEVENT_PKT_FMT_CHK BIT(20) -+#define MTK_WED_WPDMA_GLO_CFG_RX_DDONE2_WR BIT(21) -+#define MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP BIT(24) -+#define MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV BIT(28) -+ - #define MTK_WED_WPDMA_RESET_IDX 0x50c - #define MTK_WED_WPDMA_RESET_IDX_TX GENMASK(3, 0) - #define MTK_WED_WPDMA_RESET_IDX_RX GENMASK(17, 16) - -+#define MTK_WED_WPDMA_CTRL 0x518 -+#define MTK_WED_WPDMA_CTRL_SDL1_FIXED BIT(31) -+ - #define MTK_WED_WPDMA_INT_CTRL 0x520 - #define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) - - #define MTK_WED_WPDMA_INT_MASK 0x524 - -+#define MTK_WED_WPDMA_INT_CTRL_TX 0x530 -+#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN BIT(0) -+#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_CLR BIT(1) -+#define MTK_WED_WPDMA_INT_CTRL_TX0_DONE_TRIG GENMASK(6, 2) -+#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_EN BIT(8) -+#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_CLR BIT(9) -+#define MTK_WED_WPDMA_INT_CTRL_TX1_DONE_TRIG GENMASK(14, 10) -+ -+#define MTK_WED_WPDMA_INT_CTRL_RX 0x534 -+ -+#define MTK_WED_WPDMA_INT_CTRL_TX_FREE 0x538 -+#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_EN BIT(0) -+#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_CLR BIT(1) -+#define MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG GENMASK(6, 2) -+ - #define MTK_WED_PCIE_CFG_BASE 0x560 - -+#define MTK_WED_PCIE_CFG_BASE 0x560 -+#define MTK_WED_PCIE_CFG_INTM 0x564 -+#define MTK_WED_PCIE_CFG_MSIS 0x568 - #define MTK_WED_PCIE_INT_TRIGGER 0x570 - #define MTK_WED_PCIE_INT_TRIGGER_STATUS BIT(16) - -+#define MTK_WED_PCIE_INT_CTRL 0x57c -+#define MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA BIT(20) -+#define MTK_WED_PCIE_INT_CTRL_SRC_SEL GENMASK(17, 16) -+#define MTK_WED_PCIE_INT_CTRL_POLL_EN GENMASK(13, 12) -+ - #define MTK_WED_WPDMA_CFG_BASE 0x580 -+#define MTK_WED_WPDMA_CFG_INT_MASK 0x584 -+#define MTK_WED_WPDMA_CFG_TX 0x588 -+#define MTK_WED_WPDMA_CFG_TX_FREE 0x58c - - #define MTK_WED_WPDMA_TX_MIB(_n) (0x5a0 + (_n) * 4) - #define MTK_WED_WPDMA_TX_COHERENT_MIB(_n) (0x5d0 + (_n) * 4) -@@ -203,15 +266,24 @@ struct mtk_wdma_desc { - #define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16) - #define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24) - -+#define MTK_WED_WDMA_INT_CLR 0xa24 -+#define MTK_WED_WDMA_INT_CLR_RX_DONE GENMASK(17, 16) -+ - #define MTK_WED_WDMA_INT_TRIGGER 0xa28 - #define MTK_WED_WDMA_INT_TRIGGER_RX_DONE GENMASK(17, 16) - - #define MTK_WED_WDMA_INT_CTRL 0xa2c - #define MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL GENMASK(17, 16) - -+#define MTK_WED_WDMA_CFG_BASE 0xaa0 - #define MTK_WED_WDMA_OFFSET0 0xaa4 - #define MTK_WED_WDMA_OFFSET1 0xaa8 - -+#define MTK_WED_WDMA_OFST0_GLO_INTS GENMASK(15, 0) -+#define MTK_WED_WDMA_OFST0_GLO_CFG GENMASK(31, 16) -+#define MTK_WED_WDMA_OFST1_TX_CTRL GENMASK(15, 0) -+#define MTK_WED_WDMA_OFST1_RX_CTRL GENMASK(31, 16) -+ - #define MTK_WED_WDMA_RX_MIB(_n) (0xae0 + (_n) * 4) - #define MTK_WED_WDMA_RX_RECYCLE_MIB(_n) (0xae8 + (_n) * 4) - #define MTK_WED_WDMA_RX_PROCESSED_MIB(_n) (0xaf0 + (_n) * 4) -@@ -221,6 +293,7 @@ struct mtk_wdma_desc { - #define MTK_WED_RING_OFS_CPU_IDX 0x08 - #define MTK_WED_RING_OFS_DMA_IDX 0x0c - -+#define MTK_WDMA_RING_TX(_n) (0x000 + (_n) * 0x10) - #define MTK_WDMA_RING_RX(_n) (0x100 + (_n) * 0x10) - - #define MTK_WDMA_GLO_CFG 0x204 -@@ -234,6 +307,8 @@ struct mtk_wdma_desc { - #define MTK_WDMA_RESET_IDX_TX GENMASK(3, 0) - #define MTK_WDMA_RESET_IDX_RX GENMASK(17, 16) - -+#define MTK_WDMA_INT_STATUS 0x220 -+ - #define MTK_WDMA_INT_MASK 0x228 - #define MTK_WDMA_INT_MASK_TX_DONE GENMASK(3, 0) - #define MTK_WDMA_INT_MASK_RX_DONE GENMASK(17, 16) ---- a/include/linux/soc/mediatek/mtk_wed.h -+++ b/include/linux/soc/mediatek/mtk_wed.h -@@ -14,6 +14,7 @@ struct mtk_wdma_desc; - struct mtk_wed_ring { - struct mtk_wdma_desc *desc; - dma_addr_t desc_phys; -+ u32 desc_size; - int size; - - u32 reg_base; -@@ -45,10 +46,17 @@ struct mtk_wed_device { - struct pci_dev *pci_dev; - - u32 wpdma_phys; -+ u32 wpdma_int; -+ u32 wpdma_mask; -+ u32 wpdma_tx; -+ u32 wpdma_txfree; - - u16 token_start; - unsigned int nbuf; - -+ u8 tx_tbit[MTK_WED_TX_QUEUES]; -+ u8 txfree_tbit; -+ - u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id); - int (*offload_enable)(struct mtk_wed_device *wed); - void (*offload_disable)(struct mtk_wed_device *wed); diff --git a/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch b/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch deleted file mode 100644 index 70b7bad31f2..00000000000 --- a/target/linux/generic/backport-6.1/722-v6.0-net-ethernet-mtk_eth_wed-add-axi-bus-support.patch +++ /dev/null @@ -1,237 +0,0 @@ -From 6e1df49f330dce7c58a39d6772f1385b6887bb03 Mon Sep 17 00:00:00 2001 -Message-Id: <6e1df49f330dce7c58a39d6772f1385b6887bb03.1662990860.git.lorenzo@kernel.org> -From: Lorenzo Bianconi -Date: Thu, 8 Sep 2022 11:26:10 +0200 -Subject: [PATCH net-next] net: ethernet: mtk_eth_wed: add axi bus support - -Other than pcie bus, introduce support for axi bus to mtk wed driver. -Axi bus is used to connect mt7986-wmac soc chip available on mt7986 -device. - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_wed.c | 116 +++++++++++++------ - drivers/net/ethernet/mediatek/mtk_wed_regs.h | 2 + - include/linux/soc/mediatek/mtk_wed.h | 11 +- - 3 files changed, 91 insertions(+), 38 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -85,11 +85,31 @@ static struct mtk_wed_hw * - mtk_wed_assign(struct mtk_wed_device *dev) - { - struct mtk_wed_hw *hw; -+ int i; -+ -+ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { -+ hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; -+ if (!hw) -+ return NULL; -+ -+ if (!hw->wed_dev) -+ goto out; -+ -+ if (hw->version == 1) -+ return NULL; -+ -+ /* MT7986 WED devices do not have any pcie slot restrictions */ -+ } -+ /* MT7986 PCIE or AXI */ -+ for (i = 0; i < ARRAY_SIZE(hw_list); i++) { -+ hw = hw_list[i]; -+ if (hw && !hw->wed_dev) -+ goto out; -+ } - -- hw = hw_list[pci_domain_nr(dev->wlan.pci_dev->bus)]; -- if (!hw || hw->wed_dev) -- return NULL; -+ return NULL; - -+out: - hw->wed_dev = dev; - return hw; - } -@@ -322,7 +342,6 @@ mtk_wed_stop(struct mtk_wed_device *dev) - static void - mtk_wed_detach(struct mtk_wed_device *dev) - { -- struct device_node *wlan_node = dev->wlan.pci_dev->dev.of_node; - struct mtk_wed_hw *hw = dev->hw; - - mutex_lock(&hw_lock); -@@ -337,9 +356,14 @@ mtk_wed_detach(struct mtk_wed_device *de - mtk_wed_free_buffer(dev); - mtk_wed_free_tx_rings(dev); - -- if (of_dma_is_coherent(wlan_node) && hw->hifsys) -- regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, -- BIT(hw->index), BIT(hw->index)); -+ if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { -+ struct device_node *wlan_node; -+ -+ wlan_node = dev->wlan.pci_dev->dev.of_node; -+ if (of_dma_is_coherent(wlan_node) && hw->hifsys) -+ regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP, -+ BIT(hw->index), BIT(hw->index)); -+ } - - if (!hw_list[!hw->index]->wed_dev && - hw->eth->dma_dev != hw->eth->dev) -@@ -356,40 +380,54 @@ mtk_wed_detach(struct mtk_wed_device *de - static void - mtk_wed_bus_init(struct mtk_wed_device *dev) - { -- struct device_node *np = dev->hw->eth->dev->of_node; -- struct regmap *regs; -- u32 val; -- -- regs = syscon_regmap_lookup_by_phandle(np, "mediatek,wed-pcie"); -- if (IS_ERR(regs)) -- return; -+ switch (dev->wlan.bus_type) { -+ case MTK_WED_BUS_PCIE: { -+ struct device_node *np = dev->hw->eth->dev->of_node; -+ struct regmap *regs; -+ u32 val; -+ -+ regs = syscon_regmap_lookup_by_phandle(np, -+ "mediatek,wed-pcie"); -+ if (IS_ERR(regs)) -+ break; - -- regmap_update_bits(regs, 0, BIT(0), BIT(0)); -+ regmap_update_bits(regs, 0, BIT(0), BIT(0)); - -- wed_w32(dev, MTK_WED_PCIE_INT_CTRL, -- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); -+ wed_w32(dev, MTK_WED_PCIE_INT_CTRL, -+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_POLL_EN, 2)); - -- /* pcie interrupt control: pola/source selection */ -- wed_set(dev, MTK_WED_PCIE_INT_CTRL, -- MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | -- FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); -- wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -- -- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -- wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); -- wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); -- -- val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -- val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -- -- /* pcie interrupt status trigger register */ -- wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); -- wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); -- -- /* pola setting */ -- val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -- wed_set(dev, MTK_WED_PCIE_INT_CTRL, MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); -+ /* pcie interrupt control: pola/source selection */ -+ wed_set(dev, MTK_WED_PCIE_INT_CTRL, -+ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA | -+ FIELD_PREP(MTK_WED_PCIE_INT_CTRL_SRC_SEL, 1)); -+ wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -+ -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -+ wed_w32(dev, MTK_WED_PCIE_CFG_INTM, PCIE_BASE_ADDR0 | 0x180); -+ wed_w32(dev, MTK_WED_PCIE_CFG_BASE, PCIE_BASE_ADDR0 | 0x184); -+ -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_INTM); -+ val = wed_r32(dev, MTK_WED_PCIE_CFG_BASE); -+ -+ /* pcie interrupt status trigger register */ -+ wed_w32(dev, MTK_WED_PCIE_INT_TRIGGER, BIT(24)); -+ wed_r32(dev, MTK_WED_PCIE_INT_TRIGGER); -+ -+ /* pola setting */ -+ val = wed_r32(dev, MTK_WED_PCIE_INT_CTRL); -+ wed_set(dev, MTK_WED_PCIE_INT_CTRL, -+ MTK_WED_PCIE_INT_CTRL_MSK_EN_POLA); -+ break; -+ } -+ case MTK_WED_BUS_AXI: -+ wed_set(dev, MTK_WED_WPDMA_INT_CTRL, -+ MTK_WED_WPDMA_INT_CTRL_SIG_SRC | -+ FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_SRC_SEL, 0)); -+ break; -+ default: -+ break; -+ } - } - - static void -@@ -800,12 +838,14 @@ mtk_wed_attach(struct mtk_wed_device *de - __releases(RCU) - { - struct mtk_wed_hw *hw; -+ struct device *device; - int ret = 0; - - RCU_LOCKDEP_WARN(!rcu_read_lock_held(), - "mtk_wed_attach without holding the RCU read lock"); - -- if (pci_domain_nr(dev->wlan.pci_dev->bus) > 1 || -+ if ((dev->wlan.bus_type == MTK_WED_BUS_PCIE && -+ pci_domain_nr(dev->wlan.pci_dev->bus) > 1) || - !try_module_get(THIS_MODULE)) - ret = -ENODEV; - -@@ -823,8 +863,10 @@ mtk_wed_attach(struct mtk_wed_device *de - goto out; - } - -- dev_info(&dev->wlan.pci_dev->dev, -- "attaching wed device %d version %d\n", -+ device = dev->wlan.bus_type == MTK_WED_BUS_PCIE -+ ? &dev->wlan.pci_dev->dev -+ : &dev->wlan.platform_dev->dev; -+ dev_info(device, "attaching wed device %d version %d\n", - hw->index, hw->version); - - dev->hw = hw; ---- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h -+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h -@@ -198,6 +198,8 @@ struct mtk_wdma_desc { - - #define MTK_WED_WPDMA_INT_CTRL 0x520 - #define MTK_WED_WPDMA_INT_CTRL_SUBRT_ADV BIT(21) -+#define MTK_WED_WPDMA_INT_CTRL_SIG_SRC BIT(22) -+#define MTK_WED_WPDMA_INT_CTRL_SRC_SEL GENMASK(17, 16) - - #define MTK_WED_WPDMA_INT_MASK 0x524 - ---- a/include/linux/soc/mediatek/mtk_wed.h -+++ b/include/linux/soc/mediatek/mtk_wed.h -@@ -11,6 +11,11 @@ - struct mtk_wed_hw; - struct mtk_wdma_desc; - -+enum mtk_wed_bus_tye { -+ MTK_WED_BUS_PCIE, -+ MTK_WED_BUS_AXI, -+}; -+ - struct mtk_wed_ring { - struct mtk_wdma_desc *desc; - dma_addr_t desc_phys; -@@ -43,7 +48,11 @@ struct mtk_wed_device { - - /* filled by driver: */ - struct { -- struct pci_dev *pci_dev; -+ union { -+ struct platform_device *platform_dev; -+ struct pci_dev *pci_dev; -+ }; -+ enum mtk_wed_bus_tye bus_type; - - u32 wpdma_phys; - u32 wpdma_int; diff --git a/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch b/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch deleted file mode 100644 index fedcb6ccd89..00000000000 --- a/target/linux/generic/backport-6.1/723-v6.0-net-ethernet-mtk_eth_soc-introduce-flow-offloading-s.patch +++ /dev/null @@ -1,882 +0,0 @@ -From 93408c858e5dc01d97c55efa721268f63fde2ae5 Mon Sep 17 00:00:00 2001 -Message-Id: <93408c858e5dc01d97c55efa721268f63fde2ae5.1662886034.git.lorenzo@kernel.org> -In-Reply-To: -References: -From: Lorenzo Bianconi -Date: Sat, 3 Sep 2022 18:34:09 +0200 -Subject: [PATCH net-next 4/5] net: ethernet: mtk_eth_soc: introduce flow - offloading support for mt7986 - -Introduce hw flow offload support for mt7986 chipset. PPE is not enabled -yet in mt7986 since mt76 support is not available yet. - -Co-developed-by: Bo Jiao -Signed-off-by: Bo Jiao -Co-developed-by: Sujuan Chen -Signed-off-by: Sujuan Chen -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 72 ++++++ - drivers/net/ethernet/mediatek/mtk_ppe.c | 213 +++++++++++------- - drivers/net/ethernet/mediatek/mtk_ppe.h | 52 ++++- - .../net/ethernet/mediatek/mtk_ppe_offload.c | 49 ++-- - drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 8 + - 6 files changed, 289 insertions(+), 116 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1859,12 +1859,14 @@ static int mtk_poll_rx(struct napi_struc - bytes += skb->len; - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5); - hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; - if (hash != MTK_RXD5_FOE_ENTRY) - skb_set_hash(skb, jhash_1word(hash, 0), - PKT_HASH_TYPE_L4); - rxdcsum = &trxd.rxd3; - } else { -+ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); - hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; - if (hash != MTK_RXD4_FOE_ENTRY) - skb_set_hash(skb, jhash_1word(hash, 0), -@@ -1878,7 +1880,6 @@ static int mtk_poll_rx(struct napi_struc - skb_checksum_none_assert(skb); - skb->protocol = eth_type_trans(skb, netdev); - -- reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4); - if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) - mtk_ppe_check_skb(eth->ppe[0], skb, hash); - -@@ -4184,7 +4185,7 @@ static const struct mtk_soc_data mt7621_ - .required_pctl = false, - .offload_version = 2, - .hash_offset = 2, -- .foe_entry_size = sizeof(struct mtk_foe_entry), -+ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4204,7 +4205,7 @@ static const struct mtk_soc_data mt7622_ - .required_pctl = false, - .offload_version = 2, - .hash_offset = 2, -- .foe_entry_size = sizeof(struct mtk_foe_entry), -+ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4223,7 +4224,7 @@ static const struct mtk_soc_data mt7623_ - .required_pctl = true, - .offload_version = 2, - .hash_offset = 2, -- .foe_entry_size = sizeof(struct mtk_foe_entry), -+ .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma), - .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4255,9 +4256,11 @@ static const struct mtk_soc_data mt7986_ - .reg_map = &mt7986_reg_map, - .ana_rgc3 = 0x128, - .caps = MT7986_CAPS, -+ .hw_features = MTK_HW_FEATURES, - .required_clks = MT7986_CLKS_BITMAP, - .required_pctl = false, - .hash_offset = 4, -+ .foe_entry_size = sizeof(struct mtk_foe_entry), - .txrx = { - .txd_size = sizeof(struct mtk_tx_dma_v2), - .rxd_size = sizeof(struct mtk_rx_dma_v2), ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1151,6 +1151,78 @@ mtk_foe_get_entry(struct mtk_ppe *ppe, u - return ppe->foe_table + hash * soc->foe_entry_size; - } - -+static inline u32 mtk_get_ib1_ts_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB1_BIND_TIMESTAMP_V2; -+ -+ return MTK_FOE_IB1_BIND_TIMESTAMP; -+} -+ -+static inline u32 mtk_get_ib1_ppoe_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB1_BIND_PPPOE_V2; -+ -+ return MTK_FOE_IB1_BIND_PPPOE; -+} -+ -+static inline u32 mtk_get_ib1_vlan_tag_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB1_BIND_VLAN_TAG_V2; -+ -+ return MTK_FOE_IB1_BIND_VLAN_TAG; -+} -+ -+static inline u32 mtk_get_ib1_vlan_layer_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB1_BIND_VLAN_LAYER_V2; -+ -+ return MTK_FOE_IB1_BIND_VLAN_LAYER; -+} -+ -+static inline u32 mtk_prep_ib1_vlan_layer(struct mtk_eth *eth, u32 val) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); -+ -+ return FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, val); -+} -+ -+static inline u32 mtk_get_ib1_vlan_layer(struct mtk_eth *eth, u32 val) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER_V2, val); -+ -+ return FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, val); -+} -+ -+static inline u32 mtk_get_ib1_pkt_type_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB1_PACKET_TYPE_V2; -+ -+ return MTK_FOE_IB1_PACKET_TYPE; -+} -+ -+static inline u32 mtk_get_ib1_pkt_type(struct mtk_eth *eth, u32 val) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE_V2, val); -+ -+ return FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, val); -+} -+ -+static inline u32 mtk_get_ib2_multicast_mask(struct mtk_eth *eth) -+{ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) -+ return MTK_FOE_IB2_MULTICAST_V2; -+ -+ return MTK_FOE_IB2_MULTICAST; -+} -+ - /* read the hardware status register */ - void mtk_stats_update_mac(struct mtk_mac *mac); - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -56,7 +56,7 @@ static u32 ppe_clear(struct mtk_ppe *ppe - - static u32 mtk_eth_timestamp(struct mtk_eth *eth) - { -- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP; -+ return mtk_r32(eth, 0x0010) & mtk_get_ib1_ts_mask(eth); - } - - static int mtk_ppe_wait_busy(struct mtk_ppe *ppe) -@@ -93,7 +93,7 @@ static u32 mtk_ppe_hash_entry(struct mtk - u32 hv1, hv2, hv3; - u32 hash; - -- switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) { -+ switch (mtk_get_ib1_pkt_type(eth, e->ib1)) { - case MTK_PPE_PKT_TYPE_IPV4_ROUTE: - case MTK_PPE_PKT_TYPE_IPV4_HNAPT: - hv1 = e->ipv4.orig.ports; -@@ -129,9 +129,9 @@ static u32 mtk_ppe_hash_entry(struct mtk - } - - static inline struct mtk_foe_mac_info * --mtk_foe_entry_l2(struct mtk_foe_entry *entry) -+mtk_foe_entry_l2(struct mtk_eth *eth, struct mtk_foe_entry *entry) - { -- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); -+ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); - - if (type == MTK_PPE_PKT_TYPE_BRIDGE) - return &entry->bridge.l2; -@@ -143,9 +143,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e - } - - static inline u32 * --mtk_foe_entry_ib2(struct mtk_foe_entry *entry) -+mtk_foe_entry_ib2(struct mtk_eth *eth, struct mtk_foe_entry *entry) - { -- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); -+ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); - - if (type == MTK_PPE_PKT_TYPE_BRIDGE) - return &entry->bridge.ib2; -@@ -156,27 +156,38 @@ mtk_foe_entry_ib2(struct mtk_foe_entry * - return &entry->ipv4.ib2; - } - --int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, -- u8 pse_port, u8 *src_mac, u8 *dest_mac) -+int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int type, int l4proto, u8 pse_port, u8 *src_mac, -+ u8 *dest_mac) - { - struct mtk_foe_mac_info *l2; - u32 ports_pad, val; - - memset(entry, 0, sizeof(*entry)); - -- val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | -- FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | -- FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | -- MTK_FOE_IB1_BIND_TTL | -- MTK_FOE_IB1_BIND_CACHE; -- entry->ib1 = val; -- -- val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | -- FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) | -- FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | -+ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE_V2, type) | -+ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | -+ MTK_FOE_IB1_BIND_CACHE_V2 | MTK_FOE_IB1_BIND_TTL_V2; -+ entry->ib1 = val; -+ -+ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) | -+ FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf); -+ } else { -+ val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) | -+ FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) | -+ FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) | -+ MTK_FOE_IB1_BIND_CACHE | MTK_FOE_IB1_BIND_TTL; -+ entry->ib1 = val; -+ -+ val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) | -+ FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) | -+ FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f); -+ } - - if (is_multicast_ether_addr(dest_mac)) -- val |= MTK_FOE_IB2_MULTICAST; -+ val |= mtk_get_ib2_multicast_mask(eth); - - ports_pad = 0xa5a5a500 | (l4proto & 0xff); - if (type == MTK_PPE_PKT_TYPE_IPV4_ROUTE) -@@ -210,24 +221,30 @@ int mtk_foe_entry_prepare(struct mtk_foe - return 0; - } - --int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port) -+int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, u8 port) - { -- u32 *ib2 = mtk_foe_entry_ib2(entry); -- u32 val; -+ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); -+ u32 val = *ib2; - -- val = *ib2; -- val &= ~MTK_FOE_IB2_DEST_PORT; -- val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ val &= ~MTK_FOE_IB2_DEST_PORT_V2; -+ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, port); -+ } else { -+ val &= ~MTK_FOE_IB2_DEST_PORT; -+ val |= FIELD_PREP(MTK_FOE_IB2_DEST_PORT, port); -+ } - *ib2 = val; - - return 0; - } - --int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool egress, -+int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, bool egress, - __be32 src_addr, __be16 src_port, - __be32 dest_addr, __be16 dest_port) - { -- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); -+ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); - struct mtk_ipv4_tuple *t; - - switch (type) { -@@ -262,11 +279,12 @@ int mtk_foe_entry_set_ipv4_tuple(struct - return 0; - } - --int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, -+int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, - __be32 *src_addr, __be16 src_port, - __be32 *dest_addr, __be16 dest_port) - { -- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1); -+ int type = mtk_get_ib1_pkt_type(eth, entry->ib1); - u32 *src, *dest; - int i; - -@@ -297,39 +315,41 @@ int mtk_foe_entry_set_ipv6_tuple(struct - return 0; - } - --int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port) -+int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int port) - { -- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); -+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); - - l2->etype = BIT(port); - -- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER)) -- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); -+ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth))) -+ entry->ib1 |= mtk_prep_ib1_vlan_layer(eth, 1); - else - l2->etype |= BIT(8); - -- entry->ib1 &= ~MTK_FOE_IB1_BIND_VLAN_TAG; -+ entry->ib1 &= ~mtk_get_ib1_vlan_tag_mask(eth); - - return 0; - } - --int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid) -+int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int vid) - { -- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); -+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); - -- switch (FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1)) { -+ switch (mtk_prep_ib1_vlan_layer(eth, entry->ib1)) { - case 0: -- entry->ib1 |= MTK_FOE_IB1_BIND_VLAN_TAG | -- FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); -+ entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | -+ mtk_prep_ib1_vlan_layer(eth, 1); - l2->vlan1 = vid; - return 0; - case 1: -- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) { -+ if (!(entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) { - l2->vlan1 = vid; - l2->etype |= BIT(8); - } else { - l2->vlan2 = vid; -- entry->ib1 += FIELD_PREP(MTK_FOE_IB1_BIND_VLAN_LAYER, 1); -+ entry->ib1 += mtk_prep_ib1_vlan_layer(eth, 1); - } - return 0; - default: -@@ -337,34 +357,42 @@ int mtk_foe_entry_set_vlan(struct mtk_fo - } - } - --int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid) -+int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int sid) - { -- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); -+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); - -- if (!(entry->ib1 & MTK_FOE_IB1_BIND_VLAN_LAYER) || -- (entry->ib1 & MTK_FOE_IB1_BIND_VLAN_TAG)) -+ if (!(entry->ib1 & mtk_get_ib1_vlan_layer_mask(eth)) || -+ (entry->ib1 & mtk_get_ib1_vlan_tag_mask(eth))) - l2->etype = ETH_P_PPP_SES; - -- entry->ib1 |= MTK_FOE_IB1_BIND_PPPOE; -+ entry->ib1 |= mtk_get_ib1_ppoe_mask(eth); - l2->pppoe_id = sid; - - return 0; - } - --int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, -- int bss, int wcid) -+int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int wdma_idx, int txq, int bss, int wcid) - { -- struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry); -- u32 *ib2 = mtk_foe_entry_ib2(entry); -+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); -+ u32 *ib2 = mtk_foe_entry_ib2(eth, entry); - -- *ib2 &= ~MTK_FOE_IB2_PORT_MG; -- *ib2 |= MTK_FOE_IB2_WDMA_WINFO; -- if (wdma_idx) -- *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; -- -- l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | -- FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | -- FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ *ib2 &= ~MTK_FOE_IB2_PORT_MG_V2; -+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq) | -+ MTK_FOE_IB2_WDMA_WINFO_V2; -+ l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) | -+ FIELD_PREP(MTK_FOE_WINFO_BSS, bss); -+ } else { -+ *ib2 &= ~MTK_FOE_IB2_PORT_MG; -+ *ib2 |= MTK_FOE_IB2_WDMA_WINFO; -+ if (wdma_idx) -+ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX; -+ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) | -+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) | -+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq); -+ } - - return 0; - } -@@ -376,14 +404,15 @@ static inline bool mtk_foe_entry_usable( - } - - static bool --mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data) -+mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry, -+ struct mtk_foe_entry *data) - { - int type, len; - - if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP) - return false; - -- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); -+ type = mtk_get_ib1_pkt_type(eth, entry->data.ib1); - if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE) - len = offsetof(struct mtk_foe_entry, ipv6._rsv); - else -@@ -427,14 +456,12 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - - static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1) - { -- u16 timestamp; -- u16 now; -- -- now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP; -- timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; -+ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); -+ u16 now = mtk_eth_timestamp(ppe->eth); -+ u16 timestamp = ib1 & ib1_ts_mask; - - if (timestamp > now) -- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now; -+ return ib1_ts_mask + 1 - timestamp + now; - else - return now - timestamp; - } -@@ -442,6 +469,7 @@ static int __mtk_foe_entry_idle_time(str - static void - mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { -+ u32 ib1_ts_mask = mtk_get_ib1_ts_mask(ppe->eth); - struct mtk_flow_entry *cur; - struct mtk_foe_entry *hwe; - struct hlist_node *tmp; -@@ -466,8 +494,8 @@ mtk_flow_entry_update_l2(struct mtk_ppe - continue; - - idle = cur_idle; -- entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; -- entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP; -+ entry->data.ib1 &= ~ib1_ts_mask; -+ entry->data.ib1 |= hwe->ib1 & ib1_ts_mask; - } - } - -@@ -489,7 +517,7 @@ mtk_flow_entry_update(struct mtk_ppe *pp - - hwe = mtk_foe_get_entry(ppe, entry->hash); - memcpy(&foe, hwe, ppe->eth->soc->foe_entry_size); -- if (!mtk_flow_entry_match(entry, &foe)) { -+ if (!mtk_flow_entry_match(ppe->eth, entry, &foe)) { - entry->hash = 0xffff; - goto out; - } -@@ -504,16 +532,22 @@ static void - __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry, - u16 hash) - { -+ struct mtk_eth *eth = ppe->eth; -+ u16 timestamp = mtk_eth_timestamp(eth); - struct mtk_foe_entry *hwe; -- u16 timestamp; - -- timestamp = mtk_eth_timestamp(ppe->eth); -- timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP; -- entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; -- entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; -+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP_V2, -+ timestamp); -+ } else { -+ entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP; -+ entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, -+ timestamp); -+ } - - hwe = mtk_foe_get_entry(ppe, hash); -- memcpy(&hwe->data, &entry->data, ppe->eth->soc->foe_entry_size); -+ memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size); - wmb(); - hwe->ib1 = entry->ib1; - -@@ -540,8 +574,8 @@ mtk_foe_entry_commit_l2(struct mtk_ppe * - - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) - { -- int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1); - const struct mtk_soc_data *soc = ppe->eth->soc; -+ int type = mtk_get_ib1_pkt_type(ppe->eth, entry->data.ib1); - u32 hash; - - if (type == MTK_PPE_PKT_TYPE_BRIDGE) -@@ -564,7 +598,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ - struct mtk_flow_entry *flow_info; - struct mtk_foe_entry foe = {}, *hwe; - struct mtk_foe_mac_info *l2; -- u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP; -+ u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; - int type; - - flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), -@@ -584,16 +618,16 @@ mtk_foe_entry_commit_subflow(struct mtk_ - foe.ib1 &= ib1_mask; - foe.ib1 |= entry->data.ib1 & ~ib1_mask; - -- l2 = mtk_foe_entry_l2(&foe); -+ l2 = mtk_foe_entry_l2(ppe->eth, &foe); - memcpy(l2, &entry->data.bridge.l2, sizeof(*l2)); - -- type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1); -+ type = mtk_get_ib1_pkt_type(ppe->eth, foe.ib1); - if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT) - memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new)); - else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP) - l2->etype = ETH_P_IPV6; - -- *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2; -+ *mtk_foe_entry_ib2(ppe->eth, &foe) = entry->data.bridge.ib2; - - __mtk_foe_entry_commit(ppe, &foe, hash); - } -@@ -626,7 +660,7 @@ void __mtk_ppe_check_skb(struct mtk_ppe - continue; - } - -- if (found || !mtk_flow_entry_match(entry, hwe)) { -+ if (found || !mtk_flow_entry_match(ppe->eth, entry, hwe)) { - if (entry->hash != 0xffff) - entry->hash = 0xffff; - continue; -@@ -771,6 +805,8 @@ void mtk_ppe_start(struct mtk_ppe *ppe) - MTK_PPE_SCAN_MODE_KEEPALIVE_AGE) | - FIELD_PREP(MTK_PPE_TB_CFG_ENTRY_NUM, - MTK_PPE_ENTRIES_SHIFT); -+ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) -+ val |= MTK_PPE_TB_CFG_INFO_SEL; - ppe_w32(ppe, MTK_PPE_TB_CFG, val); - - ppe_w32(ppe, MTK_PPE_IP_PROTO_CHK, -@@ -778,15 +814,21 @@ void mtk_ppe_start(struct mtk_ppe *ppe) - - mtk_ppe_cache_enable(ppe, true); - -- val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | -- MTK_PPE_FLOW_CFG_IP4_UDP_FRAG | -- MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | -+ val = MTK_PPE_FLOW_CFG_IP6_3T_ROUTE | - MTK_PPE_FLOW_CFG_IP6_5T_ROUTE | - MTK_PPE_FLOW_CFG_IP6_6RD | - MTK_PPE_FLOW_CFG_IP4_NAT | - MTK_PPE_FLOW_CFG_IP4_NAPT | - MTK_PPE_FLOW_CFG_IP4_DSLITE | - MTK_PPE_FLOW_CFG_IP4_NAT_FRAG; -+ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) -+ val |= MTK_PPE_MD_TOAP_BYP_CRSN0 | -+ MTK_PPE_MD_TOAP_BYP_CRSN1 | -+ MTK_PPE_MD_TOAP_BYP_CRSN2 | -+ MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY; -+ else -+ val |= MTK_PPE_FLOW_CFG_IP4_TCP_FRAG | -+ MTK_PPE_FLOW_CFG_IP4_UDP_FRAG; - ppe_w32(ppe, MTK_PPE_FLOW_CFG, val); - - val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) | -@@ -820,6 +862,11 @@ void mtk_ppe_start(struct mtk_ppe *ppe) - ppe_w32(ppe, MTK_PPE_GLO_CFG, val); - - ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0); -+ -+ if (MTK_HAS_CAPS(ppe->eth->soc->caps, MTK_NETSYS_V2)) { -+ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); -+ ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); -+ } - } - - int mtk_ppe_stop(struct mtk_ppe *ppe) ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -32,6 +32,15 @@ - #define MTK_FOE_IB1_UDP BIT(30) - #define MTK_FOE_IB1_STATIC BIT(31) - -+/* CONFIG_MEDIATEK_NETSYS_V2 */ -+#define MTK_FOE_IB1_BIND_TIMESTAMP_V2 GENMASK(7, 0) -+#define MTK_FOE_IB1_BIND_VLAN_LAYER_V2 GENMASK(16, 14) -+#define MTK_FOE_IB1_BIND_PPPOE_V2 BIT(17) -+#define MTK_FOE_IB1_BIND_VLAN_TAG_V2 BIT(18) -+#define MTK_FOE_IB1_BIND_CACHE_V2 BIT(20) -+#define MTK_FOE_IB1_BIND_TTL_V2 BIT(22) -+#define MTK_FOE_IB1_PACKET_TYPE_V2 GENMASK(27, 23) -+ - enum { - MTK_PPE_PKT_TYPE_IPV4_HNAPT = 0, - MTK_PPE_PKT_TYPE_IPV4_ROUTE = 1, -@@ -53,14 +62,25 @@ enum { - - #define MTK_FOE_IB2_PORT_MG GENMASK(17, 12) - -+#define MTK_FOE_IB2_RX_IDX GENMASK(18, 17) - #define MTK_FOE_IB2_PORT_AG GENMASK(23, 18) - - #define MTK_FOE_IB2_DSCP GENMASK(31, 24) - -+/* CONFIG_MEDIATEK_NETSYS_V2 */ -+#define MTK_FOE_IB2_PORT_MG_V2 BIT(7) -+#define MTK_FOE_IB2_DEST_PORT_V2 GENMASK(12, 9) -+#define MTK_FOE_IB2_MULTICAST_V2 BIT(13) -+#define MTK_FOE_IB2_WDMA_WINFO_V2 BIT(19) -+#define MTK_FOE_IB2_PORT_AG_V2 GENMASK(23, 20) -+ - #define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0) - #define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6) - #define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14) - -+#define MTK_FOE_WINFO_BSS GENMASK(5, 0) -+#define MTK_FOE_WINFO_WCID GENMASK(15, 6) -+ - enum { - MTK_FOE_STATE_INVALID, - MTK_FOE_STATE_UNBIND, -@@ -81,6 +101,9 @@ struct mtk_foe_mac_info { - - u16 pppoe_id; - u16 src_mac_lo; -+ -+ u16 minfo; -+ u16 winfo; - }; - - /* software-only entry type */ -@@ -198,7 +221,7 @@ struct mtk_foe_entry { - struct mtk_foe_ipv4_dslite dslite; - struct mtk_foe_ipv6 ipv6; - struct mtk_foe_ipv6_6rd ipv6_6rd; -- u32 data[19]; -+ u32 data[23]; - }; - }; - -@@ -306,20 +329,27 @@ mtk_ppe_check_skb(struct mtk_ppe *ppe, s - __mtk_ppe_check_skb(ppe, skb, hash); - } - --int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto, -- u8 pse_port, u8 *src_mac, u8 *dest_mac); --int mtk_foe_entry_set_pse_port(struct mtk_foe_entry *entry, u8 port); --int mtk_foe_entry_set_ipv4_tuple(struct mtk_foe_entry *entry, bool orig, -+int mtk_foe_entry_prepare(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int type, int l4proto, u8 pse_port, u8 *src_mac, -+ u8 *dest_mac); -+int mtk_foe_entry_set_pse_port(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, u8 port); -+int mtk_foe_entry_set_ipv4_tuple(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, bool orig, - __be32 src_addr, __be16 src_port, - __be32 dest_addr, __be16 dest_port); --int mtk_foe_entry_set_ipv6_tuple(struct mtk_foe_entry *entry, -+int mtk_foe_entry_set_ipv6_tuple(struct mtk_eth *eth, -+ struct mtk_foe_entry *entry, - __be32 *src_addr, __be16 src_port, - __be32 *dest_addr, __be16 dest_port); --int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port); --int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid); --int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid); --int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq, -- int bss, int wcid); -+int mtk_foe_entry_set_dsa(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int port); -+int mtk_foe_entry_set_vlan(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int vid); -+int mtk_foe_entry_set_pppoe(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int sid); -+int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry, -+ int wdma_idx, int txq, int bss, int wcid); - int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); - void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); - int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); ---- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c -@@ -52,18 +52,19 @@ static const struct rhashtable_params mt - }; - - static int --mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data, -- bool egress) -+mtk_flow_set_ipv4_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe, -+ struct mtk_flow_data *data, bool egress) - { -- return mtk_foe_entry_set_ipv4_tuple(foe, egress, -+ return mtk_foe_entry_set_ipv4_tuple(eth, foe, egress, - data->v4.src_addr, data->src_port, - data->v4.dst_addr, data->dst_port); - } - - static int --mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data) -+mtk_flow_set_ipv6_addr(struct mtk_eth *eth, struct mtk_foe_entry *foe, -+ struct mtk_flow_data *data) - { -- return mtk_foe_entry_set_ipv6_tuple(foe, -+ return mtk_foe_entry_set_ipv6_tuple(eth, foe, - data->v6.src_addr.s6_addr32, data->src_port, - data->v6.dst_addr.s6_addr32, data->dst_port); - } -@@ -190,16 +191,29 @@ mtk_flow_set_output_device(struct mtk_et - int pse_port, dsa_port; - - if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) { -- mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss, -- info.wcid); -- pse_port = 3; -+ mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue, -+ info.bss, info.wcid); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -+ switch (info.wdma_idx) { -+ case 0: -+ pse_port = 8; -+ break; -+ case 1: -+ pse_port = 9; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } else { -+ pse_port = 3; -+ } - *wed_index = info.wdma_idx; - goto out; - } - - dsa_port = mtk_flow_get_dsa_port(&dev); - if (dsa_port >= 0) -- mtk_foe_entry_set_dsa(foe, dsa_port); -+ mtk_foe_entry_set_dsa(eth, foe, dsa_port); - - if (dev == eth->netdev[0]) - pse_port = 1; -@@ -209,7 +223,7 @@ mtk_flow_set_output_device(struct mtk_et - return -EOPNOTSUPP; - - out: -- mtk_foe_entry_set_pse_port(foe, pse_port); -+ mtk_foe_entry_set_pse_port(eth, foe, pse_port); - - return 0; - } -@@ -333,9 +347,8 @@ mtk_flow_offload_replace(struct mtk_eth - !is_valid_ether_addr(data.eth.h_dest)) - return -EINVAL; - -- err = mtk_foe_entry_prepare(&foe, offload_type, l4proto, 0, -- data.eth.h_source, -- data.eth.h_dest); -+ err = mtk_foe_entry_prepare(eth, &foe, offload_type, l4proto, 0, -+ data.eth.h_source, data.eth.h_dest); - if (err) - return err; - -@@ -360,7 +373,7 @@ mtk_flow_offload_replace(struct mtk_eth - data.v4.src_addr = addrs.key->src; - data.v4.dst_addr = addrs.key->dst; - -- mtk_flow_set_ipv4_addr(&foe, &data, false); -+ mtk_flow_set_ipv4_addr(eth, &foe, &data, false); - } - - if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) { -@@ -371,7 +384,7 @@ mtk_flow_offload_replace(struct mtk_eth - data.v6.src_addr = addrs.key->src; - data.v6.dst_addr = addrs.key->dst; - -- mtk_flow_set_ipv6_addr(&foe, &data); -+ mtk_flow_set_ipv6_addr(eth, &foe, &data); - } - - flow_action_for_each(i, act, &rule->action) { -@@ -401,7 +414,7 @@ mtk_flow_offload_replace(struct mtk_eth - } - - if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { -- err = mtk_flow_set_ipv4_addr(&foe, &data, true); -+ err = mtk_flow_set_ipv4_addr(eth, &foe, &data, true); - if (err) - return err; - } -@@ -413,10 +426,10 @@ mtk_flow_offload_replace(struct mtk_eth - if (data.vlan.proto != htons(ETH_P_8021Q)) - return -EOPNOTSUPP; - -- mtk_foe_entry_set_vlan(&foe, data.vlan.id); -+ mtk_foe_entry_set_vlan(eth, &foe, data.vlan.id); - } - if (data.pppoe.num == 1) -- mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid); -+ mtk_foe_entry_set_pppoe(eth, &foe, data.pppoe.sid); - - err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest, - &wed_index); ---- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h -@@ -21,6 +21,9 @@ - #define MTK_PPE_GLO_CFG_BUSY BIT(31) - - #define MTK_PPE_FLOW_CFG 0x204 -+#define MTK_PPE_MD_TOAP_BYP_CRSN0 BIT(1) -+#define MTK_PPE_MD_TOAP_BYP_CRSN1 BIT(2) -+#define MTK_PPE_MD_TOAP_BYP_CRSN2 BIT(3) - #define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6) - #define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7) - #define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8) -@@ -54,6 +57,7 @@ - #define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14) - #define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16) - #define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18) -+#define MTK_PPE_TB_CFG_INFO_SEL BIT(20) - - enum { - MTK_PPE_SCAN_MODE_DISABLED, -@@ -112,6 +116,8 @@ enum { - #define MTK_PPE_DEFAULT_CPU_PORT 0x248 - #define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4)) - -+#define MTK_PPE_DEFAULT_CPU_PORT1 0x24c -+ - #define MTK_PPE_MTU_DROP 0x308 - - #define MTK_PPE_VLAN_MTU0 0x30c -@@ -141,4 +147,6 @@ enum { - #define MTK_PPE_MIB_CACHE_CTL_EN BIT(0) - #define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2) - -+#define MTK_PPE_SBW_CTRL 0x374 -+ - #endif diff --git a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch deleted file mode 100644 index e8bb85ac940..00000000000 --- a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-enable-flow-offloading-supp.patch +++ /dev/null @@ -1,26 +0,0 @@ -From b94b02a270471337bef73c44fa3493a521e31a61 Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: -References: -From: Lorenzo Bianconi -Date: Mon, 5 Sep 2022 13:56:13 +0200 -Subject: [PATCH net-next 5/5] net: ethernet: mtk_eth_soc: enable flow - offloading support for mt7986 - -Enable hw packet engine and wireless packet dispatcher for mt7986 - -Signed-off-by: Lorenzo Bianconi ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4259,6 +4259,7 @@ static const struct mtk_soc_data mt7986_ - .hw_features = MTK_HW_FEATURES, - .required_clks = MT7986_CLKS_BITMAP, - .required_pctl = false, -+ .offload_version = 2, - .hash_offset = 4, - .foe_entry_size = sizeof(struct mtk_foe_entry), - .txrx = { diff --git a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch b/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch deleted file mode 100644 index c4bd29365c7..00000000000 --- a/target/linux/generic/backport-6.1/724-v6.0-net-ethernet-mtk_eth_soc-fix-wrong-use-of-new-helper.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 40350ce3ae8701146aafd79c5f7b5582d9955e58 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sun, 25 Sep 2022 15:12:35 +0100 -Subject: [PATCH 1/2] net: ethernet: mtk_eth_soc: fix wrong use of new helper - function -To: linux-mediatek@lists.infradead.org, - netdev@vger.kernel.org, - Lorenzo Bianconi -Cc: Sujuan Chen , - Bo Jiao , - Felix Fietkau , - John Crispin , - Sean Wang , - Mark Lee , - David S. Miller , - Eric Dumazet , - Jakub Kicinski , - Paolo Abeni , - Matthias Brugger , - Chen Minqiang - -In function mtk_foe_entry_set_vlan() the call to field accessor macro -FIELD_GET(MTK_FOE_IB1_BIND_VLAN_LAYER, entry->ib1) -has been wrongly replaced by -mtk_prep_ib1_vlan_layer(eth, entry->ib1) - -Use correct helper function mtk_get_ib1_vlan_layer instead. - -Reported-by: Chen Minqiang -Fixes: 03a3180e5c09e1 ("net: ethernet: mtk_eth_soc: introduce flow offloading support for mt7986") -Signed-off-by: Daniel Golle ---- - drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -337,7 +337,7 @@ int mtk_foe_entry_set_vlan(struct mtk_et - { - struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(eth, entry); - -- switch (mtk_prep_ib1_vlan_layer(eth, entry->ib1)) { -+ switch (mtk_get_ib1_vlan_layer(eth, entry->ib1)) { - case 0: - entry->ib1 |= mtk_get_ib1_vlan_tag_mask(eth) | - mtk_prep_ib1_vlan_layer(eth, 1); diff --git a/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch b/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch deleted file mode 100644 index bb02f401a2d..00000000000 --- a/target/linux/generic/backport-6.1/725-v6.0-net-ethernet-mtk_eth_soc-fix-usage-of-foe_entry_size.patch +++ /dev/null @@ -1,49 +0,0 @@ -From fcf14c2c5deae8f8c3d25530bab10856f63f8a63 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sun, 25 Sep 2022 15:18:54 +0100 -Subject: [PATCH 2/2] net: ethernet: mtk_eth_soc: fix usage of foe_entry_size -To: linux-mediatek@lists.infradead.org, - netdev@vger.kernel.org, - Lorenzo Bianconi -Cc: Sujuan Chen , - Bo Jiao , - Felix Fietkau , - John Crispin , - Sean Wang , - Mark Lee , - David S. Miller , - Eric Dumazet , - Jakub Kicinski , - Paolo Abeni , - Matthias Brugger , - Chen Minqiang - -As sizeof(hwe->data) can now longer be used as the actual size depends -on foe_entry_size, in commit 9d8cb4c096ab02 -("net: ethernet: mtk_eth_soc: add foe_entry_size to mtk_eth_soc") the -use of sizeof(hwe->data) is hence replaced. -However, replacing it with ppe->eth->soc->foe_entry_size is wrong as -foe_entry_size represents the size of the whole descriptor and not just -the 'data' field. -Fix this by subtracing the size of the only other field in the struct -'ib1', so we actually end up with the correct size to be copied to the -data field. - -Reported-by: Chen Minqiang -Fixes: 9d8cb4c096ab02 ("net: ethernet: mtk_eth_soc: add foe_entry_size to mtk_eth_soc") -Signed-off-by: Daniel Golle ---- - drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -547,7 +547,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p - } - - hwe = mtk_foe_get_entry(ppe, hash); -- memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size); -+ memcpy(&hwe->data, &entry->data, eth->soc->foe_entry_size - sizeof(hwe->ib1)); - wmb(); - hwe->ib1 = entry->ib1; - diff --git a/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch b/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch deleted file mode 100644 index 27c719b6635..00000000000 --- a/target/linux/generic/backport-6.1/726-v6.0-net-ethernet-mtk_eth_soc-fix-mask-of-RX_DMA_GET_SPOR.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c9da02bfb1112461e048d3b736afb1873f6f4ccf Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Tue, 27 Sep 2022 16:30:02 +0100 -Subject: [PATCH 1/1] net: ethernet: mtk_eth_soc: fix mask of - RX_DMA_GET_SPORT{,_V2} - -The bitmasks applied in RX_DMA_GET_SPORT and RX_DMA_GET_SPORT_V2 macros -were swapped. Fix that. - -Reported-by: Chen Minqiang -Fixes: 160d3a9b192985 ("net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support") -Acked-by: Lorenzo Bianconi -Signed-off-by: Daniel Golle -Link: https://lore.kernel.org/r/YzMW+mg9UsaCdKRQ@makrotopia.org -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -315,8 +315,8 @@ - #define MTK_RXD5_PPE_CPU_REASON GENMASK(22, 18) - #define MTK_RXD5_SRC_PORT GENMASK(29, 26) - --#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0xf) --#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0x7) -+#define RX_DMA_GET_SPORT(x) (((x) >> 19) & 0x7) -+#define RX_DMA_GET_SPORT_V2(x) (((x) >> 26) & 0xf) - - /* PDMA V2 descriptor rxd3 */ - #define RX_DMA_VTAG_V2 BIT(0) diff --git a/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch b/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch deleted file mode 100644 index 11465c1c5b7..00000000000 --- a/target/linux/generic/backport-6.1/727-v6.1-net-ethernet-mtk_eth_soc-fix-state-in-__mtk_foe_entr.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ae3ed15da5889263de372ff9df2e83e16acca4cb Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Fri, 30 Sep 2022 01:56:53 +0100 -Subject: [PATCH 1/1] net: ethernet: mtk_eth_soc: fix state in - __mtk_foe_entry_clear - -Setting ib1 state to MTK_FOE_STATE_UNBIND in __mtk_foe_entry_clear -routine as done by commit 0e80707d94e4c8 ("net: ethernet: mtk_eth_soc: -fix typo in __mtk_foe_entry_clear") breaks flow offloading, at least -on older MTK_NETSYS_V1 SoCs, OpenWrt users have confirmed the bug on -MT7622 and MT7621 systems. -Felix Fietkau suggested to use MTK_FOE_STATE_INVALID instead which -works well on both, MTK_NETSYS_V1 and MTK_NETSYS_V2. - -Tested on MT7622 (Linksys E8450) and MT7986 (BananaPi BPI-R3). - -Suggested-by: Felix Fietkau -Fixes: 0e80707d94e4c8 ("net: ethernet: mtk_eth_soc: fix typo in __mtk_foe_entry_clear") -Fixes: 33fc42de33278b ("net: ethernet: mtk_eth_soc: support creating mac address based offload entries") -Signed-off-by: Daniel Golle -Link: https://lore.kernel.org/r/YzY+1Yg0FBXcnrtc@makrotopia.org -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/mediatek/mtk_ppe.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -442,7 +442,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); - - hwe->ib1 &= ~MTK_FOE_IB1_STATE; -- hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_UNBIND); -+ hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); - dma_wmb(); - } - entry->hash = 0xffff; diff --git a/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch b/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch deleted file mode 100644 index b41318afd76..00000000000 --- a/target/linux/generic/backport-6.1/728-v6.1-01-net-ethernet-mtk_eth_soc-fix-possible-memory-leak-in.patch +++ /dev/null @@ -1,73 +0,0 @@ -From b3d0d98179d62f9d55635a600679c4fa362baf8d Mon Sep 17 00:00:00 2001 -From: Yang Yingliang -Date: Mon, 17 Oct 2022 11:51:54 +0800 -Subject: [PATCH 1/3] net: ethernet: mtk_eth_soc: fix possible memory leak in - mtk_probe() - -If mtk_wed_add_hw() has been called, mtk_wed_exit() needs be called -in error path or removing module to free the memory allocated in -mtk_wed_add_hw(). - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Signed-off-by: Yang Yingliang -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_eth_soc.c | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4011,19 +4011,23 @@ static int mtk_probe(struct platform_dev - eth->irq[i] = platform_get_irq(pdev, i); - if (eth->irq[i] < 0) { - dev_err(&pdev->dev, "no IRQ%d resource found\n", i); -- return -ENXIO; -+ err = -ENXIO; -+ goto err_wed_exit; - } - } - for (i = 0; i < ARRAY_SIZE(eth->clks); i++) { - eth->clks[i] = devm_clk_get(eth->dev, - mtk_clks_source_name[i]); - if (IS_ERR(eth->clks[i])) { -- if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) -- return -EPROBE_DEFER; -+ if (PTR_ERR(eth->clks[i]) == -EPROBE_DEFER) { -+ err = -EPROBE_DEFER; -+ goto err_wed_exit; -+ } - if (eth->soc->required_clks & BIT(i)) { - dev_err(&pdev->dev, "clock %s not found\n", - mtk_clks_source_name[i]); -- return -EINVAL; -+ err = -EINVAL; -+ goto err_wed_exit; - } - eth->clks[i] = NULL; - } -@@ -4034,7 +4038,7 @@ static int mtk_probe(struct platform_dev - - err = mtk_hw_init(eth); - if (err) -- return err; -+ goto err_wed_exit; - - eth->hwlro = MTK_HAS_CAPS(eth->soc->caps, MTK_HWLRO); - -@@ -4132,6 +4136,8 @@ err_free_dev: - mtk_free_dev(eth); - err_deinit_hw: - mtk_hw_deinit(eth); -+err_wed_exit: -+ mtk_wed_exit(); - - return err; - } -@@ -4151,6 +4157,7 @@ static int mtk_remove(struct platform_de - phylink_disconnect_phy(mac->phylink); - } - -+ mtk_wed_exit(); - mtk_hw_deinit(eth); - - netif_napi_del(ð->tx_napi); diff --git a/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch b/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch deleted file mode 100644 index ef5374dcc57..00000000000 --- a/target/linux/generic/backport-6.1/728-v6.1-02-net-ethernet-mtk_eth_wed-add-missing-put_device-in-m.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 9d4f20a476ca57e4c9246eb1fa2a61bea2354720 Mon Sep 17 00:00:00 2001 -From: Yang Yingliang -Date: Mon, 17 Oct 2022 11:51:55 +0800 -Subject: [PATCH 2/3] net: ethernet: mtk_eth_wed: add missing put_device() in - mtk_wed_add_hw() - -After calling get_device() in mtk_wed_add_hw(), in error path, put_device() -needs be called. - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Signed-off-by: Yang Yingliang -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_wed.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -1084,11 +1084,11 @@ void mtk_wed_add_hw(struct device_node * - get_device(&pdev->dev); - irq = platform_get_irq(pdev, 0); - if (irq < 0) -- return; -+ goto err_put_device; - - regs = syscon_regmap_lookup_by_phandle(np, NULL); - if (IS_ERR(regs)) -- return; -+ goto err_put_device; - - rcu_assign_pointer(mtk_soc_wed_ops, &wed_ops); - -@@ -1131,8 +1131,14 @@ void mtk_wed_add_hw(struct device_node * - - hw_list[index] = hw; - -+ mutex_unlock(&hw_lock); -+ -+ return; -+ - unlock: - mutex_unlock(&hw_lock); -+err_put_device: -+ put_device(&pdev->dev); - } - - void mtk_wed_exit(void) diff --git a/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch b/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch deleted file mode 100644 index 0a452d4a7d4..00000000000 --- a/target/linux/generic/backport-6.1/728-v6.1-03-net-ethernet-mtk_eth_wed-add-missing-of_node_put.patch +++ /dev/null @@ -1,43 +0,0 @@ -From e0bb4659e235770e6f53b3692e958591f49448f5 Mon Sep 17 00:00:00 2001 -From: Yang Yingliang -Date: Mon, 17 Oct 2022 11:51:56 +0800 -Subject: [PATCH 3/3] net: ethernet: mtk_eth_wed: add missing of_node_put() - -The device_node pointer returned by of_parse_phandle() with refcount -incremented, when finish using it, the refcount need be decreased. - -Fixes: 804775dfc288 ("net: ethernet: mtk_eth_soc: add support for Wireless Ethernet Dispatch (WED)") -Signed-off-by: Yang Yingliang -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/mediatek/mtk_wed.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/drivers/net/ethernet/mediatek/mtk_wed.c -+++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -1079,7 +1079,7 @@ void mtk_wed_add_hw(struct device_node * - - pdev = of_find_device_by_node(np); - if (!pdev) -- return; -+ goto err_of_node_put; - - get_device(&pdev->dev); - irq = platform_get_irq(pdev, 0); -@@ -1139,6 +1139,8 @@ unlock: - mutex_unlock(&hw_lock); - err_put_device: - put_device(&pdev->dev); -+err_of_node_put: -+ of_node_put(np); - } - - void mtk_wed_exit(void) -@@ -1159,6 +1161,7 @@ void mtk_wed_exit(void) - hw_list[i] = NULL; - debugfs_remove(hw->debugfs_dir); - put_device(hw->dev); -+ of_node_put(hw->node); - kfree(hw); - } - } diff --git a/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch b/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch deleted file mode 100644 index 003ca9bae69..00000000000 --- a/target/linux/generic/backport-6.1/729-06-v6.1-net-ethernet-mtk_eth_soc-do-not-overwrite-mtu-config.patch +++ /dev/null @@ -1,98 +0,0 @@ -From: Lorenzo Bianconi -Date: Thu, 17 Nov 2022 00:35:04 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: do not overwrite mtu - configuration running reset routine - -Restore user configured MTU running mtk_hw_init() during tx timeout routine -since it will be overwritten after a hw reset. - -Reported-by: Felix Fietkau -Fixes: 9ea4d311509f ("net: ethernet: mediatek: add the whole ethernet reset into the reset process") -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3176,6 +3176,30 @@ static void mtk_dim_tx(struct work_struc - dim->state = DIM_START_MEASURE; - } - -+static void mtk_set_mcr_max_rx(struct mtk_mac *mac, u32 val) -+{ -+ struct mtk_eth *eth = mac->hw; -+ u32 mcr_cur, mcr_new; -+ -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) -+ return; -+ -+ mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); -+ mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; -+ -+ if (val <= 1518) -+ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1518); -+ else if (val <= 1536) -+ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1536); -+ else if (val <= 1552) -+ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1552); -+ else -+ mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_2048); -+ -+ if (mcr_new != mcr_cur) -+ mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); -+} -+ - static int mtk_hw_init(struct mtk_eth *eth) - { - u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3250,8 +3274,16 @@ static int mtk_hw_init(struct mtk_eth *e - * up with the more appropriate value when mtk_mac_config call is being - * invoked. - */ -- for (i = 0; i < MTK_MAC_COUNT; i++) -+ for (i = 0; i < MTK_MAC_COUNT; i++) { -+ struct net_device *dev = eth->netdev[i]; -+ - mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i)); -+ if (dev) { -+ struct mtk_mac *mac = netdev_priv(dev); -+ -+ mtk_set_mcr_max_rx(mac, dev->mtu + MTK_RX_ETH_HLEN); -+ } -+ } - - /* Indicates CDM to parse the MTK special tag from CPU - * which also is working out for untag packets. -@@ -3367,7 +3399,6 @@ static int mtk_change_mtu(struct net_dev - int length = new_mtu + MTK_RX_ETH_HLEN; - struct mtk_mac *mac = netdev_priv(dev); - struct mtk_eth *eth = mac->hw; -- u32 mcr_cur, mcr_new; - - if (rcu_access_pointer(eth->prog) && - length > MTK_PP_MAX_BUF_SIZE) { -@@ -3375,23 +3406,7 @@ static int mtk_change_mtu(struct net_dev - return -EINVAL; - } - -- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { -- mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); -- mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; -- -- if (length <= 1518) -- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1518); -- else if (length <= 1536) -- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1536); -- else if (length <= 1552) -- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_1552); -- else -- mcr_new |= MAC_MCR_MAX_RX(MAC_MCR_MAX_RX_2048); -- -- if (mcr_new != mcr_cur) -- mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); -- } -- -+ mtk_set_mcr_max_rx(mac, length); - dev->mtu = new_mtu; - - return 0; diff --git a/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch b/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch deleted file mode 100644 index 12aa3ebf6a7..00000000000 --- a/target/linux/generic/backport-6.1/729-08-v6.2-net-ethernet-mtk_eth_soc-fix-RSTCTRL_PPE-0-1-definit.patch +++ /dev/null @@ -1,63 +0,0 @@ -From: Lorenzo Bianconi -Date: Thu, 17 Nov 2022 15:29:53 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: fix RSTCTRL_PPE{0,1} definitions - -Fix RSTCTRL_PPE0 and RSTCTRL_PPE1 register mask definitions for -MTK_NETSYS_V2. -Remove duplicated definitions. - -Fixes: 160d3a9b1929 ("net: ethernet: mtk_eth_soc: introduce MTK_NETSYS_V2 support") -Signed-off-by: Lorenzo Bianconi -Signed-off-by: David S. Miller ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3239,16 +3239,17 @@ static int mtk_hw_init(struct mtk_eth *e - return 0; - } - -- val = RSTCTRL_FE | RSTCTRL_PPE; - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { - regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); -- -- val |= RSTCTRL_ETH; -- if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) -- val |= RSTCTRL_PPE1; -+ val = RSTCTRL_PPE0_V2; -+ } else { -+ val = RSTCTRL_PPE0; - } - -- ethsys_reset(eth, val); -+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_RSTCTRL_PPE1)) -+ val |= RSTCTRL_PPE1; -+ -+ ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val); - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { - regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -445,18 +445,14 @@ - /* ethernet reset control register */ - #define ETHSYS_RSTCTRL 0x34 - #define RSTCTRL_FE BIT(6) --#define RSTCTRL_PPE BIT(31) --#define RSTCTRL_PPE1 BIT(30) -+#define RSTCTRL_PPE0 BIT(31) -+#define RSTCTRL_PPE0_V2 BIT(30) -+#define RSTCTRL_PPE1 BIT(31) - #define RSTCTRL_ETH BIT(23) - - /* ethernet reset check idle register */ - #define ETHSYS_FE_RST_CHK_IDLE_EN 0x28 - --/* ethernet reset control register */ --#define ETHSYS_RSTCTRL 0x34 --#define RSTCTRL_FE BIT(6) --#define RSTCTRL_PPE BIT(31) -- - /* ethernet dma channel agent map */ - #define ETHSYS_DMA_AG_MAP 0x408 - #define ETHSYS_DMA_AG_MAP_PDMA BIT(0) diff --git a/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch b/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch deleted file mode 100644 index 0bf48b07800..00000000000 --- a/target/linux/generic/backport-6.1/730-10-v6.3-net-ethernet-mtk_eth_soc-drop-packets-to-WDMA-if-the.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Felix Fietkau -Date: Thu, 3 Nov 2022 17:46:25 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: drop packets to WDMA if the - ring is full - -Improves handling of DMA ring overflow. -Clarify other WDMA drop related comment. - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3712,9 +3712,12 @@ static int mtk_hw_init(struct mtk_eth *e - mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); - - if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { -- /* PSE should not drop port8 and port9 packets */ -+ /* PSE should not drop port8 and port9 packets from WDMA Tx */ - mtk_w32(eth, 0x00000300, PSE_DROP_CFG); - -+ /* PSE should drop packets to port 8/9 on WDMA Rx ring full */ -+ mtk_w32(eth, 0x00000300, PSE_PPE0_DROP); -+ - /* PSE Free Queue Flow Control */ - mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2); - ---- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h -+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -140,6 +140,7 @@ - #define PSE_FQFC_CFG1 0x100 - #define PSE_FQFC_CFG2 0x104 - #define PSE_DROP_CFG 0x108 -+#define PSE_PPE0_DROP 0x110 - - /* PSE Input Queue Reservation Register*/ - #define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2)) diff --git a/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch b/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch deleted file mode 100644 index 460c5c23178..00000000000 --- a/target/linux/generic/backport-6.1/733-v6.2-01-net-ethernet-mtk_eth_soc-Avoid-truncating-allocation.patch +++ /dev/null @@ -1,60 +0,0 @@ -From f3eceaed9edd7c0e0d9fb057613131f92973626f Mon Sep 17 00:00:00 2001 -From: Kees Cook -Date: Fri, 27 Jan 2023 14:38:54 -0800 -Subject: [PATCH] net: ethernet: mtk_eth_soc: Avoid truncating allocation - -There doesn't appear to be a reason to truncate the allocation used for -flow_info, so do a full allocation and remove the unused empty struct. -GCC does not like having a reference to an object that has been -partially allocated, as bounds checking may become impossible when -such an object is passed to other code. Seen with GCC 13: - -../drivers/net/ethernet/mediatek/mtk_ppe.c: In function 'mtk_foe_entry_commit_subflow': -../drivers/net/ethernet/mediatek/mtk_ppe.c:623:18: warning: array subscript 'struct mtk_flow_entry[0]' is partly outside array bounds of 'unsigned char[48]' [-Warray-bounds=] - 623 | flow_info->l2_data.base_flow = entry; - | ^~ - -Cc: Felix Fietkau -Cc: John Crispin -Cc: Sean Wang -Cc: Mark Lee -Cc: Lorenzo Bianconi -Cc: "David S. Miller" -Cc: Eric Dumazet -Cc: Jakub Kicinski -Cc: Paolo Abeni -Cc: Matthias Brugger -Cc: netdev@vger.kernel.org -Cc: linux-arm-kernel@lists.infradead.org -Cc: linux-mediatek@lists.infradead.org -Signed-off-by: Kees Cook -Reviewed-by: Simon Horman -Link: https://lore.kernel.org/r/20230127223853.never.014-kees@kernel.org -Signed-off-by: Paolo Abeni ---- - drivers/net/ethernet/mediatek/mtk_ppe.c | 3 +-- - drivers/net/ethernet/mediatek/mtk_ppe.h | 1 - - 2 files changed, 1 insertion(+), 3 deletions(-) - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -621,8 +621,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ - u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; - int type; - -- flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end), -- GFP_ATOMIC); -+ flow_info = kzalloc(sizeof(*flow_info), GFP_ATOMIC); - if (!flow_info) - return; - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.h -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h -@@ -279,7 +279,6 @@ struct mtk_flow_entry { - struct { - struct mtk_flow_entry *base_flow; - struct hlist_node list; -- struct {} end; - } l2_data; - }; - struct rhash_head node; diff --git a/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch b/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch deleted file mode 100644 index 6788a2ec350..00000000000 --- a/target/linux/generic/backport-6.1/734-v5.16-0001-net-bgmac-improve-handling-PHY.patch +++ /dev/null @@ -1,84 +0,0 @@ -From b5375509184dc23d2b7fa0c5ed8763899ccc9674 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Sat, 2 Oct 2021 19:58:11 +0200 -Subject: [PATCH] net: bgmac: improve handling PHY -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -1. Use info from DT if available - -It allows describing for example a fixed link. It's more accurate than -just guessing there may be one (depending on a chipset). - -2. Verify PHY ID before trying to connect PHY - -PHY addr 0x1e (30) is special in Broadcom routers and means a switch -connected as MDIO devices instead of a real PHY. Don't try connecting to -it. - -Signed-off-by: Rafał Miłecki -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/broadcom/bgmac-bcma.c | 33 ++++++++++++++-------- - 1 file changed, 21 insertions(+), 12 deletions(-) - ---- a/drivers/net/ethernet/broadcom/bgmac-bcma.c -+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - #include - #include "bgmac.h" - -@@ -86,17 +87,28 @@ static int bcma_phy_connect(struct bgmac - struct phy_device *phy_dev; - char bus_id[MII_BUS_ID_SIZE + 3]; - -+ /* DT info should be the most accurate */ -+ phy_dev = of_phy_get_and_connect(bgmac->net_dev, bgmac->dev->of_node, -+ bgmac_adjust_link); -+ if (phy_dev) -+ return 0; -+ - /* Connect to the PHY */ -- snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id, -- bgmac->phyaddr); -- phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link, -- PHY_INTERFACE_MODE_MII); -- if (IS_ERR(phy_dev)) { -- dev_err(bgmac->dev, "PHY connection failed\n"); -- return PTR_ERR(phy_dev); -+ if (bgmac->mii_bus && bgmac->phyaddr != BGMAC_PHY_NOREGS) { -+ snprintf(bus_id, sizeof(bus_id), PHY_ID_FMT, bgmac->mii_bus->id, -+ bgmac->phyaddr); -+ phy_dev = phy_connect(bgmac->net_dev, bus_id, bgmac_adjust_link, -+ PHY_INTERFACE_MODE_MII); -+ if (IS_ERR(phy_dev)) { -+ dev_err(bgmac->dev, "PHY connection failed\n"); -+ return PTR_ERR(phy_dev); -+ } -+ -+ return 0; - } - -- return 0; -+ /* Assume a fixed link to the switch port */ -+ return bgmac_phy_connect_direct(bgmac); - } - - static const struct bcma_device_id bgmac_bcma_tbl[] = { -@@ -297,10 +309,7 @@ static int bgmac_probe(struct bcma_devic - bgmac->cco_ctl_maskset = bcma_bgmac_cco_ctl_maskset; - bgmac->get_bus_clock = bcma_bgmac_get_bus_clock; - bgmac->cmn_maskset32 = bcma_bgmac_cmn_maskset32; -- if (bgmac->mii_bus) -- bgmac->phy_connect = bcma_phy_connect; -- else -- bgmac->phy_connect = bgmac_phy_connect_direct; -+ bgmac->phy_connect = bcma_phy_connect; - - err = bgmac_enet_probe(bgmac); - if (err) diff --git a/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch b/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch deleted file mode 100644 index f1348282739..00000000000 --- a/target/linux/generic/backport-6.1/734-v5.16-0002-net-bgmac-support-MDIO-described-in-DT.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 45c9d966688e7fad7f24bfc450547d91e4304d0b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Sat, 2 Oct 2021 19:58:12 +0200 -Subject: [PATCH] net: bgmac: support MDIO described in DT -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Check ethernet controller DT node for "mdio" subnode and use it with -of_mdiobus_register() when present. That allows specifying MDIO and its -PHY devices in a standard DT based way. - -This is required for BCM53573 SoC support. That family is sometimes -called Northstar (by marketing?) but is quite different from it. It uses -different CPU(s) and many different hw blocks. - -One of shared blocks in BCM53573 is Ethernet controller. Switch however -is not SRAB accessible (as it Northstar) but is MDIO attached. - -Signed-off-by: Rafał Miłecki -Signed-off-by: David S. Miller ---- - drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c -+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c -@@ -10,6 +10,7 @@ - - #include - #include -+#include - #include "bgmac.h" - - static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask, -@@ -211,6 +212,7 @@ struct mii_bus *bcma_mdio_mii_register(s - { - struct bcma_device *core = bgmac->bcma.core; - struct mii_bus *mii_bus; -+ struct device_node *np; - int err; - - mii_bus = mdiobus_alloc(); -@@ -229,7 +231,9 @@ struct mii_bus *bcma_mdio_mii_register(s - mii_bus->parent = &core->dev; - mii_bus->phy_mask = ~(1 << bgmac->phyaddr); - -- err = mdiobus_register(mii_bus); -+ np = of_get_child_by_name(core->dev.of_node, "mdio"); -+ -+ err = of_mdiobus_register(mii_bus, np); - if (err) { - dev_err(&core->dev, "Registration of mii bus failed\n"); - goto err_free_bus; diff --git a/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch b/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch deleted file mode 100644 index 8f000ba9187..00000000000 --- a/target/linux/generic/backport-6.1/742-v5.16-net-phy-at803x-add-support-for-qca-8327-internal-phy.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 0ccf8511182436183c031e8a2f740ae91a02c625 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 14 Sep 2021 14:33:45 +0200 -Subject: net: phy: at803x: add support for qca 8327 internal phy - -Add support for qca8327 internal phy needed for correct init of the -switch port. It does use the same qca8337 function and reg just with a -different id. - -Signed-off-by: Ansuel Smith -Tested-by: Rosen Penev -Tested-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -1412,6 +1412,19 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -+}, { -+ /* QCA8327 */ -+ .phy_id = QCA8327_PHY_ID, -+ .phy_id_mask = QCA8K_PHY_ID_MASK, -+ .name = "QCA PHY 8327", -+ /* PHY_GBIT_FEATURES */ -+ .probe = at803x_probe, -+ .flags = PHY_IS_INTERNAL, -+ .config_init = qca83xx_config_init, -+ .soft_reset = genphy_soft_reset, -+ .get_sset_count = at803x_get_sset_count, -+ .get_strings = at803x_get_strings, -+ .get_stats = at803x_get_stats, - }, }; - - module_phy_driver(at803x_driver); -@@ -1422,6 +1435,8 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, -+ { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, -+ { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) }, - { } - }; - diff --git a/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch b/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch deleted file mode 100644 index dc149a742b1..00000000000 --- a/target/linux/generic/backport-6.1/743-v5.16-0001-net-dsa-b53-Include-all-ports-in-enabled_ports.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 983d96a9116a328668601555d96736261d33170c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Thu, 16 Sep 2021 14:03:51 +0200 -Subject: [PATCH] net: dsa: b53: Include all ports in "enabled_ports" -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Make "enabled_ports" bitfield contain all available switch ports -including a CPU port. This way there is no need for fixup during -initialization. - -For BCM53010, BCM53018 and BCM53019 include also other available ports. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Tested-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/b53/b53_common.c | 23 +++++++++++------------ - 1 file changed, 11 insertions(+), 12 deletions(-) - ---- a/drivers/net/dsa/b53/b53_common.c -+++ b/drivers/net/dsa/b53/b53_common.c -@@ -2300,7 +2300,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5325_DEVICE_ID, - .dev_name = "BCM5325", - .vlans = 16, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x3f, - .arl_bins = 2, - .arl_buckets = 1024, - .imp_port = 5, -@@ -2311,7 +2311,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5365_DEVICE_ID, - .dev_name = "BCM5365", - .vlans = 256, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x3f, - .arl_bins = 2, - .arl_buckets = 1024, - .imp_port = 5, -@@ -2322,7 +2322,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5389_DEVICE_ID, - .dev_name = "BCM5389", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x11f, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2336,7 +2336,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5395_DEVICE_ID, - .dev_name = "BCM5395", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x11f, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2350,7 +2350,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5397_DEVICE_ID, - .dev_name = "BCM5397", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x11f, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2364,7 +2364,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM5398_DEVICE_ID, - .dev_name = "BCM5398", - .vlans = 4096, -- .enabled_ports = 0x7f, -+ .enabled_ports = 0x17f, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2378,7 +2378,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM53115_DEVICE_ID, - .dev_name = "BCM53115", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x11f, - .arl_bins = 4, - .arl_buckets = 1024, - .vta_regs = B53_VTA_REGS, -@@ -2392,7 +2392,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM53125_DEVICE_ID, - .dev_name = "BCM53125", - .vlans = 4096, -- .enabled_ports = 0xff, -+ .enabled_ports = 0x1ff, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2434,7 +2434,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM53010_DEVICE_ID, - .dev_name = "BCM53010", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x1bf, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2476,7 +2476,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM53018_DEVICE_ID, - .dev_name = "BCM53018", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x1bf, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2490,7 +2490,7 @@ static const struct b53_chip_data b53_sw - .chip_id = BCM53019_DEVICE_ID, - .dev_name = "BCM53019", - .vlans = 4096, -- .enabled_ports = 0x1f, -+ .enabled_ports = 0x1bf, - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -@@ -2632,7 +2632,6 @@ static int b53_switch_init(struct b53_de - dev->cpu_port = 5; - } - -- dev->enabled_ports |= BIT(dev->cpu_port); - dev->num_ports = fls(dev->enabled_ports); - - dev->ds->num_ports = min_t(unsigned int, dev->num_ports, DSA_MAX_PORTS); diff --git a/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch b/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch deleted file mode 100644 index 23805a9027b..00000000000 --- a/target/linux/generic/backport-6.1/743-v5.16-0002-net-dsa-b53-Drop-BCM5301x-workaround-for-a-wrong-CPU.patch +++ /dev/null @@ -1,42 +0,0 @@ -From b290c6384afabbca5ae6e2af72fb1b2bc37922be Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Thu, 16 Sep 2021 14:03:52 +0200 -Subject: [PATCH] net: dsa: b53: Drop BCM5301x workaround for a wrong CPU/IMP - port -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -On BCM5301x port 8 requires a fixed link when used. - -Years ago when b53 was an OpenWrt downstream driver (with configuration -based on sometimes bugged NVRAM) there was a need for a fixup. In case -of forcing fixed link for (incorrectly specified) port 5 the code had to -actually setup port 8 link. - -For upstream b53 driver with setup based on DT there is no need for that -workaround. In DT we have and require correct ports setup. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Tested-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/b53/b53_common.c | 6 ------ - 1 file changed, 6 deletions(-) - ---- a/drivers/net/dsa/b53/b53_common.c -+++ b/drivers/net/dsa/b53/b53_common.c -@@ -1291,12 +1291,6 @@ static void b53_adjust_link(struct dsa_s - return; - } - } -- } else if (is5301x(dev)) { -- if (port != dev->cpu_port) { -- b53_force_port_config(dev, dev->cpu_port, 2000, -- DUPLEX_FULL, true, true); -- b53_force_link(dev, dev->cpu_port, 1); -- } - } - - /* Re-negotiate EEE if it was enabled already */ diff --git a/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch b/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch deleted file mode 100644 index 941fa23eb4c..00000000000 --- a/target/linux/generic/backport-6.1/743-v5.16-0003-net-dsa-b53-Improve-flow-control-setup-on-BCM5301x.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3ff26b29230c54fea2353b63124c589b61953e14 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Thu, 16 Sep 2021 14:03:53 +0200 -Subject: [PATCH] net: dsa: b53: Improve flow control setup on BCM5301x -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -According to the Broadcom's reference driver flow control needs to be -enabled for any CPU switch port (5, 7 or 8 - depending on which one is -used). Current code makes it work only for the port 5. Use -dsa_is_cpu_port() which solved that problem. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Tested-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/b53/b53_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/b53/b53_common.c -+++ b/drivers/net/dsa/b53/b53_common.c -@@ -1222,7 +1222,7 @@ static void b53_adjust_link(struct dsa_s - return; - - /* Enable flow control on BCM5301x's CPU port */ -- if (is5301x(dev) && port == dev->cpu_port) -+ if (is5301x(dev) && dsa_is_cpu_port(ds, port)) - tx_pause = rx_pause = true; - - if (phydev->pause) { diff --git a/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch b/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch deleted file mode 100644 index 07d0ec03cf1..00000000000 --- a/target/linux/generic/backport-6.1/743-v5.16-0004-net-dsa-b53-Drop-unused-cpu_port-field.patch +++ /dev/null @@ -1,205 +0,0 @@ -From 7d5af56418d7d01e43247a33b6fe6492ea871923 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Thu, 16 Sep 2021 14:03:54 +0200 -Subject: [PATCH] net: dsa: b53: Drop unused "cpu_port" field -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It's set but never used anymore. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Tested-by: Florian Fainelli -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/b53/b53_common.c | 28 ---------------------------- - drivers/net/dsa/b53/b53_priv.h | 1 - - 2 files changed, 29 deletions(-) - ---- a/drivers/net/dsa/b53/b53_common.c -+++ b/drivers/net/dsa/b53/b53_common.c -@@ -2298,7 +2298,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 2, - .arl_buckets = 1024, - .imp_port = 5, -- .cpu_port = B53_CPU_PORT_25, - .duplex_reg = B53_DUPLEX_STAT_FE, - }, - { -@@ -2309,7 +2308,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 2, - .arl_buckets = 1024, - .imp_port = 5, -- .cpu_port = B53_CPU_PORT_25, - .duplex_reg = B53_DUPLEX_STAT_FE, - }, - { -@@ -2320,7 +2318,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2334,7 +2331,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2348,7 +2344,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS_9798, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2362,7 +2357,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS_9798, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2377,7 +2371,6 @@ static const struct b53_chip_data b53_sw - .arl_buckets = 1024, - .vta_regs = B53_VTA_REGS, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, - .jumbo_size_reg = B53_JUMBO_MAX_SIZE, -@@ -2390,7 +2383,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2404,7 +2396,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2418,7 +2409,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS_63XX, - .duplex_reg = B53_DUPLEX_STAT_63XX, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK_63XX, -@@ -2432,7 +2422,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2446,7 +2435,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2460,7 +2448,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2474,7 +2461,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2488,7 +2474,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT_25, /* TODO: auto detect */ - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2502,7 +2487,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2516,7 +2500,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2545,7 +2528,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 1024, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2559,7 +2541,6 @@ static const struct b53_chip_data b53_sw - .arl_bins = 4, - .arl_buckets = 256, - .imp_port = 8, -- .cpu_port = B53_CPU_PORT, - .vta_regs = B53_VTA_REGS, - .duplex_reg = B53_DUPLEX_STAT_GE, - .jumbo_pm_reg = B53_JUMBO_PORT_MASK, -@@ -2585,7 +2566,6 @@ static int b53_switch_init(struct b53_de - dev->vta_regs[2] = chip->vta_regs[2]; - dev->jumbo_pm_reg = chip->jumbo_pm_reg; - dev->imp_port = chip->imp_port; -- dev->cpu_port = chip->cpu_port; - dev->num_vlans = chip->vlans; - dev->num_arl_bins = chip->arl_bins; - dev->num_arl_buckets = chip->arl_buckets; -@@ -2617,13 +2597,6 @@ static int b53_switch_init(struct b53_de - break; - #endif - } -- } else if (dev->chip_id == BCM53115_DEVICE_ID) { -- u64 strap_value; -- -- b53_read48(dev, B53_STAT_PAGE, B53_STRAP_VALUE, &strap_value); -- /* use second IMP port if GMII is enabled */ -- if (strap_value & SV_GMII_CTRL_115) -- dev->cpu_port = 5; - } - - dev->num_ports = fls(dev->enabled_ports); ---- a/drivers/net/dsa/b53/b53_priv.h -+++ b/drivers/net/dsa/b53/b53_priv.h -@@ -124,7 +124,6 @@ struct b53_device { - /* used ports mask */ - u16 enabled_ports; - unsigned int imp_port; -- unsigned int cpu_port; - - /* connect specific data */ - u8 current_page; diff --git a/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch b/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch deleted file mode 100644 index 99d91dfa765..00000000000 --- a/target/linux/generic/backport-6.1/745-v5.16-01-net-phy-at803x-add-support-for-qca-8327-A-variant.patch +++ /dev/null @@ -1,65 +0,0 @@ -From b4df02b562f4aa14ff6811f30e1b4d2159585c59 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 19 Sep 2021 18:28:15 +0200 -Subject: net: phy: at803x: add support for qca 8327 A variant internal phy - -For qca8327 internal phy there are 2 different switch variant with 2 -different phy id. Add this missing variant so the internal phy can be -correctly identified and fixed. - -Signed-off-by: Ansuel Smith -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 25 ++++++++++++++++++++----- - 1 file changed, 20 insertions(+), 5 deletions(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -150,7 +150,8 @@ - #define ATH8035_PHY_ID 0x004dd072 - #define AT8030_PHY_ID_MASK 0xffffffef - --#define QCA8327_PHY_ID 0x004dd034 -+#define QCA8327_A_PHY_ID 0x004dd033 -+#define QCA8327_B_PHY_ID 0x004dd034 - #define QCA8337_PHY_ID 0x004dd036 - #define QCA8K_PHY_ID_MASK 0xffffffff - -@@ -1413,10 +1414,23 @@ static struct phy_driver at803x_driver[] - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, - }, { -- /* QCA8327 */ -- .phy_id = QCA8327_PHY_ID, -+ /* QCA8327-A from switch QCA8327-AL1A */ -+ .phy_id = QCA8327_A_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, -- .name = "QCA PHY 8327", -+ .name = "QCA PHY 8327-A", -+ /* PHY_GBIT_FEATURES */ -+ .probe = at803x_probe, -+ .flags = PHY_IS_INTERNAL, -+ .config_init = qca83xx_config_init, -+ .soft_reset = genphy_soft_reset, -+ .get_sset_count = at803x_get_sset_count, -+ .get_strings = at803x_get_strings, -+ .get_stats = at803x_get_stats, -+}, { -+ /* QCA8327-B from switch QCA8327-BL1A */ -+ .phy_id = QCA8327_B_PHY_ID, -+ .phy_id_mask = QCA8K_PHY_ID_MASK, -+ .name = "QCA PHY 8327-B", - /* PHY_GBIT_FEATURES */ - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, -@@ -1436,7 +1450,8 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, -- { PHY_ID_MATCH_EXACT(QCA8327_PHY_ID) }, -+ { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, -+ { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, - { } - }; - diff --git a/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch b/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch deleted file mode 100644 index cd83fac83c8..00000000000 --- a/target/linux/generic/backport-6.1/745-v5.16-02-net-phy-at803x-add-resume-suspend-function-to-qca83x.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 15b9df4ece17d084f14eb0ca1cf05f2ad497e425 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 19 Sep 2021 18:28:16 +0200 -Subject: net: phy: at803x: add resume/suspend function to qca83xx phy - -Add resume/suspend function to qca83xx internal phy. -We can't use the at803x generic function as the documentation lacks of -any support for WoL regs. - -Signed-off-by: Ansuel Smith -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -1413,6 +1413,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, - }, { - /* QCA8327-A from switch QCA8327-AL1A */ - .phy_id = QCA8327_A_PHY_ID, -@@ -1426,6 +1428,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, - }, { - /* QCA8327-B from switch QCA8327-BL1A */ - .phy_id = QCA8327_B_PHY_ID, -@@ -1439,6 +1443,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, - }, }; - - module_phy_driver(at803x_driver); diff --git a/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch b/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch deleted file mode 100644 index 586d8953b2b..00000000000 --- a/target/linux/generic/backport-6.1/745-v5.16-03-net-phy-at803x-fix-spacing-and-improve-name-for-83xx.patch +++ /dev/null @@ -1,95 +0,0 @@ -From d44fd8604a4ab92119adb35f05fd87612af722b5 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 19 Sep 2021 18:28:17 +0200 -Subject: net: phy: at803x: fix spacing and improve name for 83xx phy - -Fix spacing and improve name for 83xx phy following other phy in the -same driver. - -Signed-off-by: Ansuel Smith -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 60 ++++++++++++++++++++++++------------------------ - 1 file changed, 30 insertions(+), 30 deletions(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -1402,47 +1402,47 @@ static struct phy_driver at803x_driver[] - .config_aneg = at803x_config_aneg, - }, { - /* QCA8337 */ -- .phy_id = QCA8337_PHY_ID, -- .phy_id_mask = QCA8K_PHY_ID_MASK, -- .name = "QCA PHY 8337", -+ .phy_id = QCA8337_PHY_ID, -+ .phy_id_mask = QCA8K_PHY_ID_MASK, -+ .name = "Qualcomm Atheros 8337 internal PHY", - /* PHY_GBIT_FEATURES */ -- .probe = at803x_probe, -- .flags = PHY_IS_INTERNAL, -- .config_init = qca83xx_config_init, -- .soft_reset = genphy_soft_reset, -- .get_sset_count = at803x_get_sset_count, -- .get_strings = at803x_get_strings, -- .get_stats = at803x_get_stats, -+ .probe = at803x_probe, -+ .flags = PHY_IS_INTERNAL, -+ .config_init = qca83xx_config_init, -+ .soft_reset = genphy_soft_reset, -+ .get_sset_count = at803x_get_sset_count, -+ .get_strings = at803x_get_strings, -+ .get_stats = at803x_get_stats, - .suspend = genphy_suspend, - .resume = genphy_resume, - }, { - /* QCA8327-A from switch QCA8327-AL1A */ -- .phy_id = QCA8327_A_PHY_ID, -- .phy_id_mask = QCA8K_PHY_ID_MASK, -- .name = "QCA PHY 8327-A", -+ .phy_id = QCA8327_A_PHY_ID, -+ .phy_id_mask = QCA8K_PHY_ID_MASK, -+ .name = "Qualcomm Atheros 8327-A internal PHY", - /* PHY_GBIT_FEATURES */ -- .probe = at803x_probe, -- .flags = PHY_IS_INTERNAL, -- .config_init = qca83xx_config_init, -- .soft_reset = genphy_soft_reset, -- .get_sset_count = at803x_get_sset_count, -- .get_strings = at803x_get_strings, -- .get_stats = at803x_get_stats, -+ .probe = at803x_probe, -+ .flags = PHY_IS_INTERNAL, -+ .config_init = qca83xx_config_init, -+ .soft_reset = genphy_soft_reset, -+ .get_sset_count = at803x_get_sset_count, -+ .get_strings = at803x_get_strings, -+ .get_stats = at803x_get_stats, - .suspend = genphy_suspend, - .resume = genphy_resume, - }, { - /* QCA8327-B from switch QCA8327-BL1A */ -- .phy_id = QCA8327_B_PHY_ID, -- .phy_id_mask = QCA8K_PHY_ID_MASK, -- .name = "QCA PHY 8327-B", -+ .phy_id = QCA8327_B_PHY_ID, -+ .phy_id_mask = QCA8K_PHY_ID_MASK, -+ .name = "Qualcomm Atheros 8327-B internal PHY", - /* PHY_GBIT_FEATURES */ -- .probe = at803x_probe, -- .flags = PHY_IS_INTERNAL, -- .config_init = qca83xx_config_init, -- .soft_reset = genphy_soft_reset, -- .get_sset_count = at803x_get_sset_count, -- .get_strings = at803x_get_strings, -- .get_stats = at803x_get_stats, -+ .probe = at803x_probe, -+ .flags = PHY_IS_INTERNAL, -+ .config_init = qca83xx_config_init, -+ .soft_reset = genphy_soft_reset, -+ .get_sset_count = at803x_get_sset_count, -+ .get_strings = at803x_get_strings, -+ .get_stats = at803x_get_stats, - .suspend = genphy_suspend, - .resume = genphy_resume, - }, }; diff --git a/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch b/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch deleted file mode 100644 index 09797ae83bc..00000000000 --- a/target/linux/generic/backport-6.1/746-v5.16-01-net-phy-at803x-fix-resume-for-QCA8327-phy.patch +++ /dev/null @@ -1,131 +0,0 @@ -From ba3c01ee02ed0d821c9f241f179bbc9457542b8f Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 10 Oct 2021 00:46:15 +0200 -Subject: net: phy: at803x: fix resume for QCA8327 phy - -From Documentation phy resume triggers phy reset and restart -auto-negotiation. Add a dedicated function to wait reset to finish as -it was notice a regression where port sometime are not reliable after a -suspend/resume session. The reset wait logic is copied from phy_poll_reset. -Add dedicated suspend function to use genphy_suspend only with QCA8337 -phy and set only additional debug settings for QCA8327. With more test -it was reported that QCA8327 doesn't proprely support this mode and -using this cause the unreliability of the switch ports, especially the -malfunction of the port0. - -Fixes: 15b9df4ece17 ("net: phy: at803x: add resume/suspend function to qca83xx phy") -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 69 +++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 63 insertions(+), 6 deletions(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -92,9 +92,14 @@ - #define AT803X_DEBUG_REG_5 0x05 - #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) - -+#define AT803X_DEBUG_REG_HIB_CTRL 0x0b -+#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) -+#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) -+ - #define AT803X_DEBUG_REG_3C 0x3C - - #define AT803X_DEBUG_REG_3D 0x3D -+#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) - - #define AT803X_DEBUG_REG_1F 0x1F - #define AT803X_DEBUG_PLL_ON BIT(2) -@@ -1304,6 +1309,58 @@ static int qca83xx_config_init(struct ph - return 0; - } - -+static int qca83xx_resume(struct phy_device *phydev) -+{ -+ int ret, val; -+ -+ /* Skip reset if not suspended */ -+ if (!phydev->suspended) -+ return 0; -+ -+ /* Reinit the port, reset values set by suspend */ -+ qca83xx_config_init(phydev); -+ -+ /* Reset the port on port resume */ -+ phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); -+ -+ /* On resume from suspend the switch execute a reset and -+ * restart auto-negotiation. Wait for reset to complete. -+ */ -+ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), -+ 50000, 600000, true); -+ if (ret) -+ return ret; -+ -+ msleep(1); -+ -+ return 0; -+} -+ -+static int qca83xx_suspend(struct phy_device *phydev) -+{ -+ u16 mask = 0; -+ -+ /* Only QCA8337 support actual suspend. -+ * QCA8327 cause port unreliability when phy suspend -+ * is set. -+ */ -+ if (phydev->drv->phy_id == QCA8337_PHY_ID) { -+ genphy_suspend(phydev); -+ } else { -+ mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); -+ phy_modify(phydev, MII_BMCR, mask, 0); -+ } -+ -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D, -+ AT803X_DEBUG_GATE_CLK_IN1000, 0); -+ -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, -+ AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | -+ AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); -+ -+ return 0; -+} -+ - static struct phy_driver at803x_driver[] = { - { - /* Qualcomm Atheros AR8035 */ -@@ -1413,8 +1470,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -+ .suspend = qca83xx_suspend, -+ .resume = qca83xx_resume, - }, { - /* QCA8327-A from switch QCA8327-AL1A */ - .phy_id = QCA8327_A_PHY_ID, -@@ -1428,8 +1485,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -+ .suspend = qca83xx_suspend, -+ .resume = qca83xx_resume, - }, { - /* QCA8327-B from switch QCA8327-BL1A */ - .phy_id = QCA8327_B_PHY_ID, -@@ -1443,8 +1500,8 @@ static struct phy_driver at803x_driver[] - .get_sset_count = at803x_get_sset_count, - .get_strings = at803x_get_strings, - .get_stats = at803x_get_stats, -- .suspend = genphy_suspend, -- .resume = genphy_resume, -+ .suspend = qca83xx_suspend, -+ .resume = qca83xx_resume, - }, }; - - module_phy_driver(at803x_driver); diff --git a/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch b/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch deleted file mode 100644 index c504c37c84f..00000000000 --- a/target/linux/generic/backport-6.1/746-v5.16-02-net-phy-at803x-add-DAC-amplitude-fix-for-8327-phy.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 1ca8311949aec5c9447645731ef1c6bc5bd71350 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 10 Oct 2021 00:46:16 +0200 -Subject: net: phy: at803x: add DAC amplitude fix for 8327 phy - -QCA8327 internal phy require DAC amplitude adjustement set to +6% with -100m speed. Also add additional define to report a change of the same -reg in QCA8337. (different scope it does set 1000m voltage) -Add link_change_notify function to set the proper amplitude adjustement -on PHY_RUNNING state and disable on any other state. - -Fixes: b4df02b562f4 ("net: phy: at803x: add support for qca 8327 A variant internal phy") -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 33 +++++++++++++++++++++++++++++++++ - 1 file changed, 33 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -87,6 +87,8 @@ - #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 - - #define AT803X_DEBUG_REG_0 0x00 -+#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) -+#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) - #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) - - #define AT803X_DEBUG_REG_5 0x05 -@@ -1306,9 +1308,37 @@ static int qca83xx_config_init(struct ph - break; - } - -+ /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. -+ * Disable on init and enable only with 100m speed following -+ * qca original source code. -+ */ -+ if (phydev->drv->phy_id == QCA8327_A_PHY_ID || -+ phydev->drv->phy_id == QCA8327_B_PHY_ID) -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ QCA8327_DEBUG_MANU_CTRL_EN, 0); -+ - return 0; - } - -+static void qca83xx_link_change_notify(struct phy_device *phydev) -+{ -+ /* QCA8337 doesn't require DAC Amplitude adjustement */ -+ if (phydev->drv->phy_id == QCA8337_PHY_ID) -+ return; -+ -+ /* Set DAC Amplitude adjustment to +6% for 100m on link running */ -+ if (phydev->state == PHY_RUNNING) { -+ if (phydev->speed == SPEED_100) -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ QCA8327_DEBUG_MANU_CTRL_EN, -+ QCA8327_DEBUG_MANU_CTRL_EN); -+ } else { -+ /* Reset DAC Amplitude adjustment */ -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ QCA8327_DEBUG_MANU_CTRL_EN, 0); -+ } -+} -+ - static int qca83xx_resume(struct phy_device *phydev) - { - int ret, val; -@@ -1463,6 +1493,7 @@ static struct phy_driver at803x_driver[] - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8337 internal PHY", - /* PHY_GBIT_FEATURES */ -+ .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, -@@ -1478,6 +1509,7 @@ static struct phy_driver at803x_driver[] - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-A internal PHY", - /* PHY_GBIT_FEATURES */ -+ .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, -@@ -1493,6 +1525,7 @@ static struct phy_driver at803x_driver[] - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-B internal PHY", - /* PHY_GBIT_FEATURES */ -+ .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, diff --git a/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch b/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch deleted file mode 100644 index 9f880593f12..00000000000 --- a/target/linux/generic/backport-6.1/746-v5.16-03-net-phy-at803x-enable-prefer-master-for-83xx-interna.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 9d1c29b4028557a496be9c5eb2b4b86063700636 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 10 Oct 2021 00:46:17 +0200 -Subject: net: phy: at803x: enable prefer master for 83xx internal phy - -From original QCA source code the port was set to prefer master as port -type in 1000BASE-T mode. Apply the same settings also here. - -Signed-off-by: Ansuel Smith -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -1317,6 +1317,9 @@ static int qca83xx_config_init(struct ph - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - -+ /* Following original QCA sourcecode set port to prefer master */ -+ phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); -+ - return 0; - } - diff --git a/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch b/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch deleted file mode 100644 index 89e9b3f6623..00000000000 --- a/target/linux/generic/backport-6.1/746-v5.16-04-net-phy-at803x-better-describe-debug-regs.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 67999555ff42e91de7654488d9a7735bd9e84555 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 10 Oct 2021 00:46:18 +0200 -Subject: net: phy: at803x: better describe debug regs - -Give a name to known debug regs from Documentation instead of using -unknown hex values. - -Signed-off-by: Ansuel Smith -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -86,12 +86,12 @@ - #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ - #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 - --#define AT803X_DEBUG_REG_0 0x00 -+#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 - #define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) - #define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) - #define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) - --#define AT803X_DEBUG_REG_5 0x05 -+#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 - #define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) - - #define AT803X_DEBUG_REG_HIB_CTRL 0x0b -@@ -100,7 +100,7 @@ - - #define AT803X_DEBUG_REG_3C 0x3C - --#define AT803X_DEBUG_REG_3D 0x3D -+#define AT803X_DEBUG_REG_GREEN 0x3D - #define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) - - #define AT803X_DEBUG_REG_1F 0x1F -@@ -284,25 +284,25 @@ static int at803x_read_page(struct phy_d - - static int at803x_enable_rx_delay(struct phy_device *phydev) - { -- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0, -+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, - AT803X_DEBUG_RX_CLK_DLY_EN); - } - - static int at803x_enable_tx_delay(struct phy_device *phydev) - { -- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0, -+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, - AT803X_DEBUG_TX_CLK_DLY_EN); - } - - static int at803x_disable_rx_delay(struct phy_device *phydev) - { -- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - AT803X_DEBUG_RX_CLK_DLY_EN, 0); - } - - static int at803x_disable_tx_delay(struct phy_device *phydev) - { -- return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, -+ return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, - AT803X_DEBUG_TX_CLK_DLY_EN, 0); - } - -@@ -1292,9 +1292,9 @@ static int qca83xx_config_init(struct ph - switch (switch_revision) { - case 1: - /* For 100M waveform */ -- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_0, 0x02ea); -+ at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); - /* Turn on Gigabit clock */ -- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x68a0); -+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); - break; - - case 2: -@@ -1302,8 +1302,8 @@ static int qca83xx_config_init(struct ph - fallthrough; - case 4: - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); -- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3D, 0x6860); -- at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_5, 0x2c46); -+ at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); -+ at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); - break; - } -@@ -1314,7 +1314,7 @@ static int qca83xx_config_init(struct ph - */ - if (phydev->drv->phy_id == QCA8327_A_PHY_ID || - phydev->drv->phy_id == QCA8327_B_PHY_ID) -- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - - /* Following original QCA sourcecode set port to prefer master */ -@@ -1332,12 +1332,12 @@ static void qca83xx_link_change_notify(s - /* Set DAC Amplitude adjustment to +6% for 100m on link running */ - if (phydev->state == PHY_RUNNING) { - if (phydev->speed == SPEED_100) -- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, - QCA8327_DEBUG_MANU_CTRL_EN); - } else { - /* Reset DAC Amplitude adjustment */ -- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - } - } -@@ -1384,7 +1384,7 @@ static int qca83xx_suspend(struct phy_de - phy_modify(phydev, MII_BMCR, mask, 0); - } - -- at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_3D, -+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, - AT803X_DEBUG_GATE_CLK_IN1000, 0); - - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, diff --git a/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch b/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch deleted file mode 100644 index c8d424de38c..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-01-dsa-qca8k-add-mac-power-sel-support.patch +++ /dev/null @@ -1,80 +0,0 @@ -From d8b6f5bae6d3b648a67b6958cb98e4e97256d652 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:06 +0200 -Subject: dsa: qca8k: add mac_power_sel support - -Add missing mac power sel support needed for ipq8064/5 SoC that require -1.8v for the internal regulator port instead of the default 1.5v. -If other device needs this, consider adding a dedicated binding to -support this. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 31 +++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 5 +++++ - 2 files changed, 36 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -951,6 +951,33 @@ qca8k_setup_of_rgmii_delay(struct qca8k_ - } - - static int -+qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) -+{ -+ u32 mask = 0; -+ int ret = 0; -+ -+ /* SoC specific settings for ipq8064. -+ * If more device require this consider adding -+ * a dedicated binding. -+ */ -+ if (of_machine_is_compatible("qcom,ipq8064")) -+ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -+ -+ /* SoC specific settings for ipq8065 */ -+ if (of_machine_is_compatible("qcom,ipq8065")) -+ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -+ -+ if (mask) { -+ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -+ QCA8K_MAC_PWR_RGMII0_1_8V | -+ QCA8K_MAC_PWR_RGMII1_1_8V, -+ mask); -+ } -+ -+ return ret; -+} -+ -+static int - qca8k_setup(struct dsa_switch *ds) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -@@ -979,6 +1006,10 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -+ ret = qca8k_setup_mac_pwr_sel(priv); -+ if (ret) -+ return ret; -+ - /* Enable CPU Port */ - ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, - QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -100,6 +100,11 @@ - #define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) - #define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) - -+/* MAC_PWR_SEL registers */ -+#define QCA8K_REG_MAC_PWR_SEL 0x0e4 -+#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) -+#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) -+ - /* EEE control registers */ - #define QCA8K_REG_EEE_CTRL 0x100 - #define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) diff --git a/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch b/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch deleted file mode 100644 index bd768ec27d4..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-02-dt-bindings-net-dsa-qca8k-Add-SGMII-clock-phase-prop.patch +++ /dev/null @@ -1,30 +0,0 @@ -From fdbf35df9c091db9c46e57e9938e3f7a4f603a7c Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:07 +0200 -Subject: dt-bindings: net: dsa: qca8k: Add SGMII clock phase properties - -Add names and descriptions of additional PORT0_PAD_CTRL properties. -qca,sgmii-(rx|tx)clk-falling-edge are for setting the respective clock -phase to failling edge. - -Co-developed-by: Matthew Hagan -Signed-off-by: Matthew Hagan -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/dsa/qca8k.txt | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt -@@ -37,6 +37,10 @@ A CPU port node has the following option - managed entity. See - Documentation/devicetree/bindings/net/fixed-link.txt - for details. -+- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge. -+ Mostly used in qca8327 with CPU port 0 set to -+ sgmii. -+- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. - - For QCA8K the 'fixed-link' sub-node supports only the following properties: - diff --git a/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch b/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch deleted file mode 100644 index e464452d82c..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-03-net-dsa-qca8k-add-support-for-sgmii-falling-edge.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 6c43809bf1bee76c434e365a26546a92a5fbec14 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:08 +0200 -Subject: net: dsa: qca8k: add support for sgmii falling edge - -Add support for this in the qca8k driver. Also add support for SGMII -rx/tx clock falling edge. This is only present for pad0, pad5 and -pad6 have these bit reserved from Documentation. Add a comment that this -is hardcoded to PAD0 as qca8327/28/34/37 have an unique sgmii line and -setting falling in port0 applies to both configuration with sgmii used -for port0 or port6. - -Co-developed-by: Matthew Hagan -Signed-off-by: Matthew Hagan -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 4 ++++ - 2 files changed, 67 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -978,6 +978,42 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri - } - - static int -+qca8k_parse_port_config(struct qca8k_priv *priv) -+{ -+ struct device_node *port_dn; -+ phy_interface_t mode; -+ struct dsa_port *dp; -+ int port, ret; -+ -+ /* We have 2 CPU port. Check them */ -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Skip every other port */ -+ if (port != 0 && port != 6) -+ continue; -+ -+ dp = dsa_to_port(priv->ds, port); -+ port_dn = dp->dn; -+ -+ if (!of_device_is_available(port_dn)) -+ continue; -+ -+ ret = of_get_phy_mode(port_dn, &mode); -+ if (ret) -+ continue; -+ -+ if (mode == PHY_INTERFACE_MODE_SGMII) { -+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -+ priv->sgmii_tx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -+ priv->sgmii_rx_clk_falling_edge = true; -+ } -+ } -+ -+ return 0; -+} -+ -+static int - qca8k_setup(struct dsa_switch *ds) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -@@ -990,6 +1026,11 @@ qca8k_setup(struct dsa_switch *ds) - return -EINVAL; - } - -+ /* Parse CPU port config to be later used in phy_link mac_config */ -+ ret = qca8k_parse_port_config(priv); -+ if (ret) -+ return ret; -+ - mutex_init(&priv->reg_mutex); - - /* Start by setting up the register mapping */ -@@ -1274,6 +1315,28 @@ qca8k_phylink_mac_config(struct dsa_swit - } - - qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -+ -+ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -+ * falling edge is set writing in the PORT0 PAD reg -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327 || -+ priv->switch_id == QCA8K_ID_QCA8337) -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ -+ val = 0; -+ -+ /* SGMII Clock phase configuration */ -+ if (priv->sgmii_rx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -+ -+ if (priv->sgmii_tx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -+ -+ if (val) -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -+ val); - break; - default: - dev_err(ds->dev, "xMII mode %s not supported for port %d\n", ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -35,6 +35,8 @@ - #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) - #define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) - #define QCA8K_REG_PORT0_PAD_CTRL 0x004 -+#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) -+#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) - #define QCA8K_REG_PORT5_PAD_CTRL 0x008 - #define QCA8K_REG_PORT6_PAD_CTRL 0x00c - #define QCA8K_PORT_PAD_RGMII_EN BIT(26) -@@ -260,6 +262,8 @@ struct qca8k_priv { - u8 switch_revision; - u8 rgmii_tx_delay; - u8 rgmii_rx_delay; -+ bool sgmii_rx_clk_falling_edge; -+ bool sgmii_tx_clk_falling_edge; - bool legacy_phy_port_mapping; - struct regmap *regmap; - struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch b/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch deleted file mode 100644 index 606ac0af3da..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-04-dt-bindings-net-dsa-qca8k-Document-support-for-CPU-p.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 731d613338ec6de482053ffa3f71be2325b0f8eb Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:09 +0200 -Subject: dt-bindings: net: dsa: qca8k: Document support for CPU port 6 - -The switch now support CPU port to be set 6 instead of be hardcoded to -0. Document support for it and describe logic selection. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/dsa/qca8k.txt | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt -@@ -29,7 +29,11 @@ the mdio MASTER is used as communication - Don't use mixed external and internal mdio-bus configurations, as this is - not supported by the hardware. - --The CPU port of this switch is always port 0. -+This switch support 2 CPU port. Normally and advised configuration is with -+CPU port set to port 0. It is also possible to set the CPU port to port 6 -+if the device requires it. The driver will configure the switch to the defined -+port. With both CPU port declared the first CPU port is selected as primary -+and the secondary CPU ignored. - - A CPU port node has the following optional node: - diff --git a/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch b/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch deleted file mode 100644 index 320db8fa9f9..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-05-net-dsa-qca8k-add-support-for-cpu-port-6.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 3fcf734aa482487df83cf8f18608438fcf59127f Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:10 +0200 -Subject: net: dsa: qca8k: add support for cpu port 6 - -Currently CPU port is always hardcoded to port 0. This switch have 2 CPU -ports. The original intention of this driver seems to be use the -mac06_exchange bit to swap MAC0 with MAC6 in the strange configuration -where device have connected only the CPU port 6. To skip the -introduction of a new binding, rework the driver to address the -secondary CPU port as primary and drop any reference of hardcoded port. -With configuration of mac06 exchange, just skip the definition of port0 -and define the CPU port as a secondary. The driver will autoconfigure -the switch to use that as the primary CPU port. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 51 ++++++++++++++++++++++++++++++++++--------------- - drivers/net/dsa/qca8k.h | 2 -- - 2 files changed, 36 insertions(+), 17 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -977,6 +977,22 @@ qca8k_setup_mac_pwr_sel(struct qca8k_pri - return ret; - } - -+static int qca8k_find_cpu_port(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Find the connected cpu port. Valid port are 0 or 6 */ -+ if (dsa_is_cpu_port(ds, 0)) -+ return 0; -+ -+ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -+ -+ if (dsa_is_cpu_port(ds, 6)) -+ return 6; -+ -+ return -EINVAL; -+} -+ - static int - qca8k_parse_port_config(struct qca8k_priv *priv) - { -@@ -1017,13 +1033,13 @@ static int - qca8k_setup(struct dsa_switch *ds) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int ret, i; -+ int cpu_port, ret, i; - u32 mask; - -- /* Make sure that port 0 is the cpu port */ -- if (!dsa_is_cpu_port(ds, 0)) { -- dev_err(priv->dev, "port 0 is not the CPU port"); -- return -EINVAL; -+ cpu_port = qca8k_find_cpu_port(ds); -+ if (cpu_port < 0) { -+ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -+ return cpu_port; - } - - /* Parse CPU port config to be later used in phy_link mac_config */ -@@ -1065,7 +1081,7 @@ qca8k_setup(struct dsa_switch *ds) - dev_warn(priv->dev, "mib init failed"); - - /* Enable QCA header mode on the cpu port */ -- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(QCA8K_CPU_PORT), -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port), - QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | - QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); - if (ret) { -@@ -1087,10 +1103,10 @@ qca8k_setup(struct dsa_switch *ds) - - /* Forward all unknown frames to CPU port for Linux processing */ - ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -- BIT(0) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -+ BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); - if (ret) - return ret; - -@@ -1098,7 +1114,7 @@ qca8k_setup(struct dsa_switch *ds) - for (i = 0; i < QCA8K_NUM_PORTS; i++) { - /* CPU port gets connected to all user ports of the switch */ - if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(QCA8K_CPU_PORT), -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port), - QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); - if (ret) - return ret; -@@ -1110,7 +1126,7 @@ qca8k_setup(struct dsa_switch *ds) - - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_MEMBER, -- BIT(QCA8K_CPU_PORT)); -+ BIT(cpu_port)); - if (ret) - return ret; - -@@ -1616,9 +1632,12 @@ static int - qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int port_mask = BIT(QCA8K_CPU_PORT); -+ int port_mask, cpu_port; - int i, ret; - -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ port_mask = BIT(cpu_port); -+ - for (i = 1; i < QCA8K_NUM_PORTS; i++) { - if (dsa_to_port(ds, i)->bridge_dev != br) - continue; -@@ -1645,7 +1664,9 @@ static void - qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int i; -+ int cpu_port, i; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; - - for (i = 1; i < QCA8K_NUM_PORTS; i++) { - if (dsa_to_port(ds, i)->bridge_dev != br) -@@ -1662,7 +1683,7 @@ qca8k_port_bridge_leave(struct dsa_switc - * this port - */ - qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, BIT(QCA8K_CPU_PORT)); -+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); - } - - static int ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -24,8 +24,6 @@ - - #define QCA8K_NUM_FDB_RECORDS 2048 - --#define QCA8K_CPU_PORT 0 -- - #define QCA8K_PORT_VID_DEF 1 - - /* Global control registers */ diff --git a/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch b/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch deleted file mode 100644 index de201764f98..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-06-net-dsa-qca8k-rework-rgmii-delay-logic-and-scan-for-.patch +++ /dev/null @@ -1,295 +0,0 @@ -From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:11 +0200 -Subject: net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6 - -Future proof commit. This switch have 2 CPU ports and one valid -configuration is first CPU port set to sgmii and second CPU port set to -rgmii-id. The current implementation detects delay only for CPU port -zero set to rgmii and doesn't count any delay set in a secondary CPU -port. Drop the current delay scan function and move it to the sgmii -parser function to generalize and implicitly add support for secondary -CPU port set to rgmii-id. Introduce new logic where delay is enabled -also with internal delay binding declared and rgmii set as PHY mode. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 165 ++++++++++++++++++++++++------------------------ - drivers/net/dsa/qca8k.h | 10 ++- - 2 files changed, 89 insertions(+), 86 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -889,68 +889,6 @@ qca8k_setup_mdio_bus(struct qca8k_priv * - } - - static int --qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv) --{ -- struct device_node *port_dn; -- phy_interface_t mode; -- struct dsa_port *dp; -- u32 val; -- -- /* CPU port is already checked */ -- dp = dsa_to_port(priv->ds, 0); -- -- port_dn = dp->dn; -- -- /* Check if port 0 is set to the correct type */ -- of_get_phy_mode(port_dn, &mode); -- if (mode != PHY_INTERFACE_MODE_RGMII_ID && -- mode != PHY_INTERFACE_MODE_RGMII_RXID && -- mode != PHY_INTERFACE_MODE_RGMII_TXID) { -- return 0; -- } -- -- switch (mode) { -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val)) -- val = 2; -- else -- /* Switch regs accept value in ns, convert ps to ns */ -- val = val / 1000; -- -- if (val > QCA8K_MAX_DELAY) { -- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -- val = 3; -- } -- -- priv->rgmii_rx_delay = val; -- /* Stop here if we need to check only for rx delay */ -- if (mode != PHY_INTERFACE_MODE_RGMII_ID) -- break; -- -- fallthrough; -- case PHY_INTERFACE_MODE_RGMII_TXID: -- if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val)) -- val = 1; -- else -- /* Switch regs accept value in ns, convert ps to ns */ -- val = val / 1000; -- -- if (val > QCA8K_MAX_DELAY) { -- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -- val = 3; -- } -- -- priv->rgmii_tx_delay = val; -- break; -- default: -- return 0; -- } -- -- return 0; --} -- --static int - qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) - { - u32 mask = 0; -@@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct ds - static int - qca8k_parse_port_config(struct qca8k_priv *priv) - { -+ int port, cpu_port_index = 0, ret; - struct device_node *port_dn; - phy_interface_t mode; - struct dsa_port *dp; -- int port, ret; -+ u32 delay; - - /* We have 2 CPU port. Check them */ -- for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { - /* Skip every other port */ - if (port != 0 && port != 6) - continue; - - dp = dsa_to_port(priv->ds, port); - port_dn = dp->dn; -+ cpu_port_index++; - - if (!of_device_is_available(port_dn)) - continue; -@@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_pri - if (ret) - continue; - -- if (mode == PHY_INTERFACE_MODE_SGMII) { -+ switch (mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID) -+ delay = 1; -+ -+ if (delay > QCA8K_MAX_DELAY) { -+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->rgmii_tx_delay[cpu_port_index] = delay; -+ -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ delay = 2; -+ -+ if (delay > QCA8K_MAX_DELAY) { -+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->rgmii_rx_delay[cpu_port_index] = delay; -+ -+ break; -+ case PHY_INTERFACE_MODE_SGMII: - if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) - priv->sgmii_tx_clk_falling_edge = true; - - if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) - priv->sgmii_rx_clk_falling_edge = true; -+ -+ break; -+ default: -+ continue; - } - } - -@@ -1059,10 +1041,6 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -- ret = qca8k_setup_of_rgmii_delay(priv); -- if (ret) -- return ret; -- - ret = qca8k_setup_mac_pwr_sel(priv); - if (ret) - return ret; -@@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_swit - const struct phylink_link_state *state) - { - struct qca8k_priv *priv = ds->priv; -- u32 reg, val; -- int ret; -+ int cpu_port_index, ret; -+ u32 reg, val, delay; - - switch (port) { - case 0: /* 1st CPU port */ -@@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_swit - return; - - reg = QCA8K_REG_PORT0_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT0; - break; - case 1: - case 2: -@@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_swit - return; - - reg = QCA8K_REG_PORT6_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT6; - break; - default: - dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -@@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_swit - - switch (state->interface) { - case PHY_INTERFACE_MODE_RGMII: -- /* RGMII mode means no delay so don't enable the delay */ -- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -- break; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: -- /* RGMII_ID needs internal delay. This is enabled through -- * PORT5_PAD_CTRL for all ports, rather than individual port -- * registers -+ val = QCA8K_PORT_PAD_RGMII_EN; -+ -+ /* Delay can be declared in 3 different way. -+ * Mode to rgmii and internal-delay standard binding defined -+ * rgmii-id or rgmii-tx/rx phy mode set. -+ * The parse logic set a delay different than 0 only when one -+ * of the 3 different way is used. In all other case delay is -+ * not enabled. With ID or TX/RXID delay is enabled and set -+ * to the default and recommended value. -+ */ -+ if (priv->rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->rgmii_tx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ } -+ -+ if (priv->rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->rgmii_rx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ } -+ -+ /* Set RGMII delay based on the selected values */ -+ qca8k_write(priv, reg, val); -+ -+ /* QCA8337 requires to set rgmii rx delay for all ports. -+ * This is enabled through PORT5_PAD_CTRL for all ports, -+ * rather than individual port registers. - */ -- qca8k_write(priv, reg, -- QCA8K_PORT_PAD_RGMII_EN | -- QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) | -- QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -- /* QCA8337 requires to set rgmii rx delay */ - if (priv->switch_id == QCA8K_ID_QCA8337) - qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, - QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -13,6 +13,7 @@ - #include - - #define QCA8K_NUM_PORTS 7 -+#define QCA8K_NUM_CPU_PORTS 2 - #define QCA8K_MAX_MTU 9000 - - #define PHY_ID_QCA8327 0x004dd034 -@@ -255,13 +256,18 @@ struct qca8k_match_data { - u8 id; - }; - -+enum { -+ QCA8K_CPU_PORT0, -+ QCA8K_CPU_PORT6, -+}; -+ - struct qca8k_priv { - u8 switch_id; - u8 switch_revision; -- u8 rgmii_tx_delay; -- u8 rgmii_rx_delay; - bool sgmii_rx_clk_falling_edge; - bool sgmii_tx_clk_falling_edge; -+ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ - bool legacy_phy_port_mapping; - struct regmap *regmap; - struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch b/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch deleted file mode 100644 index 8abd264e794..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-07-dt-bindings-net-dsa-qca8k-Document-qca-sgmii-enable-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 13ad5ccc093ff448b99ac7e138e91e78796adb48 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:12 +0200 -Subject: dt-bindings: net: dsa: qca8k: Document qca,sgmii-enable-pll - -Document qca,sgmii-enable-pll binding used in the CPU nodes to -enable SGMII PLL on MAC config. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/dsa/qca8k.txt | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt -@@ -45,6 +45,16 @@ A CPU port node has the following option - Mostly used in qca8327 with CPU port 0 set to - sgmii. - - qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. -+- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX -+ chain along with Signal Detection. -+ This should NOT be enabled for qca8327. If enabled with -+ qca8327 the sgmii port won't correctly init and an err -+ is printed. -+ This can be required for qca8337 switch with revision 2. -+ A warning is displayed when used with revision greater -+ 2. -+ With CPU port set to sgmii and qca8337 it is advised -+ to set this unless a communication problem is observed. - - For QCA8K the 'fixed-link' sub-node supports only the following properties: - diff --git a/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch b/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch deleted file mode 100644 index 2b5a84a1b0e..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-08-net-dsa-qca8k-add-explicit-SGMII-PLL-enable.patch +++ /dev/null @@ -1,65 +0,0 @@ -From bbc4799e8bb6c397e3b3fec13de68e179f5db9ff Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:13 +0200 -Subject: net: dsa: qca8k: add explicit SGMII PLL enable - -Support enabling PLL on the SGMII CPU port. Some device require this -special configuration or no traffic is transmitted and the switch -doesn't work at all. A dedicated binding is added to the CPU node -port to apply the correct reg on mac config. -Fail to correctly configure sgmii with qca8327 switch and warn if pll is -used on qca8337 with a revision greater than 1. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 19 +++++++++++++++++-- - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 18 insertions(+), 2 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1002,6 +1002,18 @@ qca8k_parse_port_config(struct qca8k_pri - if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) - priv->sgmii_rx_clk_falling_edge = true; - -+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -+ priv->sgmii_enable_pll = true; -+ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -+ priv->sgmii_enable_pll = false; -+ } -+ -+ if (priv->switch_revision < 2) -+ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -+ } -+ - break; - default: - continue; -@@ -1312,8 +1324,11 @@ qca8k_phylink_mac_config(struct dsa_swit - if (ret) - return; - -- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -- QCA8K_SGMII_EN_TX | QCA8K_SGMII_EN_SD; -+ val |= QCA8K_SGMII_EN_SD; -+ -+ if (priv->sgmii_enable_pll) -+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -+ QCA8K_SGMII_EN_TX; - - if (dsa_is_cpu_port(ds, port)) { - /* CPU port, we're talking to the CPU MAC, be a PHY */ ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -266,6 +266,7 @@ struct qca8k_priv { - u8 switch_revision; - bool sgmii_rx_clk_falling_edge; - bool sgmii_tx_clk_falling_edge; -+ bool sgmii_enable_pll; - u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ - u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ - bool legacy_phy_port_mapping; diff --git a/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch b/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch deleted file mode 100644 index 38dc954e8cb..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-09-dt-bindings-net-dsa-qca8k-Document-qca-led-open-drai.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 924087c5c3d41553700b0eb83ca2a53b91643dca Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:14 +0200 -Subject: dt-bindings: net: dsa: qca8k: Document qca,led-open-drain binding - -Document new binding qca,ignore-power-on-sel used to ignore -power on strapping and use sw regs instead. -Document qca,led-open.drain to set led to open drain mode, the -qca,ignore-power-on-sel is mandatory with this enabled or an error will -be reported. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/dsa/qca8k.txt | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt -@@ -13,6 +13,17 @@ Required properties: - Optional properties: - - - reset-gpios: GPIO to be used to reset the whole device -+- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open -+ drain or eeprom presence. This is needed for broken -+ devices that have wrong configuration or when the oem -+ decided to not use pin strapping and fallback to sw -+ regs. -+- qca,led-open-drain: Set leds to open-drain mode. This requires the -+ qca,ignore-power-on-sel to be set or the driver will fail -+ to probe. This is needed if the oem doesn't use pin -+ strapping to set this mode and prefers to set it using sw -+ regs. The pin strapping related to led open drain mode is -+ the pin B68 for QCA832x and B49 for QCA833x - - Subnodes: - diff --git a/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch b/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch deleted file mode 100644 index aa5d92a4fde..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-10-net-dsa-qca8k-add-support-for-pws-config-reg.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 362bb238d8bf1470424214a8a5968d9c6cce68fa Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:15 +0200 -Subject: net: dsa: qca8k: add support for pws config reg - -Some qca8327 switch require to force the ignore of power on sel -strapping. Some switch require to set the led open drain mode in regs -instead of using strapping. While most of the device implements this -using the correct way using pin strapping, there are still some broken -device that require to be set using sw regs. -Introduce a new binding and support these special configuration. -As led open drain require to ignore pin strapping to work, the probe -fails with EINVAL error with incorrect configuration. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 39 +++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 6 ++++++ - 2 files changed, 45 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -932,6 +932,41 @@ static int qca8k_find_cpu_port(struct ds - } - - static int -+qca8k_setup_of_pws_reg(struct qca8k_priv *priv) -+{ -+ struct device_node *node = priv->dev->of_node; -+ u32 val = 0; -+ int ret; -+ -+ /* QCA8327 require to set to the correct mode. -+ * His bigger brother QCA8328 have the 172 pin layout. -+ * Should be applied by default but we set this just to make sure. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -+ QCA8327_PWS_PACKAGE148_EN); -+ if (ret) -+ return ret; -+ } -+ -+ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -+ val |= QCA8K_PWS_POWER_ON_SEL; -+ -+ if (of_property_read_bool(node, "qca,led-open-drain")) { -+ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -+ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -+ return -EINVAL; -+ } -+ -+ val |= QCA8K_PWS_LED_OPEN_EN_CSR; -+ } -+ -+ return qca8k_rmw(priv, QCA8K_REG_PWS, -+ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -+ val); -+} -+ -+static int - qca8k_parse_port_config(struct qca8k_priv *priv) - { - int port, cpu_port_index = 0, ret; -@@ -1053,6 +1088,10 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -+ ret = qca8k_setup_of_pws_reg(priv); -+ if (ret) -+ return ret; -+ - ret = qca8k_setup_mac_pwr_sel(priv); - if (ret) - return ret; ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -46,6 +46,12 @@ - #define QCA8K_MAX_DELAY 3 - #define QCA8K_PORT_PAD_SGMII_EN BIT(7) - #define QCA8K_REG_PWS 0x010 -+#define QCA8K_PWS_POWER_ON_SEL BIT(31) -+/* This reg is only valid for QCA832x and toggle the package -+ * type from 176 pin (by default) to 148 pin used on QCA8327 -+ */ -+#define QCA8327_PWS_PACKAGE148_EN BIT(30) -+#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) - #define QCA8K_PWS_SERDES_AEN_DIS BIT(7) - #define QCA8K_REG_MODULE_EN 0x030 - #define QCA8K_MODULE_EN_MIB BIT(0) diff --git a/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch b/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch deleted file mode 100644 index 1bfb00c5b2c..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-11-dt-bindings-net-dsa-qca8k-document-support-for-qca83.patch +++ /dev/null @@ -1,32 +0,0 @@ -From ed7988d77fbfb79366b68f9e7fa60a6080da23d4 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:16 +0200 -Subject: dt-bindings: net: dsa: qca8k: document support for qca8328 - -QCA8328 is the bigger brother of qca8327. Document the new compatible -binding and add some information to understand the various switch -compatible. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/dsa/qca8k.txt | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.txt -@@ -3,9 +3,10 @@ - Required properties: - - - compatible: should be one of: -- "qca,qca8327" -- "qca,qca8334" -- "qca,qca8337" -+ "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package -+ "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package -+ "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package -+ "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package - - - #size-cells: must be 0 - - #address-cells: must be 1 diff --git a/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch b/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch deleted file mode 100644 index b300621e63e..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-12-net-dsa-qca8k-add-support-for-QCA8328.patch +++ /dev/null @@ -1,78 +0,0 @@ -From f477d1c8bdbef4f400718238e350f16f521d2a3e Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:17 +0200 -Subject: net: dsa: qca8k: add support for QCA8328 - -QCA8328 switch is the bigger brother of the qca8327. Same regs different -chip. Change the function to set the correct pin layout and introduce a -new match_data to differentiate the 2 switch as they have the same ID -and their internal PHY have the same ID. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 19 ++++++++++++++++--- - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 17 insertions(+), 3 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -935,6 +935,7 @@ static int - qca8k_setup_of_pws_reg(struct qca8k_priv *priv) - { - struct device_node *node = priv->dev->of_node; -+ const struct qca8k_match_data *data; - u32 val = 0; - int ret; - -@@ -943,8 +944,14 @@ qca8k_setup_of_pws_reg(struct qca8k_priv - * Should be applied by default but we set this just to make sure. - */ - if (priv->switch_id == QCA8K_ID_QCA8327) { -+ data = of_device_get_match_data(priv->dev); -+ -+ /* Set the correct package of 148 pin for QCA8327 */ -+ if (data->reduced_package) -+ val |= QCA8327_PWS_PACKAGE148_EN; -+ - ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -- QCA8327_PWS_PACKAGE148_EN); -+ val); - if (ret) - return ret; - } -@@ -2124,7 +2131,12 @@ static int qca8k_resume(struct device *d - static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, - qca8k_suspend, qca8k_resume); - --static const struct qca8k_match_data qca832x = { -+static const struct qca8k_match_data qca8327 = { -+ .id = QCA8K_ID_QCA8327, -+ .reduced_package = true, -+}; -+ -+static const struct qca8k_match_data qca8328 = { - .id = QCA8K_ID_QCA8327, - }; - -@@ -2133,7 +2145,8 @@ static const struct qca8k_match_data qca - }; - - static const struct of_device_id qca8k_of_match[] = { -- { .compatible = "qca,qca8327", .data = &qca832x }, -+ { .compatible = "qca,qca8327", .data = &qca8327 }, -+ { .compatible = "qca,qca8328", .data = &qca8328 }, - { .compatible = "qca,qca8334", .data = &qca833x }, - { .compatible = "qca,qca8337", .data = &qca833x }, - { /* sentinel */ }, ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -260,6 +260,7 @@ struct ar8xxx_port_status { - - struct qca8k_match_data { - u8 id; -+ bool reduced_package; - }; - - enum { diff --git a/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch b/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch deleted file mode 100644 index 27f94dca027..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-13-net-dsa-qca8k-set-internal-delay-also-for-sgmii.patch +++ /dev/null @@ -1,159 +0,0 @@ -From cef08115846e581f80ff99abf7bf218da1840616 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:18 +0200 -Subject: net: dsa: qca8k: set internal delay also for sgmii - -QCA original code report port instability and sa that SGMII also require -to set internal delay. Generalize the rgmii delay function and apply the -advised value if they are not defined in DT. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 88 +++++++++++++++++++++++++++++++++---------------- - drivers/net/dsa/qca8k.h | 2 ++ - 2 files changed, 62 insertions(+), 28 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1004,6 +1004,7 @@ qca8k_parse_port_config(struct qca8k_pri - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_SGMII: - delay = 0; - - if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -@@ -1036,8 +1037,13 @@ qca8k_parse_port_config(struct qca8k_pri - - priv->rgmii_rx_delay[cpu_port_index] = delay; - -- break; -- case PHY_INTERFACE_MODE_SGMII: -+ /* Skip sgmii parsing for rgmii* mode */ -+ if (mode == PHY_INTERFACE_MODE_RGMII || -+ mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ break; -+ - if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) - priv->sgmii_tx_clk_falling_edge = true; - -@@ -1261,12 +1267,53 @@ qca8k_setup(struct dsa_switch *ds) - } - - static void -+qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -+ u32 reg) -+{ -+ u32 delay, val = 0; -+ int ret; -+ -+ /* Delay can be declared in 3 different way. -+ * Mode to rgmii and internal-delay standard binding defined -+ * rgmii-id or rgmii-tx/rx phy mode set. -+ * The parse logic set a delay different than 0 only when one -+ * of the 3 different way is used. In all other case delay is -+ * not enabled. With ID or TX/RXID delay is enabled and set -+ * to the default and recommended value. -+ */ -+ if (priv->rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->rgmii_tx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ } -+ -+ if (priv->rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->rgmii_rx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ } -+ -+ /* Set RGMII delay based on the selected values */ -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -+ val); -+ if (ret) -+ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -+ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); -+} -+ -+static void - qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, - const struct phylink_link_state *state) - { - struct qca8k_priv *priv = ds->priv; - int cpu_port_index, ret; -- u32 reg, val, delay; -+ u32 reg, val; - - switch (port) { - case 0: /* 1st CPU port */ -@@ -1315,32 +1362,10 @@ qca8k_phylink_mac_config(struct dsa_swit - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: -- val = QCA8K_PORT_PAD_RGMII_EN; -- -- /* Delay can be declared in 3 different way. -- * Mode to rgmii and internal-delay standard binding defined -- * rgmii-id or rgmii-tx/rx phy mode set. -- * The parse logic set a delay different than 0 only when one -- * of the 3 different way is used. In all other case delay is -- * not enabled. With ID or TX/RXID delay is enabled and set -- * to the default and recommended value. -- */ -- if (priv->rgmii_tx_delay[cpu_port_index]) { -- delay = priv->rgmii_tx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -- } -- -- if (priv->rgmii_rx_delay[cpu_port_index]) { -- delay = priv->rgmii_rx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -- } -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); - -- /* Set RGMII delay based on the selected values */ -- qca8k_write(priv, reg, val); -+ /* Configure rgmii delay */ -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); - - /* QCA8337 requires to set rgmii rx delay for all ports. - * This is enabled through PORT5_PAD_CTRL for all ports, -@@ -1411,6 +1436,13 @@ qca8k_phylink_mac_config(struct dsa_swit - QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | - QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, - val); -+ -+ /* From original code is reported port instability as SGMII also -+ * require delay set. Apply advised values here or take them from DT. -+ */ -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ - break; - default: - dev_err(ds->dev, "xMII mode %s not supported for port %d\n", ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -39,7 +39,9 @@ - #define QCA8K_REG_PORT5_PAD_CTRL 0x008 - #define QCA8K_REG_PORT6_PAD_CTRL 0x00c - #define QCA8K_PORT_PAD_RGMII_EN BIT(26) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) - #define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) - #define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) - #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) - #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) diff --git a/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch b/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch deleted file mode 100644 index b991798c87f..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-14-net-dsa-qca8k-move-port-config-to-dedicated-struct.patch +++ /dev/null @@ -1,124 +0,0 @@ -From fd0bb28c547f7c8affb1691128cece38f5b626a1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:19 +0200 -Subject: net: dsa: qca8k: move port config to dedicated struct - -Move ports related config to dedicated struct to keep things organized. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 26 +++++++++++++------------- - drivers/net/dsa/qca8k.h | 10 +++++++--- - 2 files changed, 20 insertions(+), 16 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1019,7 +1019,7 @@ qca8k_parse_port_config(struct qca8k_pri - delay = 3; - } - -- priv->rgmii_tx_delay[cpu_port_index] = delay; -+ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; - - delay = 0; - -@@ -1035,7 +1035,7 @@ qca8k_parse_port_config(struct qca8k_pri - delay = 3; - } - -- priv->rgmii_rx_delay[cpu_port_index] = delay; -+ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; - - /* Skip sgmii parsing for rgmii* mode */ - if (mode == PHY_INTERFACE_MODE_RGMII || -@@ -1045,17 +1045,17 @@ qca8k_parse_port_config(struct qca8k_pri - break; - - if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -- priv->sgmii_tx_clk_falling_edge = true; -+ priv->ports_config.sgmii_tx_clk_falling_edge = true; - - if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -- priv->sgmii_rx_clk_falling_edge = true; -+ priv->ports_config.sgmii_rx_clk_falling_edge = true; - - if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -- priv->sgmii_enable_pll = true; -+ priv->ports_config.sgmii_enable_pll = true; - - if (priv->switch_id == QCA8K_ID_QCA8327) { - dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -- priv->sgmii_enable_pll = false; -+ priv->ports_config.sgmii_enable_pll = false; - } - - if (priv->switch_revision < 2) -@@ -1281,15 +1281,15 @@ qca8k_mac_config_setup_internal_delay(st - * not enabled. With ID or TX/RXID delay is enabled and set - * to the default and recommended value. - */ -- if (priv->rgmii_tx_delay[cpu_port_index]) { -- delay = priv->rgmii_tx_delay[cpu_port_index]; -+ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; - - val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | - QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; - } - -- if (priv->rgmii_rx_delay[cpu_port_index]) { -- delay = priv->rgmii_rx_delay[cpu_port_index]; -+ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; - - val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | - QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -@@ -1397,7 +1397,7 @@ qca8k_phylink_mac_config(struct dsa_swit - - val |= QCA8K_SGMII_EN_SD; - -- if (priv->sgmii_enable_pll) -+ if (priv->ports_config.sgmii_enable_pll) - val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | - QCA8K_SGMII_EN_TX; - -@@ -1425,10 +1425,10 @@ qca8k_phylink_mac_config(struct dsa_swit - val = 0; - - /* SGMII Clock phase configuration */ -- if (priv->sgmii_rx_clk_falling_edge) -+ if (priv->ports_config.sgmii_rx_clk_falling_edge) - val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; - -- if (priv->sgmii_tx_clk_falling_edge) -+ if (priv->ports_config.sgmii_tx_clk_falling_edge) - val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; - - if (val) ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -270,15 +270,19 @@ enum { - QCA8K_CPU_PORT6, - }; - --struct qca8k_priv { -- u8 switch_id; -- u8 switch_revision; -+struct qca8k_ports_config { - bool sgmii_rx_clk_falling_edge; - bool sgmii_tx_clk_falling_edge; - bool sgmii_enable_pll; - u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ - u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+}; -+ -+struct qca8k_priv { -+ u8 switch_id; -+ u8 switch_revision; - bool legacy_phy_port_mapping; -+ struct qca8k_ports_config ports_config; - struct regmap *regmap; - struct mii_bus *bus; - struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; diff --git a/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch b/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch deleted file mode 100644 index f7cb5141763..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-15-dt-bindings-net-ipq8064-mdio-fix-warning-with-new-qc.patch +++ /dev/null @@ -1,26 +0,0 @@ -From e52073a8e3086046a098b8a7cbeb282ff0cdb424 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Thu, 14 Oct 2021 00:39:20 +0200 -Subject: dt-bindings: net: ipq8064-mdio: fix warning with new qca8k switch - -Fix warning now that we have qca8k switch Documentation using yaml. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml -+++ b/Documentation/devicetree/bindings/net/qcom,ipq8064-mdio.yaml -@@ -51,6 +51,9 @@ examples: - switch@10 { - compatible = "qca,qca8337"; - reg = <0x10>; -- /* ... */ -+ -+ ports { -+ /* ... */ -+ }; - }; - }; diff --git a/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch b/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch deleted file mode 100644 index b9bce97dd3d..00000000000 --- a/target/linux/generic/backport-6.1/747-v5.16-16-dt-bindings-net-dsa-qca8k-convert-to-YAML-schema.patch +++ /dev/null @@ -1,631 +0,0 @@ -From d291fbb8245d5ba04979fed85575860a5cea7196 Mon Sep 17 00:00:00 2001 -From: Matthew Hagan -Date: Thu, 14 Oct 2021 00:39:21 +0200 -Subject: dt-bindings: net: dsa: qca8k: convert to YAML schema - -Convert the qca8k bindings to YAML format. - -Signed-off-by: Matthew Hagan -Co-developed-by: Ansuel Smith -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - .../devicetree/bindings/net/dsa/qca8k.txt | 245 -------------- - .../devicetree/bindings/net/dsa/qca8k.yaml | 362 +++++++++++++++++++++ - 2 files changed, 362 insertions(+), 245 deletions(-) - delete mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.txt - create mode 100644 Documentation/devicetree/bindings/net/dsa/qca8k.yaml - ---- a/Documentation/devicetree/bindings/net/dsa/qca8k.txt -+++ /dev/null -@@ -1,245 +0,0 @@ --* Qualcomm Atheros QCA8xxx switch family -- --Required properties: -- --- compatible: should be one of: -- "qca,qca8328": referenced as AR8328(N)-AK1(A/B) QFN 176 pin package -- "qca,qca8327": referenced as AR8327(N)-AL1A DR-QFN 148 pin package -- "qca,qca8334": referenced as QCA8334-AL3C QFN 88 pin package -- "qca,qca8337": referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package -- --- #size-cells: must be 0 --- #address-cells: must be 1 -- --Optional properties: -- --- reset-gpios: GPIO to be used to reset the whole device --- qca,ignore-power-on-sel: Ignore power on pin strapping to configure led open -- drain or eeprom presence. This is needed for broken -- devices that have wrong configuration or when the oem -- decided to not use pin strapping and fallback to sw -- regs. --- qca,led-open-drain: Set leds to open-drain mode. This requires the -- qca,ignore-power-on-sel to be set or the driver will fail -- to probe. This is needed if the oem doesn't use pin -- strapping to set this mode and prefers to set it using sw -- regs. The pin strapping related to led open drain mode is -- the pin B68 for QCA832x and B49 for QCA833x -- --Subnodes: -- --The integrated switch subnode should be specified according to the binding --described in dsa/dsa.txt. If the QCA8K switch is connect to a SoC's external --mdio-bus each subnode describing a port needs to have a valid phandle --referencing the internal PHY it is connected to. This is because there's no --N:N mapping of port and PHY id. --To declare the internal mdio-bus configuration, declare a mdio node in the --switch node and declare the phandle for the port referencing the internal --PHY is connected to. In this config a internal mdio-bus is registered and --the mdio MASTER is used as communication. -- --Don't use mixed external and internal mdio-bus configurations, as this is --not supported by the hardware. -- --This switch support 2 CPU port. Normally and advised configuration is with --CPU port set to port 0. It is also possible to set the CPU port to port 6 --if the device requires it. The driver will configure the switch to the defined --port. With both CPU port declared the first CPU port is selected as primary --and the secondary CPU ignored. -- --A CPU port node has the following optional node: -- --- fixed-link : Fixed-link subnode describing a link to a non-MDIO -- managed entity. See -- Documentation/devicetree/bindings/net/fixed-link.txt -- for details. --- qca,sgmii-rxclk-falling-edge: Set the receive clock phase to falling edge. -- Mostly used in qca8327 with CPU port 0 set to -- sgmii. --- qca,sgmii-txclk-falling-edge: Set the transmit clock phase to falling edge. --- qca,sgmii-enable-pll : For SGMII CPU port, explicitly enable PLL, TX and RX -- chain along with Signal Detection. -- This should NOT be enabled for qca8327. If enabled with -- qca8327 the sgmii port won't correctly init and an err -- is printed. -- This can be required for qca8337 switch with revision 2. -- A warning is displayed when used with revision greater -- 2. -- With CPU port set to sgmii and qca8337 it is advised -- to set this unless a communication problem is observed. -- --For QCA8K the 'fixed-link' sub-node supports only the following properties: -- --- 'speed' (integer, mandatory), to indicate the link speed. Accepted -- values are 10, 100 and 1000 --- 'full-duplex' (boolean, optional), to indicate that full duplex is -- used. When absent, half duplex is assumed. -- --Examples: -- --for the external mdio-bus configuration: -- -- &mdio0 { -- phy_port1: phy@0 { -- reg = <0>; -- }; -- -- phy_port2: phy@1 { -- reg = <1>; -- }; -- -- phy_port3: phy@2 { -- reg = <2>; -- }; -- -- phy_port4: phy@3 { -- reg = <3>; -- }; -- -- phy_port5: phy@4 { -- reg = <4>; -- }; -- -- switch@10 { -- compatible = "qca,qca8337"; -- #address-cells = <1>; -- #size-cells = <0>; -- -- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; -- reg = <0x10>; -- -- ports { -- #address-cells = <1>; -- #size-cells = <0>; -- port@0 { -- reg = <0>; -- label = "cpu"; -- ethernet = <&gmac1>; -- phy-mode = "rgmii"; -- fixed-link { -- speed = 1000; -- full-duplex; -- }; -- }; -- -- port@1 { -- reg = <1>; -- label = "lan1"; -- phy-handle = <&phy_port1>; -- }; -- -- port@2 { -- reg = <2>; -- label = "lan2"; -- phy-handle = <&phy_port2>; -- }; -- -- port@3 { -- reg = <3>; -- label = "lan3"; -- phy-handle = <&phy_port3>; -- }; -- -- port@4 { -- reg = <4>; -- label = "lan4"; -- phy-handle = <&phy_port4>; -- }; -- -- port@5 { -- reg = <5>; -- label = "wan"; -- phy-handle = <&phy_port5>; -- }; -- }; -- }; -- }; -- --for the internal master mdio-bus configuration: -- -- &mdio0 { -- switch@10 { -- compatible = "qca,qca8337"; -- #address-cells = <1>; -- #size-cells = <0>; -- -- reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; -- reg = <0x10>; -- -- ports { -- #address-cells = <1>; -- #size-cells = <0>; -- -- port@0 { -- reg = <0>; -- label = "cpu"; -- ethernet = <&gmac1>; -- phy-mode = "rgmii"; -- fixed-link { -- speed = 1000; -- full-duplex; -- }; -- }; -- -- port@1 { -- reg = <1>; -- label = "lan1"; -- phy-mode = "internal"; -- phy-handle = <&phy_port1>; -- }; -- -- port@2 { -- reg = <2>; -- label = "lan2"; -- phy-mode = "internal"; -- phy-handle = <&phy_port2>; -- }; -- -- port@3 { -- reg = <3>; -- label = "lan3"; -- phy-mode = "internal"; -- phy-handle = <&phy_port3>; -- }; -- -- port@4 { -- reg = <4>; -- label = "lan4"; -- phy-mode = "internal"; -- phy-handle = <&phy_port4>; -- }; -- -- port@5 { -- reg = <5>; -- label = "wan"; -- phy-mode = "internal"; -- phy-handle = <&phy_port5>; -- }; -- }; -- -- mdio { -- #address-cells = <1>; -- #size-cells = <0>; -- -- phy_port1: phy@0 { -- reg = <0>; -- }; -- -- phy_port2: phy@1 { -- reg = <1>; -- }; -- -- phy_port3: phy@2 { -- reg = <2>; -- }; -- -- phy_port4: phy@3 { -- reg = <3>; -- }; -- -- phy_port5: phy@4 { -- reg = <4>; -- }; -- }; -- }; -- }; ---- /dev/null -+++ b/Documentation/devicetree/bindings/net/dsa/qca8k.yaml -@@ -0,0 +1,362 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/net/dsa/qca8k.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Qualcomm Atheros QCA83xx switch family -+ -+maintainers: -+ - John Crispin -+ -+description: -+ If the QCA8K switch is connect to an SoC's external mdio-bus, each subnode -+ describing a port needs to have a valid phandle referencing the internal PHY -+ it is connected to. This is because there is no N:N mapping of port and PHY -+ ID. To declare the internal mdio-bus configuration, declare an MDIO node in -+ the switch node and declare the phandle for the port, referencing the internal -+ PHY it is connected to. In this config, an internal mdio-bus is registered and -+ the MDIO master is used for communication. Mixed external and internal -+ mdio-bus configurations are not supported by the hardware. -+ -+properties: -+ compatible: -+ oneOf: -+ - enum: -+ - qca,qca8327 -+ - qca,qca8328 -+ - qca,qca8334 -+ - qca,qca8337 -+ description: | -+ qca,qca8328: referenced as AR8328(N)-AK1(A/B) QFN 176 pin package -+ qca,qca8327: referenced as AR8327(N)-AL1A DR-QFN 148 pin package -+ qca,qca8334: referenced as QCA8334-AL3C QFN 88 pin package -+ qca,qca8337: referenced as QCA8337N-AL3(B/C) DR-QFN 148 pin package -+ -+ reg: -+ maxItems: 1 -+ -+ reset-gpios: -+ description: -+ GPIO to be used to reset the whole device -+ maxItems: 1 -+ -+ qca,ignore-power-on-sel: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ Ignore power-on pin strapping to configure LED open-drain or EEPROM -+ presence. This is needed for devices with incorrect configuration or when -+ the OEM has decided not to use pin strapping and falls back to SW regs. -+ -+ qca,led-open-drain: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ Set LEDs to open-drain mode. This requires the qca,ignore-power-on-sel to -+ be set, otherwise the driver will fail at probe. This is required if the -+ OEM does not use pin strapping to set this mode and prefers to set it -+ using SW regs. The pin strappings related to LED open-drain mode are -+ B68 on the QCA832x and B49 on the QCA833x. -+ -+ mdio: -+ type: object -+ description: Qca8k switch have an internal mdio to access switch port. -+ If this is not present, the legacy mapping is used and the -+ internal mdio access is used. -+ With the legacy mapping the reg corresponding to the internal -+ mdio is the switch reg with an offset of -1. -+ -+ properties: -+ '#address-cells': -+ const: 1 -+ '#size-cells': -+ const: 0 -+ -+ patternProperties: -+ "^(ethernet-)?phy@[0-4]$": -+ type: object -+ -+ allOf: -+ - $ref: "http://devicetree.org/schemas/net/mdio.yaml#" -+ -+ properties: -+ reg: -+ maxItems: 1 -+ -+ required: -+ - reg -+ -+patternProperties: -+ "^(ethernet-)?ports$": -+ type: object -+ properties: -+ '#address-cells': -+ const: 1 -+ '#size-cells': -+ const: 0 -+ -+ patternProperties: -+ "^(ethernet-)?port@[0-6]$": -+ type: object -+ description: Ethernet switch ports -+ -+ properties: -+ reg: -+ description: Port number -+ -+ label: -+ description: -+ Describes the label associated with this port, which will become -+ the netdev name -+ $ref: /schemas/types.yaml#/definitions/string -+ -+ link: -+ description: -+ Should be a list of phandles to other switch's DSA port. This -+ port is used as the outgoing port towards the phandle ports. The -+ full routing information must be given, not just the one hop -+ routes to neighbouring switches -+ $ref: /schemas/types.yaml#/definitions/phandle-array -+ -+ ethernet: -+ description: -+ Should be a phandle to a valid Ethernet device node. This host -+ device is what the switch port is connected to -+ $ref: /schemas/types.yaml#/definitions/phandle -+ -+ phy-handle: true -+ -+ phy-mode: true -+ -+ fixed-link: true -+ -+ mac-address: true -+ -+ sfp: true -+ -+ qca,sgmii-rxclk-falling-edge: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ Set the receive clock phase to falling edge. Mostly commonly used on -+ the QCA8327 with CPU port 0 set to SGMII. -+ -+ qca,sgmii-txclk-falling-edge: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ Set the transmit clock phase to falling edge. -+ -+ qca,sgmii-enable-pll: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ For SGMII CPU port, explicitly enable PLL, TX and RX chain along with -+ Signal Detection. On the QCA8327 this should not be enabled, otherwise -+ the SGMII port will not initialize. When used on the QCA8337, revision 3 -+ or greater, a warning will be displayed. When the CPU port is set to -+ SGMII on the QCA8337, it is advised to set this unless a communication -+ issue is observed. -+ -+ required: -+ - reg -+ -+ additionalProperties: false -+ -+oneOf: -+ - required: -+ - ports -+ - required: -+ - ethernet-ports -+ -+required: -+ - compatible -+ - reg -+ -+additionalProperties: true -+ -+examples: -+ - | -+ #include -+ -+ mdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ external_phy_port1: ethernet-phy@0 { -+ reg = <0>; -+ }; -+ -+ external_phy_port2: ethernet-phy@1 { -+ reg = <1>; -+ }; -+ -+ external_phy_port3: ethernet-phy@2 { -+ reg = <2>; -+ }; -+ -+ external_phy_port4: ethernet-phy@3 { -+ reg = <3>; -+ }; -+ -+ external_phy_port5: ethernet-phy@4 { -+ reg = <4>; -+ }; -+ -+ switch@10 { -+ compatible = "qca,qca8337"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; -+ reg = <0x10>; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ label = "cpu"; -+ ethernet = <&gmac1>; -+ phy-mode = "rgmii"; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ label = "lan1"; -+ phy-handle = <&external_phy_port1>; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ label = "lan2"; -+ phy-handle = <&external_phy_port2>; -+ }; -+ -+ port@3 { -+ reg = <3>; -+ label = "lan3"; -+ phy-handle = <&external_phy_port3>; -+ }; -+ -+ port@4 { -+ reg = <4>; -+ label = "lan4"; -+ phy-handle = <&external_phy_port4>; -+ }; -+ -+ port@5 { -+ reg = <5>; -+ label = "wan"; -+ phy-handle = <&external_phy_port5>; -+ }; -+ }; -+ }; -+ }; -+ - | -+ #include -+ -+ mdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ switch@10 { -+ compatible = "qca,qca8337"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ reset-gpios = <&gpio 42 GPIO_ACTIVE_LOW>; -+ reg = <0x10>; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ label = "cpu"; -+ ethernet = <&gmac1>; -+ phy-mode = "rgmii"; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ label = "lan1"; -+ phy-mode = "internal"; -+ phy-handle = <&internal_phy_port1>; -+ }; -+ -+ port@2 { -+ reg = <2>; -+ label = "lan2"; -+ phy-mode = "internal"; -+ phy-handle = <&internal_phy_port2>; -+ }; -+ -+ port@3 { -+ reg = <3>; -+ label = "lan3"; -+ phy-mode = "internal"; -+ phy-handle = <&internal_phy_port3>; -+ }; -+ -+ port@4 { -+ reg = <4>; -+ label = "lan4"; -+ phy-mode = "internal"; -+ phy-handle = <&internal_phy_port4>; -+ }; -+ -+ port@5 { -+ reg = <5>; -+ label = "wan"; -+ phy-mode = "internal"; -+ phy-handle = <&internal_phy_port5>; -+ }; -+ -+ port@6 { -+ reg = <0>; -+ label = "cpu"; -+ ethernet = <&gmac1>; -+ phy-mode = "sgmii"; -+ -+ qca,sgmii-rxclk-falling-edge; -+ -+ fixed-link { -+ speed = <1000>; -+ full-duplex; -+ }; -+ }; -+ }; -+ -+ mdio { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ internal_phy_port1: ethernet-phy@0 { -+ reg = <0>; -+ }; -+ -+ internal_phy_port2: ethernet-phy@1 { -+ reg = <1>; -+ }; -+ -+ internal_phy_port3: ethernet-phy@2 { -+ reg = <2>; -+ }; -+ -+ internal_phy_port4: ethernet-phy@3 { -+ reg = <3>; -+ }; -+ -+ internal_phy_port5: ethernet-phy@4 { -+ reg = <4>; -+ }; -+ }; -+ }; -+ }; diff --git a/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch b/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch deleted file mode 100644 index a510cfdc183..00000000000 --- a/target/linux/generic/backport-6.1/748-v5.16-net-dsa-qca8k-fix-delay-applied-to-wrong-cpu-in-parse-p.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 06dd34a628ae5b6a839b757e746de165d6789ca8 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sun, 17 Oct 2021 16:56:46 +0200 -Subject: net: dsa: qca8k: fix delay applied to wrong cpu in parse_port_config - -Fix delay settings applied to wrong cpu in parse_port_config. The delay -values is set to the wrong index as the cpu_port_index is incremented -too early. Start the cpu_port_index to -1 so the correct value is -applied to address also the case with invalid phy mode and not available -port. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -976,7 +976,7 @@ qca8k_setup_of_pws_reg(struct qca8k_priv - static int - qca8k_parse_port_config(struct qca8k_priv *priv) - { -- int port, cpu_port_index = 0, ret; -+ int port, cpu_port_index = -1, ret; - struct device_node *port_dn; - phy_interface_t mode; - struct dsa_port *dp; diff --git a/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch b/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch deleted file mode 100644 index 71fa3022d55..00000000000 --- a/target/linux/generic/backport-6.1/749-v5.16-net-dsa-qca8k-tidy-for-loop-in-setup-and-add-cpu-port-c.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 040e926f5813a5f4cc18dbff7c942d1e52f368f2 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 19 Oct 2021 02:08:50 +0200 -Subject: net: dsa: qca8k: tidy for loop in setup and add cpu port check - -Tidy and organize qca8k setup function from multiple for loop. -Change for loop in bridge leave/join to scan all port and skip cpu port. -No functional change intended. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 74 +++++++++++++++++++++++++++++-------------------- - 1 file changed, 44 insertions(+), 30 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1122,28 +1122,34 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - dev_warn(priv->dev, "mib init failed"); - -- /* Enable QCA header mode on the cpu port */ -- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(cpu_port), -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -- if (ret) { -- dev_err(priv->dev, "failed enabling QCA header mode"); -- return ret; -- } -- -- /* Disable forwarding by default on all ports */ -+ /* Initial setup of all ports */ - for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* Disable forwarding by default on all ports */ - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_MEMBER, 0); - if (ret) - return ret; -- } - -- /* Disable MAC by default on all ports */ -- for (i = 1; i < QCA8K_NUM_PORTS; i++) -- qca8k_port_set_status(priv, i, 0); -+ /* Enable QCA header mode on all cpu ports */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -+ QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling QCA header mode"); -+ return ret; -+ } -+ } -+ -+ /* Disable MAC by default on all user ports */ -+ if (dsa_is_user_port(ds, i)) -+ qca8k_port_set_status(priv, i, 0); -+ } - -- /* Forward all unknown frames to CPU port for Linux processing */ -+ /* Forward all unknown frames to CPU port for Linux processing -+ * Notice that in multi-cpu config only one port should be set -+ * for igmp, unknown, multicast and broadcast packet -+ */ - ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | - BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -@@ -1152,11 +1158,13 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -- /* Setup connection between CPU port & user ports */ -+ /* Setup connection between CPU port & user ports -+ * Configure specific switch configuration for ports -+ */ - for (i = 0; i < QCA8K_NUM_PORTS; i++) { - /* CPU port gets connected to all user ports of the switch */ - if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port), -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); - if (ret) - return ret; -@@ -1193,16 +1201,14 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - } -- } - -- /* The port 5 of the qca8337 have some problem in flood condition. The -- * original legacy driver had some specific buffer and priority settings -- * for the different port suggested by the QCA switch team. Add this -- * missing settings to improve switch stability under load condition. -- * This problem is limited to qca8337 and other qca8k switch are not affected. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) { -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* The port 5 of the qca8337 have some problem in flood condition. The -+ * original legacy driver had some specific buffer and priority settings -+ * for the different port suggested by the QCA switch team. Add this -+ * missing settings to improve switch stability under load condition. -+ * This problem is limited to qca8337 and other qca8k switch are not affected. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) { - switch (i) { - /* The 2 CPU port and port 5 requires some different - * priority than any other ports. -@@ -1238,6 +1244,12 @@ qca8k_setup(struct dsa_switch *ds) - QCA8K_PORT_HOL_CTRL1_WRED_EN, - mask); - } -+ -+ /* Set initial MTU for every port. -+ * We have only have a general MTU setting. So track -+ * every port and set the max across all port. -+ */ -+ priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; - } - - /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -@@ -1251,8 +1263,6 @@ qca8k_setup(struct dsa_switch *ds) - } - - /* Setup our port MTUs to match power on defaults */ -- for (i = 0; i < QCA8K_NUM_PORTS; i++) -- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; - ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); - if (ret) - dev_warn(priv->dev, "failed setting MTU settings"); -@@ -1728,7 +1738,9 @@ qca8k_port_bridge_join(struct dsa_switch - cpu_port = dsa_to_port(ds, port)->cpu_dp->index; - port_mask = BIT(cpu_port); - -- for (i = 1; i < QCA8K_NUM_PORTS; i++) { -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; - if (dsa_to_port(ds, i)->bridge_dev != br) - continue; - /* Add this port to the portvlan mask of the other ports -@@ -1758,7 +1770,9 @@ qca8k_port_bridge_leave(struct dsa_switc - - cpu_port = dsa_to_port(ds, port)->cpu_dp->index; - -- for (i = 1; i < QCA8K_NUM_PORTS; i++) { -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; - if (dsa_to_port(ds, i)->bridge_dev != br) - continue; - /* Remove this port to the portvlan mask of the other ports diff --git a/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch b/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch deleted file mode 100644 index 4a61703c527..00000000000 --- a/target/linux/generic/backport-6.1/750-v5.16-net-dsa-qca8k-make-sure-pad0-mac06-exchange-is-disabled.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5f15d392dcb4aa250a63d6f2c5adfc26c0aedc78 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 2 Nov 2021 19:30:41 +0100 -Subject: net: dsa: qca8k: make sure PAD0 MAC06 exchange is disabled - -Some device set MAC06 exchange in the bootloader. This cause some -problem as we don't support this strange mode and we just set the port6 -as the primary CPU port. With MAC06 exchange, PAD0 reg configure port6 -instead of port0. Add an extra check and explicitly disable MAC06 exchange -to correctly configure the port PAD config. - -Signed-off-by: Ansuel Smith -Fixes: 3fcf734aa482 ("net: dsa: qca8k: add support for cpu port 6") -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 8 ++++++++ - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 9 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1109,6 +1109,14 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -+ /* Make sure MAC06 is disabled */ -+ ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, -+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed disabling MAC06 exchange"); -+ return ret; -+ } -+ - /* Enable CPU Port */ - ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, - QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -34,6 +34,7 @@ - #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) - #define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) - #define QCA8K_REG_PORT0_PAD_CTRL 0x004 -+#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) - #define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) - #define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) - #define QCA8K_REG_PORT5_PAD_CTRL 0x008 diff --git a/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch b/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch deleted file mode 100644 index df9518d86cd..00000000000 --- a/target/linux/generic/backport-6.1/751-v5.16-net-dsa-qca8k-fix-internal-delay-applied-to-the-wrong-PAD.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 3b00a07c2443745d62babfe08dbb2ad8e649526e Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Fri, 19 Nov 2021 03:03:49 +0100 -Subject: [PATCH] net: dsa: qca8k: fix internal delay applied to the wrong PAD - config - -With SGMII phy the internal delay is always applied to the PAD0 config. -This is caused by the falling edge configuration that hardcode the reg -to PAD0 (as the falling edge bits are present only in PAD0 reg) -Move the delay configuration before the reg overwrite to correctly apply -the delay. - -Fixes: cef08115846e ("net: dsa: qca8k: set internal delay also for sgmii") -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1433,6 +1433,12 @@ qca8k_phylink_mac_config(struct dsa_swit - - qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); - -+ /* From original code is reported port instability as SGMII also -+ * require delay set. Apply advised values here or take them from DT. -+ */ -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ - /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and - * falling edge is set writing in the PORT0 PAD reg - */ -@@ -1455,12 +1461,6 @@ qca8k_phylink_mac_config(struct dsa_swit - QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, - val); - -- /* From original code is reported port instability as SGMII also -- * require delay set. Apply advised values here or take them from DT. -- */ -- if (state->interface == PHY_INTERFACE_MODE_SGMII) -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- - break; - default: - dev_err(ds->dev, "xMII mode %s not supported for port %d\n", diff --git a/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch b/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch deleted file mode 100644 index 7348d93ec44..00000000000 --- a/target/linux/generic/backport-6.1/752-v5.16-net-dsa-qca8k-fix-MTU-calculation.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 65258b9d8cde45689bdc86ca39b50f01f983733b Mon Sep 17 00:00:00 2001 -From: Robert Marko -Date: Fri, 19 Nov 2021 03:03:50 +0100 -Subject: [PATCH] net: dsa: qca8k: fix MTU calculation - -qca8k has a global MTU, so its tracking the MTU per port to make sure -that the largest MTU gets applied. -Since it uses the frame size instead of MTU the driver MTU change function -will then add the size of Ethernet header and checksum on top of MTU. - -The driver currently populates the per port MTU size as Ethernet frame -length + checksum which equals 1518. - -The issue is that then MTU change function will go through all of the -ports, find the largest MTU and apply the Ethernet header + checksum on -top of it again, so for a desired MTU of 1500 you will end up with 1536. - -This is obviously incorrect, so to correct it populate the per port struct -MTU with just the MTU and not include the Ethernet header + checksum size -as those will be added by the MTU change function. - -Fixes: f58d2598cf70 ("net: dsa: qca8k: implement the port MTU callbacks") -Signed-off-by: Robert Marko -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1256,8 +1256,12 @@ qca8k_setup(struct dsa_switch *ds) - /* Set initial MTU for every port. - * We have only have a general MTU setting. So track - * every port and set the max across all port. -+ * Set per port MTU to 1500 as the MTU change function -+ * will add the overhead and if its set to 1518 then it -+ * will apply the overhead again and we will end up with -+ * MTU of 1536 instead of 1518 - */ -- priv->port_mtu[i] = ETH_FRAME_LEN + ETH_FCS_LEN; -+ priv->port_mtu[i] = ETH_DATA_LEN; - } - - /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ diff --git a/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch b/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch deleted file mode 100644 index f477b1b9298..00000000000 --- a/target/linux/generic/backport-6.1/753-v5.17-net-next-net-dsa-qca8k-remove-redundant-check-in-parse_port_config.patch +++ /dev/null @@ -1,29 +0,0 @@ -From b9133f3ef5a2659730cf47a74bd0a9259f1cf8ff Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:40 +0100 -Subject: net: dsa: qca8k: remove redundant check in parse_port_config - -The very next check for port 0 and 6 already makes sure we don't go out -of bounds with the ports_config delay table. -Remove the redundant check. - -Reported-by: kernel test robot -Reported-by: Dan Carpenter -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -983,7 +983,7 @@ qca8k_parse_port_config(struct qca8k_pri - u32 delay; - - /* We have 2 CPU port. Check them */ -- for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) { -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { - /* Skip every other port */ - if (port != 0 && port != 6) - continue; diff --git a/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch b/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch deleted file mode 100644 index 2cea88089db..00000000000 --- a/target/linux/generic/backport-6.1/754-v5.17-net-next-net-dsa-qca8k-convert-to-GENMASK_FIELD_PREP_FIELD_GET.patch +++ /dev/null @@ -1,507 +0,0 @@ -From 90ae68bfc2ffcb54a4ba4f64edbeb84a80cbb57c Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:41 +0100 -Subject: net: dsa: qca8k: convert to GENMASK/FIELD_PREP/FIELD_GET - -Convert and try to standardize bit fields using -GENMASK/FIELD_PREP/FIELD_GET macros. Rework some logic to support the -standard macro and tidy things up. No functional change intended. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 98 +++++++++++++++---------------- - drivers/net/dsa/qca8k.h | 153 ++++++++++++++++++++++++++---------------------- - 2 files changed, 130 insertions(+), 121 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -319,18 +320,18 @@ qca8k_fdb_read(struct qca8k_priv *priv, - } - - /* vid - 83:72 */ -- fdb->vid = (reg[2] >> QCA8K_ATU_VID_S) & QCA8K_ATU_VID_M; -+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); - /* aging - 67:64 */ -- fdb->aging = reg[2] & QCA8K_ATU_STATUS_M; -+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); - /* portmask - 54:48 */ -- fdb->port_mask = (reg[1] >> QCA8K_ATU_PORT_S) & QCA8K_ATU_PORT_M; -+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); - /* mac - 47:0 */ -- fdb->mac[0] = (reg[1] >> QCA8K_ATU_ADDR0_S) & 0xff; -- fdb->mac[1] = reg[1] & 0xff; -- fdb->mac[2] = (reg[0] >> QCA8K_ATU_ADDR2_S) & 0xff; -- fdb->mac[3] = (reg[0] >> QCA8K_ATU_ADDR3_S) & 0xff; -- fdb->mac[4] = (reg[0] >> QCA8K_ATU_ADDR4_S) & 0xff; -- fdb->mac[5] = reg[0] & 0xff; -+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); - - return 0; - } -@@ -343,18 +344,18 @@ qca8k_fdb_write(struct qca8k_priv *priv, - int i; - - /* vid - 83:72 */ -- reg[2] = (vid & QCA8K_ATU_VID_M) << QCA8K_ATU_VID_S; -+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); - /* aging - 67:64 */ -- reg[2] |= aging & QCA8K_ATU_STATUS_M; -+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); - /* portmask - 54:48 */ -- reg[1] = (port_mask & QCA8K_ATU_PORT_M) << QCA8K_ATU_PORT_S; -+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); - /* mac - 47:0 */ -- reg[1] |= mac[0] << QCA8K_ATU_ADDR0_S; -- reg[1] |= mac[1]; -- reg[0] |= mac[2] << QCA8K_ATU_ADDR2_S; -- reg[0] |= mac[3] << QCA8K_ATU_ADDR3_S; -- reg[0] |= mac[4] << QCA8K_ATU_ADDR4_S; -- reg[0] |= mac[5]; -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); - - /* load the array into the ARL table */ - for (i = 0; i < 3; i++) -@@ -372,7 +373,7 @@ qca8k_fdb_access(struct qca8k_priv *priv - reg |= cmd; - if (port >= 0) { - reg |= QCA8K_ATU_FUNC_PORT_EN; -- reg |= (port & QCA8K_ATU_FUNC_PORT_M) << QCA8K_ATU_FUNC_PORT_S; -+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); - } - - /* Write the function register triggering the table access */ -@@ -454,7 +455,7 @@ qca8k_vlan_access(struct qca8k_priv *pri - /* Set the command and VLAN index */ - reg = QCA8K_VTU_FUNC1_BUSY; - reg |= cmd; -- reg |= vid << QCA8K_VTU_FUNC1_VID_S; -+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); - - /* Write the function register triggering the table access */ - ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -@@ -500,13 +501,11 @@ qca8k_vlan_add(struct qca8k_priv *priv, - if (ret < 0) - goto out; - reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -- reg &= ~(QCA8K_VTU_FUNC0_EG_MODE_MASK << QCA8K_VTU_FUNC0_EG_MODE_S(port)); -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); - if (untagged) -- reg |= QCA8K_VTU_FUNC0_EG_MODE_UNTAG << -- QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); - else -- reg |= QCA8K_VTU_FUNC0_EG_MODE_TAG << -- QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); - - ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); - if (ret) -@@ -534,15 +533,13 @@ qca8k_vlan_del(struct qca8k_priv *priv, - ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); - if (ret < 0) - goto out; -- reg &= ~(3 << QCA8K_VTU_FUNC0_EG_MODE_S(port)); -- reg |= QCA8K_VTU_FUNC0_EG_MODE_NOT << -- QCA8K_VTU_FUNC0_EG_MODE_S(port); -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); - - /* Check if we're the last member to be removed */ - del = true; - for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- mask = QCA8K_VTU_FUNC0_EG_MODE_NOT; -- mask <<= QCA8K_VTU_FUNC0_EG_MODE_S(i); -+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); - - if ((reg & mask) != mask) { - del = false; -@@ -1014,7 +1011,7 @@ qca8k_parse_port_config(struct qca8k_pri - mode == PHY_INTERFACE_MODE_RGMII_TXID) - delay = 1; - -- if (delay > QCA8K_MAX_DELAY) { -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { - dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); - delay = 3; - } -@@ -1030,7 +1027,7 @@ qca8k_parse_port_config(struct qca8k_pri - mode == PHY_INTERFACE_MODE_RGMII_RXID) - delay = 2; - -- if (delay > QCA8K_MAX_DELAY) { -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { - dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); - delay = 3; - } -@@ -1141,8 +1138,8 @@ qca8k_setup(struct dsa_switch *ds) - /* Enable QCA header mode on all cpu ports */ - if (dsa_is_cpu_port(ds, i)) { - ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_TX_S | -- QCA8K_PORT_HDR_CTRL_ALL << QCA8K_PORT_HDR_CTRL_RX_S); -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); - if (ret) { - dev_err(priv->dev, "failed enabling QCA header mode"); - return ret; -@@ -1159,10 +1156,10 @@ qca8k_setup(struct dsa_switch *ds) - * for igmp, unknown, multicast and broadcast packet - */ - ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_BC_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_MC_DP_S | -- BIT(cpu_port) << QCA8K_GLOBAL_FW_CTRL1_UC_DP_S); -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); - if (ret) - return ret; - -@@ -1180,8 +1177,6 @@ qca8k_setup(struct dsa_switch *ds) - - /* Individual user ports get connected to CPU port only */ - if (dsa_is_user_port(ds, i)) { -- int shift = 16 * (i % 2); -- - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), - QCA8K_PORT_LOOKUP_MEMBER, - BIT(cpu_port)); -@@ -1198,8 +1193,8 @@ qca8k_setup(struct dsa_switch *ds) - * default egress vid - */ - ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -- 0xfff << shift, -- QCA8K_PORT_VID_DEF << shift); -+ QCA8K_EGREES_VLAN_PORT_MASK(i), -+ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); - if (ret) - return ret; - -@@ -1246,7 +1241,7 @@ qca8k_setup(struct dsa_switch *ds) - QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | - QCA8K_PORT_HOL_CTRL1_WRED_EN; - qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -- QCA8K_PORT_HOL_CTRL1_ING_BUF | -+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | - QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | - QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | - QCA8K_PORT_HOL_CTRL1_WRED_EN, -@@ -1269,8 +1264,8 @@ qca8k_setup(struct dsa_switch *ds) - mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | - QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); - qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -- QCA8K_GLOBAL_FC_GOL_XON_THRES_S | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S, -+ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, - mask); - } - -@@ -1935,11 +1930,11 @@ qca8k_port_vlan_filtering(struct dsa_swi - - if (vlan_filtering) { - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, - QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); - } else { - ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, - QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); - } - -@@ -1963,10 +1958,9 @@ qca8k_port_vlan_add(struct dsa_switch *d - } - - if (pvid) { -- int shift = 16 * (port % 2); -- - ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -- 0xfff << shift, vlan->vid << shift); -+ QCA8K_EGREES_VLAN_PORT_MASK(port), -+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); - if (ret) - return ret; - -@@ -2060,7 +2054,7 @@ static int qca8k_read_switch_id(struct q - if (ret < 0) - return -ENODEV; - -- id = QCA8K_MASK_CTRL_DEVICE_ID(val & QCA8K_MASK_CTRL_DEVICE_ID_MASK); -+ id = QCA8K_MASK_CTRL_DEVICE_ID(val); - if (id != data->id) { - dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); - return -ENODEV; -@@ -2069,7 +2063,7 @@ static int qca8k_read_switch_id(struct q - priv->switch_id = id; - - /* Save revision to communicate to the internal PHY driver */ -- priv->switch_revision = (val & QCA8K_MASK_CTRL_REV_ID_MASK); -+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); - - return 0; - } ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -30,9 +30,9 @@ - /* Global control registers */ - #define QCA8K_REG_MASK_CTRL 0x000 - #define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) --#define QCA8K_MASK_CTRL_REV_ID(x) ((x) >> 0) -+#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) - #define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) --#define QCA8K_MASK_CTRL_DEVICE_ID(x) ((x) >> 8) -+#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) - #define QCA8K_REG_PORT0_PAD_CTRL 0x004 - #define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) - #define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) -@@ -41,12 +41,11 @@ - #define QCA8K_REG_PORT6_PAD_CTRL 0x00c - #define QCA8K_PORT_PAD_RGMII_EN BIT(26) - #define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) --#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) ((x) << 22) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) - #define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) --#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) ((x) << 20) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) - #define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) - #define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) --#define QCA8K_MAX_DELAY 3 - #define QCA8K_PORT_PAD_SGMII_EN BIT(7) - #define QCA8K_REG_PWS 0x010 - #define QCA8K_PWS_POWER_ON_SEL BIT(31) -@@ -68,10 +67,12 @@ - #define QCA8K_MDIO_MASTER_READ BIT(27) - #define QCA8K_MDIO_MASTER_WRITE 0 - #define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) --#define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21) --#define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16) --#define QCA8K_MDIO_MASTER_DATA(x) (x) -+#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) -+#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) -+#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) -+#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) - #define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) -+#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) - #define QCA8K_MDIO_MASTER_MAX_PORTS 5 - #define QCA8K_MDIO_MASTER_MAX_REG 32 - #define QCA8K_GOL_MAC_ADDR0 0x60 -@@ -93,9 +94,7 @@ - #define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) - #define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) - #define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) --#define QCA8K_PORT_HDR_CTRL_RX_S 2 - #define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) --#define QCA8K_PORT_HDR_CTRL_TX_S 0 - #define QCA8K_PORT_HDR_CTRL_ALL 2 - #define QCA8K_PORT_HDR_CTRL_MGMT 1 - #define QCA8K_PORT_HDR_CTRL_NONE 0 -@@ -105,10 +104,11 @@ - #define QCA8K_SGMII_EN_TX BIT(3) - #define QCA8K_SGMII_EN_SD BIT(4) - #define QCA8K_SGMII_CLK125M_DELAY BIT(7) --#define QCA8K_SGMII_MODE_CTRL_MASK (BIT(22) | BIT(23)) --#define QCA8K_SGMII_MODE_CTRL_BASEX (0 << 22) --#define QCA8K_SGMII_MODE_CTRL_PHY (1 << 22) --#define QCA8K_SGMII_MODE_CTRL_MAC (2 << 22) -+#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) -+#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) -+#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) -+#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) -+#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) - - /* MAC_PWR_SEL registers */ - #define QCA8K_REG_MAC_PWR_SEL 0x0e4 -@@ -121,100 +121,115 @@ - - /* ACL registers */ - #define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) --#define QCA8K_PORT_VLAN_CVID(x) (x << 16) --#define QCA8K_PORT_VLAN_SVID(x) x -+#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) -+#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) -+#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) -+#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) - #define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) - #define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 - #define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 - - /* Lookup registers */ - #define QCA8K_REG_ATU_DATA0 0x600 --#define QCA8K_ATU_ADDR2_S 24 --#define QCA8K_ATU_ADDR3_S 16 --#define QCA8K_ATU_ADDR4_S 8 -+#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) -+#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) -+#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) -+#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) - #define QCA8K_REG_ATU_DATA1 0x604 --#define QCA8K_ATU_PORT_M 0x7f --#define QCA8K_ATU_PORT_S 16 --#define QCA8K_ATU_ADDR0_S 8 -+#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) -+#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) -+#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) - #define QCA8K_REG_ATU_DATA2 0x608 --#define QCA8K_ATU_VID_M 0xfff --#define QCA8K_ATU_VID_S 8 --#define QCA8K_ATU_STATUS_M 0xf -+#define QCA8K_ATU_VID_MASK GENMASK(19, 8) -+#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) - #define QCA8K_ATU_STATUS_STATIC 0xf - #define QCA8K_REG_ATU_FUNC 0x60c - #define QCA8K_ATU_FUNC_BUSY BIT(31) - #define QCA8K_ATU_FUNC_PORT_EN BIT(14) - #define QCA8K_ATU_FUNC_MULTI_EN BIT(13) - #define QCA8K_ATU_FUNC_FULL BIT(12) --#define QCA8K_ATU_FUNC_PORT_M 0xf --#define QCA8K_ATU_FUNC_PORT_S 8 -+#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) - #define QCA8K_REG_VTU_FUNC0 0x610 - #define QCA8K_VTU_FUNC0_VALID BIT(20) - #define QCA8K_VTU_FUNC0_IVL_EN BIT(19) --#define QCA8K_VTU_FUNC0_EG_MODE_S(_i) (4 + (_i) * 2) --#define QCA8K_VTU_FUNC0_EG_MODE_MASK 3 --#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD 0 --#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG 1 --#define QCA8K_VTU_FUNC0_EG_MODE_TAG 2 --#define QCA8K_VTU_FUNC0_EG_MODE_NOT 3 -+/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) -+ * It does contain VLAN_MODE for each port [5:4] for port0, -+ * [7:6] for port1 ... [17:16] for port6. Use virtual port -+ * define to handle this. -+ */ -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) -+#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) - #define QCA8K_REG_VTU_FUNC1 0x614 - #define QCA8K_VTU_FUNC1_BUSY BIT(31) --#define QCA8K_VTU_FUNC1_VID_S 16 -+#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) - #define QCA8K_VTU_FUNC1_FULL BIT(4) - #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 - #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) - #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 --#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_S 24 --#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_S 16 --#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_S 8 --#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_S 0 -+#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) -+#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) -+#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) -+#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) - #define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) - #define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) --#define QCA8K_PORT_LOOKUP_VLAN_MODE GENMASK(9, 8) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE (0 << 8) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK (1 << 8) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK (2 << 8) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE (3 << 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) - #define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) --#define QCA8K_PORT_LOOKUP_STATE_DISABLED (0 << 16) --#define QCA8K_PORT_LOOKUP_STATE_BLOCKING (1 << 16) --#define QCA8K_PORT_LOOKUP_STATE_LISTENING (2 << 16) --#define QCA8K_PORT_LOOKUP_STATE_LEARNING (3 << 16) --#define QCA8K_PORT_LOOKUP_STATE_FORWARD (4 << 16) --#define QCA8K_PORT_LOOKUP_STATE GENMASK(18, 16) -+#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) -+#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) -+#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) -+#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) -+#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) -+#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) - #define QCA8K_PORT_LOOKUP_LEARN BIT(20) - - #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 --#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) ((x) << 16) --#define QCA8K_GLOBAL_FC_GOL_XON_THRES_S GENMASK(24, 16) --#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) ((x) << 0) --#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_S GENMASK(8, 0) -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) - - #define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF GENMASK(3, 0) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) ((x) << 0) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF GENMASK(7, 4) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) ((x) << 4) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF GENMASK(11, 8) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) ((x) << 8) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF GENMASK(15, 12) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) ((x) << 12) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF GENMASK(19, 16) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) ((x) << 16) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF GENMASK(23, 20) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) ((x) << 20) --#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF GENMASK(29, 24) --#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) ((x) << 24) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) - - #define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) --#define QCA8K_PORT_HOL_CTRL1_ING_BUF GENMASK(3, 0) --#define QCA8K_PORT_HOL_CTRL1_ING(x) ((x) << 0) -+#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) - #define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) - #define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) - #define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) - #define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) - - /* Pkt edit registers */ -+#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) -+#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) -+#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) - #define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) - - /* L3 registers */ diff --git a/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch b/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch deleted file mode 100644 index 8c39b8ea295..00000000000 --- a/target/linux/generic/backport-6.1/755-v5.17-net-next-net-dsa-qca8k-remove-extra-mutex_init-in-qca8k_setup.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 994c28b6f971fa5db8ae977daea37eee87d93d51 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:42 +0100 -Subject: net: dsa: qca8k: remove extra mutex_init in qca8k_setup - -Mutex is already init in sw_probe. Remove the extra init in qca8k_setup. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1086,8 +1086,6 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -- mutex_init(&priv->reg_mutex); -- - /* Start by setting up the register mapping */ - priv->regmap = devm_regmap_init(ds->dev, NULL, priv, - &qca8k_regmap_config); diff --git a/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch b/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch deleted file mode 100644 index 44d938c53e8..00000000000 --- a/target/linux/generic/backport-6.1/756-v5.17-net-next-net-dsa-qca8k-move-regmap-init-in-probe-and-set-it.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 36b8af12f424e7a7f60a935c60a0fd4aa0822378 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:43 +0100 -Subject: net: dsa: qca8k: move regmap init in probe and set it mandatory - -In preparation for regmap conversion, move regmap init in the probe -function and make it mandatory as any read/write/rmw operation will be -converted to regmap API. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 14 ++++++++------ - 1 file changed, 8 insertions(+), 6 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1086,12 +1086,6 @@ qca8k_setup(struct dsa_switch *ds) - if (ret) - return ret; - -- /* Start by setting up the register mapping */ -- priv->regmap = devm_regmap_init(ds->dev, NULL, priv, -- &qca8k_regmap_config); -- if (IS_ERR(priv->regmap)) -- dev_warn(priv->dev, "regmap initialization failed"); -- - ret = qca8k_setup_mdio_bus(priv); - if (ret) - return ret; -@@ -2096,6 +2090,14 @@ qca8k_sw_probe(struct mdio_device *mdiod - gpiod_set_value_cansleep(priv->reset_gpio, 0); - } - -+ /* Start by setting up the register mapping */ -+ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, -+ &qca8k_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ dev_err(priv->dev, "regmap initialization failed"); -+ return PTR_ERR(priv->regmap); -+ } -+ - /* Check the detected switch id */ - ret = qca8k_read_switch_id(priv); - if (ret) diff --git a/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch b/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch deleted file mode 100644 index 4ca9c8ba41d..00000000000 --- a/target/linux/generic/backport-6.1/757-v5.17-net-next-net-dsa-qca8k-initial-conversion-to-regmap-heper.patch +++ /dev/null @@ -1,249 +0,0 @@ -From 8b5f3f29a81a71934d004e21a1292c1148b05926 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:44 +0100 -Subject: net: dsa: qca8k: initial conversion to regmap helper - -Convert any qca8k set/clear/pool to regmap helper and add -missing config to regmap_config struct. -Read/write/rmw operation are reworked to use the regmap helper -internally to keep the delta of this patch low. These additional -function will then be dropped when the code split will be proposed. - -Ipq40xx SoC have the internal switch based on the qca8k regmap but use -mmio for read/write/rmw operation instead of mdio. -In preparation for the support of this internal switch, convert the -driver to regmap API to later split the driver to common and specific -code. The overhead introduced by the use of regamp API is marginal as the -internal mdio will bypass it by using its direct access and regmap will be -used only by configuration functions or fdb access. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 107 +++++++++++++++++++++--------------------------- - 1 file changed, 47 insertions(+), 60 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -152,6 +153,25 @@ qca8k_set_page(struct mii_bus *bus, u16 - static int - qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) - { -+ return regmap_read(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return regmap_write(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ return regmap_update_bits(priv->regmap, reg, mask, write_val); -+} -+ -+static int -+qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; - struct mii_bus *bus = priv->bus; - u16 r1, r2, page; - int ret; -@@ -172,8 +192,9 @@ exit: - } - - static int --qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) - { -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; - struct mii_bus *bus = priv->bus; - u16 r1, r2, page; - int ret; -@@ -194,8 +215,9 @@ exit: - } - - static int --qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) - { -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; - struct mii_bus *bus = priv->bus; - u16 r1, r2, page; - u32 val; -@@ -223,34 +245,6 @@ exit: - return ret; - } - --static int --qca8k_reg_set(struct qca8k_priv *priv, u32 reg, u32 val) --{ -- return qca8k_rmw(priv, reg, 0, val); --} -- --static int --qca8k_reg_clear(struct qca8k_priv *priv, u32 reg, u32 val) --{ -- return qca8k_rmw(priv, reg, val, 0); --} -- --static int --qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- -- return qca8k_read(priv, reg, val); --} -- --static int --qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- -- return qca8k_write(priv, reg, val); --} -- - static const struct regmap_range qca8k_readable_ranges[] = { - regmap_reg_range(0x0000, 0x00e4), /* Global control */ - regmap_reg_range(0x0100, 0x0168), /* EEE control */ -@@ -282,26 +276,19 @@ static struct regmap_config qca8k_regmap - .max_register = 0x16ac, /* end MIB - Port6 range */ - .reg_read = qca8k_regmap_read, - .reg_write = qca8k_regmap_write, -+ .reg_update_bits = qca8k_regmap_update_bits, - .rd_table = &qca8k_readable_table, -+ .disable_locking = true, /* Locking is handled by qca8k read/write */ -+ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ - }; - - static int - qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) - { -- int ret, ret1; - u32 val; - -- ret = read_poll_timeout(qca8k_read, ret1, !(val & mask), -- 0, QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- priv, reg, &val); -- -- /* Check if qca8k_read has failed for a different reason -- * before returning -ETIMEDOUT -- */ -- if (ret < 0 && ret1 < 0) -- return ret1; -- -- return ret; -+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); - } - - static int -@@ -568,7 +555,7 @@ qca8k_mib_init(struct qca8k_priv *priv) - int ret; - - mutex_lock(&priv->reg_mutex); -- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); - if (ret) - goto exit; - -@@ -576,7 +563,7 @@ qca8k_mib_init(struct qca8k_priv *priv) - if (ret) - goto exit; - -- ret = qca8k_reg_set(priv, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); - if (ret) - goto exit; - -@@ -597,9 +584,9 @@ qca8k_port_set_status(struct qca8k_priv - mask |= QCA8K_PORT_STATUS_LINK_AUTO; - - if (enable) -- qca8k_reg_set(priv, QCA8K_REG_PORT_STATUS(port), mask); -+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); - else -- qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); -+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); - } - - static u32 -@@ -861,8 +848,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv * - * a dt-overlay and driver reload changed the configuration - */ - -- return qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_EN); -+ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_EN); - } - - /* Check if the devicetree declare the port:phy mapping */ -@@ -1099,16 +1086,16 @@ qca8k_setup(struct dsa_switch *ds) - return ret; - - /* Make sure MAC06 is disabled */ -- ret = qca8k_reg_clear(priv, QCA8K_REG_PORT0_PAD_CTRL, -- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, -+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); - if (ret) { - dev_err(priv->dev, "failed disabling MAC06 exchange"); - return ret; - } - - /* Enable CPU Port */ -- ret = qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); - if (ret) { - dev_err(priv->dev, "failed enabling CPU port"); - return ret; -@@ -1176,8 +1163,8 @@ qca8k_setup(struct dsa_switch *ds) - return ret; - - /* Enable ARP Auto-learning by default */ -- ret = qca8k_reg_set(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_LEARN); -+ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_LEARN); - if (ret) - return ret; - -@@ -1745,9 +1732,9 @@ qca8k_port_bridge_join(struct dsa_switch - /* Add this port to the portvlan mask of the other ports - * in the bridge - */ -- ret = qca8k_reg_set(priv, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -+ ret = regmap_set_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); - if (ret) - return ret; - if (i != port) -@@ -1777,9 +1764,9 @@ qca8k_port_bridge_leave(struct dsa_switc - /* Remove this port to the portvlan mask of the other ports - * in the bridge - */ -- qca8k_reg_clear(priv, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -+ regmap_clear_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); - } - - /* Set the cpu port to be the only one in the portvlan mask of diff --git a/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch b/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch deleted file mode 100644 index c8c050933b6..00000000000 --- a/target/linux/generic/backport-6.1/758-v5.17-net-next-net-dsa-qca8k-add-additional-MIB-counter-and-.patch +++ /dev/null @@ -1,120 +0,0 @@ -From c126f118b330ccf0db0dda4a4bd6c729865a205f Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:45 +0100 -Subject: net: dsa: qca8k: add additional MIB counter and make it dynamic - -We are currently missing 2 additionals MIB counter present in QCA833x -switch. -QC832x switch have 39 MIB counter and QCA833X have 41 MIB counter. -Add the additional MIB counter and rework the MIB function to print the -correct supported counter from the match_data struct. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 23 ++++++++++++++++++++--- - drivers/net/dsa/qca8k.h | 4 ++++ - 2 files changed, 24 insertions(+), 3 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -70,6 +70,8 @@ static const struct qca8k_mib_desc ar832 - MIB_DESC(1, 0x9c, "TxExcDefer"), - MIB_DESC(1, 0xa0, "TxDefer"), - MIB_DESC(1, 0xa4, "TxLateCol"), -+ MIB_DESC(1, 0xa8, "RXUnicast"), -+ MIB_DESC(1, 0xac, "TXUnicast"), - }; - - /* The 32bit switch registers are accessed indirectly. To achieve this we need -@@ -1605,12 +1607,16 @@ qca8k_phylink_mac_link_up(struct dsa_swi - static void - qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) - { -+ const struct qca8k_match_data *match_data; -+ struct qca8k_priv *priv = ds->priv; - int i; - - if (stringset != ETH_SS_STATS) - return; - -- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) -+ match_data = of_device_get_match_data(priv->dev); -+ -+ for (i = 0; i < match_data->mib_count; i++) - strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, - ETH_GSTRING_LEN); - } -@@ -1620,12 +1626,15 @@ qca8k_get_ethtool_stats(struct dsa_switc - uint64_t *data) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ const struct qca8k_match_data *match_data; - const struct qca8k_mib_desc *mib; - u32 reg, i, val; - u32 hi = 0; - int ret; - -- for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++) { -+ match_data = of_device_get_match_data(priv->dev); -+ -+ for (i = 0; i < match_data->mib_count; i++) { - mib = &ar8327_mib[i]; - reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; - -@@ -1648,10 +1657,15 @@ qca8k_get_ethtool_stats(struct dsa_switc - static int - qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) - { -+ const struct qca8k_match_data *match_data; -+ struct qca8k_priv *priv = ds->priv; -+ - if (sset != ETH_SS_STATS) - return 0; - -- return ARRAY_SIZE(ar8327_mib); -+ match_data = of_device_get_match_data(priv->dev); -+ -+ return match_data->mib_count; - } - - static int -@@ -2173,14 +2187,17 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, - static const struct qca8k_match_data qca8327 = { - .id = QCA8K_ID_QCA8327, - .reduced_package = true, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, - }; - - static const struct qca8k_match_data qca8328 = { - .id = QCA8K_ID_QCA8327, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, - }; - - static const struct qca8k_match_data qca833x = { - .id = QCA8K_ID_QCA8337, -+ .mib_count = QCA8K_QCA833X_MIB_COUNT, - }; - - static const struct of_device_id qca8k_of_match[] = { ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -21,6 +21,9 @@ - #define PHY_ID_QCA8337 0x004dd036 - #define QCA8K_ID_QCA8337 0x13 - -+#define QCA8K_QCA832X_MIB_COUNT 39 -+#define QCA8K_QCA833X_MIB_COUNT 41 -+ - #define QCA8K_BUSY_WAIT_TIMEOUT 2000 - - #define QCA8K_NUM_FDB_RECORDS 2048 -@@ -279,6 +282,7 @@ struct ar8xxx_port_status { - struct qca8k_match_data { - u8 id; - bool reduced_package; -+ u8 mib_count; - }; - - enum { diff --git a/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch b/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch deleted file mode 100644 index 8ad7ab472d4..00000000000 --- a/target/linux/generic/backport-6.1/759-v5.17-net-next-net-dsa-qca8k-add-support-for-port-fast-aging.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 4592538bfb0d5d3c3c8a1d7071724d081412ac91 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:46 +0100 -Subject: net: dsa: qca8k: add support for port fast aging - -The switch supports fast aging by flushing any rule in the ARL -table for a specific port. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 11 +++++++++++ - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 12 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1790,6 +1790,16 @@ qca8k_port_bridge_leave(struct dsa_switc - QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); - } - -+static void -+qca8k_port_fast_age(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -+ mutex_unlock(&priv->reg_mutex); -+} -+ - static int - qca8k_port_enable(struct dsa_switch *ds, int port, - struct phy_device *phy) -@@ -2017,6 +2027,7 @@ static const struct dsa_switch_ops qca8k - .port_stp_state_set = qca8k_port_stp_state_set, - .port_bridge_join = qca8k_port_bridge_join, - .port_bridge_leave = qca8k_port_bridge_leave, -+ .port_fast_age = qca8k_port_fast_age, - .port_fdb_add = qca8k_port_fdb_add, - .port_fdb_del = qca8k_port_fdb_del, - .port_fdb_dump = qca8k_port_fdb_dump, ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -262,6 +262,7 @@ enum qca8k_fdb_cmd { - QCA8K_FDB_FLUSH = 1, - QCA8K_FDB_LOAD = 2, - QCA8K_FDB_PURGE = 3, -+ QCA8K_FDB_FLUSH_PORT = 5, - QCA8K_FDB_NEXT = 6, - QCA8K_FDB_SEARCH = 7, - }; diff --git a/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch b/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch deleted file mode 100644 index 659e482405a..00000000000 --- a/target/linux/generic/backport-6.1/760-v5.17-net-next-net-dsa-qca8k-add-set_ageing_time-support.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 6a3bdc5209f45d2af83aa92433ab6e5cf2297aa4 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:47 +0100 -Subject: net: dsa: qca8k: add set_ageing_time support - -qca8k support setting ageing time in step of 7s. Add support for it and -set the max value accepted of 7645m. -Documentation talks about support for 10000m but that values doesn't -make sense as the value doesn't match the max value in the reg. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 25 +++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 3 +++ - 2 files changed, 28 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1261,6 +1261,10 @@ qca8k_setup(struct dsa_switch *ds) - /* We don't have interrupts for link changes, so we need to poll */ - ds->pcs_poll = true; - -+ /* Set min a max ageing value supported */ -+ ds->ageing_time_min = 7000; -+ ds->ageing_time_max = 458745000; -+ - return 0; - } - -@@ -1801,6 +1805,26 @@ qca8k_port_fast_age(struct dsa_switch *d - } - - static int -+qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ unsigned int secs = msecs / 1000; -+ u32 val; -+ -+ /* AGE_TIME reg is set in 7s step */ -+ val = secs / 7; -+ -+ /* Handle case with 0 as val to NOT disable -+ * learning -+ */ -+ if (!val) -+ val = 1; -+ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -+ QCA8K_ATU_AGE_TIME(val)); -+} -+ -+static int - qca8k_port_enable(struct dsa_switch *ds, int port, - struct phy_device *phy) - { -@@ -2018,6 +2042,7 @@ static const struct dsa_switch_ops qca8k - .get_strings = qca8k_get_strings, - .get_ethtool_stats = qca8k_get_ethtool_stats, - .get_sset_count = qca8k_get_sset_count, -+ .set_ageing_time = qca8k_set_ageing_time, - .get_mac_eee = qca8k_get_mac_eee, - .set_mac_eee = qca8k_set_mac_eee, - .port_enable = qca8k_port_enable, ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -175,6 +175,9 @@ - #define QCA8K_VTU_FUNC1_BUSY BIT(31) - #define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) - #define QCA8K_VTU_FUNC1_FULL BIT(4) -+#define QCA8K_REG_ATU_CTRL 0x618 -+#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) -+#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) - #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 - #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) - #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 diff --git a/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch b/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch deleted file mode 100644 index 8b97939ecb2..00000000000 --- a/target/linux/generic/backport-6.1/761-v5.17-net-next-net-dsa-qca8k-add-support-for-mdb_add-del.patch +++ /dev/null @@ -1,142 +0,0 @@ -From ba8f870dfa635113ce6e8095a5eb1835ecde2e9e Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Mon, 22 Nov 2021 16:23:48 +0100 -Subject: net: dsa: qca8k: add support for mdb_add/del - -Add support for mdb add/del function. The ARL table is used to insert -the rule. The rule will be searched, deleted and reinserted with the -port mask updated. The function will check if the rule has to be updated -or insert directly with no deletion of the old rule. -If every port is removed from the port mask, the rule is removed. -The rule is set STATIC in the ARL table (aka it doesn't age) to not be -flushed by fast age function. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 99 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -436,6 +436,81 @@ qca8k_fdb_flush(struct qca8k_priv *priv) - } - - static int -+qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_fdb_read(priv, &fdb); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule exist. Delete first */ -+ if (!fdb.aging) { -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ } -+ -+ /* Add port to fdb portmask */ -+ fdb.port_mask |= port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule doesn't exist. Why delete? */ -+ if (!fdb.aging) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ -+ /* Only port in the rule is this port. Don't re insert */ -+ if (fdb.port_mask == port_mask) -+ goto exit; -+ -+ /* Remove port from port mask */ -+ fdb.port_mask &= ~port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int - qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) - { - u32 reg; -@@ -1949,6 +2024,28 @@ qca8k_port_fdb_dump(struct dsa_switch *d - } - - static int -+qca8k_port_mdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); -+} -+ -+static int -+qca8k_port_mdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); -+} -+ -+static int - qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack) - { -@@ -2056,6 +2153,8 @@ static const struct dsa_switch_ops qca8k - .port_fdb_add = qca8k_port_fdb_add, - .port_fdb_del = qca8k_port_fdb_del, - .port_fdb_dump = qca8k_port_fdb_dump, -+ .port_mdb_add = qca8k_port_mdb_add, -+ .port_mdb_del = qca8k_port_mdb_del, - .port_vlan_filtering = qca8k_port_vlan_filtering, - .port_vlan_add = qca8k_port_vlan_add, - .port_vlan_del = qca8k_port_vlan_del, diff --git a/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch b/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch deleted file mode 100644 index dc5a22935f1..00000000000 --- a/target/linux/generic/backport-6.1/762-v5.17-net-next-net-dsa-qca8k-add-support-for-mirror-mode.patch +++ /dev/null @@ -1,155 +0,0 @@ -From 2c1bdbc7e7560d7de754cad277d968d56bb1899e Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 23 Nov 2021 03:59:10 +0100 -Subject: net: dsa: qca8k: add support for mirror mode - -The switch supports mirror mode. Only one port can set as mirror port and -every other port can set to both ingress and egress mode. The mirror -port is disabled and reverted to normal operation once every port is -removed from sending packet to it. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 4 +++ - 2 files changed, 99 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -2046,6 +2046,99 @@ qca8k_port_mdb_del(struct dsa_switch *ds - } - - static int -+qca8k_port_mirror_add(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror, -+ bool ingress) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int monitor_port, ret; -+ u32 reg, val; -+ -+ /* Check for existent entry */ -+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -+ return -EEXIST; -+ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* QCA83xx can have only one port set to mirror mode. -+ * Check that the correct port is requested and return error otherwise. -+ * When no mirror port is set, the values is set to 0xF -+ */ -+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -+ return -EEXIST; -+ -+ /* Set the monitor port */ -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -+ mirror->to_local_port); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ return ret; -+ -+ if (ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_update_bits(priv->regmap, reg, val, val); -+ if (ret) -+ return ret; -+ -+ /* Track mirror port for tx and rx to decide when the -+ * mirror port has to be disabled. -+ */ -+ if (ingress) -+ priv->mirror_rx |= BIT(port); -+ else -+ priv->mirror_tx |= BIT(port); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_mirror_del(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg, val; -+ int ret; -+ -+ if (mirror->ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_clear_bits(priv->regmap, reg, val); -+ if (ret) -+ goto err; -+ -+ if (mirror->ingress) -+ priv->mirror_rx &= ~BIT(port); -+ else -+ priv->mirror_tx &= ~BIT(port); -+ -+ /* No port set to send packet to mirror port. Disable mirror port */ -+ if (!priv->mirror_rx && !priv->mirror_tx) { -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ goto err; -+ } -+err: -+ dev_err(priv->dev, "Failed to del mirror port from %d", port); -+} -+ -+static int - qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack) - { -@@ -2155,6 +2248,8 @@ static const struct dsa_switch_ops qca8k - .port_fdb_dump = qca8k_port_fdb_dump, - .port_mdb_add = qca8k_port_mdb_add, - .port_mdb_del = qca8k_port_mdb_del, -+ .port_mirror_add = qca8k_port_mirror_add, -+ .port_mirror_del = qca8k_port_mirror_del, - .port_vlan_filtering = qca8k_port_vlan_filtering, - .port_vlan_add = qca8k_port_vlan_add, - .port_vlan_del = qca8k_port_vlan_del, ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -180,6 +180,7 @@ - #define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) - #define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 - #define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) -+#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) - #define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 - #define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) - #define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) -@@ -201,6 +202,7 @@ - #define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) - #define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) - #define QCA8K_PORT_LOOKUP_LEARN BIT(20) -+#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) - - #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 - #define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) -@@ -305,6 +307,8 @@ struct qca8k_ports_config { - struct qca8k_priv { - u8 switch_id; - u8 switch_revision; -+ u8 mirror_rx; -+ u8 mirror_tx; - bool legacy_phy_port_mapping; - struct qca8k_ports_config ports_config; - struct regmap *regmap; diff --git a/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch b/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch deleted file mode 100644 index b53f1288d5a..00000000000 --- a/target/linux/generic/backport-6.1/763-v5.17-net-next-net-dsa-qca8k-add-LAG-support.patch +++ /dev/null @@ -1,288 +0,0 @@ -From def975307c01191b6f0170048c3724b0ed3348af Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 23 Nov 2021 03:59:11 +0100 -Subject: net: dsa: qca8k: add LAG support - -Add LAG support to this switch. In Documentation this is described as -trunk mode. A max of 4 LAGs are supported and each can support up to 4 -port. The current tx mode supported is Hash mode with both L2 and L2+3 -mode. -When no port are present in the trunk, the trunk is disabled in the -switch. -When a port is disconnected, the traffic is redirected to the other -available port. -The hash mode is global and each LAG require to have the same hash mode -set. To change the hash mode when multiple LAG are configured, it's -required to remove each LAG and set the desired hash mode to the last. -An error is printed when it's asked to set a not supported hadh mode. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 33 +++++++++ - 2 files changed, 210 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1340,6 +1340,9 @@ qca8k_setup(struct dsa_switch *ds) - ds->ageing_time_min = 7000; - ds->ageing_time_max = 458745000; - -+ /* Set max number of LAGs supported */ -+ ds->num_lag_ids = QCA8K_NUM_LAGS; -+ - return 0; - } - -@@ -2226,6 +2229,178 @@ qca8k_get_tag_protocol(struct dsa_switch - return DSA_TAG_PROTO_QCA; - } - -+static bool -+qca8k_lag_can_offload(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct dsa_port *dp; -+ int id, members = 0; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ if (id < 0 || id >= ds->num_lag_ids) -+ return false; -+ -+ dsa_lag_foreach_port(dp, ds->dst, lag) -+ /* Includes the port joining the LAG */ -+ members++; -+ -+ if (members > QCA8K_NUM_PORTS_FOR_LAG) -+ return false; -+ -+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -+ return false; -+ -+ if (info->hash_type != NETDEV_LAG_HASH_L2 || -+ info->hash_type != NETDEV_LAG_HASH_L23) -+ return false; -+ -+ return true; -+} -+ -+static int -+qca8k_lag_setup_hash(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ bool unique_lag = true; -+ int i, id; -+ u32 hash; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ switch (info->hash_type) { -+ case NETDEV_LAG_HASH_L23: -+ hash |= QCA8K_TRUNK_HASH_SIP_EN; -+ hash |= QCA8K_TRUNK_HASH_DIP_EN; -+ fallthrough; -+ case NETDEV_LAG_HASH_L2: -+ hash |= QCA8K_TRUNK_HASH_SA_EN; -+ hash |= QCA8K_TRUNK_HASH_DA_EN; -+ break; -+ default: /* We should NEVER reach this */ -+ return -EOPNOTSUPP; -+ } -+ -+ /* Check if we are the unique configured LAG */ -+ dsa_lags_foreach_id(i, ds->dst) -+ if (i != id && dsa_lag_dev(ds->dst, i)) { -+ unique_lag = false; -+ break; -+ } -+ -+ /* Hash Mode is global. Make sure the same Hash Mode -+ * is set to all the 4 possible lag. -+ * If we are the unique LAG we can set whatever hash -+ * mode we want. -+ * To change hash mode it's needed to remove all LAG -+ * and change the mode with the latest. -+ */ -+ if (unique_lag) { -+ priv->lag_hash_mode = hash; -+ } else if (priv->lag_hash_mode != hash) { -+ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -+ QCA8K_TRUNK_HASH_MASK, hash); -+} -+ -+static int -+qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -+ struct net_device *lag, bool delete) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret, id, i; -+ u32 val; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ /* Read current port member */ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* Shift val to the correct trunk */ -+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -+ if (delete) -+ val &= ~BIT(port); -+ else -+ val |= BIT(port); -+ -+ /* Update port member. With empty portmap disable trunk */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -+ QCA8K_REG_GOL_TRUNK_MEMBER(id) | -+ QCA8K_REG_GOL_TRUNK_EN(id), -+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -+ -+ /* Search empty member if adding or port on deleting */ -+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -+ if (ret) -+ return ret; -+ -+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -+ -+ if (delete) { -+ /* If port flagged to be disabled assume this member is -+ * empty -+ */ -+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -+ if (val != port) -+ continue; -+ } else { -+ /* If port flagged to be enabled assume this member is -+ * already set -+ */ -+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ } -+ -+ /* We have found the member to add/remove */ -+ break; -+ } -+ -+ /* Set port in the correct port mask or disable port if in delete mode */ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); -+} -+ -+static int -+qca8k_port_lag_join(struct dsa_switch *ds, int port, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ int ret; -+ -+ if (!qca8k_lag_can_offload(ds, lag, info)) -+ return -EOPNOTSUPP; -+ -+ ret = qca8k_lag_setup_hash(ds, lag, info); -+ if (ret) -+ return ret; -+ -+ return qca8k_lag_refresh_portmap(ds, port, lag, false); -+} -+ -+static int -+qca8k_port_lag_leave(struct dsa_switch *ds, int port, -+ struct net_device *lag) -+{ -+ return qca8k_lag_refresh_portmap(ds, port, lag, true); -+} -+ - static const struct dsa_switch_ops qca8k_switch_ops = { - .get_tag_protocol = qca8k_get_tag_protocol, - .setup = qca8k_setup, -@@ -2259,6 +2434,8 @@ static const struct dsa_switch_ops qca8k - .phylink_mac_link_down = qca8k_phylink_mac_link_down, - .phylink_mac_link_up = qca8k_phylink_mac_link_up, - .get_phy_flags = qca8k_get_phy_flags, -+ .port_lag_join = qca8k_port_lag_join, -+ .port_lag_leave = qca8k_port_lag_leave, - }; - - static int qca8k_read_switch_id(struct qca8k_priv *priv) ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -15,6 +15,8 @@ - #define QCA8K_NUM_PORTS 7 - #define QCA8K_NUM_CPU_PORTS 2 - #define QCA8K_MAX_MTU 9000 -+#define QCA8K_NUM_LAGS 4 -+#define QCA8K_NUM_PORTS_FOR_LAG 4 - - #define PHY_ID_QCA8327 0x004dd034 - #define QCA8K_ID_QCA8327 0x12 -@@ -122,6 +124,14 @@ - #define QCA8K_REG_EEE_CTRL 0x100 - #define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) - -+/* TRUNK_HASH_EN registers */ -+#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 -+#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) -+#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) -+#define QCA8K_TRUNK_HASH_SA_EN BIT(1) -+#define QCA8K_TRUNK_HASH_DA_EN BIT(0) -+#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) -+ - /* ACL registers */ - #define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) - #define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) -@@ -204,6 +214,28 @@ - #define QCA8K_PORT_LOOKUP_LEARN BIT(20) - #define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) - -+#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 -+/* 4 max trunk first -+ * first 6 bit for member bitmap -+ * 7th bit is to enable trunk port -+ */ -+#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) -+#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) -+#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) -+#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) -+#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) -+/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ -+#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) -+#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) -+#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) -+/* Complex shift: FIRST shift for port THEN shift for trunk */ -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) -+ - #define QCA8K_REG_GLOBAL_FC_THRESH 0x800 - #define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) - #define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) -@@ -309,6 +341,7 @@ struct qca8k_priv { - u8 switch_revision; - u8 mirror_rx; - u8 mirror_tx; -+ u8 lag_hash_mode; - bool legacy_phy_port_mapping; - struct qca8k_ports_config ports_config; - struct regmap *regmap; diff --git a/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch b/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch deleted file mode 100644 index 7d811be11ce..00000000000 --- a/target/linux/generic/backport-6.1/764-v5.17-net-next-net-dsa-qca8k-fix-warning-in-LAG-feature.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0898ca67b86e14207d4feb3f3fea8b87cec5aab1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 23 Nov 2021 16:44:46 +0100 -Subject: net: dsa: qca8k: fix warning in LAG feature - -Fix warning reported by bot. -Make sure hash is init to 0 and fix wrong logic for hash_type in -qca8k_lag_can_offload. - -Reported-by: kernel test robot -Fixes: def975307c01 ("net: dsa: qca8k: add LAG support") -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Link: https://lore.kernel.org/r/20211123154446.31019-1-ansuelsmth@gmail.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca8k.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -2251,7 +2251,7 @@ qca8k_lag_can_offload(struct dsa_switch - if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) - return false; - -- if (info->hash_type != NETDEV_LAG_HASH_L2 || -+ if (info->hash_type != NETDEV_LAG_HASH_L2 && - info->hash_type != NETDEV_LAG_HASH_L23) - return false; - -@@ -2265,8 +2265,8 @@ qca8k_lag_setup_hash(struct dsa_switch * - { - struct qca8k_priv *priv = ds->priv; - bool unique_lag = true; -+ u32 hash = 0; - int i, id; -- u32 hash; - - id = dsa_lag_id(ds->dst, lag); - diff --git a/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch b/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch deleted file mode 100644 index 77cf63b809b..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-01-net-next-net-dsa-reorder-PHY-initialization-with-MTU-setup-in.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 904e112ad431492b34f235f59738e8312802bbf9 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:12 +0200 -Subject: [PATCH 1/6] net: dsa: reorder PHY initialization with MTU setup in - slave.c - -In dsa_slave_create() there are 2 sections that take rtnl_lock(): -MTU change and netdev registration. They are separated by PHY -initialization. - -There isn't any strict ordering requirement except for the fact that -netdev registration should be last. Therefore, we can perform the MTU -change a bit later, after the PHY setup. A future change will then be -able to merge the two rtnl_lock sections into one. - -Signed-off-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/slave.c | 14 +++++++------- - 1 file changed, 7 insertions(+), 7 deletions(-) - ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -1977,13 +1977,6 @@ int dsa_slave_create(struct dsa_port *po - port->slave = slave_dev; - dsa_slave_setup_tagger(slave_dev); - -- rtnl_lock(); -- ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); -- rtnl_unlock(); -- if (ret && ret != -EOPNOTSUPP) -- dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", -- ret, ETH_DATA_LEN, port->index); -- - netif_carrier_off(slave_dev); - - ret = dsa_slave_phy_setup(slave_dev); -@@ -1995,6 +1988,13 @@ int dsa_slave_create(struct dsa_port *po - } - - rtnl_lock(); -+ ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); -+ rtnl_unlock(); -+ if (ret && ret != -EOPNOTSUPP) -+ dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", -+ ret, ETH_DATA_LEN, port->index); -+ -+ rtnl_lock(); - - ret = register_netdevice(slave_dev); - if (ret) { diff --git a/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch b/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch deleted file mode 100644 index 50aa5d8f0dd..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-02-net-next-net-dsa-merge-rtnl_lock-sections-in-dsa_slave_create.patch +++ /dev/null @@ -1,34 +0,0 @@ -From e31dbd3b6aba585231cd84a87adeb22e7c6a8c19 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:13 +0200 -Subject: [PATCH 2/6] net: dsa: merge rtnl_lock sections in dsa_slave_create - -Currently dsa_slave_create() has two sequences of rtnl_lock/rtnl_unlock -in a row. Remove the rtnl_unlock() and rtnl_lock() in between, such that -the operation can execute slighly faster. - -Signed-off-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/slave.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -1988,14 +1988,12 @@ int dsa_slave_create(struct dsa_port *po - } - - rtnl_lock(); -+ - ret = dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN); -- rtnl_unlock(); - if (ret && ret != -EOPNOTSUPP) - dev_warn(ds->dev, "nonfatal error %d setting MTU to %d on port %d\n", - ret, ETH_DATA_LEN, port->index); - -- rtnl_lock(); -- - ret = register_netdevice(slave_dev); - if (ret) { - netdev_err(master, "error %d registering interface %s\n", diff --git a/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch b/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch deleted file mode 100644 index 6c7aad69288..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-03-net-next-net-dsa-stop-updating-master-MTU-from-master.c.patch +++ /dev/null @@ -1,91 +0,0 @@ -From a1ff94c2973c43bc1e2677ac63ebb15b1d1ff846 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:14 +0200 -Subject: [PATCH 3/6] net: dsa: stop updating master MTU from master.c - -At present there are two paths for changing the MTU of the DSA master. - -The first is: - -dsa_tree_setup --> dsa_tree_setup_ports - -> dsa_port_setup - -> dsa_slave_create - -> dsa_slave_change_mtu - -> dev_set_mtu(master) - -The second is: - -dsa_tree_setup --> dsa_tree_setup_master - -> dsa_master_setup - -> dev_set_mtu(dev) - -So the dev_set_mtu() call from dsa_master_setup() has been effectively -superseded by the dsa_slave_change_mtu(slave_dev, ETH_DATA_LEN) that is -done from dsa_slave_create() for each user port. The later function also -updates the master MTU according to the largest user port MTU from the -tree. Therefore, updating the master MTU through a separate code path -isn't needed. - -Signed-off-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/master.c | 25 +------------------------ - 1 file changed, 1 insertion(+), 24 deletions(-) - ---- a/net/dsa/master.c -+++ b/net/dsa/master.c -@@ -329,28 +329,13 @@ static const struct attribute_group dsa_ - .attrs = dsa_slave_attrs, - }; - --static void dsa_master_reset_mtu(struct net_device *dev) --{ -- int err; -- -- rtnl_lock(); -- err = dev_set_mtu(dev, ETH_DATA_LEN); -- if (err) -- netdev_dbg(dev, -- "Unable to reset MTU to exclude DSA overheads\n"); -- rtnl_unlock(); --} -- - static struct lock_class_key dsa_master_addr_list_lock_key; - - int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp) - { -- const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops; - struct dsa_switch *ds = cpu_dp->ds; - struct device_link *consumer_link; -- int mtu, ret; -- -- mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops); -+ int ret; - - /* The DSA master must use SET_NETDEV_DEV for this to work. */ - consumer_link = device_link_add(ds->dev, dev->dev.parent, -@@ -360,13 +345,6 @@ int dsa_master_setup(struct net_device * - "Failed to create a device link to DSA switch %s\n", - dev_name(ds->dev)); - -- rtnl_lock(); -- ret = dev_set_mtu(dev, mtu); -- rtnl_unlock(); -- if (ret) -- netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n", -- ret, mtu); -- - /* If we use a tagging format that doesn't have an ethertype - * field, make sure that all packets from this point on get - * sent to the tag format's receive function. -@@ -404,7 +382,6 @@ void dsa_master_teardown(struct net_devi - sysfs_remove_group(&dev->dev.kobj, &dsa_group); - dsa_netdev_ops_set(dev, NULL); - dsa_master_ethtool_teardown(dev); -- dsa_master_reset_mtu(dev); - dsa_master_set_promiscuity(dev, -1); - - dev->dsa_ptr = NULL; diff --git a/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch b/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch deleted file mode 100644 index e331226fc41..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-04-net-next-net-dsa-hold-rtnl_mutex-when-calling-dsa_master_-set.patch +++ /dev/null @@ -1,78 +0,0 @@ -From c146f9bc195a9dc3ad7fd000a14540e7c9df952d Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:15 +0200 -Subject: [PATCH 4/6] net: dsa: hold rtnl_mutex when calling - dsa_master_{setup,teardown} - -DSA needs to simulate master tracking events when a binding is first -with a DSA master established and torn down, in order to give drivers -the simplifying guarantee that ->master_state_change calls are made -only when the master's readiness state to pass traffic changes. -master_state_change() provide a operational bool that DSA driver can use -to understand if DSA master is operational or not. -To avoid races, we need to block the reception of -NETDEV_UP/NETDEV_CHANGE/NETDEV_GOING_DOWN events in the netdev notifier -chain while we are changing the master's dev->dsa_ptr (this changes what -netdev_uses_dsa(dev) reports). - -The dsa_master_setup() and dsa_master_teardown() functions optionally -require the rtnl_mutex to be held, if the tagger needs the master to be -promiscuous, these functions call dev_set_promiscuity(). Move the -rtnl_lock() from that function and make it top-level. - -Signed-off-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/dsa2.c | 8 ++++++++ - net/dsa/master.c | 4 ++-- - 2 files changed, 10 insertions(+), 2 deletions(-) - ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -1034,6 +1034,8 @@ static int dsa_tree_setup_master(struct - struct dsa_port *dp; - int err; - -+ rtnl_lock(); -+ - list_for_each_entry(dp, &dst->ports, list) { - if (dsa_port_is_cpu(dp)) { - err = dsa_master_setup(dp->master, dp); -@@ -1042,6 +1044,8 @@ static int dsa_tree_setup_master(struct - } - } - -+ rtnl_unlock(); -+ - return 0; - } - -@@ -1049,9 +1053,13 @@ static void dsa_tree_teardown_master(str - { - struct dsa_port *dp; - -+ rtnl_lock(); -+ - list_for_each_entry(dp, &dst->ports, list) - if (dsa_port_is_cpu(dp)) - dsa_master_teardown(dp->master); -+ -+ rtnl_unlock(); - } - - static int dsa_tree_setup_lags(struct dsa_switch_tree *dst) ---- a/net/dsa/master.c -+++ b/net/dsa/master.c -@@ -266,9 +266,9 @@ static void dsa_master_set_promiscuity(s - if (!ops->promisc_on_master) - return; - -- rtnl_lock(); -+ ASSERT_RTNL(); -+ - dev_set_promiscuity(dev, inc); -- rtnl_unlock(); - } - - static ssize_t tagging_show(struct device *d, struct device_attribute *attr, diff --git a/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch b/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch deleted file mode 100644 index e6472c61da6..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-05-net-next-net-dsa-first-set-up-shared-ports-then-non-shared-po.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 1e3f407f3cacc5dcfe27166c412ed9bc263d82bf Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:16 +0200 -Subject: [PATCH 5/6] net: dsa: first set up shared ports, then non-shared - ports - -After commit a57d8c217aad ("net: dsa: flush switchdev workqueue before -tearing down CPU/DSA ports"), the port setup and teardown procedure -became asymmetric. - -The fact of the matter is that user ports need the shared ports to be up -before they can be used for CPU-initiated termination. And since we -register net devices for the user ports, those won't be functional until -we also call the setup for the shared (CPU, DSA) ports. But we may do -that later, depending on the port numbering scheme of the hardware we -are dealing with. - -It just makes sense that all shared ports are brought up before any user -port is. I can't pinpoint any issue due to the current behavior, but -let's change it nonetheless, for consistency's sake. - -Signed-off-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - net/dsa/dsa2.c | 50 +++++++++++++++++++++++++++++++++++++------------- - 1 file changed, 37 insertions(+), 13 deletions(-) - ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -999,23 +999,28 @@ static void dsa_tree_teardown_switches(s - dsa_switch_teardown(dp->ds); - } - --static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) -+/* Bring shared ports up first, then non-shared ports */ -+static int dsa_tree_setup_ports(struct dsa_switch_tree *dst) - { - struct dsa_port *dp; -- int err; -+ int err = 0; - - list_for_each_entry(dp, &dst->ports, list) { -- err = dsa_switch_setup(dp->ds); -- if (err) -- goto teardown; -+ if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp)) { -+ err = dsa_port_setup(dp); -+ if (err) -+ goto teardown; -+ } - } - - list_for_each_entry(dp, &dst->ports, list) { -- err = dsa_port_setup(dp); -- if (err) { -- err = dsa_port_reinit_as_unused(dp); -- if (err) -- goto teardown; -+ if (dsa_port_is_user(dp) || dsa_port_is_unused(dp)) { -+ err = dsa_port_setup(dp); -+ if (err) { -+ err = dsa_port_reinit_as_unused(dp); -+ if (err) -+ goto teardown; -+ } - } - } - -@@ -1024,7 +1029,21 @@ static int dsa_tree_setup_switches(struc - teardown: - dsa_tree_teardown_ports(dst); - -- dsa_tree_teardown_switches(dst); -+ return err; -+} -+ -+static int dsa_tree_setup_switches(struct dsa_switch_tree *dst) -+{ -+ struct dsa_port *dp; -+ int err = 0; -+ -+ list_for_each_entry(dp, &dst->ports, list) { -+ err = dsa_switch_setup(dp->ds); -+ if (err) { -+ dsa_tree_teardown_switches(dst); -+ break; -+ } -+ } - - return err; - } -@@ -1111,10 +1130,14 @@ static int dsa_tree_setup(struct dsa_swi - if (err) - goto teardown_cpu_ports; - -- err = dsa_tree_setup_master(dst); -+ err = dsa_tree_setup_ports(dst); - if (err) - goto teardown_switches; - -+ err = dsa_tree_setup_master(dst); -+ if (err) -+ goto teardown_ports; -+ - err = dsa_tree_setup_lags(dst); - if (err) - goto teardown_master; -@@ -1127,8 +1150,9 @@ static int dsa_tree_setup(struct dsa_swi - - teardown_master: - dsa_tree_teardown_master(dst); --teardown_switches: -+teardown_ports: - dsa_tree_teardown_ports(dst); -+teardown_switches: - dsa_tree_teardown_switches(dst); - teardown_cpu_ports: - dsa_tree_teardown_cpu_ports(dst); diff --git a/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch b/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch deleted file mode 100644 index 93cad0c98aa..00000000000 --- a/target/linux/generic/backport-6.1/765-v5.17-06-net-next-net-dsa-setup-master-before-ports.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 11fd667dac315ea3f2469961f6d2869271a46cae Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Thu, 6 Jan 2022 01:11:17 +0200 -Subject: [PATCH 6/6] net: dsa: setup master before ports - -It is said that as soon as a network interface is registered, all its -resources should have already been prepared, so that it is available for -sending and receiving traffic. One of the resources needed by a DSA -slave interface is the master. - -dsa_tree_setup --> dsa_tree_setup_ports - -> dsa_port_setup - -> dsa_slave_create - -> register_netdevice --> dsa_tree_setup_master - -> dsa_master_setup - -> sets up master->dsa_ptr, which enables reception - -Therefore, there is a short period of time after register_netdevice() -during which the master isn't prepared to pass traffic to the DSA layer -(master->dsa_ptr is checked by eth_type_trans). Same thing during -unregistration, there is a time frame in which packets might be missed. - -Note that this change opens us to another race: dsa_master_find_slave() -will get invoked potentially earlier than the slave creation, and later -than the slave deletion. Since dp->slave starts off as a NULL pointer, -the earlier calls aren't a problem, but the later calls are. To avoid -use-after-free, we should zeroize dp->slave before calling -dsa_slave_destroy(). - -In practice I cannot really test real life improvements brought by this -change, since in my systems, netdevice creation races with PHY autoneg -which takes a few seconds to complete, and that masks quite a few races. -Effects might be noticeable in a setup with fixed links all the way to -an external system. - -Signed-off-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - net/dsa/dsa2.c | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -545,6 +545,7 @@ static void dsa_port_teardown(struct dsa - struct devlink_port *dlp = &dp->devlink_port; - struct dsa_switch *ds = dp->ds; - struct dsa_mac_addr *a, *tmp; -+ struct net_device *slave; - - if (!dp->setup) - return; -@@ -566,9 +567,11 @@ static void dsa_port_teardown(struct dsa - dsa_port_link_unregister_of(dp); - break; - case DSA_PORT_TYPE_USER: -- if (dp->slave) { -- dsa_slave_destroy(dp->slave); -+ slave = dp->slave; -+ -+ if (slave) { - dp->slave = NULL; -+ dsa_slave_destroy(slave); - } - break; - } -@@ -1130,17 +1133,17 @@ static int dsa_tree_setup(struct dsa_swi - if (err) - goto teardown_cpu_ports; - -- err = dsa_tree_setup_ports(dst); -+ err = dsa_tree_setup_master(dst); - if (err) - goto teardown_switches; - -- err = dsa_tree_setup_master(dst); -+ err = dsa_tree_setup_ports(dst); - if (err) -- goto teardown_ports; -+ goto teardown_master; - - err = dsa_tree_setup_lags(dst); - if (err) -- goto teardown_master; -+ goto teardown_ports; - - dst->setup = true; - -@@ -1148,10 +1151,10 @@ static int dsa_tree_setup(struct dsa_swi - - return 0; - --teardown_master: -- dsa_tree_teardown_master(dst); - teardown_ports: - dsa_tree_teardown_ports(dst); -+teardown_master: -+ dsa_tree_teardown_master(dst); - teardown_switches: - dsa_tree_teardown_switches(dst); - teardown_cpu_ports: -@@ -1169,10 +1172,10 @@ static void dsa_tree_teardown(struct dsa - - dsa_tree_teardown_lags(dst); - -- dsa_tree_teardown_master(dst); -- - dsa_tree_teardown_ports(dst); - -+ dsa_tree_teardown_master(dst); -+ - dsa_tree_teardown_switches(dst); - - dsa_tree_teardown_cpu_ports(dst); diff --git a/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch b/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch deleted file mode 100644 index bffdcb28819..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-01-net-dsa-provide-switch-operations-for-tracking-the-m.patch +++ /dev/null @@ -1,254 +0,0 @@ -From 295ab96f478d0fa56393e85406f19a867e26ce22 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Wed, 2 Feb 2022 01:03:20 +0100 -Subject: [PATCH 01/16] net: dsa: provide switch operations for tracking the - master state - -Certain drivers may need to send management traffic to the switch for -things like register access, FDB dump, etc, to accelerate what their -slow bus (SPI, I2C, MDIO) can already do. - -Ethernet is faster (especially in bulk transactions) but is also more -unreliable, since the user may decide to bring the DSA master down (or -not bring it up), therefore severing the link between the host and the -attached switch. - -Drivers needing Ethernet-based register access already should have -fallback logic to the slow bus if the Ethernet method fails, but that -fallback may be based on a timeout, and the I/O to the switch may slow -down to a halt if the master is down, because every Ethernet packet will -have to time out. The driver also doesn't have the option to turn off -Ethernet-based I/O momentarily, because it wouldn't know when to turn it -back on. - -Which is where this change comes in. By tracking NETDEV_CHANGE, -NETDEV_UP and NETDEV_GOING_DOWN events on the DSA master, we should know -the exact interval of time during which this interface is reliably -available for traffic. Provide this information to switches so they can -use it as they wish. - -An helper is added dsa_port_master_is_operational() to check if a master -port is operational. - -Signed-off-by: Vladimir Oltean -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/net/dsa.h | 17 +++++++++++++++++ - net/dsa/dsa2.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ - net/dsa/dsa_priv.h | 13 +++++++++++++ - net/dsa/slave.c | 32 ++++++++++++++++++++++++++++++++ - net/dsa/switch.c | 15 +++++++++++++++ - 5 files changed, 123 insertions(+) - ---- a/include/net/dsa.h -+++ b/include/net/dsa.h -@@ -291,6 +291,10 @@ struct dsa_port { - struct list_head mdbs; - - bool setup; -+ /* Master state bits, valid only on CPU ports */ -+ u8 master_admin_up:1; -+ u8 master_oper_up:1; -+ - }; - - /* TODO: ideally DSA ports would have a single dp->link_dp member, -@@ -456,6 +460,12 @@ static inline bool dsa_port_is_unused(st - return dp->type == DSA_PORT_TYPE_UNUSED; - } - -+static inline bool dsa_port_master_is_operational(struct dsa_port *dp) -+{ -+ return dsa_port_is_cpu(dp) && dp->master_admin_up && -+ dp->master_oper_up; -+} -+ - static inline bool dsa_is_unused_port(struct dsa_switch *ds, int p) - { - return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_UNUSED; -@@ -949,6 +959,13 @@ struct dsa_switch_ops { - int (*tag_8021q_vlan_add)(struct dsa_switch *ds, int port, u16 vid, - u16 flags); - int (*tag_8021q_vlan_del)(struct dsa_switch *ds, int port, u16 vid); -+ -+ /* -+ * DSA master tracking operations -+ */ -+ void (*master_state_change)(struct dsa_switch *ds, -+ const struct net_device *master, -+ bool operational); - }; - - #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes) \ ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -1275,6 +1275,52 @@ out_unlock: - return err; - } - -+static void dsa_tree_master_state_change(struct dsa_switch_tree *dst, -+ struct net_device *master) -+{ -+ struct dsa_notifier_master_state_info info; -+ struct dsa_port *cpu_dp = master->dsa_ptr; -+ -+ info.master = master; -+ info.operational = dsa_port_master_is_operational(cpu_dp); -+ -+ dsa_tree_notify(dst, DSA_NOTIFIER_MASTER_STATE_CHANGE, &info); -+} -+ -+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, -+ struct net_device *master, -+ bool up) -+{ -+ struct dsa_port *cpu_dp = master->dsa_ptr; -+ bool notify = false; -+ -+ if ((dsa_port_master_is_operational(cpu_dp)) != -+ (up && cpu_dp->master_oper_up)) -+ notify = true; -+ -+ cpu_dp->master_admin_up = up; -+ -+ if (notify) -+ dsa_tree_master_state_change(dst, master); -+} -+ -+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, -+ struct net_device *master, -+ bool up) -+{ -+ struct dsa_port *cpu_dp = master->dsa_ptr; -+ bool notify = false; -+ -+ if ((dsa_port_master_is_operational(cpu_dp)) != -+ (cpu_dp->master_admin_up && up)) -+ notify = true; -+ -+ cpu_dp->master_oper_up = up; -+ -+ if (notify) -+ dsa_tree_master_state_change(dst, master); -+} -+ - static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) - { - struct dsa_switch_tree *dst = ds->dst; ---- a/net/dsa/dsa_priv.h -+++ b/net/dsa/dsa_priv.h -@@ -45,6 +45,7 @@ enum { - DSA_NOTIFIER_MRP_DEL_RING_ROLE, - DSA_NOTIFIER_TAG_8021Q_VLAN_ADD, - DSA_NOTIFIER_TAG_8021Q_VLAN_DEL, -+ DSA_NOTIFIER_MASTER_STATE_CHANGE, - }; - - /* DSA_NOTIFIER_AGEING_TIME */ -@@ -127,6 +128,12 @@ struct dsa_notifier_tag_8021q_vlan_info - u16 vid; - }; - -+/* DSA_NOTIFIER_MASTER_STATE_CHANGE */ -+struct dsa_notifier_master_state_info { -+ const struct net_device *master; -+ bool operational; -+}; -+ - struct dsa_switchdev_event_work { - struct dsa_switch *ds; - int port; -@@ -549,6 +556,12 @@ int dsa_tree_change_tag_proto(struct dsa - struct net_device *master, - const struct dsa_device_ops *tag_ops, - const struct dsa_device_ops *old_tag_ops); -+void dsa_tree_master_admin_state_change(struct dsa_switch_tree *dst, -+ struct net_device *master, -+ bool up); -+void dsa_tree_master_oper_state_change(struct dsa_switch_tree *dst, -+ struct net_device *master, -+ bool up); - int dsa_bridge_num_get(const struct net_device *bridge_dev, int max); - void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num); - ---- a/net/dsa/slave.c -+++ b/net/dsa/slave.c -@@ -2311,6 +2311,36 @@ static int dsa_slave_netdevice_event(str - err = dsa_port_lag_change(dp, info->lower_state_info); - return notifier_from_errno(err); - } -+ case NETDEV_CHANGE: -+ case NETDEV_UP: { -+ /* Track state of master port. -+ * DSA driver may require the master port (and indirectly -+ * the tagger) to be available for some special operation. -+ */ -+ if (netdev_uses_dsa(dev)) { -+ struct dsa_port *cpu_dp = dev->dsa_ptr; -+ struct dsa_switch_tree *dst = cpu_dp->ds->dst; -+ -+ /* Track when the master port is UP */ -+ dsa_tree_master_oper_state_change(dst, dev, -+ netif_oper_up(dev)); -+ -+ /* Track when the master port is ready and can accept -+ * packet. -+ * NETDEV_UP event is not enough to flag a port as ready. -+ * We also have to wait for linkwatch_do_dev to dev_activate -+ * and emit a NETDEV_CHANGE event. -+ * We check if a master port is ready by checking if the dev -+ * have a qdisc assigned and is not noop. -+ */ -+ dsa_tree_master_admin_state_change(dst, dev, -+ !qdisc_tx_is_noop(dev)); -+ -+ return NOTIFY_OK; -+ } -+ -+ return NOTIFY_DONE; -+ } - case NETDEV_GOING_DOWN: { - struct dsa_port *dp, *cpu_dp; - struct dsa_switch_tree *dst; -@@ -2322,6 +2352,8 @@ static int dsa_slave_netdevice_event(str - cpu_dp = dev->dsa_ptr; - dst = cpu_dp->ds->dst; - -+ dsa_tree_master_admin_state_change(dst, dev, false); -+ - list_for_each_entry(dp, &dst->ports, list) { - if (!dsa_is_user_port(dp->ds, dp->index)) - continue; ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -722,6 +722,18 @@ dsa_switch_mrp_del_ring_role(struct dsa_ - return 0; - } - -+static int -+dsa_switch_master_state_change(struct dsa_switch *ds, -+ struct dsa_notifier_master_state_info *info) -+{ -+ if (!ds->ops->master_state_change) -+ return 0; -+ -+ ds->ops->master_state_change(ds, info->master, info->operational); -+ -+ return 0; -+} -+ - static int dsa_switch_event(struct notifier_block *nb, - unsigned long event, void *info) - { -@@ -813,6 +825,9 @@ static int dsa_switch_event(struct notif - case DSA_NOTIFIER_TAG_8021Q_VLAN_DEL: - err = dsa_switch_tag_8021q_vlan_del(ds, info); - break; -+ case DSA_NOTIFIER_MASTER_STATE_CHANGE: -+ err = dsa_switch_master_state_change(ds, info); -+ break; - default: - err = -EOPNOTSUPP; - break; diff --git a/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch b/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch deleted file mode 100644 index 6478d580c01..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-02-net-dsa-replay-master-state-events-in-dsa_tree_-setu.patch +++ /dev/null @@ -1,89 +0,0 @@ -From e83d56537859849f2223b90749e554831b1f3c27 Mon Sep 17 00:00:00 2001 -From: Vladimir Oltean -Date: Wed, 2 Feb 2022 01:03:21 +0100 -Subject: [PATCH 02/16] net: dsa: replay master state events in - dsa_tree_{setup,teardown}_master - -In order for switch driver to be able to make simple and reliable use of -the master tracking operations, they must also be notified of the -initial state of the DSA master, not just of the changes. This is -because they might enable certain features only during the time when -they know that the DSA master is up and running. - -Therefore, this change explicitly checks the state of the DSA master -under the same rtnl_mutex as we were holding during the -dsa_master_setup() and dsa_master_teardown() call. The idea being that -if the DSA master became operational in between the moment in which it -became a DSA master (dsa_master_setup set dev->dsa_ptr) and the moment -when we checked for the master being up, there is a chance that we -would emit a ->master_state_change() call with no actual state change. -We need to avoid that by serializing the concurrent netdevice event with -us. If the netdevice event started before, we force it to finish before -we begin, because we take rtnl_lock before making netdev_uses_dsa() -return true. So we also handle that early event and do nothing on it. -Similarly, if the dev_open() attempt is concurrent with us, it will -attempt to take the rtnl_mutex, but we're holding it. We'll see that -the master flag IFF_UP isn't set, then when we release the rtnl_mutex -we'll process the NETDEV_UP notifier. - -Signed-off-by: Vladimir Oltean -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/dsa2.c | 28 ++++++++++++++++++++++++---- - 1 file changed, 24 insertions(+), 4 deletions(-) - ---- a/net/dsa/dsa2.c -+++ b/net/dsa/dsa2.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - - #include "dsa_priv.h" - -@@ -1060,9 +1061,18 @@ static int dsa_tree_setup_master(struct - - list_for_each_entry(dp, &dst->ports, list) { - if (dsa_port_is_cpu(dp)) { -- err = dsa_master_setup(dp->master, dp); -+ struct net_device *master = dp->master; -+ bool admin_up = (master->flags & IFF_UP) && -+ !qdisc_tx_is_noop(master); -+ -+ err = dsa_master_setup(master, dp); - if (err) - return err; -+ -+ /* Replay master state event */ -+ dsa_tree_master_admin_state_change(dst, master, admin_up); -+ dsa_tree_master_oper_state_change(dst, master, -+ netif_oper_up(master)); - } - } - -@@ -1077,9 +1087,19 @@ static void dsa_tree_teardown_master(str - - rtnl_lock(); - -- list_for_each_entry(dp, &dst->ports, list) -- if (dsa_port_is_cpu(dp)) -- dsa_master_teardown(dp->master); -+ list_for_each_entry(dp, &dst->ports, list) { -+ if (dsa_port_is_cpu(dp)) { -+ struct net_device *master = dp->master; -+ -+ /* Synthesizing an "admin down" state is sufficient for -+ * the switches to get a notification if the master is -+ * currently up and running. -+ */ -+ dsa_tree_master_admin_state_change(dst, master, false); -+ -+ dsa_master_teardown(master); -+ } -+ } - - rtnl_unlock(); - } diff --git a/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch b/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch deleted file mode 100644 index 82c94b385b5..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-03-net-dsa-tag_qca-convert-to-FIELD-macro.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 6b0458299297ca4ab6fb295800e29a4e501d50c1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:22 +0100 -Subject: [PATCH 03/16] net: dsa: tag_qca: convert to FIELD macro - -Convert driver to FIELD macro to drop redundant define. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/tag_qca.c | 34 +++++++++++++++------------------- - 1 file changed, 15 insertions(+), 19 deletions(-) - ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -4,29 +4,24 @@ - */ - - #include -+#include - - #include "dsa_priv.h" - - #define QCA_HDR_LEN 2 - #define QCA_HDR_VERSION 0x2 - --#define QCA_HDR_RECV_VERSION_MASK GENMASK(15, 14) --#define QCA_HDR_RECV_VERSION_S 14 --#define QCA_HDR_RECV_PRIORITY_MASK GENMASK(13, 11) --#define QCA_HDR_RECV_PRIORITY_S 11 --#define QCA_HDR_RECV_TYPE_MASK GENMASK(10, 6) --#define QCA_HDR_RECV_TYPE_S 6 -+#define QCA_HDR_RECV_VERSION GENMASK(15, 14) -+#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) -+#define QCA_HDR_RECV_TYPE GENMASK(10, 6) - #define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) --#define QCA_HDR_RECV_SOURCE_PORT_MASK GENMASK(2, 0) -+#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) - --#define QCA_HDR_XMIT_VERSION_MASK GENMASK(15, 14) --#define QCA_HDR_XMIT_VERSION_S 14 --#define QCA_HDR_XMIT_PRIORITY_MASK GENMASK(13, 11) --#define QCA_HDR_XMIT_PRIORITY_S 11 --#define QCA_HDR_XMIT_CONTROL_MASK GENMASK(10, 8) --#define QCA_HDR_XMIT_CONTROL_S 8 -+#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) -+#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) -+#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) - #define QCA_HDR_XMIT_FROM_CPU BIT(7) --#define QCA_HDR_XMIT_DP_BIT_MASK GENMASK(6, 0) -+#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) - - static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) - { -@@ -40,8 +35,9 @@ static struct sk_buff *qca_tag_xmit(stru - phdr = dsa_etype_header_pos_tx(skb); - - /* Set the version field, and set destination port information */ -- hdr = QCA_HDR_VERSION << QCA_HDR_XMIT_VERSION_S | -- QCA_HDR_XMIT_FROM_CPU | BIT(dp->index); -+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -+ hdr |= QCA_HDR_XMIT_FROM_CPU; -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(dp->index)); - - *phdr = htons(hdr); - -@@ -62,7 +58,7 @@ static struct sk_buff *qca_tag_rcv(struc - hdr = ntohs(*phdr); - - /* Make sure the version is correct */ -- ver = (hdr & QCA_HDR_RECV_VERSION_MASK) >> QCA_HDR_RECV_VERSION_S; -+ ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr); - if (unlikely(ver != QCA_HDR_VERSION)) - return NULL; - -@@ -71,7 +67,7 @@ static struct sk_buff *qca_tag_rcv(struc - dsa_strip_etype_header(skb, QCA_HDR_LEN); - - /* Get source port information */ -- port = (hdr & QCA_HDR_RECV_SOURCE_PORT_MASK); -+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr); - - skb->dev = dsa_master_find_slave(dev, 0, port); - if (!skb->dev) diff --git a/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch b/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch deleted file mode 100644 index c1e74ceeeb5..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-04-net-dsa-tag_qca-move-define-to-include-linux-dsa.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 3ec762fb13c7e7273800b94c80db1c2cc37590d1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:23 +0100 -Subject: [PATCH 04/16] net: dsa: tag_qca: move define to include linux/dsa - -Move tag_qca define to include dir linux/dsa as the qca8k require access -to the tagger define to support in-band mdio read/write using ethernet -packet. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/linux/dsa/tag_qca.h | 21 +++++++++++++++++++++ - net/dsa/tag_qca.c | 16 +--------------- - 2 files changed, 22 insertions(+), 15 deletions(-) - create mode 100644 include/linux/dsa/tag_qca.h - ---- /dev/null -+++ b/include/linux/dsa/tag_qca.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+#ifndef __TAG_QCA_H -+#define __TAG_QCA_H -+ -+#define QCA_HDR_LEN 2 -+#define QCA_HDR_VERSION 0x2 -+ -+#define QCA_HDR_RECV_VERSION GENMASK(15, 14) -+#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) -+#define QCA_HDR_RECV_TYPE GENMASK(10, 6) -+#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) -+#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) -+ -+#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) -+#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) -+#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) -+#define QCA_HDR_XMIT_FROM_CPU BIT(7) -+#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) -+ -+#endif /* __TAG_QCA_H */ ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -5,24 +5,10 @@ - - #include - #include -+#include - - #include "dsa_priv.h" - --#define QCA_HDR_LEN 2 --#define QCA_HDR_VERSION 0x2 -- --#define QCA_HDR_RECV_VERSION GENMASK(15, 14) --#define QCA_HDR_RECV_PRIORITY GENMASK(13, 11) --#define QCA_HDR_RECV_TYPE GENMASK(10, 6) --#define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) --#define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) -- --#define QCA_HDR_XMIT_VERSION GENMASK(15, 14) --#define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) --#define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) --#define QCA_HDR_XMIT_FROM_CPU BIT(7) --#define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) -- - static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev) - { - struct dsa_port *dp = dsa_slave_to_port(dev); diff --git a/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch b/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch deleted file mode 100644 index 9394a0dabbe..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-05-net-dsa-tag_qca-enable-promisc_on_master-flag.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 101c04c3463b87061e6a3d4f72c1bc57670685a6 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:24 +0100 -Subject: [PATCH 05/16] net: dsa: tag_qca: enable promisc_on_master flag - -Ethernet MDIO packets are non-standard and DSA master expects the first -6 octets to be the MAC DA. To address these kind of packet, enable -promisc_on_master flag for the tagger. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - net/dsa/tag_qca.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -68,6 +68,7 @@ static const struct dsa_device_ops qca_n - .xmit = qca_tag_xmit, - .rcv = qca_tag_rcv, - .needed_headroom = QCA_HDR_LEN, -+ .promisc_on_master = true, - }; - - MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch b/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch deleted file mode 100644 index 459454e03ba..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-06-net-dsa-tag_qca-add-define-for-handling-mgmt-Etherne.patch +++ /dev/null @@ -1,110 +0,0 @@ -From c2ee8181fddb293d296477f60b3eb4fa3ce4e1a6 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:25 +0100 -Subject: [PATCH 06/16] net: dsa: tag_qca: add define for handling mgmt - Ethernet packet - -Add all the required define to prepare support for mgmt read/write in -Ethernet packet. Any packet of this type has to be dropped as the only -use of these special packet is receive ack for an mgmt write request or -receive data for an mgmt read request. -A struct is used that emulates the Ethernet header but is used for a -different purpose. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/linux/dsa/tag_qca.h | 44 +++++++++++++++++++++++++++++++++++++ - net/dsa/tag_qca.c | 15 ++++++++++--- - 2 files changed, 56 insertions(+), 3 deletions(-) - ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -12,10 +12,54 @@ - #define QCA_HDR_RECV_FRAME_IS_TAGGED BIT(3) - #define QCA_HDR_RECV_SOURCE_PORT GENMASK(2, 0) - -+/* Packet type for recv */ -+#define QCA_HDR_RECV_TYPE_NORMAL 0x0 -+#define QCA_HDR_RECV_TYPE_MIB 0x1 -+#define QCA_HDR_RECV_TYPE_RW_REG_ACK 0x2 -+ - #define QCA_HDR_XMIT_VERSION GENMASK(15, 14) - #define QCA_HDR_XMIT_PRIORITY GENMASK(13, 11) - #define QCA_HDR_XMIT_CONTROL GENMASK(10, 8) - #define QCA_HDR_XMIT_FROM_CPU BIT(7) - #define QCA_HDR_XMIT_DP_BIT GENMASK(6, 0) - -+/* Packet type for xmit */ -+#define QCA_HDR_XMIT_TYPE_NORMAL 0x0 -+#define QCA_HDR_XMIT_TYPE_RW_REG 0x1 -+ -+/* Check code for a valid mgmt packet. Switch will ignore the packet -+ * with this wrong. -+ */ -+#define QCA_HDR_MGMT_CHECK_CODE_VAL 0x5 -+ -+/* Specific define for in-band MDIO read/write with Ethernet packet */ -+#define QCA_HDR_MGMT_SEQ_LEN 4 /* 4 byte for the seq */ -+#define QCA_HDR_MGMT_COMMAND_LEN 4 /* 4 byte for the command */ -+#define QCA_HDR_MGMT_DATA1_LEN 4 /* First 4 byte for the mdio data */ -+#define QCA_HDR_MGMT_HEADER_LEN (QCA_HDR_MGMT_SEQ_LEN + \ -+ QCA_HDR_MGMT_COMMAND_LEN + \ -+ QCA_HDR_MGMT_DATA1_LEN) -+ -+#define QCA_HDR_MGMT_DATA2_LEN 12 /* Other 12 byte for the mdio data */ -+#define QCA_HDR_MGMT_PADDING_LEN 34 /* Padding to reach the min Ethernet packet */ -+ -+#define QCA_HDR_MGMT_PKT_LEN (QCA_HDR_MGMT_HEADER_LEN + \ -+ QCA_HDR_LEN + \ -+ QCA_HDR_MGMT_DATA2_LEN + \ -+ QCA_HDR_MGMT_PADDING_LEN) -+ -+#define QCA_HDR_MGMT_SEQ_NUM GENMASK(31, 0) /* 63, 32 */ -+#define QCA_HDR_MGMT_CHECK_CODE GENMASK(31, 29) /* 31, 29 */ -+#define QCA_HDR_MGMT_CMD BIT(28) /* 28 */ -+#define QCA_HDR_MGMT_LENGTH GENMASK(23, 20) /* 23, 20 */ -+#define QCA_HDR_MGMT_ADDR GENMASK(18, 0) /* 18, 0 */ -+ -+/* Special struct emulating a Ethernet header */ -+struct qca_mgmt_ethhdr { -+ u32 command; /* command bit 31:0 */ -+ u32 seq; /* seq 63:32 */ -+ u32 mdio_data; /* first 4byte mdio */ -+ __be16 hdr; /* qca hdr */ -+} __packed; -+ - #endif /* __TAG_QCA_H */ ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -32,10 +32,12 @@ static struct sk_buff *qca_tag_xmit(stru - - static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) - { -- u8 ver; -- u16 hdr; -- int port; -+ u8 ver, pk_type; - __be16 *phdr; -+ int port; -+ u16 hdr; -+ -+ BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); - - if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) - return NULL; -@@ -48,6 +50,13 @@ static struct sk_buff *qca_tag_rcv(struc - if (unlikely(ver != QCA_HDR_VERSION)) - return NULL; - -+ /* Get pk type */ -+ pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); -+ -+ /* Ethernet MDIO read/write packet */ -+ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) -+ return NULL; -+ - /* Remove QCA tag and recalculate checksum */ - skb_pull_rcsum(skb, QCA_HDR_LEN); - dsa_strip_etype_header(skb, QCA_HDR_LEN); diff --git a/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch b/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch deleted file mode 100644 index 7e5dc657306..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-07-net-dsa-tag_qca-add-define-for-handling-MIB-packet.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 18be654a4345f7d937b4bfbad74bea8093e3a93c Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:26 +0100 -Subject: [PATCH 07/16] net: dsa: tag_qca: add define for handling MIB packet - -Add struct to correctly parse a mib Ethernet packet. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/linux/dsa/tag_qca.h | 10 ++++++++++ - net/dsa/tag_qca.c | 4 ++++ - 2 files changed, 14 insertions(+) - ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -62,4 +62,14 @@ struct qca_mgmt_ethhdr { - __be16 hdr; /* qca hdr */ - } __packed; - -+enum mdio_cmd { -+ MDIO_WRITE = 0x0, -+ MDIO_READ -+}; -+ -+struct mib_ethhdr { -+ u32 data[3]; /* first 3 mib counter */ -+ __be16 hdr; /* qca hdr */ -+} __packed; -+ - #endif /* __TAG_QCA_H */ ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -57,6 +57,10 @@ static struct sk_buff *qca_tag_rcv(struc - if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) - return NULL; - -+ /* Ethernet MIB counter packet */ -+ if (pk_type == QCA_HDR_RECV_TYPE_MIB) -+ return NULL; -+ - /* Remove QCA tag and recalculate checksum */ - skb_pull_rcsum(skb, QCA_HDR_LEN); - dsa_strip_etype_header(skb, QCA_HDR_LEN); diff --git a/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch b/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch deleted file mode 100644 index ad25da30e6d..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-08-net-dsa-tag_qca-add-support-for-handling-mgmt-and-MI.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 31eb6b4386ad91930417e3f5c8157a4b5e31cbd5 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:27 +0100 -Subject: [PATCH 08/16] net: dsa: tag_qca: add support for handling mgmt and - MIB Ethernet packet - -Add connect/disconnect helper to assign private struct to the DSA switch. -Add support for Ethernet mgmt and MIB if the DSA driver provide an handler -to correctly parse and elaborate the data. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - include/linux/dsa/tag_qca.h | 7 +++++++ - net/dsa/tag_qca.c | 39 ++++++++++++++++++++++++++++++++++--- - 2 files changed, 43 insertions(+), 3 deletions(-) - ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -72,4 +72,11 @@ struct mib_ethhdr { - __be16 hdr; /* qca hdr */ - } __packed; - -+struct qca_tagger_data { -+ void (*rw_reg_ack_handler)(struct dsa_switch *ds, -+ struct sk_buff *skb); -+ void (*mib_autocast_handler)(struct dsa_switch *ds, -+ struct sk_buff *skb); -+}; -+ - #endif /* __TAG_QCA_H */ ---- a/net/dsa/tag_qca.c -+++ b/net/dsa/tag_qca.c -@@ -5,6 +5,7 @@ - - #include - #include -+#include - #include - - #include "dsa_priv.h" -@@ -32,6 +33,9 @@ static struct sk_buff *qca_tag_xmit(stru - - static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) - { -+ struct qca_tagger_data *tagger_data; -+ struct dsa_port *dp = dev->dsa_ptr; -+ struct dsa_switch *ds = dp->ds; - u8 ver, pk_type; - __be16 *phdr; - int port; -@@ -39,6 +43,8 @@ static struct sk_buff *qca_tag_rcv(struc - - BUILD_BUG_ON(sizeof(struct qca_mgmt_ethhdr) != QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); - -+ tagger_data = ds->tagger_data; -+ - if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) - return NULL; - -@@ -53,13 +59,19 @@ static struct sk_buff *qca_tag_rcv(struc - /* Get pk type */ - pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); - -- /* Ethernet MDIO read/write packet */ -- if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) -+ /* Ethernet mgmt read/write packet */ -+ if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) { -+ if (likely(tagger_data->rw_reg_ack_handler)) -+ tagger_data->rw_reg_ack_handler(ds, skb); - return NULL; -+ } - - /* Ethernet MIB counter packet */ -- if (pk_type == QCA_HDR_RECV_TYPE_MIB) -+ if (pk_type == QCA_HDR_RECV_TYPE_MIB) { -+ if (likely(tagger_data->mib_autocast_handler)) -+ tagger_data->mib_autocast_handler(ds, skb); - return NULL; -+ } - - /* Remove QCA tag and recalculate checksum */ - skb_pull_rcsum(skb, QCA_HDR_LEN); -@@ -75,9 +87,30 @@ static struct sk_buff *qca_tag_rcv(struc - return skb; - } - -+static int qca_tag_connect(struct dsa_switch *ds) -+{ -+ struct qca_tagger_data *tagger_data; -+ -+ tagger_data = kzalloc(sizeof(*tagger_data), GFP_KERNEL); -+ if (!tagger_data) -+ return -ENOMEM; -+ -+ ds->tagger_data = tagger_data; -+ -+ return 0; -+} -+ -+static void qca_tag_disconnect(struct dsa_switch *ds) -+{ -+ kfree(ds->tagger_data); -+ ds->tagger_data = NULL; -+} -+ - static const struct dsa_device_ops qca_netdev_ops = { - .name = "qca", - .proto = DSA_TAG_PROTO_QCA, -+ .connect = qca_tag_connect, -+ .disconnect = qca_tag_disconnect, - .xmit = qca_tag_xmit, - .rcv = qca_tag_rcv, - .needed_headroom = QCA_HDR_LEN, diff --git a/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch b/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch deleted file mode 100644 index eb21cc39124..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-09-net-dsa-qca8k-add-tracking-state-of-master-port.patch +++ /dev/null @@ -1,67 +0,0 @@ -From cddbec19466a1dfb4d45ddd507d9f09f991d54ae Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:28 +0100 -Subject: [PATCH 09/16] net: dsa: qca8k: add tracking state of master port - -MDIO/MIB Ethernet require the master port and the tagger availabale to -correctly work. Use the new api master_state_change to track when master -is operational or not and set a bool in qca8k_priv. -We cache the first cached master available and we check if other cpu -port are operational when the cached one goes down. -This cached master will later be used by mdio read/write and mib request to -correctly use the working function. - -qca8k implementation for MDIO/MIB Ethernet is bad. CPU port0 is the only -one that answers with the ack packet or sends MIB Ethernet packets. For -this reason the master_state_change ignore CPU port6 and only checks -CPU port0 if it's operational and enables this mode. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 15 +++++++++++++++ - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 16 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -2401,6 +2401,20 @@ qca8k_port_lag_leave(struct dsa_switch * - return qca8k_lag_refresh_portmap(ds, port, lag, true); - } - -+static void -+qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, -+ bool operational) -+{ -+ struct dsa_port *dp = master->dsa_ptr; -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ -+ if (dp->index != 0) -+ return; -+ -+ priv->mgmt_master = operational ? (struct net_device *)master : NULL; -+} -+ - static const struct dsa_switch_ops qca8k_switch_ops = { - .get_tag_protocol = qca8k_get_tag_protocol, - .setup = qca8k_setup, -@@ -2436,6 +2450,7 @@ static const struct dsa_switch_ops qca8k - .get_phy_flags = qca8k_get_phy_flags, - .port_lag_join = qca8k_port_lag_join, - .port_lag_leave = qca8k_port_lag_leave, -+ .master_state_change = qca8k_master_change, - }; - - static int qca8k_read_switch_id(struct qca8k_priv *priv) ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -353,6 +353,7 @@ struct qca8k_priv { - struct dsa_switch_ops ops; - struct gpio_desc *reset_gpio; - unsigned int port_mtu[QCA8K_NUM_PORTS]; -+ struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ - }; - - struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch b/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch deleted file mode 100644 index 07c5ba46210..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-10-net-dsa-qca8k-add-support-for-mgmt-read-write-in-Eth.patch +++ /dev/null @@ -1,363 +0,0 @@ -From 5950c7c0a68c915b336c70f79388626e2d576ab7 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:29 +0100 -Subject: [PATCH 10/16] net: dsa: qca8k: add support for mgmt read/write in - Ethernet packet - -Add qca8k side support for mgmt read/write in Ethernet packet. -qca8k supports some specially crafted Ethernet packet that can be used -for mgmt read/write instead of the legacy method uart/internal mdio. -This add support for the qca8k side to craft the packet and enqueue it. -Each port and the qca8k_priv have a special struct to put data in it. -The completion API is used to wait for the packet to be received back -with the requested data. - -The various steps are: -1. Craft the special packet with the qca hdr set to mgmt read/write - mode. -2. Set the lock in the dedicated mgmt struct. -3. Increment the seq number and set it in the mgmt pkt -4. Reinit the completion. -5. Enqueue the packet. -6. Wait the packet to be received. -7. Use the data set by the tagger to complete the mdio operation. - -If the completion timeouts or the ack value is not true, the legacy -mdio way is used. - -It has to be considered that in the initial setup mdio is still used and -mdio is still used until DSA is ready to accept and tag packet. - -tag_proto_connect() is used to fill the required handler for the tagger -to correctly parse and elaborate the special Ethernet mdio packet. - -Locking is added to qca8k_master_change() to make sure no mgmt Ethernet -are in progress. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 225 ++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 13 +++ - 2 files changed, 238 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - - #include "qca8k.h" - -@@ -170,6 +171,194 @@ qca8k_rmw(struct qca8k_priv *priv, u32 r - return regmap_update_bits(priv->regmap, reg, mask, write_val); - } - -+static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ u8 len, cmd; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -+ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -+ -+ /* Make sure the seq match the requested packet */ -+ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -+ mgmt_eth_data->ack = true; -+ -+ if (cmd == MDIO_READ) { -+ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -+ -+ /* Get the rest of the 12 byte of data */ -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(mgmt_eth_data->data + 1, skb->data, -+ QCA_HDR_MGMT_DATA2_LEN); -+ } -+ -+ complete(&mgmt_eth_data->rw_done); -+} -+ -+static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -+ int priority) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ struct sk_buff *skb; -+ u16 hdr; -+ -+ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); -+ if (!skb) -+ return NULL; -+ -+ skb_reset_mac_header(skb); -+ skb_set_network_header(skb, skb->len); -+ -+ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); -+ -+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); -+ hdr |= QCA_HDR_XMIT_FROM_CPU; -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); -+ -+ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -+ QCA_HDR_MGMT_CHECK_CODE_VAL); -+ -+ if (cmd == MDIO_WRITE) -+ mgmt_ethhdr->mdio_data = *val; -+ -+ mgmt_ethhdr->hdr = htons(hdr); -+ -+ skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -+ -+ return skb; -+} -+ -+static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -+ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); -+} -+ -+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -+ QCA8K_ETHERNET_MDIO_PRIORITY); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ *val = mgmt_eth_data->data[0]; -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val, -+ QCA8K_ETHERNET_MDIO_PRIORITY); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int -+qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ u32 val = 0; -+ int ret; -+ -+ ret = qca8k_read_eth(priv, reg, &val); -+ if (ret) -+ return ret; -+ -+ val &= ~mask; -+ val |= write_val; -+ -+ return qca8k_write_eth(priv, reg, val); -+} -+ - static int - qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) - { -@@ -178,6 +367,9 @@ qca8k_regmap_read(void *ctx, uint32_t re - u16 r1, r2, page; - int ret; - -+ if (!qca8k_read_eth(priv, reg, val)) -+ return 0; -+ - qca8k_split_addr(reg, &r1, &r2, &page); - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -@@ -201,6 +393,9 @@ qca8k_regmap_write(void *ctx, uint32_t r - u16 r1, r2, page; - int ret; - -+ if (!qca8k_write_eth(priv, reg, val)) -+ return 0; -+ - qca8k_split_addr(reg, &r1, &r2, &page); - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -@@ -225,6 +420,9 @@ qca8k_regmap_update_bits(void *ctx, uint - u32 val; - int ret; - -+ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) -+ return 0; -+ - qca8k_split_addr(reg, &r1, &r2, &page); - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -@@ -2412,7 +2610,30 @@ qca8k_master_change(struct dsa_switch *d - if (dp->index != 0) - return; - -+ mutex_lock(&priv->mgmt_eth_data.mutex); -+ - priv->mgmt_master = operational ? (struct net_device *)master : NULL; -+ -+ mutex_unlock(&priv->mgmt_eth_data.mutex); -+} -+ -+static int qca8k_connect_tag_protocol(struct dsa_switch *ds, -+ enum dsa_tag_protocol proto) -+{ -+ struct qca_tagger_data *tagger_data; -+ -+ switch (proto) { -+ case DSA_TAG_PROTO_QCA: -+ tagger_data = ds->tagger_data; -+ -+ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -+ -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; - } - - static const struct dsa_switch_ops qca8k_switch_ops = { -@@ -2451,6 +2672,7 @@ static const struct dsa_switch_ops qca8k - .port_lag_join = qca8k_port_lag_join, - .port_lag_leave = qca8k_port_lag_leave, - .master_state_change = qca8k_master_change, -+ .connect_tag_protocol = qca8k_connect_tag_protocol, - }; - - static int qca8k_read_switch_id(struct qca8k_priv *priv) -@@ -2530,6 +2752,9 @@ qca8k_sw_probe(struct mdio_device *mdiod - if (!priv->ds) - return -ENOMEM; - -+ mutex_init(&priv->mgmt_eth_data.mutex); -+ init_completion(&priv->mgmt_eth_data.rw_done); -+ - priv->ds->dev = &mdiodev->dev; - priv->ds->num_ports = QCA8K_NUM_PORTS; - priv->ds->priv = priv; ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -11,6 +11,10 @@ - #include - #include - #include -+#include -+ -+#define QCA8K_ETHERNET_MDIO_PRIORITY 7 -+#define QCA8K_ETHERNET_TIMEOUT 100 - - #define QCA8K_NUM_PORTS 7 - #define QCA8K_NUM_CPU_PORTS 2 -@@ -328,6 +332,14 @@ enum { - QCA8K_CPU_PORT6, - }; - -+struct qca8k_mgmt_eth_data { -+ struct completion rw_done; -+ struct mutex mutex; /* Enforce one mdio read/write at time */ -+ bool ack; -+ u32 seq; -+ u32 data[4]; -+}; -+ - struct qca8k_ports_config { - bool sgmii_rx_clk_falling_edge; - bool sgmii_tx_clk_falling_edge; -@@ -354,6 +366,7 @@ struct qca8k_priv { - struct gpio_desc *reset_gpio; - unsigned int port_mtu[QCA8K_NUM_PORTS]; - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ -+ struct qca8k_mgmt_eth_data mgmt_eth_data; - }; - - struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch b/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch deleted file mode 100644 index 0dcf2794338..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-11-net-dsa-qca8k-add-support-for-mib-autocast-in-Ethern.patch +++ /dev/null @@ -1,226 +0,0 @@ -From 5c957c7ca78cce5e4b96866722b0115bd758d945 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:30 +0100 -Subject: [PATCH 11/16] net: dsa: qca8k: add support for mib autocast in - Ethernet packet - -The switch can autocast MIB counter using Ethernet packet. -Add support for this and provide a handler for the tagger. -The switch will send packet with MIB counter for each port, the switch -will use completion API to wait for the correct packet to be received -and will complete the task only when each packet is received. -Although the handler will drop all the other packet, we still have to -consume each MIB packet to complete the request. This is done to prevent -mixed data with concurrent ethtool request. - -connect_tag_protocol() is used to add the handler to the tag_qca tagger, -master_state_change() use the MIB lock to make sure no MIB Ethernet is -in progress. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 106 +++++++++++++++++++++++++++++++++++++++- - drivers/net/dsa/qca8k.h | 17 ++++++- - 2 files changed, 121 insertions(+), 2 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -830,7 +830,10 @@ qca8k_mib_init(struct qca8k_priv *priv) - int ret; - - mutex_lock(&priv->reg_mutex); -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_FLUSH | QCA8K_MIB_BUSY); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -+ QCA8K_MIB_BUSY); - if (ret) - goto exit; - -@@ -1901,6 +1904,97 @@ qca8k_get_strings(struct dsa_switch *ds, - ETH_GSTRING_LEN); - } - -+static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ const struct qca8k_match_data *match_data; -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ const struct qca8k_mib_desc *mib; -+ struct mib_ethhdr *mib_ethhdr; -+ int i, mib_len, offset = 0; -+ u64 *data; -+ u8 port; -+ -+ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); -+ mib_eth_data = &priv->mib_eth_data; -+ -+ /* The switch autocast every port. Ignore other packet and -+ * parse only the requested one. -+ */ -+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); -+ if (port != mib_eth_data->req_port) -+ goto exit; -+ -+ match_data = device_get_match_data(priv->dev); -+ data = mib_eth_data->data; -+ -+ for (i = 0; i < match_data->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ -+ /* First 3 mib are present in the skb head */ -+ if (i < 3) { -+ data[i] = mib_ethhdr->data[i]; -+ continue; -+ } -+ -+ mib_len = sizeof(uint32_t); -+ -+ /* Some mib are 64 bit wide */ -+ if (mib->size == 2) -+ mib_len = sizeof(uint64_t); -+ -+ /* Copy the mib value from packet to the */ -+ memcpy(data + i, skb->data + offset, mib_len); -+ -+ /* Set the offset for the next mib */ -+ offset += mib_len; -+ } -+ -+exit: -+ /* Complete on receiving all the mib packet */ -+ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) -+ complete(&mib_eth_data->rw_done); -+} -+ -+static int -+qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) -+{ -+ struct dsa_port *dp = dsa_to_port(ds, port); -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ mib_eth_data = &priv->mib_eth_data; -+ -+ mutex_lock(&mib_eth_data->mutex); -+ -+ reinit_completion(&mib_eth_data->rw_done); -+ -+ mib_eth_data->req_port = dp->index; -+ mib_eth_data->data = data; -+ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ /* Send mib autocast request */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | -+ QCA8K_MIB_BUSY); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ if (ret) -+ goto exit; -+ -+ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); -+ -+exit: -+ mutex_unlock(&mib_eth_data->mutex); -+ -+ return ret; -+} -+ - static void - qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, - uint64_t *data) -@@ -1912,6 +2006,10 @@ qca8k_get_ethtool_stats(struct dsa_switc - u32 hi = 0; - int ret; - -+ if (priv->mgmt_master && -+ qca8k_get_ethtool_stats_eth(ds, port, data) > 0) -+ return; -+ - match_data = of_device_get_match_data(priv->dev); - - for (i = 0; i < match_data->mib_count; i++) { -@@ -2611,9 +2709,11 @@ qca8k_master_change(struct dsa_switch *d - return; - - mutex_lock(&priv->mgmt_eth_data.mutex); -+ mutex_lock(&priv->mib_eth_data.mutex); - - priv->mgmt_master = operational ? (struct net_device *)master : NULL; - -+ mutex_unlock(&priv->mib_eth_data.mutex); - mutex_unlock(&priv->mgmt_eth_data.mutex); - } - -@@ -2627,6 +2727,7 @@ static int qca8k_connect_tag_protocol(st - tagger_data = ds->tagger_data; - - tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -+ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; - - break; - default: -@@ -2755,6 +2856,9 @@ qca8k_sw_probe(struct mdio_device *mdiod - mutex_init(&priv->mgmt_eth_data.mutex); - init_completion(&priv->mgmt_eth_data.rw_done); - -+ mutex_init(&priv->mib_eth_data.mutex); -+ init_completion(&priv->mib_eth_data.rw_done); -+ - priv->ds->dev = &mdiodev->dev; - priv->ds->num_ports = QCA8K_NUM_PORTS; - priv->ds->priv = priv; ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -67,7 +67,7 @@ - #define QCA8K_REG_MODULE_EN 0x030 - #define QCA8K_MODULE_EN_MIB BIT(0) - #define QCA8K_REG_MIB 0x034 --#define QCA8K_MIB_FLUSH BIT(24) -+#define QCA8K_MIB_FUNC GENMASK(26, 24) - #define QCA8K_MIB_CPU_KEEP BIT(20) - #define QCA8K_MIB_BUSY BIT(17) - #define QCA8K_MDIO_MASTER_CTRL 0x3c -@@ -317,6 +317,12 @@ enum qca8k_vlan_cmd { - QCA8K_VLAN_READ = 6, - }; - -+enum qca8k_mid_cmd { -+ QCA8K_MIB_FLUSH = 1, -+ QCA8K_MIB_FLUSH_PORT = 2, -+ QCA8K_MIB_CAST = 3, -+}; -+ - struct ar8xxx_port_status { - int enabled; - }; -@@ -340,6 +346,14 @@ struct qca8k_mgmt_eth_data { - u32 data[4]; - }; - -+struct qca8k_mib_eth_data { -+ struct completion rw_done; -+ struct mutex mutex; /* Process one command at time */ -+ refcount_t port_parsed; /* Counter to track parsed port */ -+ u8 req_port; -+ u64 *data; /* pointer to ethtool data */ -+}; -+ - struct qca8k_ports_config { - bool sgmii_rx_clk_falling_edge; - bool sgmii_tx_clk_falling_edge; -@@ -367,6 +381,7 @@ struct qca8k_priv { - unsigned int port_mtu[QCA8K_NUM_PORTS]; - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ - struct qca8k_mgmt_eth_data mgmt_eth_data; -+ struct qca8k_mib_eth_data mib_eth_data; - }; - - struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch b/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch deleted file mode 100644 index f5899eb5901..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-12-net-dsa-qca8k-add-support-for-phy-read-write-with-mg.patch +++ /dev/null @@ -1,287 +0,0 @@ -From 2cd5485663847d468dc207b3ff85fb1fab44d97f Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:31 +0100 -Subject: [PATCH 12/16] net: dsa: qca8k: add support for phy read/write with - mgmt Ethernet - -Use mgmt Ethernet also for phy read/write if availabale. Use a different -seq number to make sure we receive the correct packet. -On any error, we fallback to the legacy mdio read/write. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 216 ++++++++++++++++++++++++++++++++++++++++ - drivers/net/dsa/qca8k.h | 1 + - 2 files changed, 217 insertions(+) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -867,6 +867,199 @@ qca8k_port_set_status(struct qca8k_priv - regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); - } - -+static int -+qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, -+ struct sk_buff *read_skb, u32 *val) -+{ -+ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); -+ bool ack; -+ int ret; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the copy pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ *val = mgmt_eth_data->data[0]; -+ -+ return 0; -+} -+ -+static int -+qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, -+ int regnum, u16 data) -+{ -+ struct sk_buff *write_skb, *clear_skb, *read_skb; -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ u32 write_val, clear_val = 0, val; -+ struct net_device *mgmt_master; -+ int ret, ret1; -+ bool ack; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ if (read) { -+ write_val |= QCA8K_MDIO_MASTER_READ; -+ } else { -+ write_val |= QCA8K_MDIO_MASTER_WRITE; -+ write_val |= QCA8K_MDIO_MASTER_DATA(data); -+ } -+ -+ /* Prealloc all the needed skb before the lock */ -+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, -+ &write_val, QCA8K_ETHERNET_PHY_PRIORITY); -+ if (!write_skb) -+ return -ENOMEM; -+ -+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, -+ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); -+ if (!write_skb) { -+ ret = -ENOMEM; -+ goto err_clear_skb; -+ } -+ -+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, -+ &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); -+ if (!write_skb) { -+ ret = -ENOMEM; -+ goto err_read_skb; -+ } -+ -+ /* Actually start the request: -+ * 1. Send mdio master packet -+ * 2. Busy Wait for mdio master command -+ * 3. Get the data if we are reading -+ * 4. Reset the mdio master (even with error) -+ */ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check if mgmt_master is operational */ -+ mgmt_master = priv->mgmt_master; -+ if (!mgmt_master) { -+ mutex_unlock(&mgmt_eth_data->mutex); -+ ret = -EINVAL; -+ goto err_mgmt_master; -+ } -+ -+ read_skb->dev = mgmt_master; -+ clear_skb->dev = mgmt_master; -+ write_skb->dev = mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the write pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(write_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, -+ !(val & QCA8K_MDIO_MASTER_BUSY), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ mgmt_eth_data, read_skb, &val); -+ -+ if (ret < 0 && ret1 < 0) { -+ ret = ret1; -+ goto exit; -+ } -+ -+ if (read) { -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the read pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(read_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; -+ } else { -+ kfree_skb(read_skb); -+ } -+exit: -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the clear pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(clear_skb); -+ -+ wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ return ret; -+ -+ /* Error handling before lock */ -+err_mgmt_master: -+ kfree_skb(read_skb); -+err_read_skb: -+ kfree_skb(clear_skb); -+err_clear_skb: -+ kfree_skb(write_skb); -+ -+ return ret; -+} -+ - static u32 - qca8k_port_to_phy(int port) - { -@@ -989,6 +1182,12 @@ qca8k_internal_mdio_write(struct mii_bus - { - struct qca8k_priv *priv = slave_bus->priv; - struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); -+ if (!ret) -+ return 0; - - return qca8k_mdio_write(bus, phy, regnum, data); - } -@@ -998,6 +1197,12 @@ qca8k_internal_mdio_read(struct mii_bus - { - struct qca8k_priv *priv = slave_bus->priv; - struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); -+ if (ret >= 0) -+ return ret; - - return qca8k_mdio_read(bus, phy, regnum); - } -@@ -1006,6 +1211,7 @@ static int - qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) - { - struct qca8k_priv *priv = ds->priv; -+ int ret; - - /* Check if the legacy mapping should be used and the - * port is not correctly mapped to the right PHY in the -@@ -1014,6 +1220,11 @@ qca8k_phy_write(struct dsa_switch *ds, i - if (priv->legacy_phy_port_mapping) - port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; - -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, false, port, regnum, 0); -+ if (!ret) -+ return ret; -+ - return qca8k_mdio_write(priv->bus, port, regnum, data); - } - -@@ -1030,6 +1241,11 @@ qca8k_phy_read(struct dsa_switch *ds, in - if (priv->legacy_phy_port_mapping) - port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; - -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, true, port, regnum, 0); -+ if (ret >= 0) -+ return ret; -+ - ret = qca8k_mdio_read(priv->bus, port, regnum); - - if (ret < 0) ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -14,6 +14,7 @@ - #include - - #define QCA8K_ETHERNET_MDIO_PRIORITY 7 -+#define QCA8K_ETHERNET_PHY_PRIORITY 6 - #define QCA8K_ETHERNET_TIMEOUT 100 - - #define QCA8K_NUM_PORTS 7 diff --git a/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch b/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch deleted file mode 100644 index 4ac0bc32fdb..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-13-net-dsa-qca8k-move-page-cache-to-driver-priv.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 4264350acb75430d5021a1d7de56a33faf69a097 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:32 +0100 -Subject: [PATCH 13/16] net: dsa: qca8k: move page cache to driver priv - -There can be multiple qca8k switch on the same system. Move the static -qca8k_current_page to qca8k_priv and make it specific for each switch. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 42 ++++++++++++++++++++--------------------- - drivers/net/dsa/qca8k.h | 9 +++++++++ - 2 files changed, 29 insertions(+), 22 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -75,12 +75,6 @@ static const struct qca8k_mib_desc ar832 - MIB_DESC(1, 0xac, "TXUnicast"), - }; - --/* The 32bit switch registers are accessed indirectly. To achieve this we need -- * to set the page of the register. Track the last page that was set to reduce -- * mdio writes -- */ --static u16 qca8k_current_page = 0xffff; -- - static void - qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) - { -@@ -134,11 +128,13 @@ qca8k_mii_write32(struct mii_bus *bus, i - } - - static int --qca8k_set_page(struct mii_bus *bus, u16 page) -+qca8k_set_page(struct qca8k_priv *priv, u16 page) - { -+ u16 *cached_page = &priv->mdio_cache.page; -+ struct mii_bus *bus = priv->bus; - int ret; - -- if (page == qca8k_current_page) -+ if (page == *cached_page) - return 0; - - ret = bus->write(bus, 0x18, 0, page); -@@ -148,7 +144,7 @@ qca8k_set_page(struct mii_bus *bus, u16 - return ret; - } - -- qca8k_current_page = page; -+ *cached_page = page; - usleep_range(1000, 2000); - return 0; - } -@@ -374,7 +370,7 @@ qca8k_regmap_read(void *ctx, uint32_t re - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - -- ret = qca8k_set_page(bus, page); -+ ret = qca8k_set_page(priv, page); - if (ret < 0) - goto exit; - -@@ -400,7 +396,7 @@ qca8k_regmap_write(void *ctx, uint32_t r - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - -- ret = qca8k_set_page(bus, page); -+ ret = qca8k_set_page(priv, page); - if (ret < 0) - goto exit; - -@@ -427,7 +423,7 @@ qca8k_regmap_update_bits(void *ctx, uint - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - -- ret = qca8k_set_page(bus, page); -+ ret = qca8k_set_page(priv, page); - if (ret < 0) - goto exit; - -@@ -1098,8 +1094,9 @@ qca8k_mdio_busy_wait(struct mii_bus *bus - } - - static int --qca8k_mdio_write(struct mii_bus *bus, int phy, int regnum, u16 data) -+qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) - { -+ struct mii_bus *bus = priv->bus; - u16 r1, r2, page; - u32 val; - int ret; -@@ -1116,7 +1113,7 @@ qca8k_mdio_write(struct mii_bus *bus, in - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - -- ret = qca8k_set_page(bus, page); -+ ret = qca8k_set_page(priv, page); - if (ret) - goto exit; - -@@ -1135,8 +1132,9 @@ exit: - } - - static int --qca8k_mdio_read(struct mii_bus *bus, int phy, int regnum) -+qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) - { -+ struct mii_bus *bus = priv->bus; - u16 r1, r2, page; - u32 val; - int ret; -@@ -1152,7 +1150,7 @@ qca8k_mdio_read(struct mii_bus *bus, int - - mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); - -- ret = qca8k_set_page(bus, page); -+ ret = qca8k_set_page(priv, page); - if (ret) - goto exit; - -@@ -1181,7 +1179,6 @@ static int - qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) - { - struct qca8k_priv *priv = slave_bus->priv; -- struct mii_bus *bus = priv->bus; - int ret; - - /* Use mdio Ethernet when available, fallback to legacy one on error */ -@@ -1189,14 +1186,13 @@ qca8k_internal_mdio_write(struct mii_bus - if (!ret) - return 0; - -- return qca8k_mdio_write(bus, phy, regnum, data); -+ return qca8k_mdio_write(priv, phy, regnum, data); - } - - static int - qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) - { - struct qca8k_priv *priv = slave_bus->priv; -- struct mii_bus *bus = priv->bus; - int ret; - - /* Use mdio Ethernet when available, fallback to legacy one on error */ -@@ -1204,7 +1200,7 @@ qca8k_internal_mdio_read(struct mii_bus - if (ret >= 0) - return ret; - -- return qca8k_mdio_read(bus, phy, regnum); -+ return qca8k_mdio_read(priv, phy, regnum); - } - - static int -@@ -1225,7 +1221,7 @@ qca8k_phy_write(struct dsa_switch *ds, i - if (!ret) - return ret; - -- return qca8k_mdio_write(priv->bus, port, regnum, data); -+ return qca8k_mdio_write(priv, port, regnum, data); - } - - static int -@@ -1246,7 +1242,7 @@ qca8k_phy_read(struct dsa_switch *ds, in - if (ret >= 0) - return ret; - -- ret = qca8k_mdio_read(priv->bus, port, regnum); -+ ret = qca8k_mdio_read(priv, port, regnum); - - if (ret < 0) - return 0xffff; -@@ -3060,6 +3056,8 @@ qca8k_sw_probe(struct mdio_device *mdiod - return PTR_ERR(priv->regmap); - } - -+ priv->mdio_cache.page = 0xffff; -+ - /* Check the detected switch id */ - ret = qca8k_read_switch_id(priv); - if (ret) ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -363,6 +363,14 @@ struct qca8k_ports_config { - u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ - }; - -+struct qca8k_mdio_cache { -+/* The 32bit switch registers are accessed indirectly. To achieve this we need -+ * to set the page of the register. Track the last page that was set to reduce -+ * mdio writes -+ */ -+ u16 page; -+}; -+ - struct qca8k_priv { - u8 switch_id; - u8 switch_revision; -@@ -383,6 +391,7 @@ struct qca8k_priv { - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ - struct qca8k_mgmt_eth_data mgmt_eth_data; - struct qca8k_mib_eth_data mib_eth_data; -+ struct qca8k_mdio_cache mdio_cache; - }; - - struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch b/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch deleted file mode 100644 index e2cb2721ce9..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-14-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch +++ /dev/null @@ -1,164 +0,0 @@ -From 2481d206fae7884cd07014fd1318e63af35e99eb Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:33 +0100 -Subject: [PATCH 14/16] net: dsa: qca8k: cache lo and hi for mdio write - -From Documentation, we can cache lo and hi the same way we do with the -page. This massively reduce the mdio write as 3/4 of the time as we only -require to write the lo or hi part for a mdio write. - -Signed-off-by: Ansuel Smith -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++++++++-------- - drivers/net/dsa/qca8k.h | 5 ++++ - 2 files changed, 54 insertions(+), 12 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -89,6 +89,44 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u - } - - static int -+qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) -+{ -+ u16 *cached_lo = &priv->mdio_cache.lo; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (lo == *cached_lo) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, lo); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit lo register\n"); -+ -+ *cached_lo = lo; -+ return 0; -+} -+ -+static int -+qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) -+{ -+ u16 *cached_hi = &priv->mdio_cache.hi; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (hi == *cached_hi) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, hi); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit hi register\n"); -+ -+ *cached_hi = hi; -+ return 0; -+} -+ -+static int - qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) - { - int ret; -@@ -111,7 +149,7 @@ qca8k_mii_read32(struct mii_bus *bus, in - } - - static void --qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) -+qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) - { - u16 lo, hi; - int ret; -@@ -119,12 +157,9 @@ qca8k_mii_write32(struct mii_bus *bus, i - lo = val & 0xffff; - hi = (u16)(val >> 16); - -- ret = bus->write(bus, phy_id, regnum, lo); -+ ret = qca8k_set_lo(priv, phy_id, regnum, lo); - if (ret >= 0) -- ret = bus->write(bus, phy_id, regnum + 1, hi); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit register\n"); -+ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); - } - - static int -@@ -400,7 +435,7 @@ qca8k_regmap_write(void *ctx, uint32_t r - if (ret < 0) - goto exit; - -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); - - exit: - mutex_unlock(&bus->mdio_lock); -@@ -433,7 +468,7 @@ qca8k_regmap_update_bits(void *ctx, uint - - val &= ~mask; - val |= write_val; -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); - - exit: - mutex_unlock(&bus->mdio_lock); -@@ -1117,14 +1152,14 @@ qca8k_mdio_write(struct qca8k_priv *priv - if (ret) - goto exit; - -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); - - ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, - QCA8K_MDIO_MASTER_BUSY); - - exit: - /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); - - mutex_unlock(&bus->mdio_lock); - -@@ -1154,7 +1189,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, - if (ret) - goto exit; - -- qca8k_mii_write32(bus, 0x10 | r2, r1, val); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); - - ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, - QCA8K_MDIO_MASTER_BUSY); -@@ -1165,7 +1200,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, - - exit: - /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(bus, 0x10 | r2, r1, 0); -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); - - mutex_unlock(&bus->mdio_lock); - -@@ -3057,6 +3092,8 @@ qca8k_sw_probe(struct mdio_device *mdiod - } - - priv->mdio_cache.page = 0xffff; -+ priv->mdio_cache.lo = 0xffff; -+ priv->mdio_cache.hi = 0xffff; - - /* Check the detected switch id */ - ret = qca8k_read_switch_id(priv); ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -369,6 +369,11 @@ struct qca8k_mdio_cache { - * mdio writes - */ - u16 page; -+/* lo and hi can also be cached and from Documentation we can skip one -+ * extra mdio write if lo or hi is didn't change. -+ */ -+ u16 lo; -+ u16 hi; - }; - - struct qca8k_priv { diff --git a/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch b/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch deleted file mode 100644 index 5acd13dbad8..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-15-net-dsa-qca8k-add-support-for-larger-read-write-size.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 90386223f44e2a751d7e9e9ac8f78ea33358a891 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:34 +0100 -Subject: [PATCH 15/16] net: dsa: qca8k: add support for larger read/write size - with mgmt Ethernet - -mgmt Ethernet packet can read/write up to 16byte at times. The len reg -is limited to 15 (0xf). The switch actually sends and accepts data in 4 -different steps of len values. -Len steps: -- 0: nothing -- 1-4: first 4 byte -- 5-6: first 12 byte -- 7-15: all 16 byte - -In the alloc skb function we check if the len is 16 and we fix it to a -len of 15. It the read/write function interest to extract the real asked -data. The tagger handler will always copy the fully 16byte with a READ -command. This is useful for some big regs like the fdb reg that are -more than 4byte of data. This permits to introduce a bulk function that -will send and request the entire entry in one go. -Write function is changed and it does now require to pass the pointer to -val to also handle array val. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 61 +++++++++++++++++++++++++++-------------- - 1 file changed, 41 insertions(+), 20 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -222,7 +222,9 @@ static void qca8k_rw_reg_ack_handler(str - if (cmd == MDIO_READ) { - mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; - -- /* Get the rest of the 12 byte of data */ -+ /* Get the rest of the 12 byte of data. -+ * The read/write function will extract the requested data. -+ */ - if (len > QCA_HDR_MGMT_DATA1_LEN) - memcpy(mgmt_eth_data->data + 1, skb->data, - QCA_HDR_MGMT_DATA2_LEN); -@@ -232,16 +234,30 @@ static void qca8k_rw_reg_ack_handler(str - } - - static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -- int priority) -+ int priority, unsigned int len) - { - struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ unsigned int real_len; - struct sk_buff *skb; -+ u32 *data2; - u16 hdr; - - skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); - if (!skb) - return NULL; - -+ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -+ * Actually for some reason the steps are: -+ * 0: nothing -+ * 1-4: first 4 byte -+ * 5-6: first 12 byte -+ * 7-15: all 16 byte -+ */ -+ if (len == 16) -+ real_len = 15; -+ else -+ real_len = len; -+ - skb_reset_mac_header(skb); - skb_set_network_header(skb, skb->len); - -@@ -254,7 +270,7 @@ static struct sk_buff *qca8k_alloc_mdio_ - hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); - - mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, 4); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); - mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); - mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, - QCA_HDR_MGMT_CHECK_CODE_VAL); -@@ -264,7 +280,9 @@ static struct sk_buff *qca8k_alloc_mdio_ - - mgmt_ethhdr->hdr = htons(hdr); - -- skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -+ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -+ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); - - return skb; - } -@@ -277,7 +295,7 @@ static void qca8k_mdio_header_fill_seq_n - mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); - } - --static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val) -+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) - { - struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; - struct sk_buff *skb; -@@ -285,7 +303,7 @@ static int qca8k_read_eth(struct qca8k_p - int ret; - - skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -- QCA8K_ETHERNET_MDIO_PRIORITY); -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); - if (!skb) - return -ENOMEM; - -@@ -313,6 +331,9 @@ static int qca8k_read_eth(struct qca8k_p - msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); - - *val = mgmt_eth_data->data[0]; -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ - ack = mgmt_eth_data->ack; - - mutex_unlock(&mgmt_eth_data->mutex); -@@ -326,15 +347,15 @@ static int qca8k_read_eth(struct qca8k_p - return 0; - } - --static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 val) -+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) - { - struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; - struct sk_buff *skb; - bool ack; - int ret; - -- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, &val, -- QCA8K_ETHERNET_MDIO_PRIORITY); -+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); - if (!skb) - return -ENOMEM; - -@@ -380,14 +401,14 @@ qca8k_regmap_update_bits_eth(struct qca8 - u32 val = 0; - int ret; - -- ret = qca8k_read_eth(priv, reg, &val); -+ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); - if (ret) - return ret; - - val &= ~mask; - val |= write_val; - -- return qca8k_write_eth(priv, reg, val); -+ return qca8k_write_eth(priv, reg, &val, sizeof(val)); - } - - static int -@@ -398,7 +419,7 @@ qca8k_regmap_read(void *ctx, uint32_t re - u16 r1, r2, page; - int ret; - -- if (!qca8k_read_eth(priv, reg, val)) -+ if (!qca8k_read_eth(priv, reg, val, sizeof(val))) - return 0; - - qca8k_split_addr(reg, &r1, &r2, &page); -@@ -424,7 +445,7 @@ qca8k_regmap_write(void *ctx, uint32_t r - u16 r1, r2, page; - int ret; - -- if (!qca8k_write_eth(priv, reg, val)) -+ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) - return 0; - - qca8k_split_addr(reg, &r1, &r2, &page); -@@ -959,21 +980,21 @@ qca8k_phy_eth_command(struct qca8k_priv - } - - /* Prealloc all the needed skb before the lock */ -- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, -- &write_val, QCA8K_ETHERNET_PHY_PRIORITY); -+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); - if (!write_skb) - return -ENOMEM; - -- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, -- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); -+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); - if (!write_skb) { - ret = -ENOMEM; - goto err_clear_skb; - } - -- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, -- &clear_val, QCA8K_ETHERNET_PHY_PRIORITY); -- if (!write_skb) { -+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -+ if (!read_skb) { - ret = -ENOMEM; - goto err_read_skb; - } diff --git a/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch b/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch deleted file mode 100644 index f26c6b91ac5..00000000000 --- a/target/linux/generic/backport-6.1/766-v5.18-16-net-dsa-qca8k-introduce-qca8k_bulk_read-write-functi.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 4f3701fc599820568ba4395070d34e4248800fc0 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Wed, 2 Feb 2022 01:03:35 +0100 -Subject: [PATCH 16/16] net: dsa: qca8k: introduce qca8k_bulk_read/write - function - -Introduce qca8k_bulk_read/write() function to use mgmt Ethernet way to -read/write packet in bulk. Make use of this new function in the fdb -function and while at it reduce the reg for fdb_read from 4 to 3 as the -max bit for the ARL(fdb) table is 83 bits. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 55 ++++++++++++++++++++++++++++++++--------- - 1 file changed, 43 insertions(+), 12 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -412,6 +412,43 @@ qca8k_regmap_update_bits_eth(struct qca8 - } - - static int -+qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ -+ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ u32 tmp; -+ -+ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ tmp = val[i]; -+ -+ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int - qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -@@ -546,17 +583,13 @@ qca8k_busy_wait(struct qca8k_priv *priv, - static int - qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) - { -- u32 reg[4], val; -- int i, ret; -+ u32 reg[3]; -+ int ret; - - /* load the ARL table into an array */ -- for (i = 0; i < 4; i++) { -- ret = qca8k_read(priv, QCA8K_REG_ATU_DATA0 + (i * 4), &val); -- if (ret < 0) -- return ret; -- -- reg[i] = val; -- } -+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+ if (ret) -+ return ret; - - /* vid - 83:72 */ - fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -@@ -580,7 +613,6 @@ qca8k_fdb_write(struct qca8k_priv *priv, - u8 aging) - { - u32 reg[3] = { 0 }; -- int i; - - /* vid - 83:72 */ - reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -@@ -597,8 +629,7 @@ qca8k_fdb_write(struct qca8k_priv *priv, - reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); - - /* load the array into the ARL table */ -- for (i = 0; i < 3; i++) -- qca8k_write(priv, QCA8K_REG_ATU_DATA0 + (i * 4), reg[i]); -+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); - } - - static int diff --git a/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch b/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch deleted file mode 100644 index 34607c223ce..00000000000 --- a/target/linux/generic/backport-6.1/767-v5.18-net-dsa-qca8k-check-correct-variable-in-qca8k_phy_et.patch +++ /dev/null @@ -1,28 +0,0 @@ -From c3664d913dc115cab4a5fdb5634df4887048000e Mon Sep 17 00:00:00 2001 -From: Dan Carpenter -Date: Fri, 4 Feb 2022 13:03:36 +0300 -Subject: [PATCH 1/1] net: dsa: qca8k: check correct variable in - qca8k_phy_eth_command() - -This is a copy and paste bug. It was supposed to check "clear_skb" -instead of "write_skb". - -Fixes: 2cd548566384 ("net: dsa: qca8k: add support for phy read/write with mgmt Ethernet") -Signed-off-by: Dan Carpenter -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1018,7 +1018,7 @@ qca8k_phy_eth_command(struct qca8k_priv - - clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, - QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -- if (!write_skb) { -+ if (!clear_skb) { - ret = -ENOMEM; - goto err_clear_skb; - } diff --git a/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch b/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch deleted file mode 100644 index d8cf2663090..00000000000 --- a/target/linux/generic/backport-6.1/768-v5.18-net-dsa-qca8k-fix-noderef.cocci-warnings.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 4f5e483b8c7a644733db941a1ae00173baa7b463 Mon Sep 17 00:00:00 2001 -From: kernel test robot -Date: Thu, 10 Feb 2022 06:13:04 +0800 -Subject: [PATCH 1/1] net: dsa: qca8k: fix noderef.cocci warnings - -drivers/net/dsa/qca8k.c:422:37-43: ERROR: application of sizeof to pointer - - sizeof when applied to a pointer typed expression gives the size of - the pointer - -Generated by: scripts/coccinelle/misc/noderef.cocci - -Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet") -CC: Ansuel Smith -Reported-by: kernel test robot -Signed-off-by: kernel test robot -Reviewed-by: Florian Fainelli -Link: https://lore.kernel.org/r/20220209221304.GA17529@d2214a582157 -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca8k.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -456,7 +456,7 @@ qca8k_regmap_read(void *ctx, uint32_t re - u16 r1, r2, page; - int ret; - -- if (!qca8k_read_eth(priv, reg, val, sizeof(val))) -+ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) - return 0; - - qca8k_split_addr(reg, &r1, &r2, &page); diff --git a/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch deleted file mode 100644 index 57df4c126e4..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-01-net-dsa-qca8k-drop-MTU-tracking-from-qca8k_priv.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 69fd055957a02309ffdc23d887a01988b6e5bab1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:12 +0200 -Subject: [PATCH 1/6] net: dsa: qca8k: drop MTU tracking from qca8k_priv - -DSA set the CPU port based on the largest MTU of all the slave ports. -Based on this we can drop the MTU array from qca8k_priv and set the -port_change_mtu logic on DSA changing MTU of the CPU port as the switch -have a global MTU settingfor each port. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 26 +++++++++----------------- - drivers/net/dsa/qca8k.h | 1 - - 2 files changed, 9 insertions(+), 18 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1803,16 +1803,6 @@ qca8k_setup(struct dsa_switch *ds) - QCA8K_PORT_HOL_CTRL1_WRED_EN, - mask); - } -- -- /* Set initial MTU for every port. -- * We have only have a general MTU setting. So track -- * every port and set the max across all port. -- * Set per port MTU to 1500 as the MTU change function -- * will add the overhead and if its set to 1518 then it -- * will apply the overhead again and we will end up with -- * MTU of 1536 instead of 1518 -- */ -- priv->port_mtu[i] = ETH_DATA_LEN; - } - - /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -@@ -2525,13 +2515,16 @@ static int - qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) - { - struct qca8k_priv *priv = ds->priv; -- int ret, i, mtu = 0; -- -- priv->port_mtu[port] = new_mtu; -+ int ret; - -- for (i = 0; i < QCA8K_NUM_PORTS; i++) -- if (priv->port_mtu[i] > mtu) -- mtu = priv->port_mtu[i]; -+ /* We have only have a general MTU setting. -+ * DSA always set the CPU port's MTU to the largest MTU of the slave -+ * ports. -+ * Setting MTU just for the CPU port is sufficient to correctly set a -+ * value for every port. -+ */ -+ if (!dsa_is_cpu_port(ds, port)) -+ return 0; - - /* To change the MAX_FRAME_SIZE the cpu ports must be off or - * the switch panics. -@@ -2545,7 +2538,7 @@ qca8k_port_change_mtu(struct dsa_switch - qca8k_port_set_status(priv, 6, 0); - - /* Include L2 header / FCS length */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, mtu + ETH_HLEN + ETH_FCS_LEN); -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); - - if (priv->port_sts[0].enabled) - qca8k_port_set_status(priv, 0, 1); ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -392,7 +392,6 @@ struct qca8k_priv { - struct device *dev; - struct dsa_switch_ops ops; - struct gpio_desc *reset_gpio; -- unsigned int port_mtu[QCA8K_NUM_PORTS]; - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ - struct qca8k_mgmt_eth_data mgmt_eth_data; - struct qca8k_mib_eth_data mib_eth_data; diff --git a/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch deleted file mode 100644 index 3cacd7e4fdb..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-02-net-dsa-qca8k-drop-port_sts-from-qca8k_priv.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 2b8fd87af7f156942971789abac8ee2bb60c03bc Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:13 +0200 -Subject: [PATCH 2/6] net: dsa: qca8k: drop port_sts from qca8k_priv - -Port_sts is a thing of the past for this driver. It was something -present on the initial implementation of this driver and parts of the -original struct were dropped over time. Using an array of int to store if -a port is enabled or not to handle PM operation seems overkill. Switch -and use a simple u8 to store the port status where each bit correspond -to a port. (bit is set port is enabled, bit is not set, port is disabled) -Also add some comments to better describe why we need to track port -status. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 15 +++++++++------ - drivers/net/dsa/qca8k.h | 9 ++++----- - 2 files changed, 13 insertions(+), 11 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -2494,7 +2494,7 @@ qca8k_port_enable(struct dsa_switch *ds, - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; - - qca8k_port_set_status(priv, port, 1); -- priv->port_sts[port].enabled = 1; -+ priv->port_enabled_map |= BIT(port); - - if (dsa_is_user_port(ds, port)) - phy_support_asym_pause(phy); -@@ -2508,7 +2508,7 @@ qca8k_port_disable(struct dsa_switch *ds - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; - - qca8k_port_set_status(priv, port, 0); -- priv->port_sts[port].enabled = 0; -+ priv->port_enabled_map &= ~BIT(port); - } - - static int -@@ -2531,19 +2531,19 @@ qca8k_port_change_mtu(struct dsa_switch - * Turn off both cpu ports before applying the new value to prevent - * this. - */ -- if (priv->port_sts[0].enabled) -+ if (priv->port_enabled_map & BIT(0)) - qca8k_port_set_status(priv, 0, 0); - -- if (priv->port_sts[6].enabled) -+ if (priv->port_enabled_map & BIT(6)) - qca8k_port_set_status(priv, 6, 0); - - /* Include L2 header / FCS length */ - ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); - -- if (priv->port_sts[0].enabled) -+ if (priv->port_enabled_map & BIT(0)) - qca8k_port_set_status(priv, 0, 1); - -- if (priv->port_sts[6].enabled) -+ if (priv->port_enabled_map & BIT(6)) - qca8k_port_set_status(priv, 6, 1); - - return ret; -@@ -3199,13 +3199,16 @@ static void qca8k_sw_shutdown(struct mdi - static void - qca8k_set_pm(struct qca8k_priv *priv, int enable) - { -- int i; -+ int port; - -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (!priv->port_sts[i].enabled) -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Do not enable on resume if the port was -+ * disabled before. -+ */ -+ if (!(priv->port_enabled_map & BIT(port))) - continue; - -- qca8k_port_set_status(priv, i, enable); -+ qca8k_port_set_status(priv, port, enable); - } - } - ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -324,10 +324,6 @@ enum qca8k_mid_cmd { - QCA8K_MIB_CAST = 3, - }; - --struct ar8xxx_port_status { -- int enabled; --}; -- - struct qca8k_match_data { - u8 id; - bool reduced_package; -@@ -382,11 +378,14 @@ struct qca8k_priv { - u8 mirror_rx; - u8 mirror_tx; - u8 lag_hash_mode; -+ /* Each bit correspond to a port. This switch can support a max of 7 port. -+ * Bit 1: port enabled. Bit 0: port disabled. -+ */ -+ u8 port_enabled_map; - bool legacy_phy_port_mapping; - struct qca8k_ports_config ports_config; - struct regmap *regmap; - struct mii_bus *bus; -- struct ar8xxx_port_status port_sts[QCA8K_NUM_PORTS]; - struct dsa_switch *ds; - struct mutex reg_mutex; - struct device *dev; diff --git a/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch b/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch deleted file mode 100644 index 12c3221077c..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-03-net-dsa-qca8k-rework-and-simplify-mdiobus-logic.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 8255212e4130bd2dc1463286a3dddb74797bbdc1 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:14 +0200 -Subject: [PATCH 3/6] net: dsa: qca8k: rework and simplify mdiobus logic - -In an attempt to reduce qca8k_priv space, rework and simplify mdiobus -logic. -We now declare a mdiobus instead of relying on DSA phy_read/write even -if a mdio node is not present. This is all to make the qca8k ops static -and not switch specific. With a legacy implementation where port doesn't -have a phy map declared in the dts with a mdio node, we declare a -'qca8k-legacy' mdiobus. The conversion logic is used as legacy read and -write ops are used instead of the internal one. -Also drop the legacy_phy_port_mapping as we now declare mdiobus with ops -that already address the workaround. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 95 +++++++++++++---------------------------- - drivers/net/dsa/qca8k.h | 1 - - 2 files changed, 29 insertions(+), 67 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1291,83 +1291,63 @@ qca8k_internal_mdio_read(struct mii_bus - } - - static int --qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) -+qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) - { -- struct qca8k_priv *priv = ds->priv; -- int ret; -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; - -- /* Check if the legacy mapping should be used and the -- * port is not correctly mapped to the right PHY in the -- * devicetree -- */ -- if (priv->legacy_phy_port_mapping) -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, false, port, regnum, 0); -- if (!ret) -- return ret; -- -- return qca8k_mdio_write(priv, port, regnum, data); -+ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); - } - - static int --qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) -+qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) - { -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- /* Check if the legacy mapping should be used and the -- * port is not correctly mapped to the right PHY in the -- * devicetree -- */ -- if (priv->legacy_phy_port_mapping) -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, true, port, regnum, 0); -- if (ret >= 0) -- return ret; -- -- ret = qca8k_mdio_read(priv, port, regnum); -- -- if (ret < 0) -- return 0xffff; -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; - -- return ret; -+ return qca8k_internal_mdio_read(slave_bus, port, regnum); - } - - static int --qca8k_mdio_register(struct qca8k_priv *priv, struct device_node *mdio) -+qca8k_mdio_register(struct qca8k_priv *priv) - { - struct dsa_switch *ds = priv->ds; -+ struct device_node *mdio; - struct mii_bus *bus; - - bus = devm_mdiobus_alloc(ds->dev); -- - if (!bus) - return -ENOMEM; - - bus->priv = (void *)priv; -- bus->name = "qca8k slave mii"; -- bus->read = qca8k_internal_mdio_read; -- bus->write = qca8k_internal_mdio_write; -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", -- ds->index); -- - bus->parent = ds->dev; - bus->phy_mask = ~ds->phys_mii_mask; -- - ds->slave_mii_bus = bus; - -- return devm_of_mdiobus_register(priv->dev, bus, mdio); -+ /* Check if the devicetree declare the port:phy mapping */ -+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -+ if (of_device_is_available(mdio)) { -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index); -+ bus->name = "qca8k slave mii"; -+ bus->read = qca8k_internal_mdio_read; -+ bus->write = qca8k_internal_mdio_write; -+ return devm_of_mdiobus_register(priv->dev, bus, mdio); -+ } -+ -+ /* If a mapping can't be found the legacy mapping is used, -+ * using the qca8k_port_to_phy function -+ */ -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -+ ds->dst->index, ds->index); -+ bus->name = "qca8k-legacy slave mii"; -+ bus->read = qca8k_legacy_mdio_read; -+ bus->write = qca8k_legacy_mdio_write; -+ return devm_mdiobus_register(priv->dev, bus); - } - - static int - qca8k_setup_mdio_bus(struct qca8k_priv *priv) - { - u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -- struct device_node *ports, *port, *mdio; -+ struct device_node *ports, *port; - phy_interface_t mode; - int err; - -@@ -1429,24 +1409,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv * - QCA8K_MDIO_MASTER_EN); - } - -- /* Check if the devicetree declare the port:phy mapping */ -- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -- if (of_device_is_available(mdio)) { -- err = qca8k_mdio_register(priv, mdio); -- if (err) -- of_node_put(mdio); -- -- return err; -- } -- -- /* If a mapping can't be found the legacy mapping is used, -- * using the qca8k_port_to_phy function -- */ -- priv->legacy_phy_port_mapping = true; -- priv->ops.phy_read = qca8k_phy_read; -- priv->ops.phy_write = qca8k_phy_write; -- -- return 0; -+ return qca8k_mdio_register(priv); - } - - static int ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -382,7 +382,6 @@ struct qca8k_priv { - * Bit 1: port enabled. Bit 0: port disabled. - */ - u8 port_enabled_map; -- bool legacy_phy_port_mapping; - struct qca8k_ports_config ports_config; - struct regmap *regmap; - struct mii_bus *bus; diff --git a/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch b/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch deleted file mode 100644 index 8641000abbc..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-04-net-dsa-qca8k-drop-dsa_switch_ops-from-qca8k_priv.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 2349b83a2486c55b9dd225326f0172a84a43c5e4 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:15 +0200 -Subject: [PATCH 4/6] net: dsa: qca8k: drop dsa_switch_ops from qca8k_priv - -Now that dsa_switch_ops is not switch specific anymore, we can drop it -from qca8k_priv and use the static ops directly for the dsa_switch -pointer. - -Signed-off-by: Ansuel Smith -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 3 +-- - drivers/net/dsa/qca8k.h | 1 - - 2 files changed, 1 insertion(+), 3 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -3121,8 +3121,7 @@ qca8k_sw_probe(struct mdio_device *mdiod - priv->ds->dev = &mdiodev->dev; - priv->ds->num_ports = QCA8K_NUM_PORTS; - priv->ds->priv = priv; -- priv->ops = qca8k_switch_ops; -- priv->ds->ops = &priv->ops; -+ priv->ds->ops = &qca8k_switch_ops; - mutex_init(&priv->reg_mutex); - dev_set_drvdata(&mdiodev->dev, priv); - ---- a/drivers/net/dsa/qca8k.h -+++ b/drivers/net/dsa/qca8k.h -@@ -388,7 +388,6 @@ struct qca8k_priv { - struct dsa_switch *ds; - struct mutex reg_mutex; - struct device *dev; -- struct dsa_switch_ops ops; - struct gpio_desc *reset_gpio; - struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ - struct qca8k_mgmt_eth_data mgmt_eth_data; diff --git a/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch b/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch deleted file mode 100644 index b14b22091bc..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-05-net-dsa-qca8k-correctly-handle-mdio-read-error.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 6cfc03b602200c5cbbd8d906fd905547814e83df Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:16 +0200 -Subject: [PATCH 5/6] net: dsa: qca8k: correctly handle mdio read error - -Restore original way to handle mdio read error by returning 0xffff. -This was wrongly changed when the internal_mdio_read was introduced, -now that both legacy and internal use the same function, make sure that -they behave the same way. - -Fixes: ce062a0adbfe ("net: dsa: qca8k: fix kernel panic with legacy mdio mapping") -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1287,7 +1287,12 @@ qca8k_internal_mdio_read(struct mii_bus - if (ret >= 0) - return ret; - -- return qca8k_mdio_read(priv, phy, regnum); -+ ret = qca8k_mdio_read(priv, phy, regnum); -+ -+ if (ret < 0) -+ return 0xffff; -+ -+ return ret; - } - - static int diff --git a/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch b/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch deleted file mode 100644 index 094686f11be..00000000000 --- a/target/linux/generic/backport-6.1/769-v5.19-06-net-dsa-qca8k-unify-bus-id-naming-with-legacy-and-OF.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 8d1af50842bf2774f4edc57054206e909117469b Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 16 Apr 2022 01:30:17 +0200 -Subject: [PATCH 6/6] net: dsa: qca8k: unify bus id naming with legacy and OF - mdio bus - -Add support for multiple switch with OF mdio bus declaration. -Unify the bus id naming and use the same logic for both legacy and OF -mdio bus. - -Signed-off-by: Ansuel Smith -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca8k.c | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - ---- a/drivers/net/dsa/qca8k.c -+++ b/drivers/net/dsa/qca8k.c -@@ -1323,6 +1323,8 @@ qca8k_mdio_register(struct qca8k_priv *p - return -ENOMEM; - - bus->priv = (void *)priv; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -+ ds->dst->index, ds->index); - bus->parent = ds->dev; - bus->phy_mask = ~ds->phys_mii_mask; - ds->slave_mii_bus = bus; -@@ -1330,7 +1332,6 @@ qca8k_mdio_register(struct qca8k_priv *p - /* Check if the devicetree declare the port:phy mapping */ - mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); - if (of_device_is_available(mdio)) { -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d", ds->index); - bus->name = "qca8k slave mii"; - bus->read = qca8k_internal_mdio_read; - bus->write = qca8k_internal_mdio_write; -@@ -1340,8 +1341,6 @@ qca8k_mdio_register(struct qca8k_priv *p - /* If a mapping can't be found the legacy mapping is used, - * using the qca8k_port_to_phy function - */ -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -- ds->dst->index, ds->index); - bus->name = "qca8k-legacy slave mii"; - bus->read = qca8k_legacy_mdio_read; - bus->write = qca8k_legacy_mdio_write; diff --git a/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch b/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch deleted file mode 100644 index 1534113f1df..00000000000 --- a/target/linux/generic/backport-6.1/770-v6.0-net-dsa-qca8k-move-driver-to-qca-dir.patch +++ /dev/null @@ -1,7389 +0,0 @@ -From 4bbaf764e1e1786eb937fdb62172f656f512e116 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 13 Jul 2022 22:53:50 +0200 -Subject: [PATCH 1/1] net: dsa: qca8k: move driver to qca dir - -Move qca8k driver to qca dir in preparation for code split and -introduction of ipq4019 switch based on qca8k. - -Signed-off-by: Christian Marangi -Reviewed-by: Florian Fainelli -Signed-off-by: David S. Miller ---- - drivers/net/dsa/Kconfig | 8 -------- - drivers/net/dsa/Makefile | 1 - - drivers/net/dsa/qca/Kconfig | 8 ++++++++ - drivers/net/dsa/qca/Makefile | 1 + - drivers/net/dsa/{ => qca}/qca8k.c | 0 - drivers/net/dsa/{ => qca}/qca8k.h | 0 - 6 files changed, 9 insertions(+), 9 deletions(-) - rename drivers/net/dsa/{ => qca}/qca8k.c (100%) - rename drivers/net/dsa/{ => qca}/qca8k.h (100%) - ---- a/drivers/net/dsa/Kconfig -+++ b/drivers/net/dsa/Kconfig -@@ -60,14 +60,6 @@ source "drivers/net/dsa/sja1105/Kconfig" - - source "drivers/net/dsa/xrs700x/Kconfig" - --config NET_DSA_QCA8K -- tristate "Qualcomm Atheros QCA8K Ethernet switch family support" -- select NET_DSA_TAG_QCA -- select REGMAP -- help -- This enables support for the Qualcomm Atheros QCA8K Ethernet -- switch chips. -- - config NET_DSA_REALTEK_SMI - tristate "Realtek SMI Ethernet switch family support" - select NET_DSA_TAG_RTL4_A ---- a/drivers/net/dsa/Makefile -+++ b/drivers/net/dsa/Makefile -@@ -8,7 +8,6 @@ endif - obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o - obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o - obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o --obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o - obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o - realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o - obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o ---- a/drivers/net/dsa/qca/Kconfig -+++ b/drivers/net/dsa/qca/Kconfig -@@ -7,3 +7,11 @@ config NET_DSA_AR9331 - help - This enables support for the Qualcomm Atheros AR9331 built-in Ethernet - switch. -+ -+config NET_DSA_QCA8K -+ tristate "Qualcomm Atheros QCA8K Ethernet switch family support" -+ select NET_DSA_TAG_QCA -+ select REGMAP -+ help -+ This enables support for the Qualcomm Atheros QCA8K Ethernet -+ switch chips. ---- a/drivers/net/dsa/qca/Makefile -+++ b/drivers/net/dsa/qca/Makefile -@@ -1,2 +1,3 @@ - # SPDX-License-Identifier: GPL-2.0-only - obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o -+obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o ---- /dev/null -+++ b/drivers/net/dsa/qca/qca8k.c -@@ -0,0 +1,3243 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2016 John Crispin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "qca8k.h" -+ -+#define MIB_DESC(_s, _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+static const struct qca8k_mib_desc ar8327_mib[] = { -+ MIB_DESC(1, 0x00, "RxBroad"), -+ MIB_DESC(1, 0x04, "RxPause"), -+ MIB_DESC(1, 0x08, "RxMulti"), -+ MIB_DESC(1, 0x0c, "RxFcsErr"), -+ MIB_DESC(1, 0x10, "RxAlignErr"), -+ MIB_DESC(1, 0x14, "RxRunt"), -+ MIB_DESC(1, 0x18, "RxFragment"), -+ MIB_DESC(1, 0x1c, "Rx64Byte"), -+ MIB_DESC(1, 0x20, "Rx128Byte"), -+ MIB_DESC(1, 0x24, "Rx256Byte"), -+ MIB_DESC(1, 0x28, "Rx512Byte"), -+ MIB_DESC(1, 0x2c, "Rx1024Byte"), -+ MIB_DESC(1, 0x30, "Rx1518Byte"), -+ MIB_DESC(1, 0x34, "RxMaxByte"), -+ MIB_DESC(1, 0x38, "RxTooLong"), -+ MIB_DESC(2, 0x3c, "RxGoodByte"), -+ MIB_DESC(2, 0x44, "RxBadByte"), -+ MIB_DESC(1, 0x4c, "RxOverFlow"), -+ MIB_DESC(1, 0x50, "Filtered"), -+ MIB_DESC(1, 0x54, "TxBroad"), -+ MIB_DESC(1, 0x58, "TxPause"), -+ MIB_DESC(1, 0x5c, "TxMulti"), -+ MIB_DESC(1, 0x60, "TxUnderRun"), -+ MIB_DESC(1, 0x64, "Tx64Byte"), -+ MIB_DESC(1, 0x68, "Tx128Byte"), -+ MIB_DESC(1, 0x6c, "Tx256Byte"), -+ MIB_DESC(1, 0x70, "Tx512Byte"), -+ MIB_DESC(1, 0x74, "Tx1024Byte"), -+ MIB_DESC(1, 0x78, "Tx1518Byte"), -+ MIB_DESC(1, 0x7c, "TxMaxByte"), -+ MIB_DESC(1, 0x80, "TxOverSize"), -+ MIB_DESC(2, 0x84, "TxByte"), -+ MIB_DESC(1, 0x8c, "TxCollision"), -+ MIB_DESC(1, 0x90, "TxAbortCol"), -+ MIB_DESC(1, 0x94, "TxMultiCol"), -+ MIB_DESC(1, 0x98, "TxSingleCol"), -+ MIB_DESC(1, 0x9c, "TxExcDefer"), -+ MIB_DESC(1, 0xa0, "TxDefer"), -+ MIB_DESC(1, 0xa4, "TxLateCol"), -+ MIB_DESC(1, 0xa8, "RXUnicast"), -+ MIB_DESC(1, 0xac, "TXUnicast"), -+}; -+ -+static void -+qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) -+{ -+ regaddr >>= 1; -+ *r1 = regaddr & 0x1e; -+ -+ regaddr >>= 5; -+ *r2 = regaddr & 0x7; -+ -+ regaddr >>= 3; -+ *page = regaddr & 0x3ff; -+} -+ -+static int -+qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) -+{ -+ u16 *cached_lo = &priv->mdio_cache.lo; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (lo == *cached_lo) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, lo); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit lo register\n"); -+ -+ *cached_lo = lo; -+ return 0; -+} -+ -+static int -+qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) -+{ -+ u16 *cached_hi = &priv->mdio_cache.hi; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (hi == *cached_hi) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, hi); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit hi register\n"); -+ -+ *cached_hi = hi; -+ return 0; -+} -+ -+static int -+qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) -+{ -+ int ret; -+ -+ ret = bus->read(bus, phy_id, regnum); -+ if (ret >= 0) { -+ *val = ret; -+ ret = bus->read(bus, phy_id, regnum + 1); -+ *val |= ret << 16; -+ } -+ -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to read qca8k 32bit register\n"); -+ *val = 0; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void -+qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) -+{ -+ u16 lo, hi; -+ int ret; -+ -+ lo = val & 0xffff; -+ hi = (u16)(val >> 16); -+ -+ ret = qca8k_set_lo(priv, phy_id, regnum, lo); -+ if (ret >= 0) -+ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); -+} -+ -+static int -+qca8k_set_page(struct qca8k_priv *priv, u16 page) -+{ -+ u16 *cached_page = &priv->mdio_cache.page; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (page == *cached_page) -+ return 0; -+ -+ ret = bus->write(bus, 0x18, 0, page); -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to set qca8k page\n"); -+ return ret; -+ } -+ -+ *cached_page = page; -+ usleep_range(1000, 2000); -+ return 0; -+} -+ -+static int -+qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) -+{ -+ return regmap_read(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return regmap_write(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ return regmap_update_bits(priv->regmap, reg, mask, write_val); -+} -+ -+static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ u8 len, cmd; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -+ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -+ -+ /* Make sure the seq match the requested packet */ -+ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -+ mgmt_eth_data->ack = true; -+ -+ if (cmd == MDIO_READ) { -+ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -+ -+ /* Get the rest of the 12 byte of data. -+ * The read/write function will extract the requested data. -+ */ -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(mgmt_eth_data->data + 1, skb->data, -+ QCA_HDR_MGMT_DATA2_LEN); -+ } -+ -+ complete(&mgmt_eth_data->rw_done); -+} -+ -+static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -+ int priority, unsigned int len) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ unsigned int real_len; -+ struct sk_buff *skb; -+ u32 *data2; -+ u16 hdr; -+ -+ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); -+ if (!skb) -+ return NULL; -+ -+ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -+ * Actually for some reason the steps are: -+ * 0: nothing -+ * 1-4: first 4 byte -+ * 5-6: first 12 byte -+ * 7-15: all 16 byte -+ */ -+ if (len == 16) -+ real_len = 15; -+ else -+ real_len = len; -+ -+ skb_reset_mac_header(skb); -+ skb_set_network_header(skb, skb->len); -+ -+ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); -+ -+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); -+ hdr |= QCA_HDR_XMIT_FROM_CPU; -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); -+ -+ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -+ QCA_HDR_MGMT_CHECK_CODE_VAL); -+ -+ if (cmd == MDIO_WRITE) -+ mgmt_ethhdr->mdio_data = *val; -+ -+ mgmt_ethhdr->hdr = htons(hdr); -+ -+ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -+ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ return skb; -+} -+ -+static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -+ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); -+} -+ -+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ *val = mgmt_eth_data->data[0]; -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int -+qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ u32 val = 0; -+ int ret; -+ -+ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); -+ if (ret) -+ return ret; -+ -+ val &= ~mask; -+ val |= write_val; -+ -+ return qca8k_write_eth(priv, reg, &val, sizeof(val)); -+} -+ -+static int -+qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ -+ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ u32 tmp; -+ -+ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ tmp = val[i]; -+ -+ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ if (ret < 0) -+ goto exit; -+ -+ val &= ~mask; -+ val |= write_val; -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static const struct regmap_range qca8k_readable_ranges[] = { -+ regmap_reg_range(0x0000, 0x00e4), /* Global control */ -+ regmap_reg_range(0x0100, 0x0168), /* EEE control */ -+ regmap_reg_range(0x0200, 0x0270), /* Parser control */ -+ regmap_reg_range(0x0400, 0x0454), /* ACL */ -+ regmap_reg_range(0x0600, 0x0718), /* Lookup */ -+ regmap_reg_range(0x0800, 0x0b70), /* QM */ -+ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -+ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -+ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -+ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -+ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -+ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -+ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -+ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -+ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -+ -+}; -+ -+static const struct regmap_access_table qca8k_readable_table = { -+ .yes_ranges = qca8k_readable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), -+}; -+ -+static struct regmap_config qca8k_regmap_config = { -+ .reg_bits = 16, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = 0x16ac, /* end MIB - Port6 range */ -+ .reg_read = qca8k_regmap_read, -+ .reg_write = qca8k_regmap_write, -+ .reg_update_bits = qca8k_regmap_update_bits, -+ .rd_table = &qca8k_readable_table, -+ .disable_locking = true, /* Locking is handled by qca8k read/write */ -+ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ -+}; -+ -+static int -+qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) -+{ -+ u32 val; -+ -+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); -+} -+ -+static int -+qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) -+{ -+ u32 reg[3]; -+ int ret; -+ -+ /* load the ARL table into an array */ -+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+ if (ret) -+ return ret; -+ -+ /* vid - 83:72 */ -+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -+ /* aging - 67:64 */ -+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -+ /* portmask - 54:48 */ -+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -+ /* mac - 47:0 */ -+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -+ -+ return 0; -+} -+ -+static void -+qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -+ u8 aging) -+{ -+ u32 reg[3] = { 0 }; -+ -+ /* vid - 83:72 */ -+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -+ /* aging - 67:64 */ -+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -+ /* portmask - 54:48 */ -+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -+ /* mac - 47:0 */ -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -+ -+ /* load the array into the ARL table */ -+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+} -+ -+static int -+qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and FDB index */ -+ reg = QCA8K_ATU_FUNC_BUSY; -+ reg |= cmd; -+ if (port >= 0) { -+ reg |= QCA8K_ATU_FUNC_PORT_EN; -+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -+ } -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_FDB_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_ATU_FUNC_FULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) -+{ -+ int ret; -+ -+ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -+ if (ret < 0) -+ return ret; -+ -+ return qca8k_fdb_read(priv, fdb); -+} -+ -+static int -+qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -+ u16 vid, u8 aging) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static void -+qca8k_fdb_flush(struct qca8k_priv *priv) -+{ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_fdb_read(priv, &fdb); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule exist. Delete first */ -+ if (!fdb.aging) { -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ } -+ -+ /* Add port to fdb portmask */ -+ fdb.port_mask |= port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule doesn't exist. Why delete? */ -+ if (!fdb.aging) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ -+ /* Only port in the rule is this port. Don't re insert */ -+ if (fdb.port_mask == port_mask) -+ goto exit; -+ -+ /* Remove port from port mask */ -+ fdb.port_mask &= ~port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and VLAN index */ -+ reg = QCA8K_VTU_FUNC1_BUSY; -+ reg |= cmd; -+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_VLAN_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_VTU_FUNC1_FULL) -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) -+{ -+ u32 reg; -+ int ret; -+ -+ /* -+ We do the right thing with VLAN 0 and treat it as untagged while -+ preserving the tag on egress. -+ */ -+ if (vid == 0) -+ return 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ if (untagged) -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -+ else -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -+ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) -+{ -+ u32 reg, mask; -+ int ret, i; -+ bool del; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -+ -+ /* Check if we're the last member to be removed */ -+ del = true; -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -+ -+ if ((reg & mask) != mask) { -+ del = false; -+ break; -+ } -+ } -+ -+ if (del) { -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -+ } else { -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ } -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_mib_init(struct qca8k_priv *priv) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -+ QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static void -+qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) -+{ -+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ /* Port 0 and 6 have no internal PHY */ -+ if (port > 0 && port < 6) -+ mask |= QCA8K_PORT_STATUS_LINK_AUTO; -+ -+ if (enable) -+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+ else -+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+} -+ -+static int -+qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, -+ struct sk_buff *read_skb, u32 *val) -+{ -+ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); -+ bool ack; -+ int ret; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the copy pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ *val = mgmt_eth_data->data[0]; -+ -+ return 0; -+} -+ -+static int -+qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, -+ int regnum, u16 data) -+{ -+ struct sk_buff *write_skb, *clear_skb, *read_skb; -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ u32 write_val, clear_val = 0, val; -+ struct net_device *mgmt_master; -+ int ret, ret1; -+ bool ack; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ if (read) { -+ write_val |= QCA8K_MDIO_MASTER_READ; -+ } else { -+ write_val |= QCA8K_MDIO_MASTER_WRITE; -+ write_val |= QCA8K_MDIO_MASTER_DATA(data); -+ } -+ -+ /* Prealloc all the needed skb before the lock */ -+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); -+ if (!write_skb) -+ return -ENOMEM; -+ -+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -+ if (!clear_skb) { -+ ret = -ENOMEM; -+ goto err_clear_skb; -+ } -+ -+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -+ if (!read_skb) { -+ ret = -ENOMEM; -+ goto err_read_skb; -+ } -+ -+ /* Actually start the request: -+ * 1. Send mdio master packet -+ * 2. Busy Wait for mdio master command -+ * 3. Get the data if we are reading -+ * 4. Reset the mdio master (even with error) -+ */ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check if mgmt_master is operational */ -+ mgmt_master = priv->mgmt_master; -+ if (!mgmt_master) { -+ mutex_unlock(&mgmt_eth_data->mutex); -+ ret = -EINVAL; -+ goto err_mgmt_master; -+ } -+ -+ read_skb->dev = mgmt_master; -+ clear_skb->dev = mgmt_master; -+ write_skb->dev = mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the write pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(write_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, -+ !(val & QCA8K_MDIO_MASTER_BUSY), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ mgmt_eth_data, read_skb, &val); -+ -+ if (ret < 0 && ret1 < 0) { -+ ret = ret1; -+ goto exit; -+ } -+ -+ if (read) { -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the read pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(read_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; -+ } else { -+ kfree_skb(read_skb); -+ } -+exit: -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the clear pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(clear_skb); -+ -+ wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ return ret; -+ -+ /* Error handling before lock */ -+err_mgmt_master: -+ kfree_skb(read_skb); -+err_read_skb: -+ kfree_skb(clear_skb); -+err_clear_skb: -+ kfree_skb(write_skb); -+ -+ return ret; -+} -+ -+static u32 -+qca8k_port_to_phy(int port) -+{ -+ /* From Andrew Lunn: -+ * Port 0 has no internal phy. -+ * Port 1 has an internal PHY at MDIO address 0. -+ * Port 2 has an internal PHY at MDIO address 1. -+ * ... -+ * Port 5 has an internal PHY at MDIO address 4. -+ * Port 6 has no internal PHY. -+ */ -+ -+ return port - 1; -+} -+ -+static int -+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) -+{ -+ u16 r1, r2, page; -+ u32 val; -+ int ret, ret1; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ bus, 0x10 | r2, r1, &val); -+ -+ /* Check if qca8k_read has failed for a different reason -+ * before returnting -ETIMEDOUT -+ */ -+ if (ret < 0 && ret1 < 0) -+ return ret1; -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -+ QCA8K_MDIO_MASTER_DATA(data); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ if (ret >= 0) -+ ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -+ -+ return ret; -+} -+ -+static int -+qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); -+ if (!ret) -+ return 0; -+ -+ return qca8k_mdio_write(priv, phy, regnum, data); -+} -+ -+static int -+qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); -+ if (ret >= 0) -+ return ret; -+ -+ ret = qca8k_mdio_read(priv, phy, regnum); -+ -+ if (ret < 0) -+ return 0xffff; -+ -+ return ret; -+} -+ -+static int -+qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) -+{ -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); -+} -+ -+static int -+qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) -+{ -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ return qca8k_internal_mdio_read(slave_bus, port, regnum); -+} -+ -+static int -+qca8k_mdio_register(struct qca8k_priv *priv) -+{ -+ struct dsa_switch *ds = priv->ds; -+ struct device_node *mdio; -+ struct mii_bus *bus; -+ -+ bus = devm_mdiobus_alloc(ds->dev); -+ if (!bus) -+ return -ENOMEM; -+ -+ bus->priv = (void *)priv; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -+ ds->dst->index, ds->index); -+ bus->parent = ds->dev; -+ bus->phy_mask = ~ds->phys_mii_mask; -+ ds->slave_mii_bus = bus; -+ -+ /* Check if the devicetree declare the port:phy mapping */ -+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -+ if (of_device_is_available(mdio)) { -+ bus->name = "qca8k slave mii"; -+ bus->read = qca8k_internal_mdio_read; -+ bus->write = qca8k_internal_mdio_write; -+ return devm_of_mdiobus_register(priv->dev, bus, mdio); -+ } -+ -+ /* If a mapping can't be found the legacy mapping is used, -+ * using the qca8k_port_to_phy function -+ */ -+ bus->name = "qca8k-legacy slave mii"; -+ bus->read = qca8k_legacy_mdio_read; -+ bus->write = qca8k_legacy_mdio_write; -+ return devm_mdiobus_register(priv->dev, bus); -+} -+ -+static int -+qca8k_setup_mdio_bus(struct qca8k_priv *priv) -+{ -+ u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -+ struct device_node *ports, *port; -+ phy_interface_t mode; -+ int err; -+ -+ ports = of_get_child_by_name(priv->dev->of_node, "ports"); -+ if (!ports) -+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -+ -+ if (!ports) -+ return -EINVAL; -+ -+ for_each_available_child_of_node(ports, port) { -+ err = of_property_read_u32(port, "reg", ®); -+ if (err) { -+ of_node_put(port); -+ of_node_put(ports); -+ return err; -+ } -+ -+ if (!dsa_is_user_port(priv->ds, reg)) -+ continue; -+ -+ of_get_phy_mode(port, &mode); -+ -+ if (of_property_read_bool(port, "phy-handle") && -+ mode != PHY_INTERFACE_MODE_INTERNAL) -+ external_mdio_mask |= BIT(reg); -+ else -+ internal_mdio_mask |= BIT(reg); -+ } -+ -+ of_node_put(ports); -+ if (!external_mdio_mask && !internal_mdio_mask) { -+ dev_err(priv->dev, "no PHYs are defined.\n"); -+ return -EINVAL; -+ } -+ -+ /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -+ * the MDIO_MASTER register also _disconnects_ the external MDC -+ * passthrough to the internal PHYs. It's not possible to use both -+ * configurations at the same time! -+ * -+ * Because this came up during the review process: -+ * If the external mdio-bus driver is capable magically disabling -+ * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -+ * accessors for the time being, it would be possible to pull this -+ * off. -+ */ -+ if (!!external_mdio_mask && !!internal_mdio_mask) { -+ dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -+ return -EINVAL; -+ } -+ -+ if (external_mdio_mask) { -+ /* Make sure to disable the internal mdio bus in cases -+ * a dt-overlay and driver reload changed the configuration -+ */ -+ -+ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_EN); -+ } -+ -+ return qca8k_mdio_register(priv); -+} -+ -+static int -+qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) -+{ -+ u32 mask = 0; -+ int ret = 0; -+ -+ /* SoC specific settings for ipq8064. -+ * If more device require this consider adding -+ * a dedicated binding. -+ */ -+ if (of_machine_is_compatible("qcom,ipq8064")) -+ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -+ -+ /* SoC specific settings for ipq8065 */ -+ if (of_machine_is_compatible("qcom,ipq8065")) -+ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -+ -+ if (mask) { -+ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -+ QCA8K_MAC_PWR_RGMII0_1_8V | -+ QCA8K_MAC_PWR_RGMII1_1_8V, -+ mask); -+ } -+ -+ return ret; -+} -+ -+static int qca8k_find_cpu_port(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Find the connected cpu port. Valid port are 0 or 6 */ -+ if (dsa_is_cpu_port(ds, 0)) -+ return 0; -+ -+ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -+ -+ if (dsa_is_cpu_port(ds, 6)) -+ return 6; -+ -+ return -EINVAL; -+} -+ -+static int -+qca8k_setup_of_pws_reg(struct qca8k_priv *priv) -+{ -+ struct device_node *node = priv->dev->of_node; -+ const struct qca8k_match_data *data; -+ u32 val = 0; -+ int ret; -+ -+ /* QCA8327 require to set to the correct mode. -+ * His bigger brother QCA8328 have the 172 pin layout. -+ * Should be applied by default but we set this just to make sure. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ data = of_device_get_match_data(priv->dev); -+ -+ /* Set the correct package of 148 pin for QCA8327 */ -+ if (data->reduced_package) -+ val |= QCA8327_PWS_PACKAGE148_EN; -+ -+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -+ val); -+ if (ret) -+ return ret; -+ } -+ -+ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -+ val |= QCA8K_PWS_POWER_ON_SEL; -+ -+ if (of_property_read_bool(node, "qca,led-open-drain")) { -+ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -+ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -+ return -EINVAL; -+ } -+ -+ val |= QCA8K_PWS_LED_OPEN_EN_CSR; -+ } -+ -+ return qca8k_rmw(priv, QCA8K_REG_PWS, -+ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -+ val); -+} -+ -+static int -+qca8k_parse_port_config(struct qca8k_priv *priv) -+{ -+ int port, cpu_port_index = -1, ret; -+ struct device_node *port_dn; -+ phy_interface_t mode; -+ struct dsa_port *dp; -+ u32 delay; -+ -+ /* We have 2 CPU port. Check them */ -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Skip every other port */ -+ if (port != 0 && port != 6) -+ continue; -+ -+ dp = dsa_to_port(priv->ds, port); -+ port_dn = dp->dn; -+ cpu_port_index++; -+ -+ if (!of_device_is_available(port_dn)) -+ continue; -+ -+ ret = of_get_phy_mode(port_dn, &mode); -+ if (ret) -+ continue; -+ -+ switch (mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_SGMII: -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID) -+ delay = 1; -+ -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { -+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -+ -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ delay = 2; -+ -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { -+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -+ -+ /* Skip sgmii parsing for rgmii* mode */ -+ if (mode == PHY_INTERFACE_MODE_RGMII || -+ mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ break; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -+ priv->ports_config.sgmii_tx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -+ priv->ports_config.sgmii_rx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -+ priv->ports_config.sgmii_enable_pll = true; -+ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -+ priv->ports_config.sgmii_enable_pll = false; -+ } -+ -+ if (priv->switch_revision < 2) -+ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -+ } -+ -+ break; -+ default: -+ continue; -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_setup(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, ret, i; -+ u32 mask; -+ -+ cpu_port = qca8k_find_cpu_port(ds); -+ if (cpu_port < 0) { -+ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -+ return cpu_port; -+ } -+ -+ /* Parse CPU port config to be later used in phy_link mac_config */ -+ ret = qca8k_parse_port_config(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_mdio_bus(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_of_pws_reg(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_mac_pwr_sel(priv); -+ if (ret) -+ return ret; -+ -+ /* Make sure MAC06 is disabled */ -+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, -+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed disabling MAC06 exchange"); -+ return ret; -+ } -+ -+ /* Enable CPU Port */ -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling CPU port"); -+ return ret; -+ } -+ -+ /* Enable MIB counters */ -+ ret = qca8k_mib_init(priv); -+ if (ret) -+ dev_warn(priv->dev, "mib init failed"); -+ -+ /* Initial setup of all ports */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* Disable forwarding by default on all ports */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, 0); -+ if (ret) -+ return ret; -+ -+ /* Enable QCA header mode on all cpu ports */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling QCA header mode"); -+ return ret; -+ } -+ } -+ -+ /* Disable MAC by default on all user ports */ -+ if (dsa_is_user_port(ds, i)) -+ qca8k_port_set_status(priv, i, 0); -+ } -+ -+ /* Forward all unknown frames to CPU port for Linux processing -+ * Notice that in multi-cpu config only one port should be set -+ * for igmp, unknown, multicast and broadcast packet -+ */ -+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); -+ if (ret) -+ return ret; -+ -+ /* Setup connection between CPU port & user ports -+ * Configure specific switch configuration for ports -+ */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* CPU port gets connected to all user ports of the switch */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -+ if (ret) -+ return ret; -+ } -+ -+ /* Individual user ports get connected to CPU port only */ -+ if (dsa_is_user_port(ds, i)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, -+ BIT(cpu_port)); -+ if (ret) -+ return ret; -+ -+ /* Enable ARP Auto-learning by default */ -+ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_LEARN); -+ if (ret) -+ return ret; -+ -+ /* For port based vlans to work we need to set the -+ * default egress vid -+ */ -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -+ QCA8K_EGREES_VLAN_PORT_MASK(i), -+ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; -+ } -+ -+ /* The port 5 of the qca8337 have some problem in flood condition. The -+ * original legacy driver had some specific buffer and priority settings -+ * for the different port suggested by the QCA switch team. Add this -+ * missing settings to improve switch stability under load condition. -+ * This problem is limited to qca8337 and other qca8k switch are not affected. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) { -+ switch (i) { -+ /* The 2 CPU port and port 5 requires some different -+ * priority than any other ports. -+ */ -+ case 0: -+ case 5: -+ case 6: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -+ break; -+ default: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -+ } -+ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -+ -+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN; -+ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN, -+ mask); -+ } -+ } -+ -+ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -+ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, -+ mask); -+ } -+ -+ /* Setup our port MTUs to match power on defaults */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); -+ if (ret) -+ dev_warn(priv->dev, "failed setting MTU settings"); -+ -+ /* Flush the FDB table */ -+ qca8k_fdb_flush(priv); -+ -+ /* We don't have interrupts for link changes, so we need to poll */ -+ ds->pcs_poll = true; -+ -+ /* Set min a max ageing value supported */ -+ ds->ageing_time_min = 7000; -+ ds->ageing_time_max = 458745000; -+ -+ /* Set max number of LAGs supported */ -+ ds->num_lag_ids = QCA8K_NUM_LAGS; -+ -+ return 0; -+} -+ -+static void -+qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -+ u32 reg) -+{ -+ u32 delay, val = 0; -+ int ret; -+ -+ /* Delay can be declared in 3 different way. -+ * Mode to rgmii and internal-delay standard binding defined -+ * rgmii-id or rgmii-tx/rx phy mode set. -+ * The parse logic set a delay different than 0 only when one -+ * of the 3 different way is used. In all other case delay is -+ * not enabled. With ID or TX/RXID delay is enabled and set -+ * to the default and recommended value. -+ */ -+ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ } -+ -+ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ } -+ -+ /* Set RGMII delay based on the selected values */ -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -+ val); -+ if (ret) -+ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -+ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); -+} -+ -+static void -+qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, -+ const struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int cpu_port_index, ret; -+ u32 reg, val; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ return; -+ -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT0; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY, nothing to do */ -+ return; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ return; -+ -+ reg = QCA8K_REG_PORT6_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT6; -+ break; -+ default: -+ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -+ return; -+ } -+ -+ if (port != 6 && phylink_autoneg_inband(mode)) { -+ dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -+ __func__); -+ return; -+ } -+ -+ switch (state->interface) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -+ -+ /* Configure rgmii delay */ -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ /* QCA8337 requires to set rgmii rx delay for all ports. -+ * This is enabled through PORT5_PAD_CTRL for all ports, -+ * rather than individual port registers. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) -+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ /* Enable SGMII on the port */ -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -+ -+ /* Enable/disable SerDes auto-negotiation as necessary */ -+ ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -+ if (ret) -+ return; -+ if (phylink_autoneg_inband(mode)) -+ val &= ~QCA8K_PWS_SERDES_AEN_DIS; -+ else -+ val |= QCA8K_PWS_SERDES_AEN_DIS; -+ qca8k_write(priv, QCA8K_REG_PWS, val); -+ -+ /* Configure the SGMII parameters */ -+ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -+ if (ret) -+ return; -+ -+ val |= QCA8K_SGMII_EN_SD; -+ -+ if (priv->ports_config.sgmii_enable_pll) -+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -+ QCA8K_SGMII_EN_TX; -+ -+ if (dsa_is_cpu_port(ds, port)) { -+ /* CPU port, we're talking to the CPU MAC, be a PHY */ -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_PHY; -+ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_MAC; -+ } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_BASEX; -+ } -+ -+ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -+ -+ /* From original code is reported port instability as SGMII also -+ * require delay set. Apply advised values here or take them from DT. -+ */ -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -+ * falling edge is set writing in the PORT0 PAD reg -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327 || -+ priv->switch_id == QCA8K_ID_QCA8337) -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ -+ val = 0; -+ -+ /* SGMII Clock phase configuration */ -+ if (priv->ports_config.sgmii_rx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -+ -+ if (priv->ports_config.sgmii_tx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -+ -+ if (val) -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -+ val); -+ -+ break; -+ default: -+ dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -+ phy_modes(state->interface), port); -+ return; -+ } -+} -+ -+static void -+qca8k_phylink_validate(struct dsa_switch *ds, int port, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ goto unsupported; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_GMII && -+ state->interface != PHY_INTERFACE_MODE_INTERNAL) -+ goto unsupported; -+ break; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ goto unsupported; -+ break; -+ default: -+unsupported: -+ linkmode_zero(supported); -+ return; -+ } -+ -+ phylink_set_port_modes(mask); -+ phylink_set(mask, Autoneg); -+ -+ phylink_set(mask, 1000baseT_Full); -+ phylink_set(mask, 10baseT_Half); -+ phylink_set(mask, 10baseT_Full); -+ phylink_set(mask, 100baseT_Half); -+ phylink_set(mask, 100baseT_Full); -+ -+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -+ phylink_set(mask, 1000baseX_Full); -+ -+ phylink_set(mask, Pause); -+ phylink_set(mask, Asym_Pause); -+ -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+} -+ -+static int -+qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, -+ struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ int ret; -+ -+ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); -+ if (ret < 0) -+ return ret; -+ -+ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); -+ state->an_complete = state->link; -+ state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); -+ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : -+ DUPLEX_HALF; -+ -+ switch (reg & QCA8K_PORT_STATUS_SPEED) { -+ case QCA8K_PORT_STATUS_SPEED_10: -+ state->speed = SPEED_10; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_100: -+ state->speed = SPEED_100; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_1000: -+ state->speed = SPEED_1000; -+ break; -+ default: -+ state->speed = SPEED_UNKNOWN; -+ break; -+ } -+ -+ state->pause = MLO_PAUSE_NONE; -+ if (reg & QCA8K_PORT_STATUS_RXFLOW) -+ state->pause |= MLO_PAUSE_RX; -+ if (reg & QCA8K_PORT_STATUS_TXFLOW) -+ state->pause |= MLO_PAUSE_TX; -+ -+ return 1; -+} -+ -+static void -+qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+} -+ -+static void -+qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface, struct phy_device *phydev, -+ int speed, int duplex, bool tx_pause, bool rx_pause) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ -+ if (phylink_autoneg_inband(mode)) { -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ } else { -+ switch (speed) { -+ case SPEED_10: -+ reg = QCA8K_PORT_STATUS_SPEED_10; -+ break; -+ case SPEED_100: -+ reg = QCA8K_PORT_STATUS_SPEED_100; -+ break; -+ case SPEED_1000: -+ reg = QCA8K_PORT_STATUS_SPEED_1000; -+ break; -+ default: -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ break; -+ } -+ -+ if (duplex == DUPLEX_FULL) -+ reg |= QCA8K_PORT_STATUS_DUPLEX; -+ -+ if (rx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_RXFLOW; -+ -+ if (tx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_TXFLOW; -+ } -+ -+ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); -+} -+ -+static void -+qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) -+{ -+ const struct qca8k_match_data *match_data; -+ struct qca8k_priv *priv = ds->priv; -+ int i; -+ -+ if (stringset != ETH_SS_STATS) -+ return; -+ -+ match_data = of_device_get_match_data(priv->dev); -+ -+ for (i = 0; i < match_data->mib_count; i++) -+ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -+ ETH_GSTRING_LEN); -+} -+ -+static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ const struct qca8k_match_data *match_data; -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ const struct qca8k_mib_desc *mib; -+ struct mib_ethhdr *mib_ethhdr; -+ int i, mib_len, offset = 0; -+ u64 *data; -+ u8 port; -+ -+ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); -+ mib_eth_data = &priv->mib_eth_data; -+ -+ /* The switch autocast every port. Ignore other packet and -+ * parse only the requested one. -+ */ -+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); -+ if (port != mib_eth_data->req_port) -+ goto exit; -+ -+ match_data = device_get_match_data(priv->dev); -+ data = mib_eth_data->data; -+ -+ for (i = 0; i < match_data->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ -+ /* First 3 mib are present in the skb head */ -+ if (i < 3) { -+ data[i] = mib_ethhdr->data[i]; -+ continue; -+ } -+ -+ mib_len = sizeof(uint32_t); -+ -+ /* Some mib are 64 bit wide */ -+ if (mib->size == 2) -+ mib_len = sizeof(uint64_t); -+ -+ /* Copy the mib value from packet to the */ -+ memcpy(data + i, skb->data + offset, mib_len); -+ -+ /* Set the offset for the next mib */ -+ offset += mib_len; -+ } -+ -+exit: -+ /* Complete on receiving all the mib packet */ -+ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) -+ complete(&mib_eth_data->rw_done); -+} -+ -+static int -+qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) -+{ -+ struct dsa_port *dp = dsa_to_port(ds, port); -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ mib_eth_data = &priv->mib_eth_data; -+ -+ mutex_lock(&mib_eth_data->mutex); -+ -+ reinit_completion(&mib_eth_data->rw_done); -+ -+ mib_eth_data->req_port = dp->index; -+ mib_eth_data->data = data; -+ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ /* Send mib autocast request */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | -+ QCA8K_MIB_BUSY); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ if (ret) -+ goto exit; -+ -+ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); -+ -+exit: -+ mutex_unlock(&mib_eth_data->mutex); -+ -+ return ret; -+} -+ -+static void -+qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ const struct qca8k_match_data *match_data; -+ const struct qca8k_mib_desc *mib; -+ u32 reg, i, val; -+ u32 hi = 0; -+ int ret; -+ -+ if (priv->mgmt_master && -+ qca8k_get_ethtool_stats_eth(ds, port, data) > 0) -+ return; -+ -+ match_data = of_device_get_match_data(priv->dev); -+ -+ for (i = 0; i < match_data->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -+ -+ ret = qca8k_read(priv, reg, &val); -+ if (ret < 0) -+ continue; -+ -+ if (mib->size == 2) { -+ ret = qca8k_read(priv, reg + 4, &hi); -+ if (ret < 0) -+ continue; -+ } -+ -+ data[i] = val; -+ if (mib->size == 2) -+ data[i] |= (u64)hi << 32; -+ } -+} -+ -+static int -+qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) -+{ -+ const struct qca8k_match_data *match_data; -+ struct qca8k_priv *priv = ds->priv; -+ -+ if (sset != ETH_SS_STATS) -+ return 0; -+ -+ match_data = of_device_get_match_data(priv->dev); -+ -+ return match_data->mib_count; -+} -+ -+static int -+qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -+ u32 reg; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -+ if (ret < 0) -+ goto exit; -+ -+ if (eee->eee_enabled) -+ reg |= lpi_en; -+ else -+ reg &= ~lpi_en; -+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) -+{ -+ /* Nothing to do on the port's MAC */ -+ return 0; -+} -+ -+static void -+qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 stp_state; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -+ break; -+ case BR_STATE_LISTENING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -+ break; -+ case BR_STATE_LEARNING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ default: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -+ break; -+ } -+ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); -+} -+ -+static int -+qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int port_mask, cpu_port; -+ int i, ret; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ port_mask = BIT(cpu_port); -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Add this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ ret = regmap_set_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ if (ret) -+ return ret; -+ if (i != port) -+ port_mask |= BIT(i); -+ } -+ -+ /* Add all other ports to this ports portvlan mask */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, port_mask); -+ -+ return ret; -+} -+ -+static void -+qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, i; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Remove this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ regmap_clear_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ } -+ -+ /* Set the cpu port to be the only one in the portvlan mask of -+ * this port -+ */ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); -+} -+ -+static void -+qca8k_port_fast_age(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ unsigned int secs = msecs / 1000; -+ u32 val; -+ -+ /* AGE_TIME reg is set in 7s step */ -+ val = secs / 7; -+ -+ /* Handle case with 0 as val to NOT disable -+ * learning -+ */ -+ if (!val) -+ val = 1; -+ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -+ QCA8K_ATU_AGE_TIME(val)); -+} -+ -+static int -+qca8k_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 1); -+ priv->port_enabled_map |= BIT(port); -+ -+ if (dsa_is_user_port(ds, port)) -+ phy_support_asym_pause(phy); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_disable(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+ priv->port_enabled_map &= ~BIT(port); -+} -+ -+static int -+qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ /* We have only have a general MTU setting. -+ * DSA always set the CPU port's MTU to the largest MTU of the slave -+ * ports. -+ * Setting MTU just for the CPU port is sufficient to correctly set a -+ * value for every port. -+ */ -+ if (!dsa_is_cpu_port(ds, port)) -+ return 0; -+ -+ /* To change the MAX_FRAME_SIZE the cpu ports must be off or -+ * the switch panics. -+ * Turn off both cpu ports before applying the new value to prevent -+ * this. -+ */ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 0); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 0); -+ -+ /* Include L2 header / FCS length */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); -+ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 1); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 1); -+ -+ return ret; -+} -+ -+static int -+qca8k_port_max_mtu(struct dsa_switch *ds, int port) -+{ -+ return QCA8K_MAX_MTU; -+} -+ -+static int -+qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -+ u16 port_mask, u16 vid) -+{ -+ /* Set the vid to the port vlan id if no vid is set */ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_add(priv, addr, port_mask, vid, -+ QCA8K_ATU_STATUS_STATIC); -+} -+ -+static int -+qca8k_port_fdb_add(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_del(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_del(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -+ dsa_fdb_dump_cb_t *cb, void *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ struct qca8k_fdb _fdb = { 0 }; -+ int cnt = QCA8K_NUM_FDB_RECORDS; -+ bool is_static; -+ int ret = 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -+ if (!_fdb.aging) -+ break; -+ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -+ ret = cb(_fdb.mac, _fdb.vid, is_static, data); -+ if (ret) -+ break; -+ } -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static int -+qca8k_port_mdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); -+} -+ -+static int -+qca8k_port_mdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); -+} -+ -+static int -+qca8k_port_mirror_add(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror, -+ bool ingress) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int monitor_port, ret; -+ u32 reg, val; -+ -+ /* Check for existent entry */ -+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -+ return -EEXIST; -+ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* QCA83xx can have only one port set to mirror mode. -+ * Check that the correct port is requested and return error otherwise. -+ * When no mirror port is set, the values is set to 0xF -+ */ -+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -+ return -EEXIST; -+ -+ /* Set the monitor port */ -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -+ mirror->to_local_port); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ return ret; -+ -+ if (ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_update_bits(priv->regmap, reg, val, val); -+ if (ret) -+ return ret; -+ -+ /* Track mirror port for tx and rx to decide when the -+ * mirror port has to be disabled. -+ */ -+ if (ingress) -+ priv->mirror_rx |= BIT(port); -+ else -+ priv->mirror_tx |= BIT(port); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_mirror_del(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg, val; -+ int ret; -+ -+ if (mirror->ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_clear_bits(priv->regmap, reg, val); -+ if (ret) -+ goto err; -+ -+ if (mirror->ingress) -+ priv->mirror_rx &= ~BIT(port); -+ else -+ priv->mirror_tx &= ~BIT(port); -+ -+ /* No port set to send packet to mirror port. Disable mirror port */ -+ if (!priv->mirror_rx && !priv->mirror_tx) { -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ goto err; -+ } -+err: -+ dev_err(priv->dev, "Failed to del mirror port from %d", port); -+} -+ -+static int -+qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -+ struct netlink_ext_ack *extack) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ if (vlan_filtering) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -+ } else { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -+ } -+ -+ return ret; -+} -+ -+static int -+qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan, -+ struct netlink_ext_ack *extack) -+{ -+ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -+ if (ret) { -+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+ return ret; -+ } -+ -+ if (pvid) { -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+ QCA8K_EGREES_VLAN_PORT_MASK(port), -+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+ QCA8K_PORT_VLAN_CVID(vlan->vid) | -+ QCA8K_PORT_VLAN_SVID(vlan->vid)); -+ } -+ -+ return ret; -+} -+ -+static int -+qca8k_port_vlan_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_del(priv, port, vlan->vid); -+ if (ret) -+ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -+ -+ return ret; -+} -+ -+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Communicate to the phy internal driver the switch revision. -+ * Based on the switch revision different values needs to be -+ * set to the dbg and mmd reg on the phy. -+ * The first 2 bit are used to communicate the switch revision -+ * to the phy driver. -+ */ -+ if (port > 0 && port < 6) -+ return priv->switch_revision; -+ -+ return 0; -+} -+ -+static enum dsa_tag_protocol -+qca8k_get_tag_protocol(struct dsa_switch *ds, int port, -+ enum dsa_tag_protocol mp) -+{ -+ return DSA_TAG_PROTO_QCA; -+} -+ -+static bool -+qca8k_lag_can_offload(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct dsa_port *dp; -+ int id, members = 0; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ if (id < 0 || id >= ds->num_lag_ids) -+ return false; -+ -+ dsa_lag_foreach_port(dp, ds->dst, lag) -+ /* Includes the port joining the LAG */ -+ members++; -+ -+ if (members > QCA8K_NUM_PORTS_FOR_LAG) -+ return false; -+ -+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -+ return false; -+ -+ if (info->hash_type != NETDEV_LAG_HASH_L2 && -+ info->hash_type != NETDEV_LAG_HASH_L23) -+ return false; -+ -+ return true; -+} -+ -+static int -+qca8k_lag_setup_hash(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ bool unique_lag = true; -+ u32 hash = 0; -+ int i, id; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ switch (info->hash_type) { -+ case NETDEV_LAG_HASH_L23: -+ hash |= QCA8K_TRUNK_HASH_SIP_EN; -+ hash |= QCA8K_TRUNK_HASH_DIP_EN; -+ fallthrough; -+ case NETDEV_LAG_HASH_L2: -+ hash |= QCA8K_TRUNK_HASH_SA_EN; -+ hash |= QCA8K_TRUNK_HASH_DA_EN; -+ break; -+ default: /* We should NEVER reach this */ -+ return -EOPNOTSUPP; -+ } -+ -+ /* Check if we are the unique configured LAG */ -+ dsa_lags_foreach_id(i, ds->dst) -+ if (i != id && dsa_lag_dev(ds->dst, i)) { -+ unique_lag = false; -+ break; -+ } -+ -+ /* Hash Mode is global. Make sure the same Hash Mode -+ * is set to all the 4 possible lag. -+ * If we are the unique LAG we can set whatever hash -+ * mode we want. -+ * To change hash mode it's needed to remove all LAG -+ * and change the mode with the latest. -+ */ -+ if (unique_lag) { -+ priv->lag_hash_mode = hash; -+ } else if (priv->lag_hash_mode != hash) { -+ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -+ QCA8K_TRUNK_HASH_MASK, hash); -+} -+ -+static int -+qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -+ struct net_device *lag, bool delete) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret, id, i; -+ u32 val; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ /* Read current port member */ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* Shift val to the correct trunk */ -+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -+ if (delete) -+ val &= ~BIT(port); -+ else -+ val |= BIT(port); -+ -+ /* Update port member. With empty portmap disable trunk */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -+ QCA8K_REG_GOL_TRUNK_MEMBER(id) | -+ QCA8K_REG_GOL_TRUNK_EN(id), -+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -+ -+ /* Search empty member if adding or port on deleting */ -+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -+ if (ret) -+ return ret; -+ -+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -+ -+ if (delete) { -+ /* If port flagged to be disabled assume this member is -+ * empty -+ */ -+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -+ if (val != port) -+ continue; -+ } else { -+ /* If port flagged to be enabled assume this member is -+ * already set -+ */ -+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ } -+ -+ /* We have found the member to add/remove */ -+ break; -+ } -+ -+ /* Set port in the correct port mask or disable port if in delete mode */ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); -+} -+ -+static int -+qca8k_port_lag_join(struct dsa_switch *ds, int port, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ int ret; -+ -+ if (!qca8k_lag_can_offload(ds, lag, info)) -+ return -EOPNOTSUPP; -+ -+ ret = qca8k_lag_setup_hash(ds, lag, info); -+ if (ret) -+ return ret; -+ -+ return qca8k_lag_refresh_portmap(ds, port, lag, false); -+} -+ -+static int -+qca8k_port_lag_leave(struct dsa_switch *ds, int port, -+ struct net_device *lag) -+{ -+ return qca8k_lag_refresh_portmap(ds, port, lag, true); -+} -+ -+static void -+qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, -+ bool operational) -+{ -+ struct dsa_port *dp = master->dsa_ptr; -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ -+ if (dp->index != 0) -+ return; -+ -+ mutex_lock(&priv->mgmt_eth_data.mutex); -+ mutex_lock(&priv->mib_eth_data.mutex); -+ -+ priv->mgmt_master = operational ? (struct net_device *)master : NULL; -+ -+ mutex_unlock(&priv->mib_eth_data.mutex); -+ mutex_unlock(&priv->mgmt_eth_data.mutex); -+} -+ -+static int qca8k_connect_tag_protocol(struct dsa_switch *ds, -+ enum dsa_tag_protocol proto) -+{ -+ struct qca_tagger_data *tagger_data; -+ -+ switch (proto) { -+ case DSA_TAG_PROTO_QCA: -+ tagger_data = ds->tagger_data; -+ -+ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -+ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; -+ -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static const struct dsa_switch_ops qca8k_switch_ops = { -+ .get_tag_protocol = qca8k_get_tag_protocol, -+ .setup = qca8k_setup, -+ .get_strings = qca8k_get_strings, -+ .get_ethtool_stats = qca8k_get_ethtool_stats, -+ .get_sset_count = qca8k_get_sset_count, -+ .set_ageing_time = qca8k_set_ageing_time, -+ .get_mac_eee = qca8k_get_mac_eee, -+ .set_mac_eee = qca8k_set_mac_eee, -+ .port_enable = qca8k_port_enable, -+ .port_disable = qca8k_port_disable, -+ .port_change_mtu = qca8k_port_change_mtu, -+ .port_max_mtu = qca8k_port_max_mtu, -+ .port_stp_state_set = qca8k_port_stp_state_set, -+ .port_bridge_join = qca8k_port_bridge_join, -+ .port_bridge_leave = qca8k_port_bridge_leave, -+ .port_fast_age = qca8k_port_fast_age, -+ .port_fdb_add = qca8k_port_fdb_add, -+ .port_fdb_del = qca8k_port_fdb_del, -+ .port_fdb_dump = qca8k_port_fdb_dump, -+ .port_mdb_add = qca8k_port_mdb_add, -+ .port_mdb_del = qca8k_port_mdb_del, -+ .port_mirror_add = qca8k_port_mirror_add, -+ .port_mirror_del = qca8k_port_mirror_del, -+ .port_vlan_filtering = qca8k_port_vlan_filtering, -+ .port_vlan_add = qca8k_port_vlan_add, -+ .port_vlan_del = qca8k_port_vlan_del, -+ .phylink_validate = qca8k_phylink_validate, -+ .phylink_mac_link_state = qca8k_phylink_mac_link_state, -+ .phylink_mac_config = qca8k_phylink_mac_config, -+ .phylink_mac_link_down = qca8k_phylink_mac_link_down, -+ .phylink_mac_link_up = qca8k_phylink_mac_link_up, -+ .get_phy_flags = qca8k_get_phy_flags, -+ .port_lag_join = qca8k_port_lag_join, -+ .port_lag_leave = qca8k_port_lag_leave, -+ .master_state_change = qca8k_master_change, -+ .connect_tag_protocol = qca8k_connect_tag_protocol, -+}; -+ -+static int qca8k_read_switch_id(struct qca8k_priv *priv) -+{ -+ const struct qca8k_match_data *data; -+ u32 val; -+ u8 id; -+ int ret; -+ -+ /* get the switches ID from the compatible */ -+ data = of_device_get_match_data(priv->dev); -+ if (!data) -+ return -ENODEV; -+ -+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -+ if (ret < 0) -+ return -ENODEV; -+ -+ id = QCA8K_MASK_CTRL_DEVICE_ID(val); -+ if (id != data->id) { -+ dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); -+ return -ENODEV; -+ } -+ -+ priv->switch_id = id; -+ -+ /* Save revision to communicate to the internal PHY driver */ -+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -+ -+ return 0; -+} -+ -+static int -+qca8k_sw_probe(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv; -+ int ret; -+ -+ /* allocate the private data struct so that we can probe the switches -+ * ID register -+ */ -+ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->bus = mdiodev->bus; -+ priv->dev = &mdiodev->dev; -+ -+ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -+ GPIOD_ASIS); -+ if (IS_ERR(priv->reset_gpio)) -+ return PTR_ERR(priv->reset_gpio); -+ -+ if (priv->reset_gpio) { -+ gpiod_set_value_cansleep(priv->reset_gpio, 1); -+ /* The active low duration must be greater than 10 ms -+ * and checkpatch.pl wants 20 ms. -+ */ -+ msleep(20); -+ gpiod_set_value_cansleep(priv->reset_gpio, 0); -+ } -+ -+ /* Start by setting up the register mapping */ -+ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, -+ &qca8k_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ dev_err(priv->dev, "regmap initialization failed"); -+ return PTR_ERR(priv->regmap); -+ } -+ -+ priv->mdio_cache.page = 0xffff; -+ priv->mdio_cache.lo = 0xffff; -+ priv->mdio_cache.hi = 0xffff; -+ -+ /* Check the detected switch id */ -+ ret = qca8k_read_switch_id(priv); -+ if (ret) -+ return ret; -+ -+ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -+ if (!priv->ds) -+ return -ENOMEM; -+ -+ mutex_init(&priv->mgmt_eth_data.mutex); -+ init_completion(&priv->mgmt_eth_data.rw_done); -+ -+ mutex_init(&priv->mib_eth_data.mutex); -+ init_completion(&priv->mib_eth_data.rw_done); -+ -+ priv->ds->dev = &mdiodev->dev; -+ priv->ds->num_ports = QCA8K_NUM_PORTS; -+ priv->ds->priv = priv; -+ priv->ds->ops = &qca8k_switch_ops; -+ mutex_init(&priv->reg_mutex); -+ dev_set_drvdata(&mdiodev->dev, priv); -+ -+ return dsa_register_switch(priv->ds); -+} -+ -+static void -+qca8k_sw_remove(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ int i; -+ -+ if (!priv) -+ return; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) -+ qca8k_port_set_status(priv, i, 0); -+ -+ dsa_unregister_switch(priv->ds); -+ -+ dev_set_drvdata(&mdiodev->dev, NULL); -+} -+ -+static void qca8k_sw_shutdown(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ -+ if (!priv) -+ return; -+ -+ dsa_switch_shutdown(priv->ds); -+ -+ dev_set_drvdata(&mdiodev->dev, NULL); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static void -+qca8k_set_pm(struct qca8k_priv *priv, int enable) -+{ -+ int port; -+ -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Do not enable on resume if the port was -+ * disabled before. -+ */ -+ if (!(priv->port_enabled_map & BIT(port))) -+ continue; -+ -+ qca8k_port_set_status(priv, port, enable); -+ } -+} -+ -+static int qca8k_suspend(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 0); -+ -+ return dsa_switch_suspend(priv->ds); -+} -+ -+static int qca8k_resume(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 1); -+ -+ return dsa_switch_resume(priv->ds); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -+ qca8k_suspend, qca8k_resume); -+ -+static const struct qca8k_match_data qca8327 = { -+ .id = QCA8K_ID_QCA8327, -+ .reduced_package = true, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, -+}; -+ -+static const struct qca8k_match_data qca8328 = { -+ .id = QCA8K_ID_QCA8327, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, -+}; -+ -+static const struct qca8k_match_data qca833x = { -+ .id = QCA8K_ID_QCA8337, -+ .mib_count = QCA8K_QCA833X_MIB_COUNT, -+}; -+ -+static const struct of_device_id qca8k_of_match[] = { -+ { .compatible = "qca,qca8327", .data = &qca8327 }, -+ { .compatible = "qca,qca8328", .data = &qca8328 }, -+ { .compatible = "qca,qca8334", .data = &qca833x }, -+ { .compatible = "qca,qca8337", .data = &qca833x }, -+ { /* sentinel */ }, -+}; -+ -+static struct mdio_driver qca8kmdio_driver = { -+ .probe = qca8k_sw_probe, -+ .remove = qca8k_sw_remove, -+ .shutdown = qca8k_sw_shutdown, -+ .mdiodrv.driver = { -+ .name = "qca8k", -+ .of_match_table = qca8k_of_match, -+ .pm = &qca8k_pm_ops, -+ }, -+}; -+ -+mdio_module_driver(qca8kmdio_driver); -+ -+MODULE_AUTHOR("Mathieu Olivari, John Crispin "); -+MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qca8k"); ---- /dev/null -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -0,0 +1,411 @@ -+/* SPDX-License-Identifier: GPL-2.0-only */ -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, The Linux Foundation. All rights reserved. -+ */ -+ -+#ifndef __QCA8K_H -+#define __QCA8K_H -+ -+#include -+#include -+#include -+#include -+ -+#define QCA8K_ETHERNET_MDIO_PRIORITY 7 -+#define QCA8K_ETHERNET_PHY_PRIORITY 6 -+#define QCA8K_ETHERNET_TIMEOUT 100 -+ -+#define QCA8K_NUM_PORTS 7 -+#define QCA8K_NUM_CPU_PORTS 2 -+#define QCA8K_MAX_MTU 9000 -+#define QCA8K_NUM_LAGS 4 -+#define QCA8K_NUM_PORTS_FOR_LAG 4 -+ -+#define PHY_ID_QCA8327 0x004dd034 -+#define QCA8K_ID_QCA8327 0x12 -+#define PHY_ID_QCA8337 0x004dd036 -+#define QCA8K_ID_QCA8337 0x13 -+ -+#define QCA8K_QCA832X_MIB_COUNT 39 -+#define QCA8K_QCA833X_MIB_COUNT 41 -+ -+#define QCA8K_BUSY_WAIT_TIMEOUT 2000 -+ -+#define QCA8K_NUM_FDB_RECORDS 2048 -+ -+#define QCA8K_PORT_VID_DEF 1 -+ -+/* Global control registers */ -+#define QCA8K_REG_MASK_CTRL 0x000 -+#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) -+#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) -+#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) -+#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) -+#define QCA8K_REG_PORT0_PAD_CTRL 0x004 -+#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) -+#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) -+#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) -+#define QCA8K_REG_PORT5_PAD_CTRL 0x008 -+#define QCA8K_REG_PORT6_PAD_CTRL 0x00c -+#define QCA8K_PORT_PAD_RGMII_EN BIT(26) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) -+#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) -+#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) -+#define QCA8K_PORT_PAD_SGMII_EN BIT(7) -+#define QCA8K_REG_PWS 0x010 -+#define QCA8K_PWS_POWER_ON_SEL BIT(31) -+/* This reg is only valid for QCA832x and toggle the package -+ * type from 176 pin (by default) to 148 pin used on QCA8327 -+ */ -+#define QCA8327_PWS_PACKAGE148_EN BIT(30) -+#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) -+#define QCA8K_PWS_SERDES_AEN_DIS BIT(7) -+#define QCA8K_REG_MODULE_EN 0x030 -+#define QCA8K_MODULE_EN_MIB BIT(0) -+#define QCA8K_REG_MIB 0x034 -+#define QCA8K_MIB_FUNC GENMASK(26, 24) -+#define QCA8K_MIB_CPU_KEEP BIT(20) -+#define QCA8K_MIB_BUSY BIT(17) -+#define QCA8K_MDIO_MASTER_CTRL 0x3c -+#define QCA8K_MDIO_MASTER_BUSY BIT(31) -+#define QCA8K_MDIO_MASTER_EN BIT(30) -+#define QCA8K_MDIO_MASTER_READ BIT(27) -+#define QCA8K_MDIO_MASTER_WRITE 0 -+#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) -+#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) -+#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) -+#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) -+#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) -+#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) -+#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) -+#define QCA8K_MDIO_MASTER_MAX_PORTS 5 -+#define QCA8K_MDIO_MASTER_MAX_REG 32 -+#define QCA8K_GOL_MAC_ADDR0 0x60 -+#define QCA8K_GOL_MAC_ADDR1 0x64 -+#define QCA8K_MAX_FRAME_SIZE 0x78 -+#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) -+#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) -+#define QCA8K_PORT_STATUS_SPEED_10 0 -+#define QCA8K_PORT_STATUS_SPEED_100 0x1 -+#define QCA8K_PORT_STATUS_SPEED_1000 0x2 -+#define QCA8K_PORT_STATUS_TXMAC BIT(2) -+#define QCA8K_PORT_STATUS_RXMAC BIT(3) -+#define QCA8K_PORT_STATUS_TXFLOW BIT(4) -+#define QCA8K_PORT_STATUS_RXFLOW BIT(5) -+#define QCA8K_PORT_STATUS_DUPLEX BIT(6) -+#define QCA8K_PORT_STATUS_LINK_UP BIT(8) -+#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) -+#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) -+#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) -+#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) -+#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) -+#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) -+#define QCA8K_PORT_HDR_CTRL_ALL 2 -+#define QCA8K_PORT_HDR_CTRL_MGMT 1 -+#define QCA8K_PORT_HDR_CTRL_NONE 0 -+#define QCA8K_REG_SGMII_CTRL 0x0e0 -+#define QCA8K_SGMII_EN_PLL BIT(1) -+#define QCA8K_SGMII_EN_RX BIT(2) -+#define QCA8K_SGMII_EN_TX BIT(3) -+#define QCA8K_SGMII_EN_SD BIT(4) -+#define QCA8K_SGMII_CLK125M_DELAY BIT(7) -+#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) -+#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) -+#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) -+#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) -+#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) -+ -+/* MAC_PWR_SEL registers */ -+#define QCA8K_REG_MAC_PWR_SEL 0x0e4 -+#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) -+#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) -+ -+/* EEE control registers */ -+#define QCA8K_REG_EEE_CTRL 0x100 -+#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) -+ -+/* TRUNK_HASH_EN registers */ -+#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 -+#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) -+#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) -+#define QCA8K_TRUNK_HASH_SA_EN BIT(1) -+#define QCA8K_TRUNK_HASH_DA_EN BIT(0) -+#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) -+ -+/* ACL registers */ -+#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) -+#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) -+#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) -+#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) -+#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) -+#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) -+#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 -+#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 -+ -+/* Lookup registers */ -+#define QCA8K_REG_ATU_DATA0 0x600 -+#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) -+#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) -+#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) -+#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) -+#define QCA8K_REG_ATU_DATA1 0x604 -+#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) -+#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) -+#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) -+#define QCA8K_REG_ATU_DATA2 0x608 -+#define QCA8K_ATU_VID_MASK GENMASK(19, 8) -+#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) -+#define QCA8K_ATU_STATUS_STATIC 0xf -+#define QCA8K_REG_ATU_FUNC 0x60c -+#define QCA8K_ATU_FUNC_BUSY BIT(31) -+#define QCA8K_ATU_FUNC_PORT_EN BIT(14) -+#define QCA8K_ATU_FUNC_MULTI_EN BIT(13) -+#define QCA8K_ATU_FUNC_FULL BIT(12) -+#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) -+#define QCA8K_REG_VTU_FUNC0 0x610 -+#define QCA8K_VTU_FUNC0_VALID BIT(20) -+#define QCA8K_VTU_FUNC0_IVL_EN BIT(19) -+/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) -+ * It does contain VLAN_MODE for each port [5:4] for port0, -+ * [7:6] for port1 ... [17:16] for port6. Use virtual port -+ * define to handle this. -+ */ -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) -+#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) -+#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) -+#define QCA8K_REG_VTU_FUNC1 0x614 -+#define QCA8K_VTU_FUNC1_BUSY BIT(31) -+#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) -+#define QCA8K_VTU_FUNC1_FULL BIT(4) -+#define QCA8K_REG_ATU_CTRL 0x618 -+#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) -+#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) -+#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 -+#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) -+#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) -+#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 -+#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) -+#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) -+#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) -+#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) -+#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) -+#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) -+#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) -+#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) -+#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) -+#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) -+#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) -+#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) -+#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) -+#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) -+#define QCA8K_PORT_LOOKUP_LEARN BIT(20) -+#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) -+ -+#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 -+/* 4 max trunk first -+ * first 6 bit for member bitmap -+ * 7th bit is to enable trunk port -+ */ -+#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) -+#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) -+#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) -+#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) -+#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) -+/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ -+#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) -+#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) -+#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) -+/* Complex shift: FIRST shift for port THEN shift for trunk */ -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) -+#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) -+ -+#define QCA8K_REG_GLOBAL_FC_THRESH 0x800 -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) -+#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) -+#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) -+ -+#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) -+#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) -+#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) -+ -+#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) -+#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) -+#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) -+#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) -+#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) -+#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) -+#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) -+ -+/* Pkt edit registers */ -+#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) -+#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) -+#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) -+#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) -+ -+/* L3 registers */ -+#define QCA8K_HROUTER_CONTROL 0xe00 -+#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16) -+#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16 -+#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1 -+#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08 -+#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c -+#define QCA8K_HNAT_CONTROL 0xe38 -+ -+/* MIB registers */ -+#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100) -+ -+/* QCA specific MII registers */ -+#define MII_ATH_MMD_ADDR 0x0d -+#define MII_ATH_MMD_DATA 0x0e -+ -+enum { -+ QCA8K_PORT_SPEED_10M = 0, -+ QCA8K_PORT_SPEED_100M = 1, -+ QCA8K_PORT_SPEED_1000M = 2, -+ QCA8K_PORT_SPEED_ERR = 3, -+}; -+ -+enum qca8k_fdb_cmd { -+ QCA8K_FDB_FLUSH = 1, -+ QCA8K_FDB_LOAD = 2, -+ QCA8K_FDB_PURGE = 3, -+ QCA8K_FDB_FLUSH_PORT = 5, -+ QCA8K_FDB_NEXT = 6, -+ QCA8K_FDB_SEARCH = 7, -+}; -+ -+enum qca8k_vlan_cmd { -+ QCA8K_VLAN_FLUSH = 1, -+ QCA8K_VLAN_LOAD = 2, -+ QCA8K_VLAN_PURGE = 3, -+ QCA8K_VLAN_REMOVE_PORT = 4, -+ QCA8K_VLAN_NEXT = 5, -+ QCA8K_VLAN_READ = 6, -+}; -+ -+enum qca8k_mid_cmd { -+ QCA8K_MIB_FLUSH = 1, -+ QCA8K_MIB_FLUSH_PORT = 2, -+ QCA8K_MIB_CAST = 3, -+}; -+ -+struct qca8k_match_data { -+ u8 id; -+ bool reduced_package; -+ u8 mib_count; -+}; -+ -+enum { -+ QCA8K_CPU_PORT0, -+ QCA8K_CPU_PORT6, -+}; -+ -+struct qca8k_mgmt_eth_data { -+ struct completion rw_done; -+ struct mutex mutex; /* Enforce one mdio read/write at time */ -+ bool ack; -+ u32 seq; -+ u32 data[4]; -+}; -+ -+struct qca8k_mib_eth_data { -+ struct completion rw_done; -+ struct mutex mutex; /* Process one command at time */ -+ refcount_t port_parsed; /* Counter to track parsed port */ -+ u8 req_port; -+ u64 *data; /* pointer to ethtool data */ -+}; -+ -+struct qca8k_ports_config { -+ bool sgmii_rx_clk_falling_edge; -+ bool sgmii_tx_clk_falling_edge; -+ bool sgmii_enable_pll; -+ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -+}; -+ -+struct qca8k_mdio_cache { -+/* The 32bit switch registers are accessed indirectly. To achieve this we need -+ * to set the page of the register. Track the last page that was set to reduce -+ * mdio writes -+ */ -+ u16 page; -+/* lo and hi can also be cached and from Documentation we can skip one -+ * extra mdio write if lo or hi is didn't change. -+ */ -+ u16 lo; -+ u16 hi; -+}; -+ -+struct qca8k_priv { -+ u8 switch_id; -+ u8 switch_revision; -+ u8 mirror_rx; -+ u8 mirror_tx; -+ u8 lag_hash_mode; -+ /* Each bit correspond to a port. This switch can support a max of 7 port. -+ * Bit 1: port enabled. Bit 0: port disabled. -+ */ -+ u8 port_enabled_map; -+ struct qca8k_ports_config ports_config; -+ struct regmap *regmap; -+ struct mii_bus *bus; -+ struct dsa_switch *ds; -+ struct mutex reg_mutex; -+ struct device *dev; -+ struct gpio_desc *reset_gpio; -+ struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ -+ struct qca8k_mgmt_eth_data mgmt_eth_data; -+ struct qca8k_mib_eth_data mib_eth_data; -+ struct qca8k_mdio_cache mdio_cache; -+}; -+ -+struct qca8k_mib_desc { -+ unsigned int size; -+ unsigned int offset; -+ const char *name; -+}; -+ -+struct qca8k_fdb { -+ u16 vid; -+ u8 port_mask; -+ u8 aging; -+ u8 mac[6]; -+}; -+ -+#endif /* __QCA8K_H */ ---- a/drivers/net/dsa/qca8k.c -+++ /dev/null -@@ -1,3243 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * Copyright (C) 2009 Felix Fietkau -- * Copyright (C) 2011-2012 Gabor Juhos -- * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -- * Copyright (c) 2016 John Crispin -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "qca8k.h" -- --#define MIB_DESC(_s, _o, _n) \ -- { \ -- .size = (_s), \ -- .offset = (_o), \ -- .name = (_n), \ -- } -- --static const struct qca8k_mib_desc ar8327_mib[] = { -- MIB_DESC(1, 0x00, "RxBroad"), -- MIB_DESC(1, 0x04, "RxPause"), -- MIB_DESC(1, 0x08, "RxMulti"), -- MIB_DESC(1, 0x0c, "RxFcsErr"), -- MIB_DESC(1, 0x10, "RxAlignErr"), -- MIB_DESC(1, 0x14, "RxRunt"), -- MIB_DESC(1, 0x18, "RxFragment"), -- MIB_DESC(1, 0x1c, "Rx64Byte"), -- MIB_DESC(1, 0x20, "Rx128Byte"), -- MIB_DESC(1, 0x24, "Rx256Byte"), -- MIB_DESC(1, 0x28, "Rx512Byte"), -- MIB_DESC(1, 0x2c, "Rx1024Byte"), -- MIB_DESC(1, 0x30, "Rx1518Byte"), -- MIB_DESC(1, 0x34, "RxMaxByte"), -- MIB_DESC(1, 0x38, "RxTooLong"), -- MIB_DESC(2, 0x3c, "RxGoodByte"), -- MIB_DESC(2, 0x44, "RxBadByte"), -- MIB_DESC(1, 0x4c, "RxOverFlow"), -- MIB_DESC(1, 0x50, "Filtered"), -- MIB_DESC(1, 0x54, "TxBroad"), -- MIB_DESC(1, 0x58, "TxPause"), -- MIB_DESC(1, 0x5c, "TxMulti"), -- MIB_DESC(1, 0x60, "TxUnderRun"), -- MIB_DESC(1, 0x64, "Tx64Byte"), -- MIB_DESC(1, 0x68, "Tx128Byte"), -- MIB_DESC(1, 0x6c, "Tx256Byte"), -- MIB_DESC(1, 0x70, "Tx512Byte"), -- MIB_DESC(1, 0x74, "Tx1024Byte"), -- MIB_DESC(1, 0x78, "Tx1518Byte"), -- MIB_DESC(1, 0x7c, "TxMaxByte"), -- MIB_DESC(1, 0x80, "TxOverSize"), -- MIB_DESC(2, 0x84, "TxByte"), -- MIB_DESC(1, 0x8c, "TxCollision"), -- MIB_DESC(1, 0x90, "TxAbortCol"), -- MIB_DESC(1, 0x94, "TxMultiCol"), -- MIB_DESC(1, 0x98, "TxSingleCol"), -- MIB_DESC(1, 0x9c, "TxExcDefer"), -- MIB_DESC(1, 0xa0, "TxDefer"), -- MIB_DESC(1, 0xa4, "TxLateCol"), -- MIB_DESC(1, 0xa8, "RXUnicast"), -- MIB_DESC(1, 0xac, "TXUnicast"), --}; -- --static void --qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) --{ -- regaddr >>= 1; -- *r1 = regaddr & 0x1e; -- -- regaddr >>= 5; -- *r2 = regaddr & 0x7; -- -- regaddr >>= 3; -- *page = regaddr & 0x3ff; --} -- --static int --qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) --{ -- u16 *cached_lo = &priv->mdio_cache.lo; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (lo == *cached_lo) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, lo); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit lo register\n"); -- -- *cached_lo = lo; -- return 0; --} -- --static int --qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) --{ -- u16 *cached_hi = &priv->mdio_cache.hi; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (hi == *cached_hi) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, hi); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit hi register\n"); -- -- *cached_hi = hi; -- return 0; --} -- --static int --qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) --{ -- int ret; -- -- ret = bus->read(bus, phy_id, regnum); -- if (ret >= 0) { -- *val = ret; -- ret = bus->read(bus, phy_id, regnum + 1); -- *val |= ret << 16; -- } -- -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to read qca8k 32bit register\n"); -- *val = 0; -- return ret; -- } -- -- return 0; --} -- --static void --qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) --{ -- u16 lo, hi; -- int ret; -- -- lo = val & 0xffff; -- hi = (u16)(val >> 16); -- -- ret = qca8k_set_lo(priv, phy_id, regnum, lo); -- if (ret >= 0) -- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); --} -- --static int --qca8k_set_page(struct qca8k_priv *priv, u16 page) --{ -- u16 *cached_page = &priv->mdio_cache.page; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (page == *cached_page) -- return 0; -- -- ret = bus->write(bus, 0x18, 0, page); -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to set qca8k page\n"); -- return ret; -- } -- -- *cached_page = page; -- usleep_range(1000, 2000); -- return 0; --} -- --static int --qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) --{ -- return regmap_read(priv->regmap, reg, val); --} -- --static int --qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) --{ -- return regmap_write(priv->regmap, reg, val); --} -- --static int --qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) --{ -- return regmap_update_bits(priv->regmap, reg, mask, write_val); --} -- --static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data; -- struct qca8k_priv *priv = ds->priv; -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- u8 len, cmd; -- -- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); -- mgmt_eth_data = &priv->mgmt_eth_data; -- -- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -- -- /* Make sure the seq match the requested packet */ -- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -- mgmt_eth_data->ack = true; -- -- if (cmd == MDIO_READ) { -- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -- -- /* Get the rest of the 12 byte of data. -- * The read/write function will extract the requested data. -- */ -- if (len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(mgmt_eth_data->data + 1, skb->data, -- QCA_HDR_MGMT_DATA2_LEN); -- } -- -- complete(&mgmt_eth_data->rw_done); --} -- --static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -- int priority, unsigned int len) --{ -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- unsigned int real_len; -- struct sk_buff *skb; -- u32 *data2; -- u16 hdr; -- -- skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); -- if (!skb) -- return NULL; -- -- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -- * Actually for some reason the steps are: -- * 0: nothing -- * 1-4: first 4 byte -- * 5-6: first 12 byte -- * 7-15: all 16 byte -- */ -- if (len == 16) -- real_len = 15; -- else -- real_len = len; -- -- skb_reset_mac_header(skb); -- skb_set_network_header(skb, skb->len); -- -- mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); -- -- hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -- hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); -- hdr |= QCA_HDR_XMIT_FROM_CPU; -- hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); -- hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); -- -- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -- QCA_HDR_MGMT_CHECK_CODE_VAL); -- -- if (cmd == MDIO_WRITE) -- mgmt_ethhdr->mdio_data = *val; -- -- mgmt_ethhdr->hdr = htons(hdr); -- -- data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); -- -- return skb; --} -- --static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) --{ -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- -- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); --} -- --static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -- struct sk_buff *skb; -- bool ack; -- int ret; -- -- skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -- QCA8K_ETHERNET_MDIO_PRIORITY, len); -- if (!skb) -- return -ENOMEM; -- -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check mgmt_master if is operational */ -- if (!priv->mgmt_master) { -- kfree_skb(skb); -- mutex_unlock(&mgmt_eth_data->mutex); -- return -EINVAL; -- } -- -- skb->dev = priv->mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the mdio pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -- -- *val = mgmt_eth_data->data[0]; -- if (len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); -- -- ack = mgmt_eth_data->ack; -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- return 0; --} -- --static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -- struct sk_buff *skb; -- bool ack; -- int ret; -- -- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, -- QCA8K_ETHERNET_MDIO_PRIORITY, len); -- if (!skb) -- return -ENOMEM; -- -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check mgmt_master if is operational */ -- if (!priv->mgmt_master) { -- kfree_skb(skb); -- mutex_unlock(&mgmt_eth_data->mutex); -- return -EINVAL; -- } -- -- skb->dev = priv->mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the mdio pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -- -- ack = mgmt_eth_data->ack; -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- return 0; --} -- --static int --qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) --{ -- u32 val = 0; -- int ret; -- -- ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); -- if (ret) -- return ret; -- -- val &= ~mask; -- val |= write_val; -- -- return qca8k_write_eth(priv, reg, &val, sizeof(val)); --} -- --static int --qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- -- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int --qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- u32 tmp; -- -- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- tmp = val[i]; -- -- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int --qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; --} -- --static int --qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; --} -- --static int --qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- if (ret < 0) -- goto exit; -- -- val &= ~mask; -- val |= write_val; -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- -- return ret; --} -- --static const struct regmap_range qca8k_readable_ranges[] = { -- regmap_reg_range(0x0000, 0x00e4), /* Global control */ -- regmap_reg_range(0x0100, 0x0168), /* EEE control */ -- regmap_reg_range(0x0200, 0x0270), /* Parser control */ -- regmap_reg_range(0x0400, 0x0454), /* ACL */ -- regmap_reg_range(0x0600, 0x0718), /* Lookup */ -- regmap_reg_range(0x0800, 0x0b70), /* QM */ -- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -- --}; -- --static const struct regmap_access_table qca8k_readable_table = { -- .yes_ranges = qca8k_readable_ranges, -- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), --}; -- --static struct regmap_config qca8k_regmap_config = { -- .reg_bits = 16, -- .val_bits = 32, -- .reg_stride = 4, -- .max_register = 0x16ac, /* end MIB - Port6 range */ -- .reg_read = qca8k_regmap_read, -- .reg_write = qca8k_regmap_write, -- .reg_update_bits = qca8k_regmap_update_bits, -- .rd_table = &qca8k_readable_table, -- .disable_locking = true, /* Locking is handled by qca8k read/write */ -- .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ --}; -- --static int --qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) --{ -- u32 val; -- -- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); --} -- --static int --qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) --{ -- u32 reg[3]; -- int ret; -- -- /* load the ARL table into an array */ -- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -- if (ret) -- return ret; -- -- /* vid - 83:72 */ -- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -- /* aging - 67:64 */ -- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -- /* portmask - 54:48 */ -- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -- /* mac - 47:0 */ -- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -- -- return 0; --} -- --static void --qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -- u8 aging) --{ -- u32 reg[3] = { 0 }; -- -- /* vid - 83:72 */ -- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -- /* aging - 67:64 */ -- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -- /* portmask - 54:48 */ -- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -- /* mac - 47:0 */ -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -- -- /* load the array into the ARL table */ -- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); --} -- --static int --qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) --{ -- u32 reg; -- int ret; -- -- /* Set the command and FDB index */ -- reg = QCA8K_ATU_FUNC_BUSY; -- reg |= cmd; -- if (port >= 0) { -- reg |= QCA8K_ATU_FUNC_PORT_EN; -- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -- } -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_FDB_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_ATU_FUNC_FULL) -- return -1; -- } -- -- return 0; --} -- --static int --qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) --{ -- int ret; -- -- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -- if (ret < 0) -- return ret; -- -- return qca8k_fdb_read(priv, fdb); --} -- --static int --qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -- u16 vid, u8 aging) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static void --qca8k_fdb_flush(struct qca8k_priv *priv) --{ -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_fdb_read(priv, &fdb); -- if (ret < 0) -- goto exit; -- -- /* Rule exist. Delete first */ -- if (!fdb.aging) { -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- } -- -- /* Add port to fdb portmask */ -- fdb.port_mask |= port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- /* Rule doesn't exist. Why delete? */ -- if (!fdb.aging) { -- ret = -EINVAL; -- goto exit; -- } -- -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- -- /* Only port in the rule is this port. Don't re insert */ -- if (fdb.port_mask == port_mask) -- goto exit; -- -- /* Remove port from port mask */ -- fdb.port_mask &= ~port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) --{ -- u32 reg; -- int ret; -- -- /* Set the command and VLAN index */ -- reg = QCA8K_VTU_FUNC1_BUSY; -- reg |= cmd; -- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_VLAN_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_VTU_FUNC1_FULL) -- return -ENOMEM; -- } -- -- return 0; --} -- --static int --qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) --{ -- u32 reg; -- int ret; -- -- /* -- We do the right thing with VLAN 0 and treat it as untagged while -- preserving the tag on egress. -- */ -- if (vid == 0) -- return 0; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- if (untagged) -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -- else -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -- -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) --{ -- u32 reg, mask; -- int ret, i; -- bool del; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -- -- /* Check if we're the last member to be removed */ -- del = true; -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -- -- if ((reg & mask) != mask) { -- del = false; -- break; -- } -- } -- -- if (del) { -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -- } else { -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- } -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_mib_init(struct qca8k_priv *priv) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -- QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -- if (ret) -- goto exit; -- -- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static void --qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) --{ -- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -- -- /* Port 0 and 6 have no internal PHY */ -- if (port > 0 && port < 6) -- mask |= QCA8K_PORT_STATUS_LINK_AUTO; -- -- if (enable) -- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -- else -- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); --} -- --static int --qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, -- struct sk_buff *read_skb, u32 *val) --{ -- struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); -- bool ack; -- int ret; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the copy pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- *val = mgmt_eth_data->data[0]; -- -- return 0; --} -- --static int --qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, -- int regnum, u16 data) --{ -- struct sk_buff *write_skb, *clear_skb, *read_skb; -- struct qca8k_mgmt_eth_data *mgmt_eth_data; -- u32 write_val, clear_val = 0, val; -- struct net_device *mgmt_master; -- int ret, ret1; -- bool ack; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- mgmt_eth_data = &priv->mgmt_eth_data; -- -- write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum); -- -- if (read) { -- write_val |= QCA8K_MDIO_MASTER_READ; -- } else { -- write_val |= QCA8K_MDIO_MASTER_WRITE; -- write_val |= QCA8K_MDIO_MASTER_DATA(data); -- } -- -- /* Prealloc all the needed skb before the lock */ -- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); -- if (!write_skb) -- return -ENOMEM; -- -- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -- if (!clear_skb) { -- ret = -ENOMEM; -- goto err_clear_skb; -- } -- -- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -- if (!read_skb) { -- ret = -ENOMEM; -- goto err_read_skb; -- } -- -- /* Actually start the request: -- * 1. Send mdio master packet -- * 2. Busy Wait for mdio master command -- * 3. Get the data if we are reading -- * 4. Reset the mdio master (even with error) -- */ -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check if mgmt_master is operational */ -- mgmt_master = priv->mgmt_master; -- if (!mgmt_master) { -- mutex_unlock(&mgmt_eth_data->mutex); -- ret = -EINVAL; -- goto err_mgmt_master; -- } -- -- read_skb->dev = mgmt_master; -- clear_skb->dev = mgmt_master; -- write_skb->dev = mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the write pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(write_skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) { -- ret = -ETIMEDOUT; -- kfree_skb(read_skb); -- goto exit; -- } -- -- if (!ack) { -- ret = -EINVAL; -- kfree_skb(read_skb); -- goto exit; -- } -- -- ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, -- !(val & QCA8K_MDIO_MASTER_BUSY), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- mgmt_eth_data, read_skb, &val); -- -- if (ret < 0 && ret1 < 0) { -- ret = ret1; -- goto exit; -- } -- -- if (read) { -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the read pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(read_skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) { -- ret = -ETIMEDOUT; -- goto exit; -- } -- -- if (!ack) { -- ret = -EINVAL; -- goto exit; -- } -- -- ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; -- } else { -- kfree_skb(read_skb); -- } --exit: -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the clear pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(clear_skb); -- -- wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- return ret; -- -- /* Error handling before lock */ --err_mgmt_master: -- kfree_skb(read_skb); --err_read_skb: -- kfree_skb(clear_skb); --err_clear_skb: -- kfree_skb(write_skb); -- -- return ret; --} -- --static u32 --qca8k_port_to_phy(int port) --{ -- /* From Andrew Lunn: -- * Port 0 has no internal phy. -- * Port 1 has an internal PHY at MDIO address 0. -- * Port 2 has an internal PHY at MDIO address 1. -- * ... -- * Port 5 has an internal PHY at MDIO address 4. -- * Port 6 has no internal PHY. -- */ -- -- return port - 1; --} -- --static int --qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) --{ -- u16 r1, r2, page; -- u32 val; -- int ret, ret1; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- bus, 0x10 | r2, r1, &val); -- -- /* Check if qca8k_read has failed for a different reason -- * before returnting -ETIMEDOUT -- */ -- if (ret < 0 && ret1 < 0) -- return ret1; -- -- return ret; --} -- --static int --qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) --{ -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -- QCA8K_MDIO_MASTER_DATA(data); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- return ret; --} -- --static int --qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) --{ -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- if (ret >= 0) -- ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -- -- return ret; --} -- --static int --qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- int ret; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); -- if (!ret) -- return 0; -- -- return qca8k_mdio_write(priv, phy, regnum, data); --} -- --static int --qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- int ret; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); -- if (ret >= 0) -- return ret; -- -- ret = qca8k_mdio_read(priv, phy, regnum); -- -- if (ret < 0) -- return 0xffff; -- -- return ret; --} -- --static int --qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) --{ -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- return qca8k_internal_mdio_write(slave_bus, port, regnum, data); --} -- --static int --qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) --{ -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- return qca8k_internal_mdio_read(slave_bus, port, regnum); --} -- --static int --qca8k_mdio_register(struct qca8k_priv *priv) --{ -- struct dsa_switch *ds = priv->ds; -- struct device_node *mdio; -- struct mii_bus *bus; -- -- bus = devm_mdiobus_alloc(ds->dev); -- if (!bus) -- return -ENOMEM; -- -- bus->priv = (void *)priv; -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -- ds->dst->index, ds->index); -- bus->parent = ds->dev; -- bus->phy_mask = ~ds->phys_mii_mask; -- ds->slave_mii_bus = bus; -- -- /* Check if the devicetree declare the port:phy mapping */ -- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -- if (of_device_is_available(mdio)) { -- bus->name = "qca8k slave mii"; -- bus->read = qca8k_internal_mdio_read; -- bus->write = qca8k_internal_mdio_write; -- return devm_of_mdiobus_register(priv->dev, bus, mdio); -- } -- -- /* If a mapping can't be found the legacy mapping is used, -- * using the qca8k_port_to_phy function -- */ -- bus->name = "qca8k-legacy slave mii"; -- bus->read = qca8k_legacy_mdio_read; -- bus->write = qca8k_legacy_mdio_write; -- return devm_mdiobus_register(priv->dev, bus); --} -- --static int --qca8k_setup_mdio_bus(struct qca8k_priv *priv) --{ -- u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -- struct device_node *ports, *port; -- phy_interface_t mode; -- int err; -- -- ports = of_get_child_by_name(priv->dev->of_node, "ports"); -- if (!ports) -- ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -- -- if (!ports) -- return -EINVAL; -- -- for_each_available_child_of_node(ports, port) { -- err = of_property_read_u32(port, "reg", ®); -- if (err) { -- of_node_put(port); -- of_node_put(ports); -- return err; -- } -- -- if (!dsa_is_user_port(priv->ds, reg)) -- continue; -- -- of_get_phy_mode(port, &mode); -- -- if (of_property_read_bool(port, "phy-handle") && -- mode != PHY_INTERFACE_MODE_INTERNAL) -- external_mdio_mask |= BIT(reg); -- else -- internal_mdio_mask |= BIT(reg); -- } -- -- of_node_put(ports); -- if (!external_mdio_mask && !internal_mdio_mask) { -- dev_err(priv->dev, "no PHYs are defined.\n"); -- return -EINVAL; -- } -- -- /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -- * the MDIO_MASTER register also _disconnects_ the external MDC -- * passthrough to the internal PHYs. It's not possible to use both -- * configurations at the same time! -- * -- * Because this came up during the review process: -- * If the external mdio-bus driver is capable magically disabling -- * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -- * accessors for the time being, it would be possible to pull this -- * off. -- */ -- if (!!external_mdio_mask && !!internal_mdio_mask) { -- dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -- return -EINVAL; -- } -- -- if (external_mdio_mask) { -- /* Make sure to disable the internal mdio bus in cases -- * a dt-overlay and driver reload changed the configuration -- */ -- -- return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_EN); -- } -- -- return qca8k_mdio_register(priv); --} -- --static int --qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) --{ -- u32 mask = 0; -- int ret = 0; -- -- /* SoC specific settings for ipq8064. -- * If more device require this consider adding -- * a dedicated binding. -- */ -- if (of_machine_is_compatible("qcom,ipq8064")) -- mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -- -- /* SoC specific settings for ipq8065 */ -- if (of_machine_is_compatible("qcom,ipq8065")) -- mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -- -- if (mask) { -- ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -- QCA8K_MAC_PWR_RGMII0_1_8V | -- QCA8K_MAC_PWR_RGMII1_1_8V, -- mask); -- } -- -- return ret; --} -- --static int qca8k_find_cpu_port(struct dsa_switch *ds) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Find the connected cpu port. Valid port are 0 or 6 */ -- if (dsa_is_cpu_port(ds, 0)) -- return 0; -- -- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -- -- if (dsa_is_cpu_port(ds, 6)) -- return 6; -- -- return -EINVAL; --} -- --static int --qca8k_setup_of_pws_reg(struct qca8k_priv *priv) --{ -- struct device_node *node = priv->dev->of_node; -- const struct qca8k_match_data *data; -- u32 val = 0; -- int ret; -- -- /* QCA8327 require to set to the correct mode. -- * His bigger brother QCA8328 have the 172 pin layout. -- * Should be applied by default but we set this just to make sure. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- data = of_device_get_match_data(priv->dev); -- -- /* Set the correct package of 148 pin for QCA8327 */ -- if (data->reduced_package) -- val |= QCA8327_PWS_PACKAGE148_EN; -- -- ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -- val); -- if (ret) -- return ret; -- } -- -- if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -- val |= QCA8K_PWS_POWER_ON_SEL; -- -- if (of_property_read_bool(node, "qca,led-open-drain")) { -- if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -- dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -- return -EINVAL; -- } -- -- val |= QCA8K_PWS_LED_OPEN_EN_CSR; -- } -- -- return qca8k_rmw(priv, QCA8K_REG_PWS, -- QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -- val); --} -- --static int --qca8k_parse_port_config(struct qca8k_priv *priv) --{ -- int port, cpu_port_index = -1, ret; -- struct device_node *port_dn; -- phy_interface_t mode; -- struct dsa_port *dp; -- u32 delay; -- -- /* We have 2 CPU port. Check them */ -- for (port = 0; port < QCA8K_NUM_PORTS; port++) { -- /* Skip every other port */ -- if (port != 0 && port != 6) -- continue; -- -- dp = dsa_to_port(priv->ds, port); -- port_dn = dp->dn; -- cpu_port_index++; -- -- if (!of_device_is_available(port_dn)) -- continue; -- -- ret = of_get_phy_mode(port_dn, &mode); -- if (ret) -- continue; -- -- switch (mode) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- case PHY_INTERFACE_MODE_SGMII: -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID) -- delay = 1; -- -- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { -- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -- -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- delay = 2; -- -- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { -- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -- -- /* Skip sgmii parsing for rgmii* mode */ -- if (mode == PHY_INTERFACE_MODE_RGMII || -- mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- break; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -- priv->ports_config.sgmii_tx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -- priv->ports_config.sgmii_rx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -- priv->ports_config.sgmii_enable_pll = true; -- -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -- priv->ports_config.sgmii_enable_pll = false; -- } -- -- if (priv->switch_revision < 2) -- dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -- } -- -- break; -- default: -- continue; -- } -- } -- -- return 0; --} -- --static int --qca8k_setup(struct dsa_switch *ds) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, ret, i; -- u32 mask; -- -- cpu_port = qca8k_find_cpu_port(ds); -- if (cpu_port < 0) { -- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -- return cpu_port; -- } -- -- /* Parse CPU port config to be later used in phy_link mac_config */ -- ret = qca8k_parse_port_config(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_mdio_bus(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_of_pws_reg(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_mac_pwr_sel(priv); -- if (ret) -- return ret; -- -- /* Make sure MAC06 is disabled */ -- ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, -- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -- if (ret) { -- dev_err(priv->dev, "failed disabling MAC06 exchange"); -- return ret; -- } -- -- /* Enable CPU Port */ -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -- if (ret) { -- dev_err(priv->dev, "failed enabling CPU port"); -- return ret; -- } -- -- /* Enable MIB counters */ -- ret = qca8k_mib_init(priv); -- if (ret) -- dev_warn(priv->dev, "mib init failed"); -- -- /* Initial setup of all ports */ -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* Disable forwarding by default on all ports */ -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, 0); -- if (ret) -- return ret; -- -- /* Enable QCA header mode on all cpu ports */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | -- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); -- if (ret) { -- dev_err(priv->dev, "failed enabling QCA header mode"); -- return ret; -- } -- } -- -- /* Disable MAC by default on all user ports */ -- if (dsa_is_user_port(ds, i)) -- qca8k_port_set_status(priv, i, 0); -- } -- -- /* Forward all unknown frames to CPU port for Linux processing -- * Notice that in multi-cpu config only one port should be set -- * for igmp, unknown, multicast and broadcast packet -- */ -- ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); -- if (ret) -- return ret; -- -- /* Setup connection between CPU port & user ports -- * Configure specific switch configuration for ports -- */ -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* CPU port gets connected to all user ports of the switch */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -- if (ret) -- return ret; -- } -- -- /* Individual user ports get connected to CPU port only */ -- if (dsa_is_user_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, -- BIT(cpu_port)); -- if (ret) -- return ret; -- -- /* Enable ARP Auto-learning by default */ -- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_LEARN); -- if (ret) -- return ret; -- -- /* For port based vlans to work we need to set the -- * default egress vid -- */ -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -- QCA8K_EGREES_VLAN_PORT_MASK(i), -- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -- if (ret) -- return ret; -- } -- -- /* The port 5 of the qca8337 have some problem in flood condition. The -- * original legacy driver had some specific buffer and priority settings -- * for the different port suggested by the QCA switch team. Add this -- * missing settings to improve switch stability under load condition. -- * This problem is limited to qca8337 and other qca8k switch are not affected. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) { -- switch (i) { -- /* The 2 CPU port and port 5 requires some different -- * priority than any other ports. -- */ -- case 0: -- case 5: -- case 6: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -- break; -- default: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -- } -- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -- -- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN; -- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN, -- mask); -- } -- } -- -- /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -- qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -- QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, -- mask); -- } -- -- /* Setup our port MTUs to match power on defaults */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); -- if (ret) -- dev_warn(priv->dev, "failed setting MTU settings"); -- -- /* Flush the FDB table */ -- qca8k_fdb_flush(priv); -- -- /* We don't have interrupts for link changes, so we need to poll */ -- ds->pcs_poll = true; -- -- /* Set min a max ageing value supported */ -- ds->ageing_time_min = 7000; -- ds->ageing_time_max = 458745000; -- -- /* Set max number of LAGs supported */ -- ds->num_lag_ids = QCA8K_NUM_LAGS; -- -- return 0; --} -- --static void --qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -- u32 reg) --{ -- u32 delay, val = 0; -- int ret; -- -- /* Delay can be declared in 3 different way. -- * Mode to rgmii and internal-delay standard binding defined -- * rgmii-id or rgmii-tx/rx phy mode set. -- * The parse logic set a delay different than 0 only when one -- * of the 3 different way is used. In all other case delay is -- * not enabled. With ID or TX/RXID delay is enabled and set -- * to the default and recommended value. -- */ -- if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -- } -- -- if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -- } -- -- /* Set RGMII delay based on the selected values */ -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -- val); -- if (ret) -- dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -- cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); --} -- --static void --qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, -- const struct phylink_link_state *state) --{ -- struct qca8k_priv *priv = ds->priv; -- int cpu_port_index, ret; -- u32 reg, val; -- -- switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -- return; -- -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT0; -- break; -- case 1: -- case 2: -- case 3: -- case 4: -- case 5: -- /* Internal PHY, nothing to do */ -- return; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -- return; -- -- reg = QCA8K_REG_PORT6_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT6; -- break; -- default: -- dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -- return; -- } -- -- if (port != 6 && phylink_autoneg_inband(mode)) { -- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -- __func__); -- return; -- } -- -- switch (state->interface) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -- -- /* Configure rgmii delay */ -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- /* QCA8337 requires to set rgmii rx delay for all ports. -- * This is enabled through PORT5_PAD_CTRL for all ports, -- * rather than individual port registers. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) -- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -- break; -- case PHY_INTERFACE_MODE_SGMII: -- case PHY_INTERFACE_MODE_1000BASEX: -- /* Enable SGMII on the port */ -- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -- -- /* Enable/disable SerDes auto-negotiation as necessary */ -- ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -- if (ret) -- return; -- if (phylink_autoneg_inband(mode)) -- val &= ~QCA8K_PWS_SERDES_AEN_DIS; -- else -- val |= QCA8K_PWS_SERDES_AEN_DIS; -- qca8k_write(priv, QCA8K_REG_PWS, val); -- -- /* Configure the SGMII parameters */ -- ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -- if (ret) -- return; -- -- val |= QCA8K_SGMII_EN_SD; -- -- if (priv->ports_config.sgmii_enable_pll) -- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -- QCA8K_SGMII_EN_TX; -- -- if (dsa_is_cpu_port(ds, port)) { -- /* CPU port, we're talking to the CPU MAC, be a PHY */ -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_PHY; -- } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_MAC; -- } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_BASEX; -- } -- -- qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -- -- /* From original code is reported port instability as SGMII also -- * require delay set. Apply advised values here or take them from DT. -- */ -- if (state->interface == PHY_INTERFACE_MODE_SGMII) -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -- * falling edge is set writing in the PORT0 PAD reg -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327 || -- priv->switch_id == QCA8K_ID_QCA8337) -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- -- val = 0; -- -- /* SGMII Clock phase configuration */ -- if (priv->ports_config.sgmii_rx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -- -- if (priv->ports_config.sgmii_tx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -- -- if (val) -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -- val); -- -- break; -- default: -- dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -- phy_modes(state->interface), port); -- return; -- } --} -- --static void --qca8k_phylink_validate(struct dsa_switch *ds, int port, -- unsigned long *supported, -- struct phylink_link_state *state) --{ -- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- -- switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -- goto unsupported; -- break; -- case 1: -- case 2: -- case 3: -- case 4: -- case 5: -- /* Internal PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_GMII && -- state->interface != PHY_INTERFACE_MODE_INTERNAL) -- goto unsupported; -- break; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -- goto unsupported; -- break; -- default: --unsupported: -- linkmode_zero(supported); -- return; -- } -- -- phylink_set_port_modes(mask); -- phylink_set(mask, Autoneg); -- -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -- -- if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -- phylink_set(mask, 1000baseX_Full); -- -- phylink_set(mask, Pause); -- phylink_set(mask, Asym_Pause); -- -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); --} -- --static int --qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, -- struct phylink_link_state *state) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg; -- int ret; -- -- ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); -- if (ret < 0) -- return ret; -- -- state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); -- state->an_complete = state->link; -- state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); -- state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : -- DUPLEX_HALF; -- -- switch (reg & QCA8K_PORT_STATUS_SPEED) { -- case QCA8K_PORT_STATUS_SPEED_10: -- state->speed = SPEED_10; -- break; -- case QCA8K_PORT_STATUS_SPEED_100: -- state->speed = SPEED_100; -- break; -- case QCA8K_PORT_STATUS_SPEED_1000: -- state->speed = SPEED_1000; -- break; -- default: -- state->speed = SPEED_UNKNOWN; -- break; -- } -- -- state->pause = MLO_PAUSE_NONE; -- if (reg & QCA8K_PORT_STATUS_RXFLOW) -- state->pause |= MLO_PAUSE_RX; -- if (reg & QCA8K_PORT_STATUS_TXFLOW) -- state->pause |= MLO_PAUSE_TX; -- -- return 1; --} -- --static void --qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, -- phy_interface_t interface) --{ -- struct qca8k_priv *priv = ds->priv; -- -- qca8k_port_set_status(priv, port, 0); --} -- --static void --qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, -- phy_interface_t interface, struct phy_device *phydev, -- int speed, int duplex, bool tx_pause, bool rx_pause) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg; -- -- if (phylink_autoneg_inband(mode)) { -- reg = QCA8K_PORT_STATUS_LINK_AUTO; -- } else { -- switch (speed) { -- case SPEED_10: -- reg = QCA8K_PORT_STATUS_SPEED_10; -- break; -- case SPEED_100: -- reg = QCA8K_PORT_STATUS_SPEED_100; -- break; -- case SPEED_1000: -- reg = QCA8K_PORT_STATUS_SPEED_1000; -- break; -- default: -- reg = QCA8K_PORT_STATUS_LINK_AUTO; -- break; -- } -- -- if (duplex == DUPLEX_FULL) -- reg |= QCA8K_PORT_STATUS_DUPLEX; -- -- if (rx_pause || dsa_is_cpu_port(ds, port)) -- reg |= QCA8K_PORT_STATUS_RXFLOW; -- -- if (tx_pause || dsa_is_cpu_port(ds, port)) -- reg |= QCA8K_PORT_STATUS_TXFLOW; -- } -- -- reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -- -- qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); --} -- --static void --qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) --{ -- const struct qca8k_match_data *match_data; -- struct qca8k_priv *priv = ds->priv; -- int i; -- -- if (stringset != ETH_SS_STATS) -- return; -- -- match_data = of_device_get_match_data(priv->dev); -- -- for (i = 0; i < match_data->mib_count; i++) -- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -- ETH_GSTRING_LEN); --} -- --static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) --{ -- const struct qca8k_match_data *match_data; -- struct qca8k_mib_eth_data *mib_eth_data; -- struct qca8k_priv *priv = ds->priv; -- const struct qca8k_mib_desc *mib; -- struct mib_ethhdr *mib_ethhdr; -- int i, mib_len, offset = 0; -- u64 *data; -- u8 port; -- -- mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); -- mib_eth_data = &priv->mib_eth_data; -- -- /* The switch autocast every port. Ignore other packet and -- * parse only the requested one. -- */ -- port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); -- if (port != mib_eth_data->req_port) -- goto exit; -- -- match_data = device_get_match_data(priv->dev); -- data = mib_eth_data->data; -- -- for (i = 0; i < match_data->mib_count; i++) { -- mib = &ar8327_mib[i]; -- -- /* First 3 mib are present in the skb head */ -- if (i < 3) { -- data[i] = mib_ethhdr->data[i]; -- continue; -- } -- -- mib_len = sizeof(uint32_t); -- -- /* Some mib are 64 bit wide */ -- if (mib->size == 2) -- mib_len = sizeof(uint64_t); -- -- /* Copy the mib value from packet to the */ -- memcpy(data + i, skb->data + offset, mib_len); -- -- /* Set the offset for the next mib */ -- offset += mib_len; -- } -- --exit: -- /* Complete on receiving all the mib packet */ -- if (refcount_dec_and_test(&mib_eth_data->port_parsed)) -- complete(&mib_eth_data->rw_done); --} -- --static int --qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) --{ -- struct dsa_port *dp = dsa_to_port(ds, port); -- struct qca8k_mib_eth_data *mib_eth_data; -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- mib_eth_data = &priv->mib_eth_data; -- -- mutex_lock(&mib_eth_data->mutex); -- -- reinit_completion(&mib_eth_data->rw_done); -- -- mib_eth_data->req_port = dp->index; -- mib_eth_data->data = data; -- refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); -- -- mutex_lock(&priv->reg_mutex); -- -- /* Send mib autocast request */ -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | -- QCA8K_MIB_BUSY); -- -- mutex_unlock(&priv->reg_mutex); -- -- if (ret) -- goto exit; -- -- ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); -- --exit: -- mutex_unlock(&mib_eth_data->mutex); -- -- return ret; --} -- --static void --qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -- uint64_t *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- const struct qca8k_match_data *match_data; -- const struct qca8k_mib_desc *mib; -- u32 reg, i, val; -- u32 hi = 0; -- int ret; -- -- if (priv->mgmt_master && -- qca8k_get_ethtool_stats_eth(ds, port, data) > 0) -- return; -- -- match_data = of_device_get_match_data(priv->dev); -- -- for (i = 0; i < match_data->mib_count; i++) { -- mib = &ar8327_mib[i]; -- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -- -- ret = qca8k_read(priv, reg, &val); -- if (ret < 0) -- continue; -- -- if (mib->size == 2) { -- ret = qca8k_read(priv, reg + 4, &hi); -- if (ret < 0) -- continue; -- } -- -- data[i] = val; -- if (mib->size == 2) -- data[i] |= (u64)hi << 32; -- } --} -- --static int --qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) --{ -- const struct qca8k_match_data *match_data; -- struct qca8k_priv *priv = ds->priv; -- -- if (sset != ETH_SS_STATS) -- return 0; -- -- match_data = of_device_get_match_data(priv->dev); -- -- return match_data->mib_count; --} -- --static int --qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -- u32 reg; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -- if (ret < 0) -- goto exit; -- -- if (eee->eee_enabled) -- reg |= lpi_en; -- else -- reg &= ~lpi_en; -- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) --{ -- /* Nothing to do on the port's MAC */ -- return 0; --} -- --static void --qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 stp_state; -- -- switch (state) { -- case BR_STATE_DISABLED: -- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -- break; -- case BR_STATE_BLOCKING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -- break; -- case BR_STATE_LISTENING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -- break; -- case BR_STATE_LEARNING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -- break; -- case BR_STATE_FORWARDING: -- default: -- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -- break; -- } -- -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); --} -- --static int --qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int port_mask, cpu_port; -- int i, ret; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- port_mask = BIT(cpu_port); -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Add this port to the portvlan mask of the other ports -- * in the bridge -- */ -- ret = regmap_set_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- if (ret) -- return ret; -- if (i != port) -- port_mask |= BIT(i); -- } -- -- /* Add all other ports to this ports portvlan mask */ -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, port_mask); -- -- return ret; --} -- --static void --qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, i; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Remove this port to the portvlan mask of the other ports -- * in the bridge -- */ -- regmap_clear_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- } -- -- /* Set the cpu port to be the only one in the portvlan mask of -- * this port -- */ -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); --} -- --static void --qca8k_port_fast_age(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) --{ -- struct qca8k_priv *priv = ds->priv; -- unsigned int secs = msecs / 1000; -- u32 val; -- -- /* AGE_TIME reg is set in 7s step */ -- val = secs / 7; -- -- /* Handle case with 0 as val to NOT disable -- * learning -- */ -- if (!val) -- val = 1; -- -- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -- QCA8K_ATU_AGE_TIME(val)); --} -- --static int --qca8k_port_enable(struct dsa_switch *ds, int port, -- struct phy_device *phy) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 1); -- priv->port_enabled_map |= BIT(port); -- -- if (dsa_is_user_port(ds, port)) -- phy_support_asym_pause(phy); -- -- return 0; --} -- --static void --qca8k_port_disable(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 0); -- priv->port_enabled_map &= ~BIT(port); --} -- --static int --qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- /* We have only have a general MTU setting. -- * DSA always set the CPU port's MTU to the largest MTU of the slave -- * ports. -- * Setting MTU just for the CPU port is sufficient to correctly set a -- * value for every port. -- */ -- if (!dsa_is_cpu_port(ds, port)) -- return 0; -- -- /* To change the MAX_FRAME_SIZE the cpu ports must be off or -- * the switch panics. -- * Turn off both cpu ports before applying the new value to prevent -- * this. -- */ -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 0); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 0); -- -- /* Include L2 header / FCS length */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); -- -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 1); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 1); -- -- return ret; --} -- --static int --qca8k_port_max_mtu(struct dsa_switch *ds, int port) --{ -- return QCA8K_MAX_MTU; --} -- --static int --qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -- u16 port_mask, u16 vid) --{ -- /* Set the vid to the port vlan id if no vid is set */ -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_add(priv, addr, port_mask, vid, -- QCA8K_ATU_STATUS_STATIC); --} -- --static int --qca8k_port_fdb_add(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_del(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_del(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -- dsa_fdb_dump_cb_t *cb, void *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- struct qca8k_fdb _fdb = { 0 }; -- int cnt = QCA8K_NUM_FDB_RECORDS; -- bool is_static; -- int ret = 0; -- -- mutex_lock(&priv->reg_mutex); -- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -- if (!_fdb.aging) -- break; -- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -- ret = cb(_fdb.mac, _fdb.vid, is_static, data); -- if (ret) -- break; -- } -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --qca8k_port_mdb_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); --} -- --static int --qca8k_port_mdb_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); --} -- --static int --qca8k_port_mirror_add(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror, -- bool ingress) --{ -- struct qca8k_priv *priv = ds->priv; -- int monitor_port, ret; -- u32 reg, val; -- -- /* Check for existent entry */ -- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -- return -EEXIST; -- -- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -- if (ret) -- return ret; -- -- /* QCA83xx can have only one port set to mirror mode. -- * Check that the correct port is requested and return error otherwise. -- * When no mirror port is set, the values is set to 0xF -- */ -- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -- return -EEXIST; -- -- /* Set the monitor port */ -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -- mirror->to_local_port); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- return ret; -- -- if (ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_update_bits(priv->regmap, reg, val, val); -- if (ret) -- return ret; -- -- /* Track mirror port for tx and rx to decide when the -- * mirror port has to be disabled. -- */ -- if (ingress) -- priv->mirror_rx |= BIT(port); -- else -- priv->mirror_tx |= BIT(port); -- -- return 0; --} -- --static void --qca8k_port_mirror_del(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg, val; -- int ret; -- -- if (mirror->ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_clear_bits(priv->regmap, reg, val); -- if (ret) -- goto err; -- -- if (mirror->ingress) -- priv->mirror_rx &= ~BIT(port); -- else -- priv->mirror_tx &= ~BIT(port); -- -- /* No port set to send packet to mirror port. Disable mirror port */ -- if (!priv->mirror_rx && !priv->mirror_tx) { -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- goto err; -- } --err: -- dev_err(priv->dev, "Failed to del mirror port from %d", port); --} -- --static int --qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -- struct netlink_ext_ack *extack) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- if (vlan_filtering) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -- } else { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan, -- struct netlink_ext_ack *extack) --{ -- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -- if (ret) { -- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -- return ret; -- } -- -- if (pvid) { -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -- QCA8K_EGREES_VLAN_PORT_MASK(port), -- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -- QCA8K_PORT_VLAN_CVID(vlan->vid) | -- QCA8K_PORT_VLAN_SVID(vlan->vid)); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_del(priv, port, vlan->vid); -- if (ret) -- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -- -- return ret; --} -- --static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Communicate to the phy internal driver the switch revision. -- * Based on the switch revision different values needs to be -- * set to the dbg and mmd reg on the phy. -- * The first 2 bit are used to communicate the switch revision -- * to the phy driver. -- */ -- if (port > 0 && port < 6) -- return priv->switch_revision; -- -- return 0; --} -- --static enum dsa_tag_protocol --qca8k_get_tag_protocol(struct dsa_switch *ds, int port, -- enum dsa_tag_protocol mp) --{ -- return DSA_TAG_PROTO_QCA; --} -- --static bool --qca8k_lag_can_offload(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct dsa_port *dp; -- int id, members = 0; -- -- id = dsa_lag_id(ds->dst, lag); -- if (id < 0 || id >= ds->num_lag_ids) -- return false; -- -- dsa_lag_foreach_port(dp, ds->dst, lag) -- /* Includes the port joining the LAG */ -- members++; -- -- if (members > QCA8K_NUM_PORTS_FOR_LAG) -- return false; -- -- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -- return false; -- -- if (info->hash_type != NETDEV_LAG_HASH_L2 && -- info->hash_type != NETDEV_LAG_HASH_L23) -- return false; -- -- return true; --} -- --static int --qca8k_lag_setup_hash(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct qca8k_priv *priv = ds->priv; -- bool unique_lag = true; -- u32 hash = 0; -- int i, id; -- -- id = dsa_lag_id(ds->dst, lag); -- -- switch (info->hash_type) { -- case NETDEV_LAG_HASH_L23: -- hash |= QCA8K_TRUNK_HASH_SIP_EN; -- hash |= QCA8K_TRUNK_HASH_DIP_EN; -- fallthrough; -- case NETDEV_LAG_HASH_L2: -- hash |= QCA8K_TRUNK_HASH_SA_EN; -- hash |= QCA8K_TRUNK_HASH_DA_EN; -- break; -- default: /* We should NEVER reach this */ -- return -EOPNOTSUPP; -- } -- -- /* Check if we are the unique configured LAG */ -- dsa_lags_foreach_id(i, ds->dst) -- if (i != id && dsa_lag_dev(ds->dst, i)) { -- unique_lag = false; -- break; -- } -- -- /* Hash Mode is global. Make sure the same Hash Mode -- * is set to all the 4 possible lag. -- * If we are the unique LAG we can set whatever hash -- * mode we want. -- * To change hash mode it's needed to remove all LAG -- * and change the mode with the latest. -- */ -- if (unique_lag) { -- priv->lag_hash_mode = hash; -- } else if (priv->lag_hash_mode != hash) { -- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -- return -EOPNOTSUPP; -- } -- -- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -- QCA8K_TRUNK_HASH_MASK, hash); --} -- --static int --qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -- struct net_device *lag, bool delete) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret, id, i; -- u32 val; -- -- id = dsa_lag_id(ds->dst, lag); -- -- /* Read current port member */ -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -- if (ret) -- return ret; -- -- /* Shift val to the correct trunk */ -- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -- if (delete) -- val &= ~BIT(port); -- else -- val |= BIT(port); -- -- /* Update port member. With empty portmap disable trunk */ -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -- QCA8K_REG_GOL_TRUNK_MEMBER(id) | -- QCA8K_REG_GOL_TRUNK_EN(id), -- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -- -- /* Search empty member if adding or port on deleting */ -- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -- if (ret) -- return ret; -- -- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -- -- if (delete) { -- /* If port flagged to be disabled assume this member is -- * empty -- */ -- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -- if (val != port) -- continue; -- } else { -- /* If port flagged to be enabled assume this member is -- * already set -- */ -- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- } -- -- /* We have found the member to add/remove */ -- break; -- } -- -- /* Set port in the correct port mask or disable port if in delete mode */ -- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); --} -- --static int --qca8k_port_lag_join(struct dsa_switch *ds, int port, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- int ret; -- -- if (!qca8k_lag_can_offload(ds, lag, info)) -- return -EOPNOTSUPP; -- -- ret = qca8k_lag_setup_hash(ds, lag, info); -- if (ret) -- return ret; -- -- return qca8k_lag_refresh_portmap(ds, port, lag, false); --} -- --static int --qca8k_port_lag_leave(struct dsa_switch *ds, int port, -- struct net_device *lag) --{ -- return qca8k_lag_refresh_portmap(ds, port, lag, true); --} -- --static void --qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, -- bool operational) --{ -- struct dsa_port *dp = master->dsa_ptr; -- struct qca8k_priv *priv = ds->priv; -- -- /* Ethernet MIB/MDIO is only supported for CPU port 0 */ -- if (dp->index != 0) -- return; -- -- mutex_lock(&priv->mgmt_eth_data.mutex); -- mutex_lock(&priv->mib_eth_data.mutex); -- -- priv->mgmt_master = operational ? (struct net_device *)master : NULL; -- -- mutex_unlock(&priv->mib_eth_data.mutex); -- mutex_unlock(&priv->mgmt_eth_data.mutex); --} -- --static int qca8k_connect_tag_protocol(struct dsa_switch *ds, -- enum dsa_tag_protocol proto) --{ -- struct qca_tagger_data *tagger_data; -- -- switch (proto) { -- case DSA_TAG_PROTO_QCA: -- tagger_data = ds->tagger_data; -- -- tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -- tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; -- -- break; -- default: -- return -EOPNOTSUPP; -- } -- -- return 0; --} -- --static const struct dsa_switch_ops qca8k_switch_ops = { -- .get_tag_protocol = qca8k_get_tag_protocol, -- .setup = qca8k_setup, -- .get_strings = qca8k_get_strings, -- .get_ethtool_stats = qca8k_get_ethtool_stats, -- .get_sset_count = qca8k_get_sset_count, -- .set_ageing_time = qca8k_set_ageing_time, -- .get_mac_eee = qca8k_get_mac_eee, -- .set_mac_eee = qca8k_set_mac_eee, -- .port_enable = qca8k_port_enable, -- .port_disable = qca8k_port_disable, -- .port_change_mtu = qca8k_port_change_mtu, -- .port_max_mtu = qca8k_port_max_mtu, -- .port_stp_state_set = qca8k_port_stp_state_set, -- .port_bridge_join = qca8k_port_bridge_join, -- .port_bridge_leave = qca8k_port_bridge_leave, -- .port_fast_age = qca8k_port_fast_age, -- .port_fdb_add = qca8k_port_fdb_add, -- .port_fdb_del = qca8k_port_fdb_del, -- .port_fdb_dump = qca8k_port_fdb_dump, -- .port_mdb_add = qca8k_port_mdb_add, -- .port_mdb_del = qca8k_port_mdb_del, -- .port_mirror_add = qca8k_port_mirror_add, -- .port_mirror_del = qca8k_port_mirror_del, -- .port_vlan_filtering = qca8k_port_vlan_filtering, -- .port_vlan_add = qca8k_port_vlan_add, -- .port_vlan_del = qca8k_port_vlan_del, -- .phylink_validate = qca8k_phylink_validate, -- .phylink_mac_link_state = qca8k_phylink_mac_link_state, -- .phylink_mac_config = qca8k_phylink_mac_config, -- .phylink_mac_link_down = qca8k_phylink_mac_link_down, -- .phylink_mac_link_up = qca8k_phylink_mac_link_up, -- .get_phy_flags = qca8k_get_phy_flags, -- .port_lag_join = qca8k_port_lag_join, -- .port_lag_leave = qca8k_port_lag_leave, -- .master_state_change = qca8k_master_change, -- .connect_tag_protocol = qca8k_connect_tag_protocol, --}; -- --static int qca8k_read_switch_id(struct qca8k_priv *priv) --{ -- const struct qca8k_match_data *data; -- u32 val; -- u8 id; -- int ret; -- -- /* get the switches ID from the compatible */ -- data = of_device_get_match_data(priv->dev); -- if (!data) -- return -ENODEV; -- -- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -- if (ret < 0) -- return -ENODEV; -- -- id = QCA8K_MASK_CTRL_DEVICE_ID(val); -- if (id != data->id) { -- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); -- return -ENODEV; -- } -- -- priv->switch_id = id; -- -- /* Save revision to communicate to the internal PHY driver */ -- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -- -- return 0; --} -- --static int --qca8k_sw_probe(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv; -- int ret; -- -- /* allocate the private data struct so that we can probe the switches -- * ID register -- */ -- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -- -- priv->bus = mdiodev->bus; -- priv->dev = &mdiodev->dev; -- -- priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -- GPIOD_ASIS); -- if (IS_ERR(priv->reset_gpio)) -- return PTR_ERR(priv->reset_gpio); -- -- if (priv->reset_gpio) { -- gpiod_set_value_cansleep(priv->reset_gpio, 1); -- /* The active low duration must be greater than 10 ms -- * and checkpatch.pl wants 20 ms. -- */ -- msleep(20); -- gpiod_set_value_cansleep(priv->reset_gpio, 0); -- } -- -- /* Start by setting up the register mapping */ -- priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, -- &qca8k_regmap_config); -- if (IS_ERR(priv->regmap)) { -- dev_err(priv->dev, "regmap initialization failed"); -- return PTR_ERR(priv->regmap); -- } -- -- priv->mdio_cache.page = 0xffff; -- priv->mdio_cache.lo = 0xffff; -- priv->mdio_cache.hi = 0xffff; -- -- /* Check the detected switch id */ -- ret = qca8k_read_switch_id(priv); -- if (ret) -- return ret; -- -- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -- if (!priv->ds) -- return -ENOMEM; -- -- mutex_init(&priv->mgmt_eth_data.mutex); -- init_completion(&priv->mgmt_eth_data.rw_done); -- -- mutex_init(&priv->mib_eth_data.mutex); -- init_completion(&priv->mib_eth_data.rw_done); -- -- priv->ds->dev = &mdiodev->dev; -- priv->ds->num_ports = QCA8K_NUM_PORTS; -- priv->ds->priv = priv; -- priv->ds->ops = &qca8k_switch_ops; -- mutex_init(&priv->reg_mutex); -- dev_set_drvdata(&mdiodev->dev, priv); -- -- return dsa_register_switch(priv->ds); --} -- --static void --qca8k_sw_remove(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -- int i; -- -- if (!priv) -- return; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) -- qca8k_port_set_status(priv, i, 0); -- -- dsa_unregister_switch(priv->ds); -- -- dev_set_drvdata(&mdiodev->dev, NULL); --} -- --static void qca8k_sw_shutdown(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -- -- if (!priv) -- return; -- -- dsa_switch_shutdown(priv->ds); -- -- dev_set_drvdata(&mdiodev->dev, NULL); --} -- --#ifdef CONFIG_PM_SLEEP --static void --qca8k_set_pm(struct qca8k_priv *priv, int enable) --{ -- int port; -- -- for (port = 0; port < QCA8K_NUM_PORTS; port++) { -- /* Do not enable on resume if the port was -- * disabled before. -- */ -- if (!(priv->port_enabled_map & BIT(port))) -- continue; -- -- qca8k_port_set_status(priv, port, enable); -- } --} -- --static int qca8k_suspend(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 0); -- -- return dsa_switch_suspend(priv->ds); --} -- --static int qca8k_resume(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 1); -- -- return dsa_switch_resume(priv->ds); --} --#endif /* CONFIG_PM_SLEEP */ -- --static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -- qca8k_suspend, qca8k_resume); -- --static const struct qca8k_match_data qca8327 = { -- .id = QCA8K_ID_QCA8327, -- .reduced_package = true, -- .mib_count = QCA8K_QCA832X_MIB_COUNT, --}; -- --static const struct qca8k_match_data qca8328 = { -- .id = QCA8K_ID_QCA8327, -- .mib_count = QCA8K_QCA832X_MIB_COUNT, --}; -- --static const struct qca8k_match_data qca833x = { -- .id = QCA8K_ID_QCA8337, -- .mib_count = QCA8K_QCA833X_MIB_COUNT, --}; -- --static const struct of_device_id qca8k_of_match[] = { -- { .compatible = "qca,qca8327", .data = &qca8327 }, -- { .compatible = "qca,qca8328", .data = &qca8328 }, -- { .compatible = "qca,qca8334", .data = &qca833x }, -- { .compatible = "qca,qca8337", .data = &qca833x }, -- { /* sentinel */ }, --}; -- --static struct mdio_driver qca8kmdio_driver = { -- .probe = qca8k_sw_probe, -- .remove = qca8k_sw_remove, -- .shutdown = qca8k_sw_shutdown, -- .mdiodrv.driver = { -- .name = "qca8k", -- .of_match_table = qca8k_of_match, -- .pm = &qca8k_pm_ops, -- }, --}; -- --mdio_module_driver(qca8kmdio_driver); -- --MODULE_AUTHOR("Mathieu Olivari, John Crispin "); --MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); --MODULE_LICENSE("GPL v2"); --MODULE_ALIAS("platform:qca8k"); ---- a/drivers/net/dsa/qca8k.h -+++ /dev/null -@@ -1,411 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ --/* -- * Copyright (C) 2009 Felix Fietkau -- * Copyright (C) 2011-2012 Gabor Juhos -- * Copyright (c) 2015, The Linux Foundation. All rights reserved. -- */ -- --#ifndef __QCA8K_H --#define __QCA8K_H -- --#include --#include --#include --#include -- --#define QCA8K_ETHERNET_MDIO_PRIORITY 7 --#define QCA8K_ETHERNET_PHY_PRIORITY 6 --#define QCA8K_ETHERNET_TIMEOUT 100 -- --#define QCA8K_NUM_PORTS 7 --#define QCA8K_NUM_CPU_PORTS 2 --#define QCA8K_MAX_MTU 9000 --#define QCA8K_NUM_LAGS 4 --#define QCA8K_NUM_PORTS_FOR_LAG 4 -- --#define PHY_ID_QCA8327 0x004dd034 --#define QCA8K_ID_QCA8327 0x12 --#define PHY_ID_QCA8337 0x004dd036 --#define QCA8K_ID_QCA8337 0x13 -- --#define QCA8K_QCA832X_MIB_COUNT 39 --#define QCA8K_QCA833X_MIB_COUNT 41 -- --#define QCA8K_BUSY_WAIT_TIMEOUT 2000 -- --#define QCA8K_NUM_FDB_RECORDS 2048 -- --#define QCA8K_PORT_VID_DEF 1 -- --/* Global control registers */ --#define QCA8K_REG_MASK_CTRL 0x000 --#define QCA8K_MASK_CTRL_REV_ID_MASK GENMASK(7, 0) --#define QCA8K_MASK_CTRL_REV_ID(x) FIELD_GET(QCA8K_MASK_CTRL_REV_ID_MASK, x) --#define QCA8K_MASK_CTRL_DEVICE_ID_MASK GENMASK(15, 8) --#define QCA8K_MASK_CTRL_DEVICE_ID(x) FIELD_GET(QCA8K_MASK_CTRL_DEVICE_ID_MASK, x) --#define QCA8K_REG_PORT0_PAD_CTRL 0x004 --#define QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN BIT(31) --#define QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE BIT(19) --#define QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE BIT(18) --#define QCA8K_REG_PORT5_PAD_CTRL 0x008 --#define QCA8K_REG_PORT6_PAD_CTRL 0x00c --#define QCA8K_PORT_PAD_RGMII_EN BIT(26) --#define QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK GENMASK(23, 22) --#define QCA8K_PORT_PAD_RGMII_TX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, x) --#define QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK GENMASK(21, 20) --#define QCA8K_PORT_PAD_RGMII_RX_DELAY(x) FIELD_PREP(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, x) --#define QCA8K_PORT_PAD_RGMII_TX_DELAY_EN BIT(25) --#define QCA8K_PORT_PAD_RGMII_RX_DELAY_EN BIT(24) --#define QCA8K_PORT_PAD_SGMII_EN BIT(7) --#define QCA8K_REG_PWS 0x010 --#define QCA8K_PWS_POWER_ON_SEL BIT(31) --/* This reg is only valid for QCA832x and toggle the package -- * type from 176 pin (by default) to 148 pin used on QCA8327 -- */ --#define QCA8327_PWS_PACKAGE148_EN BIT(30) --#define QCA8K_PWS_LED_OPEN_EN_CSR BIT(24) --#define QCA8K_PWS_SERDES_AEN_DIS BIT(7) --#define QCA8K_REG_MODULE_EN 0x030 --#define QCA8K_MODULE_EN_MIB BIT(0) --#define QCA8K_REG_MIB 0x034 --#define QCA8K_MIB_FUNC GENMASK(26, 24) --#define QCA8K_MIB_CPU_KEEP BIT(20) --#define QCA8K_MIB_BUSY BIT(17) --#define QCA8K_MDIO_MASTER_CTRL 0x3c --#define QCA8K_MDIO_MASTER_BUSY BIT(31) --#define QCA8K_MDIO_MASTER_EN BIT(30) --#define QCA8K_MDIO_MASTER_READ BIT(27) --#define QCA8K_MDIO_MASTER_WRITE 0 --#define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) --#define QCA8K_MDIO_MASTER_PHY_ADDR_MASK GENMASK(25, 21) --#define QCA8K_MDIO_MASTER_PHY_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_PHY_ADDR_MASK, x) --#define QCA8K_MDIO_MASTER_REG_ADDR_MASK GENMASK(20, 16) --#define QCA8K_MDIO_MASTER_REG_ADDR(x) FIELD_PREP(QCA8K_MDIO_MASTER_REG_ADDR_MASK, x) --#define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) --#define QCA8K_MDIO_MASTER_DATA(x) FIELD_PREP(QCA8K_MDIO_MASTER_DATA_MASK, x) --#define QCA8K_MDIO_MASTER_MAX_PORTS 5 --#define QCA8K_MDIO_MASTER_MAX_REG 32 --#define QCA8K_GOL_MAC_ADDR0 0x60 --#define QCA8K_GOL_MAC_ADDR1 0x64 --#define QCA8K_MAX_FRAME_SIZE 0x78 --#define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) --#define QCA8K_PORT_STATUS_SPEED GENMASK(1, 0) --#define QCA8K_PORT_STATUS_SPEED_10 0 --#define QCA8K_PORT_STATUS_SPEED_100 0x1 --#define QCA8K_PORT_STATUS_SPEED_1000 0x2 --#define QCA8K_PORT_STATUS_TXMAC BIT(2) --#define QCA8K_PORT_STATUS_RXMAC BIT(3) --#define QCA8K_PORT_STATUS_TXFLOW BIT(4) --#define QCA8K_PORT_STATUS_RXFLOW BIT(5) --#define QCA8K_PORT_STATUS_DUPLEX BIT(6) --#define QCA8K_PORT_STATUS_LINK_UP BIT(8) --#define QCA8K_PORT_STATUS_LINK_AUTO BIT(9) --#define QCA8K_PORT_STATUS_LINK_PAUSE BIT(10) --#define QCA8K_PORT_STATUS_FLOW_AUTO BIT(12) --#define QCA8K_REG_PORT_HDR_CTRL(_i) (0x9c + (_i * 4)) --#define QCA8K_PORT_HDR_CTRL_RX_MASK GENMASK(3, 2) --#define QCA8K_PORT_HDR_CTRL_TX_MASK GENMASK(1, 0) --#define QCA8K_PORT_HDR_CTRL_ALL 2 --#define QCA8K_PORT_HDR_CTRL_MGMT 1 --#define QCA8K_PORT_HDR_CTRL_NONE 0 --#define QCA8K_REG_SGMII_CTRL 0x0e0 --#define QCA8K_SGMII_EN_PLL BIT(1) --#define QCA8K_SGMII_EN_RX BIT(2) --#define QCA8K_SGMII_EN_TX BIT(3) --#define QCA8K_SGMII_EN_SD BIT(4) --#define QCA8K_SGMII_CLK125M_DELAY BIT(7) --#define QCA8K_SGMII_MODE_CTRL_MASK GENMASK(23, 22) --#define QCA8K_SGMII_MODE_CTRL(x) FIELD_PREP(QCA8K_SGMII_MODE_CTRL_MASK, x) --#define QCA8K_SGMII_MODE_CTRL_BASEX QCA8K_SGMII_MODE_CTRL(0x0) --#define QCA8K_SGMII_MODE_CTRL_PHY QCA8K_SGMII_MODE_CTRL(0x1) --#define QCA8K_SGMII_MODE_CTRL_MAC QCA8K_SGMII_MODE_CTRL(0x2) -- --/* MAC_PWR_SEL registers */ --#define QCA8K_REG_MAC_PWR_SEL 0x0e4 --#define QCA8K_MAC_PWR_RGMII1_1_8V BIT(18) --#define QCA8K_MAC_PWR_RGMII0_1_8V BIT(19) -- --/* EEE control registers */ --#define QCA8K_REG_EEE_CTRL 0x100 --#define QCA8K_REG_EEE_CTRL_LPI_EN(_i) ((_i + 1) * 2) -- --/* TRUNK_HASH_EN registers */ --#define QCA8K_TRUNK_HASH_EN_CTRL 0x270 --#define QCA8K_TRUNK_HASH_SIP_EN BIT(3) --#define QCA8K_TRUNK_HASH_DIP_EN BIT(2) --#define QCA8K_TRUNK_HASH_SA_EN BIT(1) --#define QCA8K_TRUNK_HASH_DA_EN BIT(0) --#define QCA8K_TRUNK_HASH_MASK GENMASK(3, 0) -- --/* ACL registers */ --#define QCA8K_REG_PORT_VLAN_CTRL0(_i) (0x420 + (_i * 8)) --#define QCA8K_PORT_VLAN_CVID_MASK GENMASK(27, 16) --#define QCA8K_PORT_VLAN_CVID(x) FIELD_PREP(QCA8K_PORT_VLAN_CVID_MASK, x) --#define QCA8K_PORT_VLAN_SVID_MASK GENMASK(11, 0) --#define QCA8K_PORT_VLAN_SVID(x) FIELD_PREP(QCA8K_PORT_VLAN_SVID_MASK, x) --#define QCA8K_REG_PORT_VLAN_CTRL1(_i) (0x424 + (_i * 8)) --#define QCA8K_REG_IPV4_PRI_BASE_ADDR 0x470 --#define QCA8K_REG_IPV4_PRI_ADDR_MASK 0x474 -- --/* Lookup registers */ --#define QCA8K_REG_ATU_DATA0 0x600 --#define QCA8K_ATU_ADDR2_MASK GENMASK(31, 24) --#define QCA8K_ATU_ADDR3_MASK GENMASK(23, 16) --#define QCA8K_ATU_ADDR4_MASK GENMASK(15, 8) --#define QCA8K_ATU_ADDR5_MASK GENMASK(7, 0) --#define QCA8K_REG_ATU_DATA1 0x604 --#define QCA8K_ATU_PORT_MASK GENMASK(22, 16) --#define QCA8K_ATU_ADDR0_MASK GENMASK(15, 8) --#define QCA8K_ATU_ADDR1_MASK GENMASK(7, 0) --#define QCA8K_REG_ATU_DATA2 0x608 --#define QCA8K_ATU_VID_MASK GENMASK(19, 8) --#define QCA8K_ATU_STATUS_MASK GENMASK(3, 0) --#define QCA8K_ATU_STATUS_STATIC 0xf --#define QCA8K_REG_ATU_FUNC 0x60c --#define QCA8K_ATU_FUNC_BUSY BIT(31) --#define QCA8K_ATU_FUNC_PORT_EN BIT(14) --#define QCA8K_ATU_FUNC_MULTI_EN BIT(13) --#define QCA8K_ATU_FUNC_FULL BIT(12) --#define QCA8K_ATU_FUNC_PORT_MASK GENMASK(11, 8) --#define QCA8K_REG_VTU_FUNC0 0x610 --#define QCA8K_VTU_FUNC0_VALID BIT(20) --#define QCA8K_VTU_FUNC0_IVL_EN BIT(19) --/* QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(17, 4) -- * It does contain VLAN_MODE for each port [5:4] for port0, -- * [7:6] for port1 ... [17:16] for port6. Use virtual port -- * define to handle this. -- */ --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i) (4 + (_i) * 2) --#define QCA8K_VTU_FUNC0_EG_MODE_MASK GENMASK(1, 0) --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(_i) (GENMASK(1, 0) << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) --#define QCA8K_VTU_FUNC0_EG_MODE_UNMOD FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x0) --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNMOD(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNMOD << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) --#define QCA8K_VTU_FUNC0_EG_MODE_UNTAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x1) --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_UNTAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) --#define QCA8K_VTU_FUNC0_EG_MODE_TAG FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x2) --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(_i) (QCA8K_VTU_FUNC0_EG_MODE_TAG << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) --#define QCA8K_VTU_FUNC0_EG_MODE_NOT FIELD_PREP(QCA8K_VTU_FUNC0_EG_MODE_MASK, 0x3) --#define QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(_i) (QCA8K_VTU_FUNC0_EG_MODE_NOT << QCA8K_VTU_FUNC0_EG_MODE_PORT_SHIFT(_i)) --#define QCA8K_REG_VTU_FUNC1 0x614 --#define QCA8K_VTU_FUNC1_BUSY BIT(31) --#define QCA8K_VTU_FUNC1_VID_MASK GENMASK(27, 16) --#define QCA8K_VTU_FUNC1_FULL BIT(4) --#define QCA8K_REG_ATU_CTRL 0x618 --#define QCA8K_ATU_AGE_TIME_MASK GENMASK(15, 0) --#define QCA8K_ATU_AGE_TIME(x) FIELD_PREP(QCA8K_ATU_AGE_TIME_MASK, (x)) --#define QCA8K_REG_GLOBAL_FW_CTRL0 0x620 --#define QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN BIT(10) --#define QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM GENMASK(7, 4) --#define QCA8K_REG_GLOBAL_FW_CTRL1 0x624 --#define QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK GENMASK(30, 24) --#define QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK GENMASK(22, 16) --#define QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK GENMASK(14, 8) --#define QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK GENMASK(6, 0) --#define QCA8K_PORT_LOOKUP_CTRL(_i) (0x660 + (_i) * 0xc) --#define QCA8K_PORT_LOOKUP_MEMBER GENMASK(6, 0) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_MASK GENMASK(9, 8) --#define QCA8K_PORT_LOOKUP_VLAN_MODE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, x) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_NONE QCA8K_PORT_LOOKUP_VLAN_MODE(0x0) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_FALLBACK QCA8K_PORT_LOOKUP_VLAN_MODE(0x1) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_CHECK QCA8K_PORT_LOOKUP_VLAN_MODE(0x2) --#define QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE QCA8K_PORT_LOOKUP_VLAN_MODE(0x3) --#define QCA8K_PORT_LOOKUP_STATE_MASK GENMASK(18, 16) --#define QCA8K_PORT_LOOKUP_STATE(x) FIELD_PREP(QCA8K_PORT_LOOKUP_STATE_MASK, x) --#define QCA8K_PORT_LOOKUP_STATE_DISABLED QCA8K_PORT_LOOKUP_STATE(0x0) --#define QCA8K_PORT_LOOKUP_STATE_BLOCKING QCA8K_PORT_LOOKUP_STATE(0x1) --#define QCA8K_PORT_LOOKUP_STATE_LISTENING QCA8K_PORT_LOOKUP_STATE(0x2) --#define QCA8K_PORT_LOOKUP_STATE_LEARNING QCA8K_PORT_LOOKUP_STATE(0x3) --#define QCA8K_PORT_LOOKUP_STATE_FORWARD QCA8K_PORT_LOOKUP_STATE(0x4) --#define QCA8K_PORT_LOOKUP_LEARN BIT(20) --#define QCA8K_PORT_LOOKUP_ING_MIRROR_EN BIT(25) -- --#define QCA8K_REG_GOL_TRUNK_CTRL0 0x700 --/* 4 max trunk first -- * first 6 bit for member bitmap -- * 7th bit is to enable trunk port -- */ --#define QCA8K_REG_GOL_TRUNK_SHIFT(_i) ((_i) * 8) --#define QCA8K_REG_GOL_TRUNK_EN_MASK BIT(7) --#define QCA8K_REG_GOL_TRUNK_EN(_i) (QCA8K_REG_GOL_TRUNK_EN_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) --#define QCA8K_REG_GOL_TRUNK_MEMBER_MASK GENMASK(6, 0) --#define QCA8K_REG_GOL_TRUNK_MEMBER(_i) (QCA8K_REG_GOL_TRUNK_MEMBER_MASK << QCA8K_REG_GOL_TRUNK_SHIFT(_i)) --/* 0x704 for TRUNK 0-1 --- 0x708 for TRUNK 2-3 */ --#define QCA8K_REG_GOL_TRUNK_CTRL(_i) (0x704 + (((_i) / 2) * 4)) --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK GENMASK(3, 0) --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK BIT(3) --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK GENMASK(2, 0) --#define QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i) (((_i) / 2) * 16) --#define QCA8K_REG_GOL_MEM_ID_SHIFT(_i) ((_i) * 4) --/* Complex shift: FIRST shift for port THEN shift for trunk */ --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j) (QCA8K_REG_GOL_MEM_ID_SHIFT(_j) + QCA8K_REG_GOL_TRUNK_ID_SHIFT(_i)) --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) --#define QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(_i, _j) (QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(_i, _j)) -- --#define QCA8K_REG_GLOBAL_FC_THRESH 0x800 --#define QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK GENMASK(24, 16) --#define QCA8K_GLOBAL_FC_GOL_XON_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK, x) --#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK GENMASK(8, 0) --#define QCA8K_GLOBAL_FC_GOL_XOFF_THRES(x) FIELD_PREP(QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, x) -- --#define QCA8K_REG_PORT_HOL_CTRL0(_i) (0x970 + (_i) * 0x8) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK GENMASK(3, 0) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI0(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI0_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK GENMASK(7, 4) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI1(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI1_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK GENMASK(11, 8) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI2(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI2_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK GENMASK(15, 12) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI3(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI3_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK GENMASK(19, 16) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI4(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI4_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK GENMASK(23, 20) --#define QCA8K_PORT_HOL_CTRL0_EG_PRI5(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PRI5_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK GENMASK(29, 24) --#define QCA8K_PORT_HOL_CTRL0_EG_PORT(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL0_EG_PORT_BUF_MASK, x) -- --#define QCA8K_REG_PORT_HOL_CTRL1(_i) (0x974 + (_i) * 0x8) --#define QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK GENMASK(3, 0) --#define QCA8K_PORT_HOL_CTRL1_ING(x) FIELD_PREP(QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK, x) --#define QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN BIT(6) --#define QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN BIT(7) --#define QCA8K_PORT_HOL_CTRL1_WRED_EN BIT(8) --#define QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN BIT(16) -- --/* Pkt edit registers */ --#define QCA8K_EGREES_VLAN_PORT_SHIFT(_i) (16 * ((_i) % 2)) --#define QCA8K_EGREES_VLAN_PORT_MASK(_i) (GENMASK(11, 0) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) --#define QCA8K_EGREES_VLAN_PORT(_i, x) ((x) << QCA8K_EGREES_VLAN_PORT_SHIFT(_i)) --#define QCA8K_EGRESS_VLAN(x) (0x0c70 + (4 * (x / 2))) -- --/* L3 registers */ --#define QCA8K_HROUTER_CONTROL 0xe00 --#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_M GENMASK(17, 16) --#define QCA8K_HROUTER_CONTROL_GLB_LOCKTIME_S 16 --#define QCA8K_HROUTER_CONTROL_ARP_AGE_MODE 1 --#define QCA8K_HROUTER_PBASED_CONTROL1 0xe08 --#define QCA8K_HROUTER_PBASED_CONTROL2 0xe0c --#define QCA8K_HNAT_CONTROL 0xe38 -- --/* MIB registers */ --#define QCA8K_PORT_MIB_COUNTER(_i) (0x1000 + (_i) * 0x100) -- --/* QCA specific MII registers */ --#define MII_ATH_MMD_ADDR 0x0d --#define MII_ATH_MMD_DATA 0x0e -- --enum { -- QCA8K_PORT_SPEED_10M = 0, -- QCA8K_PORT_SPEED_100M = 1, -- QCA8K_PORT_SPEED_1000M = 2, -- QCA8K_PORT_SPEED_ERR = 3, --}; -- --enum qca8k_fdb_cmd { -- QCA8K_FDB_FLUSH = 1, -- QCA8K_FDB_LOAD = 2, -- QCA8K_FDB_PURGE = 3, -- QCA8K_FDB_FLUSH_PORT = 5, -- QCA8K_FDB_NEXT = 6, -- QCA8K_FDB_SEARCH = 7, --}; -- --enum qca8k_vlan_cmd { -- QCA8K_VLAN_FLUSH = 1, -- QCA8K_VLAN_LOAD = 2, -- QCA8K_VLAN_PURGE = 3, -- QCA8K_VLAN_REMOVE_PORT = 4, -- QCA8K_VLAN_NEXT = 5, -- QCA8K_VLAN_READ = 6, --}; -- --enum qca8k_mid_cmd { -- QCA8K_MIB_FLUSH = 1, -- QCA8K_MIB_FLUSH_PORT = 2, -- QCA8K_MIB_CAST = 3, --}; -- --struct qca8k_match_data { -- u8 id; -- bool reduced_package; -- u8 mib_count; --}; -- --enum { -- QCA8K_CPU_PORT0, -- QCA8K_CPU_PORT6, --}; -- --struct qca8k_mgmt_eth_data { -- struct completion rw_done; -- struct mutex mutex; /* Enforce one mdio read/write at time */ -- bool ack; -- u32 seq; -- u32 data[4]; --}; -- --struct qca8k_mib_eth_data { -- struct completion rw_done; -- struct mutex mutex; /* Process one command at time */ -- refcount_t port_parsed; /* Counter to track parsed port */ -- u8 req_port; -- u64 *data; /* pointer to ethtool data */ --}; -- --struct qca8k_ports_config { -- bool sgmii_rx_clk_falling_edge; -- bool sgmii_tx_clk_falling_edge; -- bool sgmii_enable_pll; -- u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ -- u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */ --}; -- --struct qca8k_mdio_cache { --/* The 32bit switch registers are accessed indirectly. To achieve this we need -- * to set the page of the register. Track the last page that was set to reduce -- * mdio writes -- */ -- u16 page; --/* lo and hi can also be cached and from Documentation we can skip one -- * extra mdio write if lo or hi is didn't change. -- */ -- u16 lo; -- u16 hi; --}; -- --struct qca8k_priv { -- u8 switch_id; -- u8 switch_revision; -- u8 mirror_rx; -- u8 mirror_tx; -- u8 lag_hash_mode; -- /* Each bit correspond to a port. This switch can support a max of 7 port. -- * Bit 1: port enabled. Bit 0: port disabled. -- */ -- u8 port_enabled_map; -- struct qca8k_ports_config ports_config; -- struct regmap *regmap; -- struct mii_bus *bus; -- struct dsa_switch *ds; -- struct mutex reg_mutex; -- struct device *dev; -- struct gpio_desc *reset_gpio; -- struct net_device *mgmt_master; /* Track if mdio/mib Ethernet is available */ -- struct qca8k_mgmt_eth_data mgmt_eth_data; -- struct qca8k_mib_eth_data mib_eth_data; -- struct qca8k_mdio_cache mdio_cache; --}; -- --struct qca8k_mib_desc { -- unsigned int size; -- unsigned int offset; -- const char *name; --}; -- --struct qca8k_fdb { -- u16 vid; -- u8 port_mask; -- u8 aging; -- u8 mac[6]; --}; -- --#endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch b/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch deleted file mode 100644 index 77fe64632f4..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-01-net-dsa-qca8k-cache-match-data-to-speed-up-access.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 3bb0844e7bcd0fb0bcfab6202b5edd349ef5250a Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:10 +0200 -Subject: [PATCH 01/14] net: dsa: qca8k: cache match data to speed up access - -Using of_device_get_match_data is expensive. Cache match data to speed -up access and rework user of match data to use the new cached value. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k.c | 35 +++++++++++------------------------ - drivers/net/dsa/qca/qca8k.h | 1 + - 2 files changed, 12 insertions(+), 24 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k.c -+++ b/drivers/net/dsa/qca/qca8k.c -@@ -1462,8 +1462,8 @@ static int qca8k_find_cpu_port(struct ds - static int - qca8k_setup_of_pws_reg(struct qca8k_priv *priv) - { -+ const struct qca8k_match_data *data = priv->info; - struct device_node *node = priv->dev->of_node; -- const struct qca8k_match_data *data; - u32 val = 0; - int ret; - -@@ -1472,8 +1472,6 @@ qca8k_setup_of_pws_reg(struct qca8k_priv - * Should be applied by default but we set this just to make sure. - */ - if (priv->switch_id == QCA8K_ID_QCA8327) { -- data = of_device_get_match_data(priv->dev); -- - /* Set the correct package of 148 pin for QCA8327 */ - if (data->reduced_package) - val |= QCA8327_PWS_PACKAGE148_EN; -@@ -2146,23 +2144,19 @@ qca8k_phylink_mac_link_up(struct dsa_swi - static void - qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) - { -- const struct qca8k_match_data *match_data; - struct qca8k_priv *priv = ds->priv; - int i; - - if (stringset != ETH_SS_STATS) - return; - -- match_data = of_device_get_match_data(priv->dev); -- -- for (i = 0; i < match_data->mib_count; i++) -+ for (i = 0; i < priv->info->mib_count; i++) - strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, - ETH_GSTRING_LEN); - } - - static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) - { -- const struct qca8k_match_data *match_data; - struct qca8k_mib_eth_data *mib_eth_data; - struct qca8k_priv *priv = ds->priv; - const struct qca8k_mib_desc *mib; -@@ -2181,10 +2175,9 @@ static void qca8k_mib_autocast_handler(s - if (port != mib_eth_data->req_port) - goto exit; - -- match_data = device_get_match_data(priv->dev); - data = mib_eth_data->data; - -- for (i = 0; i < match_data->mib_count; i++) { -+ for (i = 0; i < priv->info->mib_count; i++) { - mib = &ar8327_mib[i]; - - /* First 3 mib are present in the skb head */ -@@ -2256,7 +2249,6 @@ qca8k_get_ethtool_stats(struct dsa_switc - uint64_t *data) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- const struct qca8k_match_data *match_data; - const struct qca8k_mib_desc *mib; - u32 reg, i, val; - u32 hi = 0; -@@ -2266,9 +2258,7 @@ qca8k_get_ethtool_stats(struct dsa_switc - qca8k_get_ethtool_stats_eth(ds, port, data) > 0) - return; - -- match_data = of_device_get_match_data(priv->dev); -- -- for (i = 0; i < match_data->mib_count; i++) { -+ for (i = 0; i < priv->info->mib_count; i++) { - mib = &ar8327_mib[i]; - reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; - -@@ -2291,15 +2281,12 @@ qca8k_get_ethtool_stats(struct dsa_switc - static int - qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) - { -- const struct qca8k_match_data *match_data; - struct qca8k_priv *priv = ds->priv; - - if (sset != ETH_SS_STATS) - return 0; - -- match_data = of_device_get_match_data(priv->dev); -- -- return match_data->mib_count; -+ return priv->info->mib_count; - } - - static int -@@ -3037,14 +3024,11 @@ static const struct dsa_switch_ops qca8k - - static int qca8k_read_switch_id(struct qca8k_priv *priv) - { -- const struct qca8k_match_data *data; - u32 val; - u8 id; - int ret; - -- /* get the switches ID from the compatible */ -- data = of_device_get_match_data(priv->dev); -- if (!data) -+ if (!priv->info) - return -ENODEV; - - ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -@@ -3052,8 +3036,10 @@ static int qca8k_read_switch_id(struct q - return -ENODEV; - - id = QCA8K_MASK_CTRL_DEVICE_ID(val); -- if (id != data->id) { -- dev_err(priv->dev, "Switch id detected %x but expected %x", id, data->id); -+ if (id != priv->info->id) { -+ dev_err(priv->dev, -+ "Switch id detected %x but expected %x", -+ id, priv->info->id); - return -ENODEV; - } - -@@ -3078,6 +3064,7 @@ qca8k_sw_probe(struct mdio_device *mdiod - if (!priv) - return -ENOMEM; - -+ priv->info = of_device_get_match_data(priv->dev); - priv->bus = mdiodev->bus; - priv->dev = &mdiodev->dev; - ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -393,6 +393,7 @@ struct qca8k_priv { - struct qca8k_mgmt_eth_data mgmt_eth_data; - struct qca8k_mib_eth_data mib_eth_data; - struct qca8k_mdio_cache mdio_cache; -+ const struct qca8k_match_data *info; - }; - - struct qca8k_mib_desc { diff --git a/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch b/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch deleted file mode 100644 index 5b2dce4c556..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-02-net-dsa-qca8k-make-mib-autocast-feature-optional.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 533c64bca62a8654f00698bc893f639013e38c7b Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:11 +0200 -Subject: [PATCH 02/14] net: dsa: qca8k: make mib autocast feature optional - -Some switch may not support mib autocast feature and require the legacy -way of reading the regs directly. -Make the mib autocast feature optional and permit to declare support for -it using match_data struct in a dedicated qca8k_info_ops struct. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k.c | 11 +++++++++-- - drivers/net/dsa/qca/qca8k.h | 5 +++++ - 2 files changed, 14 insertions(+), 2 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k.c -+++ b/drivers/net/dsa/qca/qca8k.c -@@ -2254,8 +2254,8 @@ qca8k_get_ethtool_stats(struct dsa_switc - u32 hi = 0; - int ret; - -- if (priv->mgmt_master && -- qca8k_get_ethtool_stats_eth(ds, port, data) > 0) -+ if (priv->mgmt_master && priv->info->ops->autocast_mib && -+ priv->info->ops->autocast_mib(ds, port, data) > 0) - return; - - for (i = 0; i < priv->info->mib_count; i++) { -@@ -3187,20 +3187,27 @@ static int qca8k_resume(struct device *d - static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, - qca8k_suspend, qca8k_resume); - -+static const struct qca8k_info_ops qca8xxx_ops = { -+ .autocast_mib = qca8k_get_ethtool_stats_eth, -+}; -+ - static const struct qca8k_match_data qca8327 = { - .id = QCA8K_ID_QCA8327, - .reduced_package = true, - .mib_count = QCA8K_QCA832X_MIB_COUNT, -+ .ops = &qca8xxx_ops, - }; - - static const struct qca8k_match_data qca8328 = { - .id = QCA8K_ID_QCA8327, - .mib_count = QCA8K_QCA832X_MIB_COUNT, -+ .ops = &qca8xxx_ops, - }; - - static const struct qca8k_match_data qca833x = { - .id = QCA8K_ID_QCA8337, - .mib_count = QCA8K_QCA833X_MIB_COUNT, -+ .ops = &qca8xxx_ops, - }; - - static const struct of_device_id qca8k_of_match[] = { ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -324,10 +324,15 @@ enum qca8k_mid_cmd { - QCA8K_MIB_CAST = 3, - }; - -+struct qca8k_info_ops { -+ int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data); -+}; -+ - struct qca8k_match_data { - u8 id; - bool reduced_package; - u8 mib_count; -+ const struct qca8k_info_ops *ops; - }; - - enum { diff --git a/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch deleted file mode 100644 index afa466693a9..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-03-net-dsa-qca8k-move-mib-struct-to-common-code.patch +++ /dev/null @@ -1,6532 +0,0 @@ -From 027152b830434e3632ad5dd678cc5d4740358dbb Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:12 +0200 -Subject: [PATCH 03/14] net: dsa: qca8k: move mib struct to common code - -The same MIB struct is used by drivers based on qca8k family switch. Move -it to common code to make it accessible also by other drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/Makefile | 1 + - drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} | 51 --------------- - drivers/net/dsa/qca/qca8k-common.c | 63 +++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 3 + - 4 files changed, 67 insertions(+), 51 deletions(-) - rename drivers/net/dsa/qca/{qca8k.c => qca8k-8xxx.c} (98%) - create mode 100644 drivers/net/dsa/qca/qca8k-common.c - ---- a/drivers/net/dsa/qca/Makefile -+++ b/drivers/net/dsa/qca/Makefile -@@ -1,3 +1,4 @@ - # SPDX-License-Identifier: GPL-2.0-only - obj-$(CONFIG_NET_DSA_AR9331) += ar9331.o - obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o -+qca8k-y += qca8k-common.o qca8k-8xxx.o ---- a/drivers/net/dsa/qca/qca8k.c -+++ /dev/null -@@ -1,3237 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * Copyright (C) 2009 Felix Fietkau -- * Copyright (C) 2011-2012 Gabor Juhos -- * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -- * Copyright (c) 2016 John Crispin -- */ -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "qca8k.h" -- --#define MIB_DESC(_s, _o, _n) \ -- { \ -- .size = (_s), \ -- .offset = (_o), \ -- .name = (_n), \ -- } -- --static const struct qca8k_mib_desc ar8327_mib[] = { -- MIB_DESC(1, 0x00, "RxBroad"), -- MIB_DESC(1, 0x04, "RxPause"), -- MIB_DESC(1, 0x08, "RxMulti"), -- MIB_DESC(1, 0x0c, "RxFcsErr"), -- MIB_DESC(1, 0x10, "RxAlignErr"), -- MIB_DESC(1, 0x14, "RxRunt"), -- MIB_DESC(1, 0x18, "RxFragment"), -- MIB_DESC(1, 0x1c, "Rx64Byte"), -- MIB_DESC(1, 0x20, "Rx128Byte"), -- MIB_DESC(1, 0x24, "Rx256Byte"), -- MIB_DESC(1, 0x28, "Rx512Byte"), -- MIB_DESC(1, 0x2c, "Rx1024Byte"), -- MIB_DESC(1, 0x30, "Rx1518Byte"), -- MIB_DESC(1, 0x34, "RxMaxByte"), -- MIB_DESC(1, 0x38, "RxTooLong"), -- MIB_DESC(2, 0x3c, "RxGoodByte"), -- MIB_DESC(2, 0x44, "RxBadByte"), -- MIB_DESC(1, 0x4c, "RxOverFlow"), -- MIB_DESC(1, 0x50, "Filtered"), -- MIB_DESC(1, 0x54, "TxBroad"), -- MIB_DESC(1, 0x58, "TxPause"), -- MIB_DESC(1, 0x5c, "TxMulti"), -- MIB_DESC(1, 0x60, "TxUnderRun"), -- MIB_DESC(1, 0x64, "Tx64Byte"), -- MIB_DESC(1, 0x68, "Tx128Byte"), -- MIB_DESC(1, 0x6c, "Tx256Byte"), -- MIB_DESC(1, 0x70, "Tx512Byte"), -- MIB_DESC(1, 0x74, "Tx1024Byte"), -- MIB_DESC(1, 0x78, "Tx1518Byte"), -- MIB_DESC(1, 0x7c, "TxMaxByte"), -- MIB_DESC(1, 0x80, "TxOverSize"), -- MIB_DESC(2, 0x84, "TxByte"), -- MIB_DESC(1, 0x8c, "TxCollision"), -- MIB_DESC(1, 0x90, "TxAbortCol"), -- MIB_DESC(1, 0x94, "TxMultiCol"), -- MIB_DESC(1, 0x98, "TxSingleCol"), -- MIB_DESC(1, 0x9c, "TxExcDefer"), -- MIB_DESC(1, 0xa0, "TxDefer"), -- MIB_DESC(1, 0xa4, "TxLateCol"), -- MIB_DESC(1, 0xa8, "RXUnicast"), -- MIB_DESC(1, 0xac, "TXUnicast"), --}; -- --static void --qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) --{ -- regaddr >>= 1; -- *r1 = regaddr & 0x1e; -- -- regaddr >>= 5; -- *r2 = regaddr & 0x7; -- -- regaddr >>= 3; -- *page = regaddr & 0x3ff; --} -- --static int --qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) --{ -- u16 *cached_lo = &priv->mdio_cache.lo; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (lo == *cached_lo) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, lo); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit lo register\n"); -- -- *cached_lo = lo; -- return 0; --} -- --static int --qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) --{ -- u16 *cached_hi = &priv->mdio_cache.hi; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (hi == *cached_hi) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, hi); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit hi register\n"); -- -- *cached_hi = hi; -- return 0; --} -- --static int --qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) --{ -- int ret; -- -- ret = bus->read(bus, phy_id, regnum); -- if (ret >= 0) { -- *val = ret; -- ret = bus->read(bus, phy_id, regnum + 1); -- *val |= ret << 16; -- } -- -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to read qca8k 32bit register\n"); -- *val = 0; -- return ret; -- } -- -- return 0; --} -- --static void --qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) --{ -- u16 lo, hi; -- int ret; -- -- lo = val & 0xffff; -- hi = (u16)(val >> 16); -- -- ret = qca8k_set_lo(priv, phy_id, regnum, lo); -- if (ret >= 0) -- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); --} -- --static int --qca8k_set_page(struct qca8k_priv *priv, u16 page) --{ -- u16 *cached_page = &priv->mdio_cache.page; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (page == *cached_page) -- return 0; -- -- ret = bus->write(bus, 0x18, 0, page); -- if (ret < 0) { -- dev_err_ratelimited(&bus->dev, -- "failed to set qca8k page\n"); -- return ret; -- } -- -- *cached_page = page; -- usleep_range(1000, 2000); -- return 0; --} -- --static int --qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) --{ -- return regmap_read(priv->regmap, reg, val); --} -- --static int --qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) --{ -- return regmap_write(priv->regmap, reg, val); --} -- --static int --qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) --{ -- return regmap_update_bits(priv->regmap, reg, mask, write_val); --} -- --static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data; -- struct qca8k_priv *priv = ds->priv; -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- u8 len, cmd; -- -- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); -- mgmt_eth_data = &priv->mgmt_eth_data; -- -- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -- -- /* Make sure the seq match the requested packet */ -- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -- mgmt_eth_data->ack = true; -- -- if (cmd == MDIO_READ) { -- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -- -- /* Get the rest of the 12 byte of data. -- * The read/write function will extract the requested data. -- */ -- if (len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(mgmt_eth_data->data + 1, skb->data, -- QCA_HDR_MGMT_DATA2_LEN); -- } -- -- complete(&mgmt_eth_data->rw_done); --} -- --static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -- int priority, unsigned int len) --{ -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- unsigned int real_len; -- struct sk_buff *skb; -- u32 *data2; -- u16 hdr; -- -- skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); -- if (!skb) -- return NULL; -- -- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -- * Actually for some reason the steps are: -- * 0: nothing -- * 1-4: first 4 byte -- * 5-6: first 12 byte -- * 7-15: all 16 byte -- */ -- if (len == 16) -- real_len = 15; -- else -- real_len = len; -- -- skb_reset_mac_header(skb); -- skb_set_network_header(skb, skb->len); -- -- mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); -- -- hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -- hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); -- hdr |= QCA_HDR_XMIT_FROM_CPU; -- hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); -- hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); -- -- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -- QCA_HDR_MGMT_CHECK_CODE_VAL); -- -- if (cmd == MDIO_WRITE) -- mgmt_ethhdr->mdio_data = *val; -- -- mgmt_ethhdr->hdr = htons(hdr); -- -- data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); -- -- return skb; --} -- --static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) --{ -- struct qca_mgmt_ethhdr *mgmt_ethhdr; -- -- mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); --} -- --static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -- struct sk_buff *skb; -- bool ack; -- int ret; -- -- skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -- QCA8K_ETHERNET_MDIO_PRIORITY, len); -- if (!skb) -- return -ENOMEM; -- -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check mgmt_master if is operational */ -- if (!priv->mgmt_master) { -- kfree_skb(skb); -- mutex_unlock(&mgmt_eth_data->mutex); -- return -EINVAL; -- } -- -- skb->dev = priv->mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the mdio pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -- -- *val = mgmt_eth_data->data[0]; -- if (len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); -- -- ack = mgmt_eth_data->ack; -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- return 0; --} -- --static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -- struct sk_buff *skb; -- bool ack; -- int ret; -- -- skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, -- QCA8K_ETHERNET_MDIO_PRIORITY, len); -- if (!skb) -- return -ENOMEM; -- -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check mgmt_master if is operational */ -- if (!priv->mgmt_master) { -- kfree_skb(skb); -- mutex_unlock(&mgmt_eth_data->mutex); -- return -EINVAL; -- } -- -- skb->dev = priv->mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the mdio pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -- -- ack = mgmt_eth_data->ack; -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- return 0; --} -- --static int --qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) --{ -- u32 val = 0; -- int ret; -- -- ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); -- if (ret) -- return ret; -- -- val &= ~mask; -- val |= write_val; -- -- return qca8k_write_eth(priv, reg, &val, sizeof(val)); --} -- --static int --qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- -- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int --qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- u32 tmp; -- -- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- tmp = val[i]; -- -- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int --qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; --} -- --static int --qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- int ret; -- -- if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- return ret; --} -- --static int --qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) -- return 0; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- if (ret < 0) -- goto exit; -- -- val &= ~mask; -- val |= write_val; -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- --exit: -- mutex_unlock(&bus->mdio_lock); -- -- return ret; --} -- --static const struct regmap_range qca8k_readable_ranges[] = { -- regmap_reg_range(0x0000, 0x00e4), /* Global control */ -- regmap_reg_range(0x0100, 0x0168), /* EEE control */ -- regmap_reg_range(0x0200, 0x0270), /* Parser control */ -- regmap_reg_range(0x0400, 0x0454), /* ACL */ -- regmap_reg_range(0x0600, 0x0718), /* Lookup */ -- regmap_reg_range(0x0800, 0x0b70), /* QM */ -- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -- --}; -- --static const struct regmap_access_table qca8k_readable_table = { -- .yes_ranges = qca8k_readable_ranges, -- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), --}; -- --static struct regmap_config qca8k_regmap_config = { -- .reg_bits = 16, -- .val_bits = 32, -- .reg_stride = 4, -- .max_register = 0x16ac, /* end MIB - Port6 range */ -- .reg_read = qca8k_regmap_read, -- .reg_write = qca8k_regmap_write, -- .reg_update_bits = qca8k_regmap_update_bits, -- .rd_table = &qca8k_readable_table, -- .disable_locking = true, /* Locking is handled by qca8k read/write */ -- .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ --}; -- --static int --qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) --{ -- u32 val; -- -- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); --} -- --static int --qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) --{ -- u32 reg[3]; -- int ret; -- -- /* load the ARL table into an array */ -- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -- if (ret) -- return ret; -- -- /* vid - 83:72 */ -- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -- /* aging - 67:64 */ -- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -- /* portmask - 54:48 */ -- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -- /* mac - 47:0 */ -- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -- -- return 0; --} -- --static void --qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -- u8 aging) --{ -- u32 reg[3] = { 0 }; -- -- /* vid - 83:72 */ -- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -- /* aging - 67:64 */ -- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -- /* portmask - 54:48 */ -- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -- /* mac - 47:0 */ -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -- -- /* load the array into the ARL table */ -- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); --} -- --static int --qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) --{ -- u32 reg; -- int ret; -- -- /* Set the command and FDB index */ -- reg = QCA8K_ATU_FUNC_BUSY; -- reg |= cmd; -- if (port >= 0) { -- reg |= QCA8K_ATU_FUNC_PORT_EN; -- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -- } -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_FDB_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_ATU_FUNC_FULL) -- return -1; -- } -- -- return 0; --} -- --static int --qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) --{ -- int ret; -- -- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -- if (ret < 0) -- return ret; -- -- return qca8k_fdb_read(priv, fdb); --} -- --static int --qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -- u16 vid, u8 aging) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static void --qca8k_fdb_flush(struct qca8k_priv *priv) --{ -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_fdb_read(priv, &fdb); -- if (ret < 0) -- goto exit; -- -- /* Rule exist. Delete first */ -- if (!fdb.aging) { -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- } -- -- /* Add port to fdb portmask */ -- fdb.port_mask |= port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- /* Rule doesn't exist. Why delete? */ -- if (!fdb.aging) { -- ret = -EINVAL; -- goto exit; -- } -- -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- -- /* Only port in the rule is this port. Don't re insert */ -- if (fdb.port_mask == port_mask) -- goto exit; -- -- /* Remove port from port mask */ -- fdb.port_mask &= ~port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) --{ -- u32 reg; -- int ret; -- -- /* Set the command and VLAN index */ -- reg = QCA8K_VTU_FUNC1_BUSY; -- reg |= cmd; -- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_VLAN_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_VTU_FUNC1_FULL) -- return -ENOMEM; -- } -- -- return 0; --} -- --static int --qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) --{ -- u32 reg; -- int ret; -- -- /* -- We do the right thing with VLAN 0 and treat it as untagged while -- preserving the tag on egress. -- */ -- if (vid == 0) -- return 0; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- if (untagged) -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -- else -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -- -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) --{ -- u32 reg, mask; -- int ret, i; -- bool del; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -- -- /* Check if we're the last member to be removed */ -- del = true; -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -- -- if ((reg & mask) != mask) { -- del = false; -- break; -- } -- } -- -- if (del) { -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -- } else { -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- } -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_mib_init(struct qca8k_priv *priv) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -- QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -- if (ret) -- goto exit; -- -- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static void --qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) --{ -- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -- -- /* Port 0 and 6 have no internal PHY */ -- if (port > 0 && port < 6) -- mask |= QCA8K_PORT_STATUS_LINK_AUTO; -- -- if (enable) -- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -- else -- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); --} -- --static int --qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, -- struct sk_buff *read_skb, u32 *val) --{ -- struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); -- bool ack; -- int ret; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the copy pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) -- return -ETIMEDOUT; -- -- if (!ack) -- return -EINVAL; -- -- *val = mgmt_eth_data->data[0]; -- -- return 0; --} -- --static int --qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, -- int regnum, u16 data) --{ -- struct sk_buff *write_skb, *clear_skb, *read_skb; -- struct qca8k_mgmt_eth_data *mgmt_eth_data; -- u32 write_val, clear_val = 0, val; -- struct net_device *mgmt_master; -- int ret, ret1; -- bool ack; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- mgmt_eth_data = &priv->mgmt_eth_data; -- -- write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum); -- -- if (read) { -- write_val |= QCA8K_MDIO_MASTER_READ; -- } else { -- write_val |= QCA8K_MDIO_MASTER_WRITE; -- write_val |= QCA8K_MDIO_MASTER_DATA(data); -- } -- -- /* Prealloc all the needed skb before the lock */ -- write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); -- if (!write_skb) -- return -ENOMEM; -- -- clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -- if (!clear_skb) { -- ret = -ENOMEM; -- goto err_clear_skb; -- } -- -- read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, -- QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -- if (!read_skb) { -- ret = -ENOMEM; -- goto err_read_skb; -- } -- -- /* Actually start the request: -- * 1. Send mdio master packet -- * 2. Busy Wait for mdio master command -- * 3. Get the data if we are reading -- * 4. Reset the mdio master (even with error) -- */ -- mutex_lock(&mgmt_eth_data->mutex); -- -- /* Check if mgmt_master is operational */ -- mgmt_master = priv->mgmt_master; -- if (!mgmt_master) { -- mutex_unlock(&mgmt_eth_data->mutex); -- ret = -EINVAL; -- goto err_mgmt_master; -- } -- -- read_skb->dev = mgmt_master; -- clear_skb->dev = mgmt_master; -- write_skb->dev = mgmt_master; -- -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the write pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(write_skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) { -- ret = -ETIMEDOUT; -- kfree_skb(read_skb); -- goto exit; -- } -- -- if (!ack) { -- ret = -EINVAL; -- kfree_skb(read_skb); -- goto exit; -- } -- -- ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, -- !(val & QCA8K_MDIO_MASTER_BUSY), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- mgmt_eth_data, read_skb, &val); -- -- if (ret < 0 && ret1 < 0) { -- ret = ret1; -- goto exit; -- } -- -- if (read) { -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the read pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(read_skb); -- -- ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- ack = mgmt_eth_data->ack; -- -- if (ret <= 0) { -- ret = -ETIMEDOUT; -- goto exit; -- } -- -- if (!ack) { -- ret = -EINVAL; -- goto exit; -- } -- -- ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; -- } else { -- kfree_skb(read_skb); -- } --exit: -- reinit_completion(&mgmt_eth_data->rw_done); -- -- /* Increment seq_num and set it in the clear pkt */ -- mgmt_eth_data->seq++; -- qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); -- mgmt_eth_data->ack = false; -- -- dev_queue_xmit(clear_skb); -- -- wait_for_completion_timeout(&mgmt_eth_data->rw_done, -- QCA8K_ETHERNET_TIMEOUT); -- -- mutex_unlock(&mgmt_eth_data->mutex); -- -- return ret; -- -- /* Error handling before lock */ --err_mgmt_master: -- kfree_skb(read_skb); --err_read_skb: -- kfree_skb(clear_skb); --err_clear_skb: -- kfree_skb(write_skb); -- -- return ret; --} -- --static u32 --qca8k_port_to_phy(int port) --{ -- /* From Andrew Lunn: -- * Port 0 has no internal phy. -- * Port 1 has an internal PHY at MDIO address 0. -- * Port 2 has an internal PHY at MDIO address 1. -- * ... -- * Port 5 has an internal PHY at MDIO address 4. -- * Port 6 has no internal PHY. -- */ -- -- return port - 1; --} -- --static int --qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) --{ -- u16 r1, r2, page; -- u32 val; -- int ret, ret1; -- -- qca8k_split_addr(reg, &r1, &r2, &page); -- -- ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -- bus, 0x10 | r2, r1, &val); -- -- /* Check if qca8k_read has failed for a different reason -- * before returnting -ETIMEDOUT -- */ -- if (ret < 0 && ret1 < 0) -- return ret1; -- -- return ret; --} -- --static int --qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) --{ -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -- QCA8K_MDIO_MASTER_DATA(data); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- return ret; --} -- --static int --qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) --{ -- struct mii_bus *bus = priv->bus; -- u16 r1, r2, page; -- u32 val; -- int ret; -- -- if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -- return -EINVAL; -- -- val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -- QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -- QCA8K_MDIO_MASTER_REG_ADDR(regnum); -- -- qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -- -- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -- -- ret = qca8k_set_page(priv, page); -- if (ret) -- goto exit; -- -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -- -- ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -- --exit: -- /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -- -- mutex_unlock(&bus->mdio_lock); -- -- if (ret >= 0) -- ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -- -- return ret; --} -- --static int --qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- int ret; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); -- if (!ret) -- return 0; -- -- return qca8k_mdio_write(priv, phy, regnum, data); --} -- --static int --qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) --{ -- struct qca8k_priv *priv = slave_bus->priv; -- int ret; -- -- /* Use mdio Ethernet when available, fallback to legacy one on error */ -- ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); -- if (ret >= 0) -- return ret; -- -- ret = qca8k_mdio_read(priv, phy, regnum); -- -- if (ret < 0) -- return 0xffff; -- -- return ret; --} -- --static int --qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) --{ -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- return qca8k_internal_mdio_write(slave_bus, port, regnum, data); --} -- --static int --qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) --{ -- port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -- -- return qca8k_internal_mdio_read(slave_bus, port, regnum); --} -- --static int --qca8k_mdio_register(struct qca8k_priv *priv) --{ -- struct dsa_switch *ds = priv->ds; -- struct device_node *mdio; -- struct mii_bus *bus; -- -- bus = devm_mdiobus_alloc(ds->dev); -- if (!bus) -- return -ENOMEM; -- -- bus->priv = (void *)priv; -- snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -- ds->dst->index, ds->index); -- bus->parent = ds->dev; -- bus->phy_mask = ~ds->phys_mii_mask; -- ds->slave_mii_bus = bus; -- -- /* Check if the devicetree declare the port:phy mapping */ -- mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -- if (of_device_is_available(mdio)) { -- bus->name = "qca8k slave mii"; -- bus->read = qca8k_internal_mdio_read; -- bus->write = qca8k_internal_mdio_write; -- return devm_of_mdiobus_register(priv->dev, bus, mdio); -- } -- -- /* If a mapping can't be found the legacy mapping is used, -- * using the qca8k_port_to_phy function -- */ -- bus->name = "qca8k-legacy slave mii"; -- bus->read = qca8k_legacy_mdio_read; -- bus->write = qca8k_legacy_mdio_write; -- return devm_mdiobus_register(priv->dev, bus); --} -- --static int --qca8k_setup_mdio_bus(struct qca8k_priv *priv) --{ -- u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -- struct device_node *ports, *port; -- phy_interface_t mode; -- int err; -- -- ports = of_get_child_by_name(priv->dev->of_node, "ports"); -- if (!ports) -- ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -- -- if (!ports) -- return -EINVAL; -- -- for_each_available_child_of_node(ports, port) { -- err = of_property_read_u32(port, "reg", ®); -- if (err) { -- of_node_put(port); -- of_node_put(ports); -- return err; -- } -- -- if (!dsa_is_user_port(priv->ds, reg)) -- continue; -- -- of_get_phy_mode(port, &mode); -- -- if (of_property_read_bool(port, "phy-handle") && -- mode != PHY_INTERFACE_MODE_INTERNAL) -- external_mdio_mask |= BIT(reg); -- else -- internal_mdio_mask |= BIT(reg); -- } -- -- of_node_put(ports); -- if (!external_mdio_mask && !internal_mdio_mask) { -- dev_err(priv->dev, "no PHYs are defined.\n"); -- return -EINVAL; -- } -- -- /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -- * the MDIO_MASTER register also _disconnects_ the external MDC -- * passthrough to the internal PHYs. It's not possible to use both -- * configurations at the same time! -- * -- * Because this came up during the review process: -- * If the external mdio-bus driver is capable magically disabling -- * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -- * accessors for the time being, it would be possible to pull this -- * off. -- */ -- if (!!external_mdio_mask && !!internal_mdio_mask) { -- dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -- return -EINVAL; -- } -- -- if (external_mdio_mask) { -- /* Make sure to disable the internal mdio bus in cases -- * a dt-overlay and driver reload changed the configuration -- */ -- -- return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, -- QCA8K_MDIO_MASTER_EN); -- } -- -- return qca8k_mdio_register(priv); --} -- --static int --qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) --{ -- u32 mask = 0; -- int ret = 0; -- -- /* SoC specific settings for ipq8064. -- * If more device require this consider adding -- * a dedicated binding. -- */ -- if (of_machine_is_compatible("qcom,ipq8064")) -- mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -- -- /* SoC specific settings for ipq8065 */ -- if (of_machine_is_compatible("qcom,ipq8065")) -- mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -- -- if (mask) { -- ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -- QCA8K_MAC_PWR_RGMII0_1_8V | -- QCA8K_MAC_PWR_RGMII1_1_8V, -- mask); -- } -- -- return ret; --} -- --static int qca8k_find_cpu_port(struct dsa_switch *ds) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Find the connected cpu port. Valid port are 0 or 6 */ -- if (dsa_is_cpu_port(ds, 0)) -- return 0; -- -- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -- -- if (dsa_is_cpu_port(ds, 6)) -- return 6; -- -- return -EINVAL; --} -- --static int --qca8k_setup_of_pws_reg(struct qca8k_priv *priv) --{ -- const struct qca8k_match_data *data = priv->info; -- struct device_node *node = priv->dev->of_node; -- u32 val = 0; -- int ret; -- -- /* QCA8327 require to set to the correct mode. -- * His bigger brother QCA8328 have the 172 pin layout. -- * Should be applied by default but we set this just to make sure. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- /* Set the correct package of 148 pin for QCA8327 */ -- if (data->reduced_package) -- val |= QCA8327_PWS_PACKAGE148_EN; -- -- ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -- val); -- if (ret) -- return ret; -- } -- -- if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -- val |= QCA8K_PWS_POWER_ON_SEL; -- -- if (of_property_read_bool(node, "qca,led-open-drain")) { -- if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -- dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -- return -EINVAL; -- } -- -- val |= QCA8K_PWS_LED_OPEN_EN_CSR; -- } -- -- return qca8k_rmw(priv, QCA8K_REG_PWS, -- QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -- val); --} -- --static int --qca8k_parse_port_config(struct qca8k_priv *priv) --{ -- int port, cpu_port_index = -1, ret; -- struct device_node *port_dn; -- phy_interface_t mode; -- struct dsa_port *dp; -- u32 delay; -- -- /* We have 2 CPU port. Check them */ -- for (port = 0; port < QCA8K_NUM_PORTS; port++) { -- /* Skip every other port */ -- if (port != 0 && port != 6) -- continue; -- -- dp = dsa_to_port(priv->ds, port); -- port_dn = dp->dn; -- cpu_port_index++; -- -- if (!of_device_is_available(port_dn)) -- continue; -- -- ret = of_get_phy_mode(port_dn, &mode); -- if (ret) -- continue; -- -- switch (mode) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- case PHY_INTERFACE_MODE_SGMII: -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID) -- delay = 1; -- -- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { -- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -- -- delay = 0; -- -- if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -- /* Switch regs accept value in ns, convert ps to ns */ -- delay = delay / 1000; -- else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- delay = 2; -- -- if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { -- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -- delay = 3; -- } -- -- priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -- -- /* Skip sgmii parsing for rgmii* mode */ -- if (mode == PHY_INTERFACE_MODE_RGMII || -- mode == PHY_INTERFACE_MODE_RGMII_ID || -- mode == PHY_INTERFACE_MODE_RGMII_TXID || -- mode == PHY_INTERFACE_MODE_RGMII_RXID) -- break; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -- priv->ports_config.sgmii_tx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -- priv->ports_config.sgmii_rx_clk_falling_edge = true; -- -- if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -- priv->ports_config.sgmii_enable_pll = true; -- -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -- priv->ports_config.sgmii_enable_pll = false; -- } -- -- if (priv->switch_revision < 2) -- dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -- } -- -- break; -- default: -- continue; -- } -- } -- -- return 0; --} -- --static int --qca8k_setup(struct dsa_switch *ds) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, ret, i; -- u32 mask; -- -- cpu_port = qca8k_find_cpu_port(ds); -- if (cpu_port < 0) { -- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -- return cpu_port; -- } -- -- /* Parse CPU port config to be later used in phy_link mac_config */ -- ret = qca8k_parse_port_config(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_mdio_bus(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_of_pws_reg(priv); -- if (ret) -- return ret; -- -- ret = qca8k_setup_mac_pwr_sel(priv); -- if (ret) -- return ret; -- -- /* Make sure MAC06 is disabled */ -- ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, -- QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -- if (ret) { -- dev_err(priv->dev, "failed disabling MAC06 exchange"); -- return ret; -- } -- -- /* Enable CPU Port */ -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -- if (ret) { -- dev_err(priv->dev, "failed enabling CPU port"); -- return ret; -- } -- -- /* Enable MIB counters */ -- ret = qca8k_mib_init(priv); -- if (ret) -- dev_warn(priv->dev, "mib init failed"); -- -- /* Initial setup of all ports */ -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* Disable forwarding by default on all ports */ -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, 0); -- if (ret) -- return ret; -- -- /* Enable QCA header mode on all cpu ports */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -- FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | -- FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); -- if (ret) { -- dev_err(priv->dev, "failed enabling QCA header mode"); -- return ret; -- } -- } -- -- /* Disable MAC by default on all user ports */ -- if (dsa_is_user_port(ds, i)) -- qca8k_port_set_status(priv, i, 0); -- } -- -- /* Forward all unknown frames to CPU port for Linux processing -- * Notice that in multi-cpu config only one port should be set -- * for igmp, unknown, multicast and broadcast packet -- */ -- ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | -- FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); -- if (ret) -- return ret; -- -- /* Setup connection between CPU port & user ports -- * Configure specific switch configuration for ports -- */ -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- /* CPU port gets connected to all user ports of the switch */ -- if (dsa_is_cpu_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -- if (ret) -- return ret; -- } -- -- /* Individual user ports get connected to CPU port only */ -- if (dsa_is_user_port(ds, i)) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_MEMBER, -- BIT(cpu_port)); -- if (ret) -- return ret; -- -- /* Enable ARP Auto-learning by default */ -- ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), -- QCA8K_PORT_LOOKUP_LEARN); -- if (ret) -- return ret; -- -- /* For port based vlans to work we need to set the -- * default egress vid -- */ -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -- QCA8K_EGREES_VLAN_PORT_MASK(i), -- QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -- QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -- QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -- if (ret) -- return ret; -- } -- -- /* The port 5 of the qca8337 have some problem in flood condition. The -- * original legacy driver had some specific buffer and priority settings -- * for the different port suggested by the QCA switch team. Add this -- * missing settings to improve switch stability under load condition. -- * This problem is limited to qca8337 and other qca8k switch are not affected. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) { -- switch (i) { -- /* The 2 CPU port and port 5 requires some different -- * priority than any other ports. -- */ -- case 0: -- case 5: -- case 6: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -- break; -- default: -- mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -- QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -- QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -- } -- qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -- -- mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN; -- qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -- QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | -- QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -- QCA8K_PORT_HOL_CTRL1_WRED_EN, -- mask); -- } -- } -- -- /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -- if (priv->switch_id == QCA8K_ID_QCA8327) { -- mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -- qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -- QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | -- QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, -- mask); -- } -- -- /* Setup our port MTUs to match power on defaults */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); -- if (ret) -- dev_warn(priv->dev, "failed setting MTU settings"); -- -- /* Flush the FDB table */ -- qca8k_fdb_flush(priv); -- -- /* We don't have interrupts for link changes, so we need to poll */ -- ds->pcs_poll = true; -- -- /* Set min a max ageing value supported */ -- ds->ageing_time_min = 7000; -- ds->ageing_time_max = 458745000; -- -- /* Set max number of LAGs supported */ -- ds->num_lag_ids = QCA8K_NUM_LAGS; -- -- return 0; --} -- --static void --qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -- u32 reg) --{ -- u32 delay, val = 0; -- int ret; -- -- /* Delay can be declared in 3 different way. -- * Mode to rgmii and internal-delay standard binding defined -- * rgmii-id or rgmii-tx/rx phy mode set. -- * The parse logic set a delay different than 0 only when one -- * of the 3 different way is used. In all other case delay is -- * not enabled. With ID or TX/RXID delay is enabled and set -- * to the default and recommended value. -- */ -- if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -- } -- -- if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -- delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -- -- val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -- } -- -- /* Set RGMII delay based on the selected values */ -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -- val); -- if (ret) -- dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -- cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); --} -- --static void --qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, -- const struct phylink_link_state *state) --{ -- struct qca8k_priv *priv = ds->priv; -- int cpu_port_index, ret; -- u32 reg, val; -- -- switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -- return; -- -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT0; -- break; -- case 1: -- case 2: -- case 3: -- case 4: -- case 5: -- /* Internal PHY, nothing to do */ -- return; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -- return; -- -- reg = QCA8K_REG_PORT6_PAD_CTRL; -- cpu_port_index = QCA8K_CPU_PORT6; -- break; -- default: -- dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -- return; -- } -- -- if (port != 6 && phylink_autoneg_inband(mode)) { -- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -- __func__); -- return; -- } -- -- switch (state->interface) { -- case PHY_INTERFACE_MODE_RGMII: -- case PHY_INTERFACE_MODE_RGMII_ID: -- case PHY_INTERFACE_MODE_RGMII_TXID: -- case PHY_INTERFACE_MODE_RGMII_RXID: -- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -- -- /* Configure rgmii delay */ -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- /* QCA8337 requires to set rgmii rx delay for all ports. -- * This is enabled through PORT5_PAD_CTRL for all ports, -- * rather than individual port registers. -- */ -- if (priv->switch_id == QCA8K_ID_QCA8337) -- qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -- break; -- case PHY_INTERFACE_MODE_SGMII: -- case PHY_INTERFACE_MODE_1000BASEX: -- /* Enable SGMII on the port */ -- qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -- -- /* Enable/disable SerDes auto-negotiation as necessary */ -- ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -- if (ret) -- return; -- if (phylink_autoneg_inband(mode)) -- val &= ~QCA8K_PWS_SERDES_AEN_DIS; -- else -- val |= QCA8K_PWS_SERDES_AEN_DIS; -- qca8k_write(priv, QCA8K_REG_PWS, val); -- -- /* Configure the SGMII parameters */ -- ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -- if (ret) -- return; -- -- val |= QCA8K_SGMII_EN_SD; -- -- if (priv->ports_config.sgmii_enable_pll) -- val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -- QCA8K_SGMII_EN_TX; -- -- if (dsa_is_cpu_port(ds, port)) { -- /* CPU port, we're talking to the CPU MAC, be a PHY */ -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_PHY; -- } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_MAC; -- } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -- val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -- val |= QCA8K_SGMII_MODE_CTRL_BASEX; -- } -- -- qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -- -- /* From original code is reported port instability as SGMII also -- * require delay set. Apply advised values here or take them from DT. -- */ -- if (state->interface == PHY_INTERFACE_MODE_SGMII) -- qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -- -- /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -- * falling edge is set writing in the PORT0 PAD reg -- */ -- if (priv->switch_id == QCA8K_ID_QCA8327 || -- priv->switch_id == QCA8K_ID_QCA8337) -- reg = QCA8K_REG_PORT0_PAD_CTRL; -- -- val = 0; -- -- /* SGMII Clock phase configuration */ -- if (priv->ports_config.sgmii_rx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -- -- if (priv->ports_config.sgmii_tx_clk_falling_edge) -- val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -- -- if (val) -- ret = qca8k_rmw(priv, reg, -- QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -- QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -- val); -- -- break; -- default: -- dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -- phy_modes(state->interface), port); -- return; -- } --} -- --static void --qca8k_phylink_validate(struct dsa_switch *ds, int port, -- unsigned long *supported, -- struct phylink_link_state *state) --{ -- __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -- -- switch (port) { -- case 0: /* 1st CPU port */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII) -- goto unsupported; -- break; -- case 1: -- case 2: -- case 3: -- case 4: -- case 5: -- /* Internal PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_GMII && -- state->interface != PHY_INTERFACE_MODE_INTERNAL) -- goto unsupported; -- break; -- case 6: /* 2nd CPU port / external PHY */ -- if (state->interface != PHY_INTERFACE_MODE_NA && -- state->interface != PHY_INTERFACE_MODE_RGMII && -- state->interface != PHY_INTERFACE_MODE_RGMII_ID && -- state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -- state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -- state->interface != PHY_INTERFACE_MODE_SGMII && -- state->interface != PHY_INTERFACE_MODE_1000BASEX) -- goto unsupported; -- break; -- default: --unsupported: -- linkmode_zero(supported); -- return; -- } -- -- phylink_set_port_modes(mask); -- phylink_set(mask, Autoneg); -- -- phylink_set(mask, 1000baseT_Full); -- phylink_set(mask, 10baseT_Half); -- phylink_set(mask, 10baseT_Full); -- phylink_set(mask, 100baseT_Half); -- phylink_set(mask, 100baseT_Full); -- -- if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -- phylink_set(mask, 1000baseX_Full); -- -- phylink_set(mask, Pause); -- phylink_set(mask, Asym_Pause); -- -- linkmode_and(supported, supported, mask); -- linkmode_and(state->advertising, state->advertising, mask); --} -- --static int --qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, -- struct phylink_link_state *state) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg; -- int ret; -- -- ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); -- if (ret < 0) -- return ret; -- -- state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); -- state->an_complete = state->link; -- state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); -- state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : -- DUPLEX_HALF; -- -- switch (reg & QCA8K_PORT_STATUS_SPEED) { -- case QCA8K_PORT_STATUS_SPEED_10: -- state->speed = SPEED_10; -- break; -- case QCA8K_PORT_STATUS_SPEED_100: -- state->speed = SPEED_100; -- break; -- case QCA8K_PORT_STATUS_SPEED_1000: -- state->speed = SPEED_1000; -- break; -- default: -- state->speed = SPEED_UNKNOWN; -- break; -- } -- -- state->pause = MLO_PAUSE_NONE; -- if (reg & QCA8K_PORT_STATUS_RXFLOW) -- state->pause |= MLO_PAUSE_RX; -- if (reg & QCA8K_PORT_STATUS_TXFLOW) -- state->pause |= MLO_PAUSE_TX; -- -- return 1; --} -- --static void --qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, -- phy_interface_t interface) --{ -- struct qca8k_priv *priv = ds->priv; -- -- qca8k_port_set_status(priv, port, 0); --} -- --static void --qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, -- phy_interface_t interface, struct phy_device *phydev, -- int speed, int duplex, bool tx_pause, bool rx_pause) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg; -- -- if (phylink_autoneg_inband(mode)) { -- reg = QCA8K_PORT_STATUS_LINK_AUTO; -- } else { -- switch (speed) { -- case SPEED_10: -- reg = QCA8K_PORT_STATUS_SPEED_10; -- break; -- case SPEED_100: -- reg = QCA8K_PORT_STATUS_SPEED_100; -- break; -- case SPEED_1000: -- reg = QCA8K_PORT_STATUS_SPEED_1000; -- break; -- default: -- reg = QCA8K_PORT_STATUS_LINK_AUTO; -- break; -- } -- -- if (duplex == DUPLEX_FULL) -- reg |= QCA8K_PORT_STATUS_DUPLEX; -- -- if (rx_pause || dsa_is_cpu_port(ds, port)) -- reg |= QCA8K_PORT_STATUS_RXFLOW; -- -- if (tx_pause || dsa_is_cpu_port(ds, port)) -- reg |= QCA8K_PORT_STATUS_TXFLOW; -- } -- -- reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -- -- qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); --} -- --static void --qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) --{ -- struct qca8k_priv *priv = ds->priv; -- int i; -- -- if (stringset != ETH_SS_STATS) -- return; -- -- for (i = 0; i < priv->info->mib_count; i++) -- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -- ETH_GSTRING_LEN); --} -- --static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) --{ -- struct qca8k_mib_eth_data *mib_eth_data; -- struct qca8k_priv *priv = ds->priv; -- const struct qca8k_mib_desc *mib; -- struct mib_ethhdr *mib_ethhdr; -- int i, mib_len, offset = 0; -- u64 *data; -- u8 port; -- -- mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); -- mib_eth_data = &priv->mib_eth_data; -- -- /* The switch autocast every port. Ignore other packet and -- * parse only the requested one. -- */ -- port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); -- if (port != mib_eth_data->req_port) -- goto exit; -- -- data = mib_eth_data->data; -- -- for (i = 0; i < priv->info->mib_count; i++) { -- mib = &ar8327_mib[i]; -- -- /* First 3 mib are present in the skb head */ -- if (i < 3) { -- data[i] = mib_ethhdr->data[i]; -- continue; -- } -- -- mib_len = sizeof(uint32_t); -- -- /* Some mib are 64 bit wide */ -- if (mib->size == 2) -- mib_len = sizeof(uint64_t); -- -- /* Copy the mib value from packet to the */ -- memcpy(data + i, skb->data + offset, mib_len); -- -- /* Set the offset for the next mib */ -- offset += mib_len; -- } -- --exit: -- /* Complete on receiving all the mib packet */ -- if (refcount_dec_and_test(&mib_eth_data->port_parsed)) -- complete(&mib_eth_data->rw_done); --} -- --static int --qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) --{ -- struct dsa_port *dp = dsa_to_port(ds, port); -- struct qca8k_mib_eth_data *mib_eth_data; -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- mib_eth_data = &priv->mib_eth_data; -- -- mutex_lock(&mib_eth_data->mutex); -- -- reinit_completion(&mib_eth_data->rw_done); -- -- mib_eth_data->req_port = dp->index; -- mib_eth_data->data = data; -- refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); -- -- mutex_lock(&priv->reg_mutex); -- -- /* Send mib autocast request */ -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | -- QCA8K_MIB_BUSY); -- -- mutex_unlock(&priv->reg_mutex); -- -- if (ret) -- goto exit; -- -- ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); -- --exit: -- mutex_unlock(&mib_eth_data->mutex); -- -- return ret; --} -- --static void --qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -- uint64_t *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- const struct qca8k_mib_desc *mib; -- u32 reg, i, val; -- u32 hi = 0; -- int ret; -- -- if (priv->mgmt_master && priv->info->ops->autocast_mib && -- priv->info->ops->autocast_mib(ds, port, data) > 0) -- return; -- -- for (i = 0; i < priv->info->mib_count; i++) { -- mib = &ar8327_mib[i]; -- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -- -- ret = qca8k_read(priv, reg, &val); -- if (ret < 0) -- continue; -- -- if (mib->size == 2) { -- ret = qca8k_read(priv, reg + 4, &hi); -- if (ret < 0) -- continue; -- } -- -- data[i] = val; -- if (mib->size == 2) -- data[i] |= (u64)hi << 32; -- } --} -- --static int --qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) --{ -- struct qca8k_priv *priv = ds->priv; -- -- if (sset != ETH_SS_STATS) -- return 0; -- -- return priv->info->mib_count; --} -- --static int --qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -- u32 reg; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -- if (ret < 0) -- goto exit; -- -- if (eee->eee_enabled) -- reg |= lpi_en; -- else -- reg &= ~lpi_en; -- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) --{ -- /* Nothing to do on the port's MAC */ -- return 0; --} -- --static void --qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 stp_state; -- -- switch (state) { -- case BR_STATE_DISABLED: -- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -- break; -- case BR_STATE_BLOCKING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -- break; -- case BR_STATE_LISTENING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -- break; -- case BR_STATE_LEARNING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -- break; -- case BR_STATE_FORWARDING: -- default: -- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -- break; -- } -- -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); --} -- --static int --qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int port_mask, cpu_port; -- int i, ret; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- port_mask = BIT(cpu_port); -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Add this port to the portvlan mask of the other ports -- * in the bridge -- */ -- ret = regmap_set_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- if (ret) -- return ret; -- if (i != port) -- port_mask |= BIT(i); -- } -- -- /* Add all other ports to this ports portvlan mask */ -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, port_mask); -- -- return ret; --} -- --static void --qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, i; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Remove this port to the portvlan mask of the other ports -- * in the bridge -- */ -- regmap_clear_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- } -- -- /* Set the cpu port to be the only one in the portvlan mask of -- * this port -- */ -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); --} -- --static void --qca8k_port_fast_age(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) --{ -- struct qca8k_priv *priv = ds->priv; -- unsigned int secs = msecs / 1000; -- u32 val; -- -- /* AGE_TIME reg is set in 7s step */ -- val = secs / 7; -- -- /* Handle case with 0 as val to NOT disable -- * learning -- */ -- if (!val) -- val = 1; -- -- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -- QCA8K_ATU_AGE_TIME(val)); --} -- --static int --qca8k_port_enable(struct dsa_switch *ds, int port, -- struct phy_device *phy) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 1); -- priv->port_enabled_map |= BIT(port); -- -- if (dsa_is_user_port(ds, port)) -- phy_support_asym_pause(phy); -- -- return 0; --} -- --static void --qca8k_port_disable(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 0); -- priv->port_enabled_map &= ~BIT(port); --} -- --static int --qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- /* We have only have a general MTU setting. -- * DSA always set the CPU port's MTU to the largest MTU of the slave -- * ports. -- * Setting MTU just for the CPU port is sufficient to correctly set a -- * value for every port. -- */ -- if (!dsa_is_cpu_port(ds, port)) -- return 0; -- -- /* To change the MAX_FRAME_SIZE the cpu ports must be off or -- * the switch panics. -- * Turn off both cpu ports before applying the new value to prevent -- * this. -- */ -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 0); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 0); -- -- /* Include L2 header / FCS length */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); -- -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 1); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 1); -- -- return ret; --} -- --static int --qca8k_port_max_mtu(struct dsa_switch *ds, int port) --{ -- return QCA8K_MAX_MTU; --} -- --static int --qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -- u16 port_mask, u16 vid) --{ -- /* Set the vid to the port vlan id if no vid is set */ -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_add(priv, addr, port_mask, vid, -- QCA8K_ATU_STATUS_STATIC); --} -- --static int --qca8k_port_fdb_add(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_del(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_del(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -- dsa_fdb_dump_cb_t *cb, void *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- struct qca8k_fdb _fdb = { 0 }; -- int cnt = QCA8K_NUM_FDB_RECORDS; -- bool is_static; -- int ret = 0; -- -- mutex_lock(&priv->reg_mutex); -- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -- if (!_fdb.aging) -- break; -- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -- ret = cb(_fdb.mac, _fdb.vid, is_static, data); -- if (ret) -- break; -- } -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --qca8k_port_mdb_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); --} -- --static int --qca8k_port_mdb_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); --} -- --static int --qca8k_port_mirror_add(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror, -- bool ingress) --{ -- struct qca8k_priv *priv = ds->priv; -- int monitor_port, ret; -- u32 reg, val; -- -- /* Check for existent entry */ -- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -- return -EEXIST; -- -- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -- if (ret) -- return ret; -- -- /* QCA83xx can have only one port set to mirror mode. -- * Check that the correct port is requested and return error otherwise. -- * When no mirror port is set, the values is set to 0xF -- */ -- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -- return -EEXIST; -- -- /* Set the monitor port */ -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -- mirror->to_local_port); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- return ret; -- -- if (ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_update_bits(priv->regmap, reg, val, val); -- if (ret) -- return ret; -- -- /* Track mirror port for tx and rx to decide when the -- * mirror port has to be disabled. -- */ -- if (ingress) -- priv->mirror_rx |= BIT(port); -- else -- priv->mirror_tx |= BIT(port); -- -- return 0; --} -- --static void --qca8k_port_mirror_del(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg, val; -- int ret; -- -- if (mirror->ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_clear_bits(priv->regmap, reg, val); -- if (ret) -- goto err; -- -- if (mirror->ingress) -- priv->mirror_rx &= ~BIT(port); -- else -- priv->mirror_tx &= ~BIT(port); -- -- /* No port set to send packet to mirror port. Disable mirror port */ -- if (!priv->mirror_rx && !priv->mirror_tx) { -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- goto err; -- } --err: -- dev_err(priv->dev, "Failed to del mirror port from %d", port); --} -- --static int --qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -- struct netlink_ext_ack *extack) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- if (vlan_filtering) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -- } else { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan, -- struct netlink_ext_ack *extack) --{ -- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -- if (ret) { -- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -- return ret; -- } -- -- if (pvid) { -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -- QCA8K_EGREES_VLAN_PORT_MASK(port), -- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -- QCA8K_PORT_VLAN_CVID(vlan->vid) | -- QCA8K_PORT_VLAN_SVID(vlan->vid)); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_del(priv, port, vlan->vid); -- if (ret) -- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -- -- return ret; --} -- --static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- /* Communicate to the phy internal driver the switch revision. -- * Based on the switch revision different values needs to be -- * set to the dbg and mmd reg on the phy. -- * The first 2 bit are used to communicate the switch revision -- * to the phy driver. -- */ -- if (port > 0 && port < 6) -- return priv->switch_revision; -- -- return 0; --} -- --static enum dsa_tag_protocol --qca8k_get_tag_protocol(struct dsa_switch *ds, int port, -- enum dsa_tag_protocol mp) --{ -- return DSA_TAG_PROTO_QCA; --} -- --static bool --qca8k_lag_can_offload(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct dsa_port *dp; -- int id, members = 0; -- -- id = dsa_lag_id(ds->dst, lag); -- if (id < 0 || id >= ds->num_lag_ids) -- return false; -- -- dsa_lag_foreach_port(dp, ds->dst, lag) -- /* Includes the port joining the LAG */ -- members++; -- -- if (members > QCA8K_NUM_PORTS_FOR_LAG) -- return false; -- -- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -- return false; -- -- if (info->hash_type != NETDEV_LAG_HASH_L2 && -- info->hash_type != NETDEV_LAG_HASH_L23) -- return false; -- -- return true; --} -- --static int --qca8k_lag_setup_hash(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct qca8k_priv *priv = ds->priv; -- bool unique_lag = true; -- u32 hash = 0; -- int i, id; -- -- id = dsa_lag_id(ds->dst, lag); -- -- switch (info->hash_type) { -- case NETDEV_LAG_HASH_L23: -- hash |= QCA8K_TRUNK_HASH_SIP_EN; -- hash |= QCA8K_TRUNK_HASH_DIP_EN; -- fallthrough; -- case NETDEV_LAG_HASH_L2: -- hash |= QCA8K_TRUNK_HASH_SA_EN; -- hash |= QCA8K_TRUNK_HASH_DA_EN; -- break; -- default: /* We should NEVER reach this */ -- return -EOPNOTSUPP; -- } -- -- /* Check if we are the unique configured LAG */ -- dsa_lags_foreach_id(i, ds->dst) -- if (i != id && dsa_lag_dev(ds->dst, i)) { -- unique_lag = false; -- break; -- } -- -- /* Hash Mode is global. Make sure the same Hash Mode -- * is set to all the 4 possible lag. -- * If we are the unique LAG we can set whatever hash -- * mode we want. -- * To change hash mode it's needed to remove all LAG -- * and change the mode with the latest. -- */ -- if (unique_lag) { -- priv->lag_hash_mode = hash; -- } else if (priv->lag_hash_mode != hash) { -- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -- return -EOPNOTSUPP; -- } -- -- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -- QCA8K_TRUNK_HASH_MASK, hash); --} -- --static int --qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -- struct net_device *lag, bool delete) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret, id, i; -- u32 val; -- -- id = dsa_lag_id(ds->dst, lag); -- -- /* Read current port member */ -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -- if (ret) -- return ret; -- -- /* Shift val to the correct trunk */ -- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -- if (delete) -- val &= ~BIT(port); -- else -- val |= BIT(port); -- -- /* Update port member. With empty portmap disable trunk */ -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -- QCA8K_REG_GOL_TRUNK_MEMBER(id) | -- QCA8K_REG_GOL_TRUNK_EN(id), -- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -- -- /* Search empty member if adding or port on deleting */ -- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -- if (ret) -- return ret; -- -- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -- -- if (delete) { -- /* If port flagged to be disabled assume this member is -- * empty -- */ -- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -- if (val != port) -- continue; -- } else { -- /* If port flagged to be enabled assume this member is -- * already set -- */ -- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- } -- -- /* We have found the member to add/remove */ -- break; -- } -- -- /* Set port in the correct port mask or disable port if in delete mode */ -- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); --} -- --static int --qca8k_port_lag_join(struct dsa_switch *ds, int port, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- int ret; -- -- if (!qca8k_lag_can_offload(ds, lag, info)) -- return -EOPNOTSUPP; -- -- ret = qca8k_lag_setup_hash(ds, lag, info); -- if (ret) -- return ret; -- -- return qca8k_lag_refresh_portmap(ds, port, lag, false); --} -- --static int --qca8k_port_lag_leave(struct dsa_switch *ds, int port, -- struct net_device *lag) --{ -- return qca8k_lag_refresh_portmap(ds, port, lag, true); --} -- --static void --qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, -- bool operational) --{ -- struct dsa_port *dp = master->dsa_ptr; -- struct qca8k_priv *priv = ds->priv; -- -- /* Ethernet MIB/MDIO is only supported for CPU port 0 */ -- if (dp->index != 0) -- return; -- -- mutex_lock(&priv->mgmt_eth_data.mutex); -- mutex_lock(&priv->mib_eth_data.mutex); -- -- priv->mgmt_master = operational ? (struct net_device *)master : NULL; -- -- mutex_unlock(&priv->mib_eth_data.mutex); -- mutex_unlock(&priv->mgmt_eth_data.mutex); --} -- --static int qca8k_connect_tag_protocol(struct dsa_switch *ds, -- enum dsa_tag_protocol proto) --{ -- struct qca_tagger_data *tagger_data; -- -- switch (proto) { -- case DSA_TAG_PROTO_QCA: -- tagger_data = ds->tagger_data; -- -- tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -- tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; -- -- break; -- default: -- return -EOPNOTSUPP; -- } -- -- return 0; --} -- --static const struct dsa_switch_ops qca8k_switch_ops = { -- .get_tag_protocol = qca8k_get_tag_protocol, -- .setup = qca8k_setup, -- .get_strings = qca8k_get_strings, -- .get_ethtool_stats = qca8k_get_ethtool_stats, -- .get_sset_count = qca8k_get_sset_count, -- .set_ageing_time = qca8k_set_ageing_time, -- .get_mac_eee = qca8k_get_mac_eee, -- .set_mac_eee = qca8k_set_mac_eee, -- .port_enable = qca8k_port_enable, -- .port_disable = qca8k_port_disable, -- .port_change_mtu = qca8k_port_change_mtu, -- .port_max_mtu = qca8k_port_max_mtu, -- .port_stp_state_set = qca8k_port_stp_state_set, -- .port_bridge_join = qca8k_port_bridge_join, -- .port_bridge_leave = qca8k_port_bridge_leave, -- .port_fast_age = qca8k_port_fast_age, -- .port_fdb_add = qca8k_port_fdb_add, -- .port_fdb_del = qca8k_port_fdb_del, -- .port_fdb_dump = qca8k_port_fdb_dump, -- .port_mdb_add = qca8k_port_mdb_add, -- .port_mdb_del = qca8k_port_mdb_del, -- .port_mirror_add = qca8k_port_mirror_add, -- .port_mirror_del = qca8k_port_mirror_del, -- .port_vlan_filtering = qca8k_port_vlan_filtering, -- .port_vlan_add = qca8k_port_vlan_add, -- .port_vlan_del = qca8k_port_vlan_del, -- .phylink_validate = qca8k_phylink_validate, -- .phylink_mac_link_state = qca8k_phylink_mac_link_state, -- .phylink_mac_config = qca8k_phylink_mac_config, -- .phylink_mac_link_down = qca8k_phylink_mac_link_down, -- .phylink_mac_link_up = qca8k_phylink_mac_link_up, -- .get_phy_flags = qca8k_get_phy_flags, -- .port_lag_join = qca8k_port_lag_join, -- .port_lag_leave = qca8k_port_lag_leave, -- .master_state_change = qca8k_master_change, -- .connect_tag_protocol = qca8k_connect_tag_protocol, --}; -- --static int qca8k_read_switch_id(struct qca8k_priv *priv) --{ -- u32 val; -- u8 id; -- int ret; -- -- if (!priv->info) -- return -ENODEV; -- -- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -- if (ret < 0) -- return -ENODEV; -- -- id = QCA8K_MASK_CTRL_DEVICE_ID(val); -- if (id != priv->info->id) { -- dev_err(priv->dev, -- "Switch id detected %x but expected %x", -- id, priv->info->id); -- return -ENODEV; -- } -- -- priv->switch_id = id; -- -- /* Save revision to communicate to the internal PHY driver */ -- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -- -- return 0; --} -- --static int --qca8k_sw_probe(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv; -- int ret; -- -- /* allocate the private data struct so that we can probe the switches -- * ID register -- */ -- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -- if (!priv) -- return -ENOMEM; -- -- priv->info = of_device_get_match_data(priv->dev); -- priv->bus = mdiodev->bus; -- priv->dev = &mdiodev->dev; -- -- priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -- GPIOD_ASIS); -- if (IS_ERR(priv->reset_gpio)) -- return PTR_ERR(priv->reset_gpio); -- -- if (priv->reset_gpio) { -- gpiod_set_value_cansleep(priv->reset_gpio, 1); -- /* The active low duration must be greater than 10 ms -- * and checkpatch.pl wants 20 ms. -- */ -- msleep(20); -- gpiod_set_value_cansleep(priv->reset_gpio, 0); -- } -- -- /* Start by setting up the register mapping */ -- priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, -- &qca8k_regmap_config); -- if (IS_ERR(priv->regmap)) { -- dev_err(priv->dev, "regmap initialization failed"); -- return PTR_ERR(priv->regmap); -- } -- -- priv->mdio_cache.page = 0xffff; -- priv->mdio_cache.lo = 0xffff; -- priv->mdio_cache.hi = 0xffff; -- -- /* Check the detected switch id */ -- ret = qca8k_read_switch_id(priv); -- if (ret) -- return ret; -- -- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -- if (!priv->ds) -- return -ENOMEM; -- -- mutex_init(&priv->mgmt_eth_data.mutex); -- init_completion(&priv->mgmt_eth_data.rw_done); -- -- mutex_init(&priv->mib_eth_data.mutex); -- init_completion(&priv->mib_eth_data.rw_done); -- -- priv->ds->dev = &mdiodev->dev; -- priv->ds->num_ports = QCA8K_NUM_PORTS; -- priv->ds->priv = priv; -- priv->ds->ops = &qca8k_switch_ops; -- mutex_init(&priv->reg_mutex); -- dev_set_drvdata(&mdiodev->dev, priv); -- -- return dsa_register_switch(priv->ds); --} -- --static void --qca8k_sw_remove(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -- int i; -- -- if (!priv) -- return; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) -- qca8k_port_set_status(priv, i, 0); -- -- dsa_unregister_switch(priv->ds); -- -- dev_set_drvdata(&mdiodev->dev, NULL); --} -- --static void qca8k_sw_shutdown(struct mdio_device *mdiodev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -- -- if (!priv) -- return; -- -- dsa_switch_shutdown(priv->ds); -- -- dev_set_drvdata(&mdiodev->dev, NULL); --} -- --#ifdef CONFIG_PM_SLEEP --static void --qca8k_set_pm(struct qca8k_priv *priv, int enable) --{ -- int port; -- -- for (port = 0; port < QCA8K_NUM_PORTS; port++) { -- /* Do not enable on resume if the port was -- * disabled before. -- */ -- if (!(priv->port_enabled_map & BIT(port))) -- continue; -- -- qca8k_port_set_status(priv, port, enable); -- } --} -- --static int qca8k_suspend(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 0); -- -- return dsa_switch_suspend(priv->ds); --} -- --static int qca8k_resume(struct device *dev) --{ -- struct qca8k_priv *priv = dev_get_drvdata(dev); -- -- qca8k_set_pm(priv, 1); -- -- return dsa_switch_resume(priv->ds); --} --#endif /* CONFIG_PM_SLEEP */ -- --static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -- qca8k_suspend, qca8k_resume); -- --static const struct qca8k_info_ops qca8xxx_ops = { -- .autocast_mib = qca8k_get_ethtool_stats_eth, --}; -- --static const struct qca8k_match_data qca8327 = { -- .id = QCA8K_ID_QCA8327, -- .reduced_package = true, -- .mib_count = QCA8K_QCA832X_MIB_COUNT, -- .ops = &qca8xxx_ops, --}; -- --static const struct qca8k_match_data qca8328 = { -- .id = QCA8K_ID_QCA8327, -- .mib_count = QCA8K_QCA832X_MIB_COUNT, -- .ops = &qca8xxx_ops, --}; -- --static const struct qca8k_match_data qca833x = { -- .id = QCA8K_ID_QCA8337, -- .mib_count = QCA8K_QCA833X_MIB_COUNT, -- .ops = &qca8xxx_ops, --}; -- --static const struct of_device_id qca8k_of_match[] = { -- { .compatible = "qca,qca8327", .data = &qca8327 }, -- { .compatible = "qca,qca8328", .data = &qca8328 }, -- { .compatible = "qca,qca8334", .data = &qca833x }, -- { .compatible = "qca,qca8337", .data = &qca833x }, -- { /* sentinel */ }, --}; -- --static struct mdio_driver qca8kmdio_driver = { -- .probe = qca8k_sw_probe, -- .remove = qca8k_sw_remove, -- .shutdown = qca8k_sw_shutdown, -- .mdiodrv.driver = { -- .name = "qca8k", -- .of_match_table = qca8k_of_match, -- .pm = &qca8k_pm_ops, -- }, --}; -- --mdio_module_driver(qca8kmdio_driver); -- --MODULE_AUTHOR("Mathieu Olivari, John Crispin "); --MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); --MODULE_LICENSE("GPL v2"); --MODULE_ALIAS("platform:qca8k"); ---- /dev/null -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -0,0 +1,3186 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2016 John Crispin -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "qca8k.h" -+ -+static void -+qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) -+{ -+ regaddr >>= 1; -+ *r1 = regaddr & 0x1e; -+ -+ regaddr >>= 5; -+ *r2 = regaddr & 0x7; -+ -+ regaddr >>= 3; -+ *page = regaddr & 0x3ff; -+} -+ -+static int -+qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) -+{ -+ u16 *cached_lo = &priv->mdio_cache.lo; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (lo == *cached_lo) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, lo); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit lo register\n"); -+ -+ *cached_lo = lo; -+ return 0; -+} -+ -+static int -+qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) -+{ -+ u16 *cached_hi = &priv->mdio_cache.hi; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (hi == *cached_hi) -+ return 0; -+ -+ ret = bus->write(bus, phy_id, regnum, hi); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit hi register\n"); -+ -+ *cached_hi = hi; -+ return 0; -+} -+ -+static int -+qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) -+{ -+ int ret; -+ -+ ret = bus->read(bus, phy_id, regnum); -+ if (ret >= 0) { -+ *val = ret; -+ ret = bus->read(bus, phy_id, regnum + 1); -+ *val |= ret << 16; -+ } -+ -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to read qca8k 32bit register\n"); -+ *val = 0; -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static void -+qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) -+{ -+ u16 lo, hi; -+ int ret; -+ -+ lo = val & 0xffff; -+ hi = (u16)(val >> 16); -+ -+ ret = qca8k_set_lo(priv, phy_id, regnum, lo); -+ if (ret >= 0) -+ ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); -+} -+ -+static int -+qca8k_set_page(struct qca8k_priv *priv, u16 page) -+{ -+ u16 *cached_page = &priv->mdio_cache.page; -+ struct mii_bus *bus = priv->bus; -+ int ret; -+ -+ if (page == *cached_page) -+ return 0; -+ -+ ret = bus->write(bus, 0x18, 0, page); -+ if (ret < 0) { -+ dev_err_ratelimited(&bus->dev, -+ "failed to set qca8k page\n"); -+ return ret; -+ } -+ -+ *cached_page = page; -+ usleep_range(1000, 2000); -+ return 0; -+} -+ -+static int -+qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) -+{ -+ return regmap_read(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return regmap_write(priv->regmap, reg, val); -+} -+ -+static int -+qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ return regmap_update_bits(priv->regmap, reg, mask, write_val); -+} -+ -+static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ u8 len, cmd; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -+ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -+ -+ /* Make sure the seq match the requested packet */ -+ if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -+ mgmt_eth_data->ack = true; -+ -+ if (cmd == MDIO_READ) { -+ mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -+ -+ /* Get the rest of the 12 byte of data. -+ * The read/write function will extract the requested data. -+ */ -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(mgmt_eth_data->data + 1, skb->data, -+ QCA_HDR_MGMT_DATA2_LEN); -+ } -+ -+ complete(&mgmt_eth_data->rw_done); -+} -+ -+static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, -+ int priority, unsigned int len) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ unsigned int real_len; -+ struct sk_buff *skb; -+ u32 *data2; -+ u16 hdr; -+ -+ skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); -+ if (!skb) -+ return NULL; -+ -+ /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -+ * Actually for some reason the steps are: -+ * 0: nothing -+ * 1-4: first 4 byte -+ * 5-6: first 12 byte -+ * 7-15: all 16 byte -+ */ -+ if (len == 16) -+ real_len = 15; -+ else -+ real_len = len; -+ -+ skb_reset_mac_header(skb); -+ skb_set_network_header(skb, skb->len); -+ -+ mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); -+ -+ hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); -+ hdr |= QCA_HDR_XMIT_FROM_CPU; -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); -+ hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); -+ -+ mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -+ mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -+ QCA_HDR_MGMT_CHECK_CODE_VAL); -+ -+ if (cmd == MDIO_WRITE) -+ mgmt_ethhdr->mdio_data = *val; -+ -+ mgmt_ethhdr->hdr = htons(hdr); -+ -+ data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -+ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ return skb; -+} -+ -+static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) -+{ -+ struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ -+ mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -+ mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); -+} -+ -+static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ *val = mgmt_eth_data->data[0]; -+ if (len > QCA_HDR_MGMT_DATA1_LEN) -+ memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; -+ struct sk_buff *skb; -+ bool ack; -+ int ret; -+ -+ skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, -+ QCA8K_ETHERNET_MDIO_PRIORITY, len); -+ if (!skb) -+ return -ENOMEM; -+ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check mgmt_master if is operational */ -+ if (!priv->mgmt_master) { -+ kfree_skb(skb); -+ mutex_unlock(&mgmt_eth_data->mutex); -+ return -EINVAL; -+ } -+ -+ skb->dev = priv->mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the mdio pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); -+ -+ ack = mgmt_eth_data->ack; -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int -+qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ u32 val = 0; -+ int ret; -+ -+ ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); -+ if (ret) -+ return ret; -+ -+ val &= ~mask; -+ val |= write_val; -+ -+ return qca8k_write_eth(priv, reg, &val, sizeof(val)); -+} -+ -+static int -+qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ -+ if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ u32 tmp; -+ -+ if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ tmp = val[i]; -+ -+ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ int ret; -+ -+ if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ return ret; -+} -+ -+static int -+qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) -+ return 0; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ if (ret < 0) -+ goto exit; -+ -+ val &= ~mask; -+ val |= write_val; -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+exit: -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static const struct regmap_range qca8k_readable_ranges[] = { -+ regmap_reg_range(0x0000, 0x00e4), /* Global control */ -+ regmap_reg_range(0x0100, 0x0168), /* EEE control */ -+ regmap_reg_range(0x0200, 0x0270), /* Parser control */ -+ regmap_reg_range(0x0400, 0x0454), /* ACL */ -+ regmap_reg_range(0x0600, 0x0718), /* Lookup */ -+ regmap_reg_range(0x0800, 0x0b70), /* QM */ -+ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -+ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -+ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -+ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -+ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -+ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -+ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -+ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -+ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -+ -+}; -+ -+static const struct regmap_access_table qca8k_readable_table = { -+ .yes_ranges = qca8k_readable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), -+}; -+ -+static struct regmap_config qca8k_regmap_config = { -+ .reg_bits = 16, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .max_register = 0x16ac, /* end MIB - Port6 range */ -+ .reg_read = qca8k_regmap_read, -+ .reg_write = qca8k_regmap_write, -+ .reg_update_bits = qca8k_regmap_update_bits, -+ .rd_table = &qca8k_readable_table, -+ .disable_locking = true, /* Locking is handled by qca8k read/write */ -+ .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ -+}; -+ -+static int -+qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) -+{ -+ u32 val; -+ -+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); -+} -+ -+static int -+qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) -+{ -+ u32 reg[3]; -+ int ret; -+ -+ /* load the ARL table into an array */ -+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+ if (ret) -+ return ret; -+ -+ /* vid - 83:72 */ -+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -+ /* aging - 67:64 */ -+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -+ /* portmask - 54:48 */ -+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -+ /* mac - 47:0 */ -+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -+ -+ return 0; -+} -+ -+static void -+qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -+ u8 aging) -+{ -+ u32 reg[3] = { 0 }; -+ -+ /* vid - 83:72 */ -+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -+ /* aging - 67:64 */ -+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -+ /* portmask - 54:48 */ -+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -+ /* mac - 47:0 */ -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -+ -+ /* load the array into the ARL table */ -+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+} -+ -+static int -+qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and FDB index */ -+ reg = QCA8K_ATU_FUNC_BUSY; -+ reg |= cmd; -+ if (port >= 0) { -+ reg |= QCA8K_ATU_FUNC_PORT_EN; -+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -+ } -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_FDB_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_ATU_FUNC_FULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) -+{ -+ int ret; -+ -+ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -+ if (ret < 0) -+ return ret; -+ -+ return qca8k_fdb_read(priv, fdb); -+} -+ -+static int -+qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -+ u16 vid, u8 aging) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static void -+qca8k_fdb_flush(struct qca8k_priv *priv) -+{ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_fdb_read(priv, &fdb); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule exist. Delete first */ -+ if (!fdb.aging) { -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ } -+ -+ /* Add port to fdb portmask */ -+ fdb.port_mask |= port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule doesn't exist. Why delete? */ -+ if (!fdb.aging) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ -+ /* Only port in the rule is this port. Don't re insert */ -+ if (fdb.port_mask == port_mask) -+ goto exit; -+ -+ /* Remove port from port mask */ -+ fdb.port_mask &= ~port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and VLAN index */ -+ reg = QCA8K_VTU_FUNC1_BUSY; -+ reg |= cmd; -+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_VLAN_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_VTU_FUNC1_FULL) -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) -+{ -+ u32 reg; -+ int ret; -+ -+ /* -+ We do the right thing with VLAN 0 and treat it as untagged while -+ preserving the tag on egress. -+ */ -+ if (vid == 0) -+ return 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ if (untagged) -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -+ else -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -+ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) -+{ -+ u32 reg, mask; -+ int ret, i; -+ bool del; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -+ -+ /* Check if we're the last member to be removed */ -+ del = true; -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -+ -+ if ((reg & mask) != mask) { -+ del = false; -+ break; -+ } -+ } -+ -+ if (del) { -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -+ } else { -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ } -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int -+qca8k_mib_init(struct qca8k_priv *priv) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -+ QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static void -+qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) -+{ -+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ /* Port 0 and 6 have no internal PHY */ -+ if (port > 0 && port < 6) -+ mask |= QCA8K_PORT_STATUS_LINK_AUTO; -+ -+ if (enable) -+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+ else -+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+} -+ -+static int -+qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, -+ struct sk_buff *read_skb, u32 *val) -+{ -+ struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); -+ bool ack; -+ int ret; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the copy pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) -+ return -ETIMEDOUT; -+ -+ if (!ack) -+ return -EINVAL; -+ -+ *val = mgmt_eth_data->data[0]; -+ -+ return 0; -+} -+ -+static int -+qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, -+ int regnum, u16 data) -+{ -+ struct sk_buff *write_skb, *clear_skb, *read_skb; -+ struct qca8k_mgmt_eth_data *mgmt_eth_data; -+ u32 write_val, clear_val = 0, val; -+ struct net_device *mgmt_master; -+ int ret, ret1; -+ bool ack; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ mgmt_eth_data = &priv->mgmt_eth_data; -+ -+ write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ if (read) { -+ write_val |= QCA8K_MDIO_MASTER_READ; -+ } else { -+ write_val |= QCA8K_MDIO_MASTER_WRITE; -+ write_val |= QCA8K_MDIO_MASTER_DATA(data); -+ } -+ -+ /* Prealloc all the needed skb before the lock */ -+ write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); -+ if (!write_skb) -+ return -ENOMEM; -+ -+ clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -+ if (!clear_skb) { -+ ret = -ENOMEM; -+ goto err_clear_skb; -+ } -+ -+ read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, -+ QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); -+ if (!read_skb) { -+ ret = -ENOMEM; -+ goto err_read_skb; -+ } -+ -+ /* Actually start the request: -+ * 1. Send mdio master packet -+ * 2. Busy Wait for mdio master command -+ * 3. Get the data if we are reading -+ * 4. Reset the mdio master (even with error) -+ */ -+ mutex_lock(&mgmt_eth_data->mutex); -+ -+ /* Check if mgmt_master is operational */ -+ mgmt_master = priv->mgmt_master; -+ if (!mgmt_master) { -+ mutex_unlock(&mgmt_eth_data->mutex); -+ ret = -EINVAL; -+ goto err_mgmt_master; -+ } -+ -+ read_skb->dev = mgmt_master; -+ clear_skb->dev = mgmt_master; -+ write_skb->dev = mgmt_master; -+ -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the write pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(write_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ kfree_skb(read_skb); -+ goto exit; -+ } -+ -+ ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, -+ !(val & QCA8K_MDIO_MASTER_BUSY), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ mgmt_eth_data, read_skb, &val); -+ -+ if (ret < 0 && ret1 < 0) { -+ ret = ret1; -+ goto exit; -+ } -+ -+ if (read) { -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the read pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(read_skb); -+ -+ ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ ack = mgmt_eth_data->ack; -+ -+ if (ret <= 0) { -+ ret = -ETIMEDOUT; -+ goto exit; -+ } -+ -+ if (!ack) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; -+ } else { -+ kfree_skb(read_skb); -+ } -+exit: -+ reinit_completion(&mgmt_eth_data->rw_done); -+ -+ /* Increment seq_num and set it in the clear pkt */ -+ mgmt_eth_data->seq++; -+ qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); -+ mgmt_eth_data->ack = false; -+ -+ dev_queue_xmit(clear_skb); -+ -+ wait_for_completion_timeout(&mgmt_eth_data->rw_done, -+ QCA8K_ETHERNET_TIMEOUT); -+ -+ mutex_unlock(&mgmt_eth_data->mutex); -+ -+ return ret; -+ -+ /* Error handling before lock */ -+err_mgmt_master: -+ kfree_skb(read_skb); -+err_read_skb: -+ kfree_skb(clear_skb); -+err_clear_skb: -+ kfree_skb(write_skb); -+ -+ return ret; -+} -+ -+static u32 -+qca8k_port_to_phy(int port) -+{ -+ /* From Andrew Lunn: -+ * Port 0 has no internal phy. -+ * Port 1 has an internal PHY at MDIO address 0. -+ * Port 2 has an internal PHY at MDIO address 1. -+ * ... -+ * Port 5 has an internal PHY at MDIO address 4. -+ * Port 6 has no internal PHY. -+ */ -+ -+ return port - 1; -+} -+ -+static int -+qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) -+{ -+ u16 r1, r2, page; -+ u32 val; -+ int ret, ret1; -+ -+ qca8k_split_addr(reg, &r1, &r2, &page); -+ -+ ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, -+ bus, 0x10 | r2, r1, &val); -+ -+ /* Check if qca8k_read has failed for a different reason -+ * before returnting -ETIMEDOUT -+ */ -+ if (ret < 0 && ret1 < 0) -+ return ret1; -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum) | -+ QCA8K_MDIO_MASTER_DATA(data); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ return ret; -+} -+ -+static int -+qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) -+{ -+ struct mii_bus *bus = priv->bus; -+ u16 r1, r2, page; -+ u32 val; -+ int ret; -+ -+ if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) -+ return -EINVAL; -+ -+ val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | -+ QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | -+ QCA8K_MDIO_MASTER_REG_ADDR(regnum); -+ -+ qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ -+ ret = qca8k_set_page(priv, page); -+ if (ret) -+ goto exit; -+ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ -+ ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); -+ -+exit: -+ /* even if the busy_wait timeouts try to clear the MASTER_EN */ -+ qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ -+ mutex_unlock(&bus->mdio_lock); -+ -+ if (ret >= 0) -+ ret = val & QCA8K_MDIO_MASTER_DATA_MASK; -+ -+ return ret; -+} -+ -+static int -+qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); -+ if (!ret) -+ return 0; -+ -+ return qca8k_mdio_write(priv, phy, regnum, data); -+} -+ -+static int -+qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) -+{ -+ struct qca8k_priv *priv = slave_bus->priv; -+ int ret; -+ -+ /* Use mdio Ethernet when available, fallback to legacy one on error */ -+ ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); -+ if (ret >= 0) -+ return ret; -+ -+ ret = qca8k_mdio_read(priv, phy, regnum); -+ -+ if (ret < 0) -+ return 0xffff; -+ -+ return ret; -+} -+ -+static int -+qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) -+{ -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ return qca8k_internal_mdio_write(slave_bus, port, regnum, data); -+} -+ -+static int -+qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) -+{ -+ port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; -+ -+ return qca8k_internal_mdio_read(slave_bus, port, regnum); -+} -+ -+static int -+qca8k_mdio_register(struct qca8k_priv *priv) -+{ -+ struct dsa_switch *ds = priv->ds; -+ struct device_node *mdio; -+ struct mii_bus *bus; -+ -+ bus = devm_mdiobus_alloc(ds->dev); -+ if (!bus) -+ return -ENOMEM; -+ -+ bus->priv = (void *)priv; -+ snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", -+ ds->dst->index, ds->index); -+ bus->parent = ds->dev; -+ bus->phy_mask = ~ds->phys_mii_mask; -+ ds->slave_mii_bus = bus; -+ -+ /* Check if the devicetree declare the port:phy mapping */ -+ mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); -+ if (of_device_is_available(mdio)) { -+ bus->name = "qca8k slave mii"; -+ bus->read = qca8k_internal_mdio_read; -+ bus->write = qca8k_internal_mdio_write; -+ return devm_of_mdiobus_register(priv->dev, bus, mdio); -+ } -+ -+ /* If a mapping can't be found the legacy mapping is used, -+ * using the qca8k_port_to_phy function -+ */ -+ bus->name = "qca8k-legacy slave mii"; -+ bus->read = qca8k_legacy_mdio_read; -+ bus->write = qca8k_legacy_mdio_write; -+ return devm_mdiobus_register(priv->dev, bus); -+} -+ -+static int -+qca8k_setup_mdio_bus(struct qca8k_priv *priv) -+{ -+ u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; -+ struct device_node *ports, *port; -+ phy_interface_t mode; -+ int err; -+ -+ ports = of_get_child_by_name(priv->dev->of_node, "ports"); -+ if (!ports) -+ ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); -+ -+ if (!ports) -+ return -EINVAL; -+ -+ for_each_available_child_of_node(ports, port) { -+ err = of_property_read_u32(port, "reg", ®); -+ if (err) { -+ of_node_put(port); -+ of_node_put(ports); -+ return err; -+ } -+ -+ if (!dsa_is_user_port(priv->ds, reg)) -+ continue; -+ -+ of_get_phy_mode(port, &mode); -+ -+ if (of_property_read_bool(port, "phy-handle") && -+ mode != PHY_INTERFACE_MODE_INTERNAL) -+ external_mdio_mask |= BIT(reg); -+ else -+ internal_mdio_mask |= BIT(reg); -+ } -+ -+ of_node_put(ports); -+ if (!external_mdio_mask && !internal_mdio_mask) { -+ dev_err(priv->dev, "no PHYs are defined.\n"); -+ return -EINVAL; -+ } -+ -+ /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through -+ * the MDIO_MASTER register also _disconnects_ the external MDC -+ * passthrough to the internal PHYs. It's not possible to use both -+ * configurations at the same time! -+ * -+ * Because this came up during the review process: -+ * If the external mdio-bus driver is capable magically disabling -+ * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's -+ * accessors for the time being, it would be possible to pull this -+ * off. -+ */ -+ if (!!external_mdio_mask && !!internal_mdio_mask) { -+ dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); -+ return -EINVAL; -+ } -+ -+ if (external_mdio_mask) { -+ /* Make sure to disable the internal mdio bus in cases -+ * a dt-overlay and driver reload changed the configuration -+ */ -+ -+ return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, -+ QCA8K_MDIO_MASTER_EN); -+ } -+ -+ return qca8k_mdio_register(priv); -+} -+ -+static int -+qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) -+{ -+ u32 mask = 0; -+ int ret = 0; -+ -+ /* SoC specific settings for ipq8064. -+ * If more device require this consider adding -+ * a dedicated binding. -+ */ -+ if (of_machine_is_compatible("qcom,ipq8064")) -+ mask |= QCA8K_MAC_PWR_RGMII0_1_8V; -+ -+ /* SoC specific settings for ipq8065 */ -+ if (of_machine_is_compatible("qcom,ipq8065")) -+ mask |= QCA8K_MAC_PWR_RGMII1_1_8V; -+ -+ if (mask) { -+ ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, -+ QCA8K_MAC_PWR_RGMII0_1_8V | -+ QCA8K_MAC_PWR_RGMII1_1_8V, -+ mask); -+ } -+ -+ return ret; -+} -+ -+static int qca8k_find_cpu_port(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Find the connected cpu port. Valid port are 0 or 6 */ -+ if (dsa_is_cpu_port(ds, 0)) -+ return 0; -+ -+ dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); -+ -+ if (dsa_is_cpu_port(ds, 6)) -+ return 6; -+ -+ return -EINVAL; -+} -+ -+static int -+qca8k_setup_of_pws_reg(struct qca8k_priv *priv) -+{ -+ const struct qca8k_match_data *data = priv->info; -+ struct device_node *node = priv->dev->of_node; -+ u32 val = 0; -+ int ret; -+ -+ /* QCA8327 require to set to the correct mode. -+ * His bigger brother QCA8328 have the 172 pin layout. -+ * Should be applied by default but we set this just to make sure. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ /* Set the correct package of 148 pin for QCA8327 */ -+ if (data->reduced_package) -+ val |= QCA8327_PWS_PACKAGE148_EN; -+ -+ ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, -+ val); -+ if (ret) -+ return ret; -+ } -+ -+ if (of_property_read_bool(node, "qca,ignore-power-on-sel")) -+ val |= QCA8K_PWS_POWER_ON_SEL; -+ -+ if (of_property_read_bool(node, "qca,led-open-drain")) { -+ if (!(val & QCA8K_PWS_POWER_ON_SEL)) { -+ dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); -+ return -EINVAL; -+ } -+ -+ val |= QCA8K_PWS_LED_OPEN_EN_CSR; -+ } -+ -+ return qca8k_rmw(priv, QCA8K_REG_PWS, -+ QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, -+ val); -+} -+ -+static int -+qca8k_parse_port_config(struct qca8k_priv *priv) -+{ -+ int port, cpu_port_index = -1, ret; -+ struct device_node *port_dn; -+ phy_interface_t mode; -+ struct dsa_port *dp; -+ u32 delay; -+ -+ /* We have 2 CPU port. Check them */ -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Skip every other port */ -+ if (port != 0 && port != 6) -+ continue; -+ -+ dp = dsa_to_port(priv->ds, port); -+ port_dn = dp->dn; -+ cpu_port_index++; -+ -+ if (!of_device_is_available(port_dn)) -+ continue; -+ -+ ret = of_get_phy_mode(port_dn, &mode); -+ if (ret) -+ continue; -+ -+ switch (mode) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ case PHY_INTERFACE_MODE_SGMII: -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID) -+ delay = 1; -+ -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { -+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; -+ -+ delay = 0; -+ -+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) -+ /* Switch regs accept value in ns, convert ps to ns */ -+ delay = delay / 1000; -+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ delay = 2; -+ -+ if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { -+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); -+ delay = 3; -+ } -+ -+ priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; -+ -+ /* Skip sgmii parsing for rgmii* mode */ -+ if (mode == PHY_INTERFACE_MODE_RGMII || -+ mode == PHY_INTERFACE_MODE_RGMII_ID || -+ mode == PHY_INTERFACE_MODE_RGMII_TXID || -+ mode == PHY_INTERFACE_MODE_RGMII_RXID) -+ break; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) -+ priv->ports_config.sgmii_tx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) -+ priv->ports_config.sgmii_rx_clk_falling_edge = true; -+ -+ if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { -+ priv->ports_config.sgmii_enable_pll = true; -+ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); -+ priv->ports_config.sgmii_enable_pll = false; -+ } -+ -+ if (priv->switch_revision < 2) -+ dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); -+ } -+ -+ break; -+ default: -+ continue; -+ } -+ } -+ -+ return 0; -+} -+ -+static int -+qca8k_setup(struct dsa_switch *ds) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, ret, i; -+ u32 mask; -+ -+ cpu_port = qca8k_find_cpu_port(ds); -+ if (cpu_port < 0) { -+ dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); -+ return cpu_port; -+ } -+ -+ /* Parse CPU port config to be later used in phy_link mac_config */ -+ ret = qca8k_parse_port_config(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_mdio_bus(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_of_pws_reg(priv); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_setup_mac_pwr_sel(priv); -+ if (ret) -+ return ret; -+ -+ /* Make sure MAC06 is disabled */ -+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, -+ QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed disabling MAC06 exchange"); -+ return ret; -+ } -+ -+ /* Enable CPU Port */ -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling CPU port"); -+ return ret; -+ } -+ -+ /* Enable MIB counters */ -+ ret = qca8k_mib_init(priv); -+ if (ret) -+ dev_warn(priv->dev, "mib init failed"); -+ -+ /* Initial setup of all ports */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* Disable forwarding by default on all ports */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, 0); -+ if (ret) -+ return ret; -+ -+ /* Enable QCA header mode on all cpu ports */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | -+ FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); -+ if (ret) { -+ dev_err(priv->dev, "failed enabling QCA header mode"); -+ return ret; -+ } -+ } -+ -+ /* Disable MAC by default on all user ports */ -+ if (dsa_is_user_port(ds, i)) -+ qca8k_port_set_status(priv, i, 0); -+ } -+ -+ /* Forward all unknown frames to CPU port for Linux processing -+ * Notice that in multi-cpu config only one port should be set -+ * for igmp, unknown, multicast and broadcast packet -+ */ -+ ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | -+ FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); -+ if (ret) -+ return ret; -+ -+ /* Setup connection between CPU port & user ports -+ * Configure specific switch configuration for ports -+ */ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ /* CPU port gets connected to all user ports of the switch */ -+ if (dsa_is_cpu_port(ds, i)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); -+ if (ret) -+ return ret; -+ } -+ -+ /* Individual user ports get connected to CPU port only */ -+ if (dsa_is_user_port(ds, i)) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_MEMBER, -+ BIT(cpu_port)); -+ if (ret) -+ return ret; -+ -+ /* Enable ARP Auto-learning by default */ -+ ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), -+ QCA8K_PORT_LOOKUP_LEARN); -+ if (ret) -+ return ret; -+ -+ /* For port based vlans to work we need to set the -+ * default egress vid -+ */ -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), -+ QCA8K_EGREES_VLAN_PORT_MASK(i), -+ QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), -+ QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | -+ QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); -+ if (ret) -+ return ret; -+ } -+ -+ /* The port 5 of the qca8337 have some problem in flood condition. The -+ * original legacy driver had some specific buffer and priority settings -+ * for the different port suggested by the QCA switch team. Add this -+ * missing settings to improve switch stability under load condition. -+ * This problem is limited to qca8337 and other qca8k switch are not affected. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) { -+ switch (i) { -+ /* The 2 CPU port and port 5 requires some different -+ * priority than any other ports. -+ */ -+ case 0: -+ case 5: -+ case 6: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); -+ break; -+ default: -+ mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | -+ QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | -+ QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); -+ } -+ qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); -+ -+ mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN; -+ qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), -+ QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | -+ QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | -+ QCA8K_PORT_HOL_CTRL1_WRED_EN, -+ mask); -+ } -+ } -+ -+ /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ -+ if (priv->switch_id == QCA8K_ID_QCA8327) { -+ mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); -+ qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, -+ QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | -+ QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, -+ mask); -+ } -+ -+ /* Setup our port MTUs to match power on defaults */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); -+ if (ret) -+ dev_warn(priv->dev, "failed setting MTU settings"); -+ -+ /* Flush the FDB table */ -+ qca8k_fdb_flush(priv); -+ -+ /* We don't have interrupts for link changes, so we need to poll */ -+ ds->pcs_poll = true; -+ -+ /* Set min a max ageing value supported */ -+ ds->ageing_time_min = 7000; -+ ds->ageing_time_max = 458745000; -+ -+ /* Set max number of LAGs supported */ -+ ds->num_lag_ids = QCA8K_NUM_LAGS; -+ -+ return 0; -+} -+ -+static void -+qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, -+ u32 reg) -+{ -+ u32 delay, val = 0; -+ int ret; -+ -+ /* Delay can be declared in 3 different way. -+ * Mode to rgmii and internal-delay standard binding defined -+ * rgmii-id or rgmii-tx/rx phy mode set. -+ * The parse logic set a delay different than 0 only when one -+ * of the 3 different way is used. In all other case delay is -+ * not enabled. With ID or TX/RXID delay is enabled and set -+ * to the default and recommended value. -+ */ -+ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; -+ } -+ -+ if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { -+ delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; -+ -+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; -+ } -+ -+ /* Set RGMII delay based on the selected values */ -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | -+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, -+ val); -+ if (ret) -+ dev_err(priv->dev, "Failed to set internal delay for CPU port%d", -+ cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); -+} -+ -+static void -+qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, -+ const struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int cpu_port_index, ret; -+ u32 reg, val; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ return; -+ -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT0; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY, nothing to do */ -+ return; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ return; -+ -+ reg = QCA8K_REG_PORT6_PAD_CTRL; -+ cpu_port_index = QCA8K_CPU_PORT6; -+ break; -+ default: -+ dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); -+ return; -+ } -+ -+ if (port != 6 && phylink_autoneg_inband(mode)) { -+ dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -+ __func__); -+ return; -+ } -+ -+ switch (state->interface) { -+ case PHY_INTERFACE_MODE_RGMII: -+ case PHY_INTERFACE_MODE_RGMII_ID: -+ case PHY_INTERFACE_MODE_RGMII_TXID: -+ case PHY_INTERFACE_MODE_RGMII_RXID: -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); -+ -+ /* Configure rgmii delay */ -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ /* QCA8337 requires to set rgmii rx delay for all ports. -+ * This is enabled through PORT5_PAD_CTRL for all ports, -+ * rather than individual port registers. -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8337) -+ qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, -+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); -+ break; -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_1000BASEX: -+ /* Enable SGMII on the port */ -+ qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); -+ -+ /* Enable/disable SerDes auto-negotiation as necessary */ -+ ret = qca8k_read(priv, QCA8K_REG_PWS, &val); -+ if (ret) -+ return; -+ if (phylink_autoneg_inband(mode)) -+ val &= ~QCA8K_PWS_SERDES_AEN_DIS; -+ else -+ val |= QCA8K_PWS_SERDES_AEN_DIS; -+ qca8k_write(priv, QCA8K_REG_PWS, val); -+ -+ /* Configure the SGMII parameters */ -+ ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); -+ if (ret) -+ return; -+ -+ val |= QCA8K_SGMII_EN_SD; -+ -+ if (priv->ports_config.sgmii_enable_pll) -+ val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | -+ QCA8K_SGMII_EN_TX; -+ -+ if (dsa_is_cpu_port(ds, port)) { -+ /* CPU port, we're talking to the CPU MAC, be a PHY */ -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_PHY; -+ } else if (state->interface == PHY_INTERFACE_MODE_SGMII) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_MAC; -+ } else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) { -+ val &= ~QCA8K_SGMII_MODE_CTRL_MASK; -+ val |= QCA8K_SGMII_MODE_CTRL_BASEX; -+ } -+ -+ qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); -+ -+ /* From original code is reported port instability as SGMII also -+ * require delay set. Apply advised values here or take them from DT. -+ */ -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); -+ -+ /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and -+ * falling edge is set writing in the PORT0 PAD reg -+ */ -+ if (priv->switch_id == QCA8K_ID_QCA8327 || -+ priv->switch_id == QCA8K_ID_QCA8337) -+ reg = QCA8K_REG_PORT0_PAD_CTRL; -+ -+ val = 0; -+ -+ /* SGMII Clock phase configuration */ -+ if (priv->ports_config.sgmii_rx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; -+ -+ if (priv->ports_config.sgmii_tx_clk_falling_edge) -+ val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; -+ -+ if (val) -+ ret = qca8k_rmw(priv, reg, -+ QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | -+ QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, -+ val); -+ -+ break; -+ default: -+ dev_err(ds->dev, "xMII mode %s not supported for port %d\n", -+ phy_modes(state->interface), port); -+ return; -+ } -+} -+ -+static void -+qca8k_phylink_validate(struct dsa_switch *ds, int port, -+ unsigned long *supported, -+ struct phylink_link_state *state) -+{ -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; -+ -+ switch (port) { -+ case 0: /* 1st CPU port */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII) -+ goto unsupported; -+ break; -+ case 1: -+ case 2: -+ case 3: -+ case 4: -+ case 5: -+ /* Internal PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_GMII && -+ state->interface != PHY_INTERFACE_MODE_INTERNAL) -+ goto unsupported; -+ break; -+ case 6: /* 2nd CPU port / external PHY */ -+ if (state->interface != PHY_INTERFACE_MODE_NA && -+ state->interface != PHY_INTERFACE_MODE_RGMII && -+ state->interface != PHY_INTERFACE_MODE_RGMII_ID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_TXID && -+ state->interface != PHY_INTERFACE_MODE_RGMII_RXID && -+ state->interface != PHY_INTERFACE_MODE_SGMII && -+ state->interface != PHY_INTERFACE_MODE_1000BASEX) -+ goto unsupported; -+ break; -+ default: -+unsupported: -+ linkmode_zero(supported); -+ return; -+ } -+ -+ phylink_set_port_modes(mask); -+ phylink_set(mask, Autoneg); -+ -+ phylink_set(mask, 1000baseT_Full); -+ phylink_set(mask, 10baseT_Half); -+ phylink_set(mask, 10baseT_Full); -+ phylink_set(mask, 100baseT_Half); -+ phylink_set(mask, 100baseT_Full); -+ -+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX) -+ phylink_set(mask, 1000baseX_Full); -+ -+ phylink_set(mask, Pause); -+ phylink_set(mask, Asym_Pause); -+ -+ linkmode_and(supported, supported, mask); -+ linkmode_and(state->advertising, state->advertising, mask); -+} -+ -+static int -+qca8k_phylink_mac_link_state(struct dsa_switch *ds, int port, -+ struct phylink_link_state *state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ int ret; -+ -+ ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); -+ if (ret < 0) -+ return ret; -+ -+ state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); -+ state->an_complete = state->link; -+ state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); -+ state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : -+ DUPLEX_HALF; -+ -+ switch (reg & QCA8K_PORT_STATUS_SPEED) { -+ case QCA8K_PORT_STATUS_SPEED_10: -+ state->speed = SPEED_10; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_100: -+ state->speed = SPEED_100; -+ break; -+ case QCA8K_PORT_STATUS_SPEED_1000: -+ state->speed = SPEED_1000; -+ break; -+ default: -+ state->speed = SPEED_UNKNOWN; -+ break; -+ } -+ -+ state->pause = MLO_PAUSE_NONE; -+ if (reg & QCA8K_PORT_STATUS_RXFLOW) -+ state->pause |= MLO_PAUSE_RX; -+ if (reg & QCA8K_PORT_STATUS_TXFLOW) -+ state->pause |= MLO_PAUSE_TX; -+ -+ return 1; -+} -+ -+static void -+qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+} -+ -+static void -+qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, -+ phy_interface_t interface, struct phy_device *phydev, -+ int speed, int duplex, bool tx_pause, bool rx_pause) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ -+ if (phylink_autoneg_inband(mode)) { -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ } else { -+ switch (speed) { -+ case SPEED_10: -+ reg = QCA8K_PORT_STATUS_SPEED_10; -+ break; -+ case SPEED_100: -+ reg = QCA8K_PORT_STATUS_SPEED_100; -+ break; -+ case SPEED_1000: -+ reg = QCA8K_PORT_STATUS_SPEED_1000; -+ break; -+ default: -+ reg = QCA8K_PORT_STATUS_LINK_AUTO; -+ break; -+ } -+ -+ if (duplex == DUPLEX_FULL) -+ reg |= QCA8K_PORT_STATUS_DUPLEX; -+ -+ if (rx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_RXFLOW; -+ -+ if (tx_pause || dsa_is_cpu_port(ds, port)) -+ reg |= QCA8K_PORT_STATUS_TXFLOW; -+ } -+ -+ reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); -+} -+ -+static void -+qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int i; -+ -+ if (stringset != ETH_SS_STATS) -+ return; -+ -+ for (i = 0; i < priv->info->mib_count; i++) -+ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -+ ETH_GSTRING_LEN); -+} -+ -+static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) -+{ -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ const struct qca8k_mib_desc *mib; -+ struct mib_ethhdr *mib_ethhdr; -+ int i, mib_len, offset = 0; -+ u64 *data; -+ u8 port; -+ -+ mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); -+ mib_eth_data = &priv->mib_eth_data; -+ -+ /* The switch autocast every port. Ignore other packet and -+ * parse only the requested one. -+ */ -+ port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); -+ if (port != mib_eth_data->req_port) -+ goto exit; -+ -+ data = mib_eth_data->data; -+ -+ for (i = 0; i < priv->info->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ -+ /* First 3 mib are present in the skb head */ -+ if (i < 3) { -+ data[i] = mib_ethhdr->data[i]; -+ continue; -+ } -+ -+ mib_len = sizeof(uint32_t); -+ -+ /* Some mib are 64 bit wide */ -+ if (mib->size == 2) -+ mib_len = sizeof(uint64_t); -+ -+ /* Copy the mib value from packet to the */ -+ memcpy(data + i, skb->data + offset, mib_len); -+ -+ /* Set the offset for the next mib */ -+ offset += mib_len; -+ } -+ -+exit: -+ /* Complete on receiving all the mib packet */ -+ if (refcount_dec_and_test(&mib_eth_data->port_parsed)) -+ complete(&mib_eth_data->rw_done); -+} -+ -+static int -+qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) -+{ -+ struct dsa_port *dp = dsa_to_port(ds, port); -+ struct qca8k_mib_eth_data *mib_eth_data; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ mib_eth_data = &priv->mib_eth_data; -+ -+ mutex_lock(&mib_eth_data->mutex); -+ -+ reinit_completion(&mib_eth_data->rw_done); -+ -+ mib_eth_data->req_port = dp->index; -+ mib_eth_data->data = data; -+ refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ /* Send mib autocast request */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | -+ QCA8K_MIB_BUSY); -+ -+ mutex_unlock(&priv->reg_mutex); -+ -+ if (ret) -+ goto exit; -+ -+ ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); -+ -+exit: -+ mutex_unlock(&mib_eth_data->mutex); -+ -+ return ret; -+} -+ -+static void -+qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ const struct qca8k_mib_desc *mib; -+ u32 reg, i, val; -+ u32 hi = 0; -+ int ret; -+ -+ if (priv->mgmt_master && priv->info->ops->autocast_mib && -+ priv->info->ops->autocast_mib(ds, port, data) > 0) -+ return; -+ -+ for (i = 0; i < priv->info->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -+ -+ ret = qca8k_read(priv, reg, &val); -+ if (ret < 0) -+ continue; -+ -+ if (mib->size == 2) { -+ ret = qca8k_read(priv, reg + 4, &hi); -+ if (ret < 0) -+ continue; -+ } -+ -+ data[i] = val; -+ if (mib->size == 2) -+ data[i] |= (u64)hi << 32; -+ } -+} -+ -+static int -+qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ if (sset != ETH_SS_STATS) -+ return 0; -+ -+ return priv->info->mib_count; -+} -+ -+static int -+qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -+ u32 reg; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -+ if (ret < 0) -+ goto exit; -+ -+ if (eee->eee_enabled) -+ reg |= lpi_en; -+ else -+ reg &= ~lpi_en; -+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int -+qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) -+{ -+ /* Nothing to do on the port's MAC */ -+ return 0; -+} -+ -+static void -+qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u32 stp_state; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -+ break; -+ case BR_STATE_LISTENING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -+ break; -+ case BR_STATE_LEARNING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ default: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -+ break; -+ } -+ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); -+} -+ -+static int -+qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int port_mask, cpu_port; -+ int i, ret; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ port_mask = BIT(cpu_port); -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Add this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ ret = regmap_set_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ if (ret) -+ return ret; -+ if (i != port) -+ port_mask |= BIT(i); -+ } -+ -+ /* Add all other ports to this ports portvlan mask */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, port_mask); -+ -+ return ret; -+} -+ -+static void -+qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ int cpu_port, i; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Remove this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ regmap_clear_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ } -+ -+ /* Set the cpu port to be the only one in the portvlan mask of -+ * this port -+ */ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); -+} -+ -+static void -+qca8k_port_fast_age(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int -+qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ unsigned int secs = msecs / 1000; -+ u32 val; -+ -+ /* AGE_TIME reg is set in 7s step */ -+ val = secs / 7; -+ -+ /* Handle case with 0 as val to NOT disable -+ * learning -+ */ -+ if (!val) -+ val = 1; -+ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -+ QCA8K_ATU_AGE_TIME(val)); -+} -+ -+static int -+qca8k_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 1); -+ priv->port_enabled_map |= BIT(port); -+ -+ if (dsa_is_user_port(ds, port)) -+ phy_support_asym_pause(phy); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_disable(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+ priv->port_enabled_map &= ~BIT(port); -+} -+ -+static int -+qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ /* We have only have a general MTU setting. -+ * DSA always set the CPU port's MTU to the largest MTU of the slave -+ * ports. -+ * Setting MTU just for the CPU port is sufficient to correctly set a -+ * value for every port. -+ */ -+ if (!dsa_is_cpu_port(ds, port)) -+ return 0; -+ -+ /* To change the MAX_FRAME_SIZE the cpu ports must be off or -+ * the switch panics. -+ * Turn off both cpu ports before applying the new value to prevent -+ * this. -+ */ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 0); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 0); -+ -+ /* Include L2 header / FCS length */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); -+ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 1); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 1); -+ -+ return ret; -+} -+ -+static int -+qca8k_port_max_mtu(struct dsa_switch *ds, int port) -+{ -+ return QCA8K_MAX_MTU; -+} -+ -+static int -+qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -+ u16 port_mask, u16 vid) -+{ -+ /* Set the vid to the port vlan id if no vid is set */ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_add(priv, addr, port_mask, vid, -+ QCA8K_ATU_STATUS_STATIC); -+} -+ -+static int -+qca8k_port_fdb_add(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_del(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_del(priv, addr, port_mask, vid); -+} -+ -+static int -+qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -+ dsa_fdb_dump_cb_t *cb, void *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ struct qca8k_fdb _fdb = { 0 }; -+ int cnt = QCA8K_NUM_FDB_RECORDS; -+ bool is_static; -+ int ret = 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -+ if (!_fdb.aging) -+ break; -+ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -+ ret = cb(_fdb.mac, _fdb.vid, is_static, data); -+ if (ret) -+ break; -+ } -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+static int -+qca8k_port_mdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); -+} -+ -+static int -+qca8k_port_mdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); -+} -+ -+static int -+qca8k_port_mirror_add(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror, -+ bool ingress) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int monitor_port, ret; -+ u32 reg, val; -+ -+ /* Check for existent entry */ -+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -+ return -EEXIST; -+ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* QCA83xx can have only one port set to mirror mode. -+ * Check that the correct port is requested and return error otherwise. -+ * When no mirror port is set, the values is set to 0xF -+ */ -+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -+ return -EEXIST; -+ -+ /* Set the monitor port */ -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -+ mirror->to_local_port); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ return ret; -+ -+ if (ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_update_bits(priv->regmap, reg, val, val); -+ if (ret) -+ return ret; -+ -+ /* Track mirror port for tx and rx to decide when the -+ * mirror port has to be disabled. -+ */ -+ if (ingress) -+ priv->mirror_rx |= BIT(port); -+ else -+ priv->mirror_tx |= BIT(port); -+ -+ return 0; -+} -+ -+static void -+qca8k_port_mirror_del(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg, val; -+ int ret; -+ -+ if (mirror->ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_clear_bits(priv->regmap, reg, val); -+ if (ret) -+ goto err; -+ -+ if (mirror->ingress) -+ priv->mirror_rx &= ~BIT(port); -+ else -+ priv->mirror_tx &= ~BIT(port); -+ -+ /* No port set to send packet to mirror port. Disable mirror port */ -+ if (!priv->mirror_rx && !priv->mirror_tx) { -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ goto err; -+ } -+err: -+ dev_err(priv->dev, "Failed to del mirror port from %d", port); -+} -+ -+static int -+qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -+ struct netlink_ext_ack *extack) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ if (vlan_filtering) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -+ } else { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -+ } -+ -+ return ret; -+} -+ -+static int -+qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan, -+ struct netlink_ext_ack *extack) -+{ -+ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -+ if (ret) { -+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+ return ret; -+ } -+ -+ if (pvid) { -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+ QCA8K_EGREES_VLAN_PORT_MASK(port), -+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+ QCA8K_PORT_VLAN_CVID(vlan->vid) | -+ QCA8K_PORT_VLAN_SVID(vlan->vid)); -+ } -+ -+ return ret; -+} -+ -+static int -+qca8k_port_vlan_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_del(priv, port, vlan->vid); -+ if (ret) -+ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -+ -+ return ret; -+} -+ -+static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Communicate to the phy internal driver the switch revision. -+ * Based on the switch revision different values needs to be -+ * set to the dbg and mmd reg on the phy. -+ * The first 2 bit are used to communicate the switch revision -+ * to the phy driver. -+ */ -+ if (port > 0 && port < 6) -+ return priv->switch_revision; -+ -+ return 0; -+} -+ -+static enum dsa_tag_protocol -+qca8k_get_tag_protocol(struct dsa_switch *ds, int port, -+ enum dsa_tag_protocol mp) -+{ -+ return DSA_TAG_PROTO_QCA; -+} -+ -+static bool -+qca8k_lag_can_offload(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct dsa_port *dp; -+ int id, members = 0; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ if (id < 0 || id >= ds->num_lag_ids) -+ return false; -+ -+ dsa_lag_foreach_port(dp, ds->dst, lag) -+ /* Includes the port joining the LAG */ -+ members++; -+ -+ if (members > QCA8K_NUM_PORTS_FOR_LAG) -+ return false; -+ -+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -+ return false; -+ -+ if (info->hash_type != NETDEV_LAG_HASH_L2 && -+ info->hash_type != NETDEV_LAG_HASH_L23) -+ return false; -+ -+ return true; -+} -+ -+static int -+qca8k_lag_setup_hash(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ bool unique_lag = true; -+ u32 hash = 0; -+ int i, id; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ switch (info->hash_type) { -+ case NETDEV_LAG_HASH_L23: -+ hash |= QCA8K_TRUNK_HASH_SIP_EN; -+ hash |= QCA8K_TRUNK_HASH_DIP_EN; -+ fallthrough; -+ case NETDEV_LAG_HASH_L2: -+ hash |= QCA8K_TRUNK_HASH_SA_EN; -+ hash |= QCA8K_TRUNK_HASH_DA_EN; -+ break; -+ default: /* We should NEVER reach this */ -+ return -EOPNOTSUPP; -+ } -+ -+ /* Check if we are the unique configured LAG */ -+ dsa_lags_foreach_id(i, ds->dst) -+ if (i != id && dsa_lag_dev(ds->dst, i)) { -+ unique_lag = false; -+ break; -+ } -+ -+ /* Hash Mode is global. Make sure the same Hash Mode -+ * is set to all the 4 possible lag. -+ * If we are the unique LAG we can set whatever hash -+ * mode we want. -+ * To change hash mode it's needed to remove all LAG -+ * and change the mode with the latest. -+ */ -+ if (unique_lag) { -+ priv->lag_hash_mode = hash; -+ } else if (priv->lag_hash_mode != hash) { -+ netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -+ QCA8K_TRUNK_HASH_MASK, hash); -+} -+ -+static int -+qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -+ struct net_device *lag, bool delete) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret, id, i; -+ u32 val; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ /* Read current port member */ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* Shift val to the correct trunk */ -+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -+ if (delete) -+ val &= ~BIT(port); -+ else -+ val |= BIT(port); -+ -+ /* Update port member. With empty portmap disable trunk */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -+ QCA8K_REG_GOL_TRUNK_MEMBER(id) | -+ QCA8K_REG_GOL_TRUNK_EN(id), -+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -+ -+ /* Search empty member if adding or port on deleting */ -+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -+ if (ret) -+ return ret; -+ -+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -+ -+ if (delete) { -+ /* If port flagged to be disabled assume this member is -+ * empty -+ */ -+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -+ if (val != port) -+ continue; -+ } else { -+ /* If port flagged to be enabled assume this member is -+ * already set -+ */ -+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ } -+ -+ /* We have found the member to add/remove */ -+ break; -+ } -+ -+ /* Set port in the correct port mask or disable port if in delete mode */ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); -+} -+ -+static int -+qca8k_port_lag_join(struct dsa_switch *ds, int port, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ int ret; -+ -+ if (!qca8k_lag_can_offload(ds, lag, info)) -+ return -EOPNOTSUPP; -+ -+ ret = qca8k_lag_setup_hash(ds, lag, info); -+ if (ret) -+ return ret; -+ -+ return qca8k_lag_refresh_portmap(ds, port, lag, false); -+} -+ -+static int -+qca8k_port_lag_leave(struct dsa_switch *ds, int port, -+ struct net_device *lag) -+{ -+ return qca8k_lag_refresh_portmap(ds, port, lag, true); -+} -+ -+static void -+qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, -+ bool operational) -+{ -+ struct dsa_port *dp = master->dsa_ptr; -+ struct qca8k_priv *priv = ds->priv; -+ -+ /* Ethernet MIB/MDIO is only supported for CPU port 0 */ -+ if (dp->index != 0) -+ return; -+ -+ mutex_lock(&priv->mgmt_eth_data.mutex); -+ mutex_lock(&priv->mib_eth_data.mutex); -+ -+ priv->mgmt_master = operational ? (struct net_device *)master : NULL; -+ -+ mutex_unlock(&priv->mib_eth_data.mutex); -+ mutex_unlock(&priv->mgmt_eth_data.mutex); -+} -+ -+static int qca8k_connect_tag_protocol(struct dsa_switch *ds, -+ enum dsa_tag_protocol proto) -+{ -+ struct qca_tagger_data *tagger_data; -+ -+ switch (proto) { -+ case DSA_TAG_PROTO_QCA: -+ tagger_data = ds->tagger_data; -+ -+ tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; -+ tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; -+ -+ break; -+ default: -+ return -EOPNOTSUPP; -+ } -+ -+ return 0; -+} -+ -+static const struct dsa_switch_ops qca8k_switch_ops = { -+ .get_tag_protocol = qca8k_get_tag_protocol, -+ .setup = qca8k_setup, -+ .get_strings = qca8k_get_strings, -+ .get_ethtool_stats = qca8k_get_ethtool_stats, -+ .get_sset_count = qca8k_get_sset_count, -+ .set_ageing_time = qca8k_set_ageing_time, -+ .get_mac_eee = qca8k_get_mac_eee, -+ .set_mac_eee = qca8k_set_mac_eee, -+ .port_enable = qca8k_port_enable, -+ .port_disable = qca8k_port_disable, -+ .port_change_mtu = qca8k_port_change_mtu, -+ .port_max_mtu = qca8k_port_max_mtu, -+ .port_stp_state_set = qca8k_port_stp_state_set, -+ .port_bridge_join = qca8k_port_bridge_join, -+ .port_bridge_leave = qca8k_port_bridge_leave, -+ .port_fast_age = qca8k_port_fast_age, -+ .port_fdb_add = qca8k_port_fdb_add, -+ .port_fdb_del = qca8k_port_fdb_del, -+ .port_fdb_dump = qca8k_port_fdb_dump, -+ .port_mdb_add = qca8k_port_mdb_add, -+ .port_mdb_del = qca8k_port_mdb_del, -+ .port_mirror_add = qca8k_port_mirror_add, -+ .port_mirror_del = qca8k_port_mirror_del, -+ .port_vlan_filtering = qca8k_port_vlan_filtering, -+ .port_vlan_add = qca8k_port_vlan_add, -+ .port_vlan_del = qca8k_port_vlan_del, -+ .phylink_validate = qca8k_phylink_validate, -+ .phylink_mac_link_state = qca8k_phylink_mac_link_state, -+ .phylink_mac_config = qca8k_phylink_mac_config, -+ .phylink_mac_link_down = qca8k_phylink_mac_link_down, -+ .phylink_mac_link_up = qca8k_phylink_mac_link_up, -+ .get_phy_flags = qca8k_get_phy_flags, -+ .port_lag_join = qca8k_port_lag_join, -+ .port_lag_leave = qca8k_port_lag_leave, -+ .master_state_change = qca8k_master_change, -+ .connect_tag_protocol = qca8k_connect_tag_protocol, -+}; -+ -+static int qca8k_read_switch_id(struct qca8k_priv *priv) -+{ -+ u32 val; -+ u8 id; -+ int ret; -+ -+ if (!priv->info) -+ return -ENODEV; -+ -+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -+ if (ret < 0) -+ return -ENODEV; -+ -+ id = QCA8K_MASK_CTRL_DEVICE_ID(val); -+ if (id != priv->info->id) { -+ dev_err(priv->dev, -+ "Switch id detected %x but expected %x", -+ id, priv->info->id); -+ return -ENODEV; -+ } -+ -+ priv->switch_id = id; -+ -+ /* Save revision to communicate to the internal PHY driver */ -+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -+ -+ return 0; -+} -+ -+static int -+qca8k_sw_probe(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv; -+ int ret; -+ -+ /* allocate the private data struct so that we can probe the switches -+ * ID register -+ */ -+ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->info = of_device_get_match_data(priv->dev); -+ priv->bus = mdiodev->bus; -+ priv->dev = &mdiodev->dev; -+ -+ priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", -+ GPIOD_ASIS); -+ if (IS_ERR(priv->reset_gpio)) -+ return PTR_ERR(priv->reset_gpio); -+ -+ if (priv->reset_gpio) { -+ gpiod_set_value_cansleep(priv->reset_gpio, 1); -+ /* The active low duration must be greater than 10 ms -+ * and checkpatch.pl wants 20 ms. -+ */ -+ msleep(20); -+ gpiod_set_value_cansleep(priv->reset_gpio, 0); -+ } -+ -+ /* Start by setting up the register mapping */ -+ priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, -+ &qca8k_regmap_config); -+ if (IS_ERR(priv->regmap)) { -+ dev_err(priv->dev, "regmap initialization failed"); -+ return PTR_ERR(priv->regmap); -+ } -+ -+ priv->mdio_cache.page = 0xffff; -+ priv->mdio_cache.lo = 0xffff; -+ priv->mdio_cache.hi = 0xffff; -+ -+ /* Check the detected switch id */ -+ ret = qca8k_read_switch_id(priv); -+ if (ret) -+ return ret; -+ -+ priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); -+ if (!priv->ds) -+ return -ENOMEM; -+ -+ mutex_init(&priv->mgmt_eth_data.mutex); -+ init_completion(&priv->mgmt_eth_data.rw_done); -+ -+ mutex_init(&priv->mib_eth_data.mutex); -+ init_completion(&priv->mib_eth_data.rw_done); -+ -+ priv->ds->dev = &mdiodev->dev; -+ priv->ds->num_ports = QCA8K_NUM_PORTS; -+ priv->ds->priv = priv; -+ priv->ds->ops = &qca8k_switch_ops; -+ mutex_init(&priv->reg_mutex); -+ dev_set_drvdata(&mdiodev->dev, priv); -+ -+ return dsa_register_switch(priv->ds); -+} -+ -+static void -+qca8k_sw_remove(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ int i; -+ -+ if (!priv) -+ return; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) -+ qca8k_port_set_status(priv, i, 0); -+ -+ dsa_unregister_switch(priv->ds); -+ -+ dev_set_drvdata(&mdiodev->dev, NULL); -+} -+ -+static void qca8k_sw_shutdown(struct mdio_device *mdiodev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); -+ -+ if (!priv) -+ return; -+ -+ dsa_switch_shutdown(priv->ds); -+ -+ dev_set_drvdata(&mdiodev->dev, NULL); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static void -+qca8k_set_pm(struct qca8k_priv *priv, int enable) -+{ -+ int port; -+ -+ for (port = 0; port < QCA8K_NUM_PORTS; port++) { -+ /* Do not enable on resume if the port was -+ * disabled before. -+ */ -+ if (!(priv->port_enabled_map & BIT(port))) -+ continue; -+ -+ qca8k_port_set_status(priv, port, enable); -+ } -+} -+ -+static int qca8k_suspend(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 0); -+ -+ return dsa_switch_suspend(priv->ds); -+} -+ -+static int qca8k_resume(struct device *dev) -+{ -+ struct qca8k_priv *priv = dev_get_drvdata(dev); -+ -+ qca8k_set_pm(priv, 1); -+ -+ return dsa_switch_resume(priv->ds); -+} -+#endif /* CONFIG_PM_SLEEP */ -+ -+static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, -+ qca8k_suspend, qca8k_resume); -+ -+static const struct qca8k_info_ops qca8xxx_ops = { -+ .autocast_mib = qca8k_get_ethtool_stats_eth, -+}; -+ -+static const struct qca8k_match_data qca8327 = { -+ .id = QCA8K_ID_QCA8327, -+ .reduced_package = true, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, -+ .ops = &qca8xxx_ops, -+}; -+ -+static const struct qca8k_match_data qca8328 = { -+ .id = QCA8K_ID_QCA8327, -+ .mib_count = QCA8K_QCA832X_MIB_COUNT, -+ .ops = &qca8xxx_ops, -+}; -+ -+static const struct qca8k_match_data qca833x = { -+ .id = QCA8K_ID_QCA8337, -+ .mib_count = QCA8K_QCA833X_MIB_COUNT, -+ .ops = &qca8xxx_ops, -+}; -+ -+static const struct of_device_id qca8k_of_match[] = { -+ { .compatible = "qca,qca8327", .data = &qca8327 }, -+ { .compatible = "qca,qca8328", .data = &qca8328 }, -+ { .compatible = "qca,qca8334", .data = &qca833x }, -+ { .compatible = "qca,qca8337", .data = &qca833x }, -+ { /* sentinel */ }, -+}; -+ -+static struct mdio_driver qca8kmdio_driver = { -+ .probe = qca8k_sw_probe, -+ .remove = qca8k_sw_remove, -+ .shutdown = qca8k_sw_shutdown, -+ .mdiodrv.driver = { -+ .name = "qca8k", -+ .of_match_table = qca8k_of_match, -+ .pm = &qca8k_pm_ops, -+ }, -+}; -+ -+mdio_module_driver(qca8kmdio_driver); -+ -+MODULE_AUTHOR("Mathieu Olivari, John Crispin "); -+MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); -+MODULE_LICENSE("GPL v2"); -+MODULE_ALIAS("platform:qca8k"); ---- /dev/null -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -0,0 +1,63 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2009 Felix Fietkau -+ * Copyright (C) 2011-2012 Gabor Juhos -+ * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. -+ * Copyright (c) 2016 John Crispin -+ */ -+ -+#include -+#include -+ -+#include "qca8k.h" -+ -+#define MIB_DESC(_s, _o, _n) \ -+ { \ -+ .size = (_s), \ -+ .offset = (_o), \ -+ .name = (_n), \ -+ } -+ -+const struct qca8k_mib_desc ar8327_mib[] = { -+ MIB_DESC(1, 0x00, "RxBroad"), -+ MIB_DESC(1, 0x04, "RxPause"), -+ MIB_DESC(1, 0x08, "RxMulti"), -+ MIB_DESC(1, 0x0c, "RxFcsErr"), -+ MIB_DESC(1, 0x10, "RxAlignErr"), -+ MIB_DESC(1, 0x14, "RxRunt"), -+ MIB_DESC(1, 0x18, "RxFragment"), -+ MIB_DESC(1, 0x1c, "Rx64Byte"), -+ MIB_DESC(1, 0x20, "Rx128Byte"), -+ MIB_DESC(1, 0x24, "Rx256Byte"), -+ MIB_DESC(1, 0x28, "Rx512Byte"), -+ MIB_DESC(1, 0x2c, "Rx1024Byte"), -+ MIB_DESC(1, 0x30, "Rx1518Byte"), -+ MIB_DESC(1, 0x34, "RxMaxByte"), -+ MIB_DESC(1, 0x38, "RxTooLong"), -+ MIB_DESC(2, 0x3c, "RxGoodByte"), -+ MIB_DESC(2, 0x44, "RxBadByte"), -+ MIB_DESC(1, 0x4c, "RxOverFlow"), -+ MIB_DESC(1, 0x50, "Filtered"), -+ MIB_DESC(1, 0x54, "TxBroad"), -+ MIB_DESC(1, 0x58, "TxPause"), -+ MIB_DESC(1, 0x5c, "TxMulti"), -+ MIB_DESC(1, 0x60, "TxUnderRun"), -+ MIB_DESC(1, 0x64, "Tx64Byte"), -+ MIB_DESC(1, 0x68, "Tx128Byte"), -+ MIB_DESC(1, 0x6c, "Tx256Byte"), -+ MIB_DESC(1, 0x70, "Tx512Byte"), -+ MIB_DESC(1, 0x74, "Tx1024Byte"), -+ MIB_DESC(1, 0x78, "Tx1518Byte"), -+ MIB_DESC(1, 0x7c, "TxMaxByte"), -+ MIB_DESC(1, 0x80, "TxOverSize"), -+ MIB_DESC(2, 0x84, "TxByte"), -+ MIB_DESC(1, 0x8c, "TxCollision"), -+ MIB_DESC(1, 0x90, "TxAbortCol"), -+ MIB_DESC(1, 0x94, "TxMultiCol"), -+ MIB_DESC(1, 0x98, "TxSingleCol"), -+ MIB_DESC(1, 0x9c, "TxExcDefer"), -+ MIB_DESC(1, 0xa0, "TxDefer"), -+ MIB_DESC(1, 0xa4, "TxLateCol"), -+ MIB_DESC(1, 0xa8, "RXUnicast"), -+ MIB_DESC(1, 0xac, "TXUnicast"), -+}; ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -414,4 +414,7 @@ struct qca8k_fdb { - u8 mac[6]; - }; - -+/* Common setup function */ -+extern const struct qca8k_mib_desc ar8327_mib[]; -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch b/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch deleted file mode 100644 index 012ab854742..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-04-net-dsa-qca8k-move-qca8k-read-write-rmw-and-reg-tabl.patch +++ /dev/null @@ -1,135 +0,0 @@ -From d5f901eab2e9dfed1095995dfc98f231f4fd2971 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:13 +0200 -Subject: [PATCH 04/14] net: dsa: qca8k: move qca8k read/write/rmw and reg - table to common code - -The same reg table and read/write/rmw function are used by drivers -based on qca8k family switch. -Move them to common code to make it accessible also by other drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 42 ------------------------------ - drivers/net/dsa/qca/qca8k-common.c | 38 +++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 6 +++++ - 3 files changed, 44 insertions(+), 42 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -133,24 +133,6 @@ qca8k_set_page(struct qca8k_priv *priv, - return 0; - } - --static int --qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) --{ -- return regmap_read(priv->regmap, reg, val); --} -- --static int --qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) --{ -- return regmap_write(priv->regmap, reg, val); --} -- --static int --qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) --{ -- return regmap_update_bits(priv->regmap, reg, mask, write_val); --} -- - static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) - { - struct qca8k_mgmt_eth_data *mgmt_eth_data; -@@ -483,30 +465,6 @@ exit: - return ret; - } - --static const struct regmap_range qca8k_readable_ranges[] = { -- regmap_reg_range(0x0000, 0x00e4), /* Global control */ -- regmap_reg_range(0x0100, 0x0168), /* EEE control */ -- regmap_reg_range(0x0200, 0x0270), /* Parser control */ -- regmap_reg_range(0x0400, 0x0454), /* ACL */ -- regmap_reg_range(0x0600, 0x0718), /* Lookup */ -- regmap_reg_range(0x0800, 0x0b70), /* QM */ -- regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -- regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -- regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -- regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -- regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -- regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -- regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -- regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -- regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -- --}; -- --static const struct regmap_access_table qca8k_readable_table = { -- .yes_ranges = qca8k_readable_ranges, -- .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), --}; -- - static struct regmap_config qca8k_regmap_config = { - .reg_bits = 16, - .val_bits = 32, ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -61,3 +61,41 @@ const struct qca8k_mib_desc ar8327_mib[] - MIB_DESC(1, 0xa8, "RXUnicast"), - MIB_DESC(1, 0xac, "TXUnicast"), - }; -+ -+int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val) -+{ -+ return regmap_read(priv->regmap, reg, val); -+} -+ -+int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val) -+{ -+ return regmap_write(priv->regmap, reg, val); -+} -+ -+int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) -+{ -+ return regmap_update_bits(priv->regmap, reg, mask, write_val); -+} -+ -+static const struct regmap_range qca8k_readable_ranges[] = { -+ regmap_reg_range(0x0000, 0x00e4), /* Global control */ -+ regmap_reg_range(0x0100, 0x0168), /* EEE control */ -+ regmap_reg_range(0x0200, 0x0270), /* Parser control */ -+ regmap_reg_range(0x0400, 0x0454), /* ACL */ -+ regmap_reg_range(0x0600, 0x0718), /* Lookup */ -+ regmap_reg_range(0x0800, 0x0b70), /* QM */ -+ regmap_reg_range(0x0c00, 0x0c80), /* PKT */ -+ regmap_reg_range(0x0e00, 0x0e98), /* L3 */ -+ regmap_reg_range(0x1000, 0x10ac), /* MIB - Port0 */ -+ regmap_reg_range(0x1100, 0x11ac), /* MIB - Port1 */ -+ regmap_reg_range(0x1200, 0x12ac), /* MIB - Port2 */ -+ regmap_reg_range(0x1300, 0x13ac), /* MIB - Port3 */ -+ regmap_reg_range(0x1400, 0x14ac), /* MIB - Port4 */ -+ regmap_reg_range(0x1500, 0x15ac), /* MIB - Port5 */ -+ regmap_reg_range(0x1600, 0x16ac), /* MIB - Port6 */ -+}; -+ -+const struct regmap_access_table qca8k_readable_table = { -+ .yes_ranges = qca8k_readable_ranges, -+ .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), -+}; ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -416,5 +416,11 @@ struct qca8k_fdb { - - /* Common setup function */ - extern const struct qca8k_mib_desc ar8327_mib[]; -+extern const struct regmap_access_table qca8k_readable_table; -+ -+/* Common read/write/rmw function */ -+int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); -+int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); -+int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); - - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch b/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch deleted file mode 100644 index 0ed7ed41fbe..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-05-net-dsa-qca8k-move-qca8k-bulk-read-write-helper-to-c.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 910746444313dc463396cd63024cdf54ef04ef39 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:14 +0200 -Subject: [PATCH 05/14] net: dsa: qca8k: move qca8k bulk read/write helper to - common code - -The same ATU function are used by drivers based on qca8k family switch. -Move the bulk read/write helper to common code to declare these shared -ATU functions in common code. -These helper will be dropped when regmap correctly support bulk -read/write. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 39 ++---------------------------- - drivers/net/dsa/qca/qca8k-common.c | 39 ++++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 8 ++++++ - 3 files changed, 49 insertions(+), 37 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -343,43 +343,6 @@ qca8k_regmap_update_bits_eth(struct qca8 - } - - static int --qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- -- if (priv->mgmt_master && !qca8k_read_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int --qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) --{ -- int i, count = len / sizeof(u32), ret; -- u32 tmp; -- -- if (priv->mgmt_master && !qca8k_write_eth(priv, reg, val, len)) -- return 0; -- -- for (i = 0; i < count; i++) { -- tmp = val[i]; -- -- ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -- if (ret < 0) -- return ret; -- } -- -- return 0; --} -- --static int - qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ctx; -@@ -3096,6 +3059,8 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, - - static const struct qca8k_info_ops qca8xxx_ops = { - .autocast_mib = qca8k_get_ethtool_stats_eth, -+ .read_eth = qca8k_read_eth, -+ .write_eth = qca8k_write_eth, - }; - - static const struct qca8k_match_data qca8327 = { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -99,3 +99,42 @@ const struct regmap_access_table qca8k_r - .yes_ranges = qca8k_readable_ranges, - .n_yes_ranges = ARRAY_SIZE(qca8k_readable_ranges), - }; -+ -+/* TODO: remove these extra ops when we can support regmap bulk read/write */ -+int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ -+ if (priv->mgmt_master && priv->info->ops->read_eth && -+ !priv->info->ops->read_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ ret = regmap_read(priv->regmap, reg + (i * 4), val + i); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* TODO: remove these extra ops when we can support regmap bulk read/write */ -+int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+{ -+ int i, count = len / sizeof(u32), ret; -+ u32 tmp; -+ -+ if (priv->mgmt_master && priv->info->ops->write_eth && -+ !priv->info->ops->write_eth(priv, reg, val, len)) -+ return 0; -+ -+ for (i = 0; i < count; i++) { -+ tmp = val[i]; -+ -+ ret = regmap_write(priv->regmap, reg + (i * 4), tmp); -+ if (ret < 0) -+ return ret; -+ } -+ -+ return 0; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -324,8 +324,13 @@ enum qca8k_mid_cmd { - QCA8K_MIB_CAST = 3, - }; - -+struct qca8k_priv; -+ - struct qca8k_info_ops { - int (*autocast_mib)(struct dsa_switch *ds, int port, u64 *data); -+ /* TODO: remove these extra ops when we can support regmap bulk read/write */ -+ int (*read_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len); -+ int (*write_eth)(struct qca8k_priv *priv, u32 reg, u32 *val, int len); - }; - - struct qca8k_match_data { -@@ -423,4 +428,7 @@ int qca8k_read(struct qca8k_priv *priv, - int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); - int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); - -+int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); -+int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch deleted file mode 100644 index a39a55b89b4..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-06-net-dsa-qca8k-move-mib-init-function-to-common-code.patch +++ /dev/null @@ -1,137 +0,0 @@ -From fce1ec0c4e2d03d9c62ffc615a42bdba78eb4c14 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:15 +0200 -Subject: [PATCH 06/14] net: dsa: qca8k: move mib init function to common code - -The same mib function is used by drivers based on qca8k family switch. -Move it to common code to make it accessible also by other drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 37 ------------------------------ - drivers/net/dsa/qca/qca8k-common.c | 35 ++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 4 ++++ - 3 files changed, 39 insertions(+), 37 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -442,15 +442,6 @@ static struct regmap_config qca8k_regmap - }; - - static int --qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) --{ -- u32 val; -- -- return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -- QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); --} -- --static int - qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) - { - u32 reg[3]; -@@ -777,34 +768,6 @@ out: - return ret; - } - --static int --qca8k_mib_init(struct qca8k_priv *priv) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -- QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -- FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -- QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -- if (ret) -- goto exit; -- -- ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -- if (ret) -- goto exit; -- -- ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- - static void - qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) - { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -7,6 +7,7 @@ - */ - - #include -+#include - #include - - #include "qca8k.h" -@@ -138,3 +139,38 @@ int qca8k_bulk_write(struct qca8k_priv * - - return 0; - } -+ -+int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) -+{ -+ u32 val; -+ -+ return regmap_read_poll_timeout(priv->regmap, reg, val, !(val & mask), 0, -+ QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); -+} -+ -+int qca8k_mib_init(struct qca8k_priv *priv) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, -+ QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, -+ FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_FLUSH) | -+ QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_MIB, QCA8K_MIB_BUSY); -+ if (ret) -+ goto exit; -+ -+ ret = regmap_set_bits(priv->regmap, QCA8K_REG_MIB, QCA8K_MIB_CPU_KEEP); -+ if (ret) -+ goto exit; -+ -+ ret = qca8k_write(priv, QCA8K_REG_MODULE_EN, QCA8K_MODULE_EN_MIB); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -422,6 +422,7 @@ struct qca8k_fdb { - /* Common setup function */ - extern const struct qca8k_mib_desc ar8327_mib[]; - extern const struct regmap_access_table qca8k_readable_table; -+int qca8k_mib_init(struct qca8k_priv *priv); - - /* Common read/write/rmw function */ - int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); -@@ -431,4 +432,7 @@ int qca8k_rmw(struct qca8k_priv *priv, u - int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); - int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); - -+/* Common ops function */ -+int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch b/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch deleted file mode 100644 index 6fd1c66b0ae..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-07-net-dsa-qca8k-move-port-set-status-eee-ethtool-stats.patch +++ /dev/null @@ -1,281 +0,0 @@ -From 472fcea160f27a5d9b7526093d9d8d89ba0b6137 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:16 +0200 -Subject: [PATCH 07/14] net: dsa: qca8k: move port set status/eee/ethtool stats - function to common code - -The same logic to disable/enable port, set eee and get ethtool stats is -used by drivers based on qca8k family switch. -Move it to common code to make it accessible also by other drivers. -While at it also drop unnecessary qca8k_priv cast for void pointers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 105 ----------------------------- - drivers/net/dsa/qca/qca8k-common.c | 102 ++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 11 +++ - 3 files changed, 113 insertions(+), 105 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -768,21 +768,6 @@ out: - return ret; - } - --static void --qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) --{ -- u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -- -- /* Port 0 and 6 have no internal PHY */ -- if (port > 0 && port < 6) -- mask |= QCA8K_PORT_STATUS_LINK_AUTO; -- -- if (enable) -- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -- else -- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); --} -- - static int - qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, - struct sk_buff *read_skb, u32 *val) -@@ -1974,20 +1959,6 @@ qca8k_phylink_mac_link_up(struct dsa_swi - qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); - } - --static void --qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data) --{ -- struct qca8k_priv *priv = ds->priv; -- int i; -- -- if (stringset != ETH_SS_STATS) -- return; -- -- for (i = 0; i < priv->info->mib_count; i++) -- strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -- ETH_GSTRING_LEN); --} -- - static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) - { - struct qca8k_mib_eth_data *mib_eth_data; -@@ -2078,82 +2049,6 @@ exit: - } - - static void --qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -- uint64_t *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- const struct qca8k_mib_desc *mib; -- u32 reg, i, val; -- u32 hi = 0; -- int ret; -- -- if (priv->mgmt_master && priv->info->ops->autocast_mib && -- priv->info->ops->autocast_mib(ds, port, data) > 0) -- return; -- -- for (i = 0; i < priv->info->mib_count; i++) { -- mib = &ar8327_mib[i]; -- reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -- -- ret = qca8k_read(priv, reg, &val); -- if (ret < 0) -- continue; -- -- if (mib->size == 2) { -- ret = qca8k_read(priv, reg + 4, &hi); -- if (ret < 0) -- continue; -- } -- -- data[i] = val; -- if (mib->size == 2) -- data[i] |= (u64)hi << 32; -- } --} -- --static int --qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) --{ -- struct qca8k_priv *priv = ds->priv; -- -- if (sset != ETH_SS_STATS) -- return 0; -- -- return priv->info->mib_count; --} -- --static int --qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -- u32 reg; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -- if (ret < 0) -- goto exit; -- -- if (eee->eee_enabled) -- reg |= lpi_en; -- else -- reg &= ~lpi_en; -- ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) --{ -- /* Nothing to do on the port's MAC */ -- return 0; --} -- --static void - qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) - { - struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -174,3 +174,105 @@ exit: - mutex_unlock(&priv->reg_mutex); - return ret; - } -+ -+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) -+{ -+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; -+ -+ /* Port 0 and 6 have no internal PHY */ -+ if (port > 0 && port < 6) -+ mask |= QCA8K_PORT_STATUS_LINK_AUTO; -+ -+ if (enable) -+ regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+ else -+ regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask); -+} -+ -+void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, -+ uint8_t *data) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int i; -+ -+ if (stringset != ETH_SS_STATS) -+ return; -+ -+ for (i = 0; i < priv->info->mib_count; i++) -+ strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name, -+ ETH_GSTRING_LEN); -+} -+ -+void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const struct qca8k_mib_desc *mib; -+ u32 reg, i, val; -+ u32 hi = 0; -+ int ret; -+ -+ if (priv->mgmt_master && priv->info->ops->autocast_mib && -+ priv->info->ops->autocast_mib(ds, port, data) > 0) -+ return; -+ -+ for (i = 0; i < priv->info->mib_count; i++) { -+ mib = &ar8327_mib[i]; -+ reg = QCA8K_PORT_MIB_COUNTER(port) + mib->offset; -+ -+ ret = qca8k_read(priv, reg, &val); -+ if (ret < 0) -+ continue; -+ -+ if (mib->size == 2) { -+ ret = qca8k_read(priv, reg + 4, &hi); -+ if (ret < 0) -+ continue; -+ } -+ -+ data[i] = val; -+ if (mib->size == 2) -+ data[i] |= (u64)hi << 32; -+ } -+} -+ -+int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ if (sset != ETH_SS_STATS) -+ return 0; -+ -+ return priv->info->mib_count; -+} -+ -+int qca8k_set_mac_eee(struct dsa_switch *ds, int port, -+ struct ethtool_eee *eee) -+{ -+ u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_read(priv, QCA8K_REG_EEE_CTRL, ®); -+ if (ret < 0) -+ goto exit; -+ -+ if (eee->eee_enabled) -+ reg |= lpi_en; -+ else -+ reg &= ~lpi_en; -+ ret = qca8k_write(priv, QCA8K_REG_EEE_CTRL, reg); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+int qca8k_get_mac_eee(struct dsa_switch *ds, int port, -+ struct ethtool_eee *e) -+{ -+ /* Nothing to do on the port's MAC */ -+ return 0; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -423,6 +423,7 @@ struct qca8k_fdb { - extern const struct qca8k_mib_desc ar8327_mib[]; - extern const struct regmap_access_table qca8k_readable_table; - int qca8k_mib_init(struct qca8k_priv *priv); -+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable); - - /* Common read/write/rmw function */ - int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); -@@ -435,4 +436,14 @@ int qca8k_bulk_write(struct qca8k_priv * - /* Common ops function */ - int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); - -+/* Common ethtool stats function */ -+void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); -+void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, -+ uint64_t *data); -+int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset); -+ -+/* Common eee function */ -+int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); -+int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch deleted file mode 100644 index 3ca682d72cc..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-08-net-dsa-qca8k-move-bridge-functions-to-common-code.patch +++ /dev/null @@ -1,237 +0,0 @@ -From fd3cae2f3ac190d06e48f43739237e02f9dc51ff Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:17 +0200 -Subject: [PATCH 08/14] net: dsa: qca8k: move bridge functions to common code - -The same bridge functions are used by drivers based on qca8k family -switch. Move them to common code to make them accessible also by other -drivers. -While at it also drop unnecessary qca8k_priv cast for void pointers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------ - drivers/net/dsa/qca/qca8k-common.c | 93 ++++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 9 +++ - 3 files changed, 102 insertions(+), 93 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -2049,97 +2049,6 @@ exit: - } - - static void --qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u32 stp_state; -- -- switch (state) { -- case BR_STATE_DISABLED: -- stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -- break; -- case BR_STATE_BLOCKING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -- break; -- case BR_STATE_LISTENING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -- break; -- case BR_STATE_LEARNING: -- stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -- break; -- case BR_STATE_FORWARDING: -- default: -- stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -- break; -- } -- -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); --} -- --static int --qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int port_mask, cpu_port; -- int i, ret; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- port_mask = BIT(cpu_port); -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Add this port to the portvlan mask of the other ports -- * in the bridge -- */ -- ret = regmap_set_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- if (ret) -- return ret; -- if (i != port) -- port_mask |= BIT(i); -- } -- -- /* Add all other ports to this ports portvlan mask */ -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, port_mask); -- -- return ret; --} -- --static void --qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- int cpu_port, i; -- -- cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -- -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- if (dsa_is_cpu_port(ds, i)) -- continue; -- if (dsa_to_port(ds, i)->bridge_dev != br) -- continue; -- /* Remove this port to the portvlan mask of the other ports -- * in the bridge -- */ -- regmap_clear_bits(priv->regmap, -- QCA8K_PORT_LOOKUP_CTRL(i), -- BIT(port)); -- } -- -- /* Set the cpu port to be the only one in the portvlan mask of -- * this port -- */ -- qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); --} -- --static void - qca8k_port_fast_age(struct dsa_switch *ds, int port) - { - struct qca8k_priv *priv = ds->priv; ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - - #include "qca8k.h" - -@@ -276,3 +277,93 @@ int qca8k_get_mac_eee(struct dsa_switch - /* Nothing to do on the port's MAC */ - return 0; - } -+ -+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 stp_state; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_BLOCKING; -+ break; -+ case BR_STATE_LISTENING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LISTENING; -+ break; -+ case BR_STATE_LEARNING: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ default: -+ stp_state = QCA8K_PORT_LOOKUP_STATE_FORWARD; -+ break; -+ } -+ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_STATE_MASK, stp_state); -+} -+ -+int qca8k_port_bridge_join(struct dsa_switch *ds, int port, -+ struct net_device *br) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int port_mask, cpu_port; -+ int i, ret; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ port_mask = BIT(cpu_port); -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Add this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ ret = regmap_set_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ if (ret) -+ return ret; -+ if (i != port) -+ port_mask |= BIT(i); -+ } -+ -+ /* Add all other ports to this ports portvlan mask */ -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, port_mask); -+ -+ return ret; -+} -+ -+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, -+ struct net_device *br) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int cpu_port, i; -+ -+ cpu_port = dsa_to_port(ds, port)->cpu_dp->index; -+ -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ if (dsa_is_cpu_port(ds, i)) -+ continue; -+ if (dsa_to_port(ds, i)->bridge_dev != br) -+ continue; -+ /* Remove this port to the portvlan mask of the other ports -+ * in the bridge -+ */ -+ regmap_clear_bits(priv->regmap, -+ QCA8K_PORT_LOOKUP_CTRL(i), -+ BIT(port)); -+ } -+ -+ /* Set the cpu port to be the only one in the portvlan mask of -+ * this port -+ */ -+ qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -446,4 +446,11 @@ int qca8k_get_sset_count(struct dsa_swit - int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); - int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); - -+/* Common bridge function */ -+void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); -+int qca8k_port_bridge_join(struct dsa_switch *ds, int port, -+ struct net_device *br); -+void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, -+ struct net_device *br); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch b/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch deleted file mode 100644 index e3414408d64..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-09-net-dsa-qca8k-move-set-age-MTU-port-enable-disable-f.patch +++ /dev/null @@ -1,227 +0,0 @@ -From b3a302b171f73425b41de8d3357fae3fa7057322 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:18 +0200 -Subject: [PATCH 09/14] net: dsa: qca8k: move set age/MTU/port enable/disable - functions to common code - -The same set age, MTU and port enable/disable function are used by -driver based on qca8k family switch. -Move them to common code to make them accessible also by other drivers. -While at it also drop unnecessary qca8k_priv cast for void pointers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 88 ------------------------------ - drivers/net/dsa/qca/qca8k-common.c | 85 +++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 12 ++++ - 3 files changed, 97 insertions(+), 88 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -2059,94 +2059,6 @@ qca8k_port_fast_age(struct dsa_switch *d - } - - static int --qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) --{ -- struct qca8k_priv *priv = ds->priv; -- unsigned int secs = msecs / 1000; -- u32 val; -- -- /* AGE_TIME reg is set in 7s step */ -- val = secs / 7; -- -- /* Handle case with 0 as val to NOT disable -- * learning -- */ -- if (!val) -- val = 1; -- -- return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, QCA8K_ATU_AGE_TIME_MASK, -- QCA8K_ATU_AGE_TIME(val)); --} -- --static int --qca8k_port_enable(struct dsa_switch *ds, int port, -- struct phy_device *phy) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 1); -- priv->port_enabled_map |= BIT(port); -- -- if (dsa_is_user_port(ds, port)) -- phy_support_asym_pause(phy); -- -- return 0; --} -- --static void --qca8k_port_disable(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- -- qca8k_port_set_status(priv, port, 0); -- priv->port_enabled_map &= ~BIT(port); --} -- --static int --qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- /* We have only have a general MTU setting. -- * DSA always set the CPU port's MTU to the largest MTU of the slave -- * ports. -- * Setting MTU just for the CPU port is sufficient to correctly set a -- * value for every port. -- */ -- if (!dsa_is_cpu_port(ds, port)) -- return 0; -- -- /* To change the MAX_FRAME_SIZE the cpu ports must be off or -- * the switch panics. -- * Turn off both cpu ports before applying the new value to prevent -- * this. -- */ -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 0); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 0); -- -- /* Include L2 header / FCS length */ -- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + ETH_HLEN + ETH_FCS_LEN); -- -- if (priv->port_enabled_map & BIT(0)) -- qca8k_port_set_status(priv, 0, 1); -- -- if (priv->port_enabled_map & BIT(6)) -- qca8k_port_set_status(priv, 6, 1); -- -- return ret; --} -- --static int --qca8k_port_max_mtu(struct dsa_switch *ds, int port) --{ -- return QCA8K_MAX_MTU; --} -- --static int - qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, - u16 port_mask, u16 vid) - { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -367,3 +367,88 @@ void qca8k_port_bridge_leave(struct dsa_ - qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), - QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); - } -+ -+int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ unsigned int secs = msecs / 1000; -+ u32 val; -+ -+ /* AGE_TIME reg is set in 7s step */ -+ val = secs / 7; -+ -+ /* Handle case with 0 as val to NOT disable -+ * learning -+ */ -+ if (!val) -+ val = 1; -+ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_ATU_CTRL, -+ QCA8K_ATU_AGE_TIME_MASK, -+ QCA8K_ATU_AGE_TIME(val)); -+} -+ -+int qca8k_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ qca8k_port_set_status(priv, port, 1); -+ priv->port_enabled_map |= BIT(port); -+ -+ if (dsa_is_user_port(ds, port)) -+ phy_support_asym_pause(phy); -+ -+ return 0; -+} -+ -+void qca8k_port_disable(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ qca8k_port_set_status(priv, port, 0); -+ priv->port_enabled_map &= ~BIT(port); -+} -+ -+int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ /* We have only have a general MTU setting. -+ * DSA always set the CPU port's MTU to the largest MTU of the slave -+ * ports. -+ * Setting MTU just for the CPU port is sufficient to correctly set a -+ * value for every port. -+ */ -+ if (!dsa_is_cpu_port(ds, port)) -+ return 0; -+ -+ /* To change the MAX_FRAME_SIZE the cpu ports must be off or -+ * the switch panics. -+ * Turn off both cpu ports before applying the new value to prevent -+ * this. -+ */ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 0); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 0); -+ -+ /* Include L2 header / FCS length */ -+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu + -+ ETH_HLEN + ETH_FCS_LEN); -+ -+ if (priv->port_enabled_map & BIT(0)) -+ qca8k_port_set_status(priv, 0, 1); -+ -+ if (priv->port_enabled_map & BIT(6)) -+ qca8k_port_set_status(priv, 6, 1); -+ -+ return ret; -+} -+ -+int qca8k_port_max_mtu(struct dsa_switch *ds, int port) -+{ -+ return QCA8K_MAX_MTU; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -453,4 +453,16 @@ int qca8k_port_bridge_join(struct dsa_sw - void qca8k_port_bridge_leave(struct dsa_switch *ds, int port, - struct net_device *br); - -+/* Common port enable/disable function */ -+int qca8k_port_enable(struct dsa_switch *ds, int port, -+ struct phy_device *phy); -+void qca8k_port_disable(struct dsa_switch *ds, int port); -+ -+/* Common MTU function */ -+int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu); -+int qca8k_port_max_mtu(struct dsa_switch *ds, int port); -+ -+/* Common fast age function */ -+int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch b/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch deleted file mode 100644 index 96468ae74e9..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-10-net-dsa-qca8k-move-port-FDB-MDB-function-to-common-c.patch +++ /dev/null @@ -1,704 +0,0 @@ -From 2e5bd96eea86a246b4de3bf756f7a11b43e6187d Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:19 +0200 -Subject: [PATCH 10/14] net: dsa: qca8k: move port FDB/MDB function to common - code - -The same port FDB/MDB function are used by drivers based on qca8k family -switch. Move them to common code to make them accessible also by other -drivers. -Also drop bulk read/write functions and make them static - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 306 ----------------------------- - drivers/net/dsa/qca/qca8k-common.c | 297 +++++++++++++++++++++++++++- - drivers/net/dsa/qca/qca8k.h | 25 ++- - 3 files changed, 317 insertions(+), 311 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -442,217 +442,6 @@ static struct regmap_config qca8k_regmap - }; - - static int --qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) --{ -- u32 reg[3]; -- int ret; -- -- /* load the ARL table into an array */ -- ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -- if (ret) -- return ret; -- -- /* vid - 83:72 */ -- fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -- /* aging - 67:64 */ -- fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -- /* portmask - 54:48 */ -- fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -- /* mac - 47:0 */ -- fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -- fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -- fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -- fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -- fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -- fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -- -- return 0; --} -- --static void --qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, const u8 *mac, -- u8 aging) --{ -- u32 reg[3] = { 0 }; -- -- /* vid - 83:72 */ -- reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -- /* aging - 67:64 */ -- reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -- /* portmask - 54:48 */ -- reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -- /* mac - 47:0 */ -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -- reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -- reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -- -- /* load the array into the ARL table */ -- qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); --} -- --static int --qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, int port) --{ -- u32 reg; -- int ret; -- -- /* Set the command and FDB index */ -- reg = QCA8K_ATU_FUNC_BUSY; -- reg |= cmd; -- if (port >= 0) { -- reg |= QCA8K_ATU_FUNC_PORT_EN; -- reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -- } -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_FDB_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_ATU_FUNC_FULL) -- return -1; -- } -- -- return 0; --} -- --static int --qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, int port) --{ -- int ret; -- -- qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -- if (ret < 0) -- return ret; -- -- return qca8k_fdb_read(priv, fdb); --} -- --static int --qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, -- u16 vid, u8 aging) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, u16 port_mask, u16 vid) --{ -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_write(priv, vid, port_mask, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static void --qca8k_fdb_flush(struct qca8k_priv *priv) --{ -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- ret = qca8k_fdb_read(priv, &fdb); -- if (ret < 0) -- goto exit; -- -- /* Rule exist. Delete first */ -- if (!fdb.aging) { -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- } -- -- /* Add port to fdb portmask */ -- fdb.port_mask |= port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int --qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -- const u8 *mac, u16 vid) --{ -- struct qca8k_fdb fdb = { 0 }; -- int ret; -- -- mutex_lock(&priv->reg_mutex); -- -- qca8k_fdb_write(priv, vid, 0, mac, 0); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -- if (ret < 0) -- goto exit; -- -- /* Rule doesn't exist. Why delete? */ -- if (!fdb.aging) { -- ret = -EINVAL; -- goto exit; -- } -- -- ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -- if (ret) -- goto exit; -- -- /* Only port in the rule is this port. Don't re insert */ -- if (fdb.port_mask == port_mask) -- goto exit; -- -- /* Remove port from port mask */ -- fdb.port_mask &= ~port_mask; -- -- qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -- ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -- --exit: -- mutex_unlock(&priv->reg_mutex); -- return ret; --} -- --static int - qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) - { - u32 reg; -@@ -2048,97 +1837,6 @@ exit: - return ret; - } - --static void --qca8k_port_fast_age(struct dsa_switch *ds, int port) --{ -- struct qca8k_priv *priv = ds->priv; -- -- mutex_lock(&priv->reg_mutex); -- qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -- mutex_unlock(&priv->reg_mutex); --} -- --static int --qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -- u16 port_mask, u16 vid) --{ -- /* Set the vid to the port vlan id if no vid is set */ -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_add(priv, addr, port_mask, vid, -- QCA8K_ATU_STATUS_STATIC); --} -- --static int --qca8k_port_fdb_add(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- return qca8k_port_fdb_insert(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_del(struct dsa_switch *ds, int port, -- const unsigned char *addr, u16 vid) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- u16 port_mask = BIT(port); -- -- if (!vid) -- vid = QCA8K_PORT_VID_DEF; -- -- return qca8k_fdb_del(priv, addr, port_mask, vid); --} -- --static int --qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -- dsa_fdb_dump_cb_t *cb, void *data) --{ -- struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -- struct qca8k_fdb _fdb = { 0 }; -- int cnt = QCA8K_NUM_FDB_RECORDS; -- bool is_static; -- int ret = 0; -- -- mutex_lock(&priv->reg_mutex); -- while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -- if (!_fdb.aging) -- break; -- is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -- ret = cb(_fdb.mac, _fdb.vid, is_static, data); -- if (ret) -- break; -- } -- mutex_unlock(&priv->reg_mutex); -- -- return 0; --} -- --static int --qca8k_port_mdb_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); --} -- --static int --qca8k_port_mdb_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_mdb *mdb) --{ -- struct qca8k_priv *priv = ds->priv; -- const u8 *addr = mdb->addr; -- u16 vid = mdb->vid; -- -- return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); --} -- - static int - qca8k_port_mirror_add(struct dsa_switch *ds, int port, - struct dsa_mall_mirror_tc_entry *mirror, ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -103,7 +103,7 @@ const struct regmap_access_table qca8k_r - }; - - /* TODO: remove these extra ops when we can support regmap bulk read/write */ --int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+static int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len) - { - int i, count = len / sizeof(u32), ret; - -@@ -121,7 +121,7 @@ int qca8k_bulk_read(struct qca8k_priv *p - } - - /* TODO: remove these extra ops when we can support regmap bulk read/write */ --int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) -+static int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len) - { - int i, count = len / sizeof(u32), ret; - u32 tmp; -@@ -149,6 +149,211 @@ int qca8k_busy_wait(struct qca8k_priv *p - QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC); - } - -+static int qca8k_fdb_read(struct qca8k_priv *priv, struct qca8k_fdb *fdb) -+{ -+ u32 reg[3]; -+ int ret; -+ -+ /* load the ARL table into an array */ -+ ret = qca8k_bulk_read(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+ if (ret) -+ return ret; -+ -+ /* vid - 83:72 */ -+ fdb->vid = FIELD_GET(QCA8K_ATU_VID_MASK, reg[2]); -+ /* aging - 67:64 */ -+ fdb->aging = FIELD_GET(QCA8K_ATU_STATUS_MASK, reg[2]); -+ /* portmask - 54:48 */ -+ fdb->port_mask = FIELD_GET(QCA8K_ATU_PORT_MASK, reg[1]); -+ /* mac - 47:0 */ -+ fdb->mac[0] = FIELD_GET(QCA8K_ATU_ADDR0_MASK, reg[1]); -+ fdb->mac[1] = FIELD_GET(QCA8K_ATU_ADDR1_MASK, reg[1]); -+ fdb->mac[2] = FIELD_GET(QCA8K_ATU_ADDR2_MASK, reg[0]); -+ fdb->mac[3] = FIELD_GET(QCA8K_ATU_ADDR3_MASK, reg[0]); -+ fdb->mac[4] = FIELD_GET(QCA8K_ATU_ADDR4_MASK, reg[0]); -+ fdb->mac[5] = FIELD_GET(QCA8K_ATU_ADDR5_MASK, reg[0]); -+ -+ return 0; -+} -+ -+static void qca8k_fdb_write(struct qca8k_priv *priv, u16 vid, u8 port_mask, -+ const u8 *mac, u8 aging) -+{ -+ u32 reg[3] = { 0 }; -+ -+ /* vid - 83:72 */ -+ reg[2] = FIELD_PREP(QCA8K_ATU_VID_MASK, vid); -+ /* aging - 67:64 */ -+ reg[2] |= FIELD_PREP(QCA8K_ATU_STATUS_MASK, aging); -+ /* portmask - 54:48 */ -+ reg[1] = FIELD_PREP(QCA8K_ATU_PORT_MASK, port_mask); -+ /* mac - 47:0 */ -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR0_MASK, mac[0]); -+ reg[1] |= FIELD_PREP(QCA8K_ATU_ADDR1_MASK, mac[1]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR2_MASK, mac[2]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR3_MASK, mac[3]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR4_MASK, mac[4]); -+ reg[0] |= FIELD_PREP(QCA8K_ATU_ADDR5_MASK, mac[5]); -+ -+ /* load the array into the ARL table */ -+ qca8k_bulk_write(priv, QCA8K_REG_ATU_DATA0, reg, sizeof(reg)); -+} -+ -+static int qca8k_fdb_access(struct qca8k_priv *priv, enum qca8k_fdb_cmd cmd, -+ int port) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and FDB index */ -+ reg = QCA8K_ATU_FUNC_BUSY; -+ reg |= cmd; -+ if (port >= 0) { -+ reg |= QCA8K_ATU_FUNC_PORT_EN; -+ reg |= FIELD_PREP(QCA8K_ATU_FUNC_PORT_MASK, port); -+ } -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_ATU_FUNC, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_ATU_FUNC, QCA8K_ATU_FUNC_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_FDB_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_ATU_FUNC, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_ATU_FUNC_FULL) -+ return -1; -+ } -+ -+ return 0; -+} -+ -+static int qca8k_fdb_next(struct qca8k_priv *priv, struct qca8k_fdb *fdb, -+ int port) -+{ -+ int ret; -+ -+ qca8k_fdb_write(priv, fdb->vid, fdb->port_mask, fdb->mac, fdb->aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_NEXT, port); -+ if (ret < 0) -+ return ret; -+ -+ return qca8k_fdb_read(priv, fdb); -+} -+ -+static int qca8k_fdb_add(struct qca8k_priv *priv, const u8 *mac, -+ u16 port_mask, u16 vid, u8 aging) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int qca8k_fdb_del(struct qca8k_priv *priv, const u8 *mac, -+ u16 port_mask, u16 vid) -+{ -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_write(priv, vid, port_mask, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+void qca8k_fdb_flush(struct qca8k_priv *priv) -+{ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH, -1); -+ mutex_unlock(&priv->reg_mutex); -+} -+ -+static int qca8k_fdb_search_and_insert(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ ret = qca8k_fdb_read(priv, &fdb); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule exist. Delete first */ -+ if (!fdb.aging) { -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ } -+ -+ /* Add port to fdb portmask */ -+ fdb.port_mask |= port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ -+static int qca8k_fdb_search_and_del(struct qca8k_priv *priv, u8 port_mask, -+ const u8 *mac, u16 vid) -+{ -+ struct qca8k_fdb fdb = { 0 }; -+ int ret; -+ -+ mutex_lock(&priv->reg_mutex); -+ -+ qca8k_fdb_write(priv, vid, 0, mac, 0); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_SEARCH, -1); -+ if (ret < 0) -+ goto exit; -+ -+ /* Rule doesn't exist. Why delete? */ -+ if (!fdb.aging) { -+ ret = -EINVAL; -+ goto exit; -+ } -+ -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_PURGE, -1); -+ if (ret) -+ goto exit; -+ -+ /* Only port in the rule is this port. Don't re insert */ -+ if (fdb.port_mask == port_mask) -+ goto exit; -+ -+ /* Remove port from port mask */ -+ fdb.port_mask &= ~port_mask; -+ -+ qca8k_fdb_write(priv, vid, fdb.port_mask, mac, fdb.aging); -+ ret = qca8k_fdb_access(priv, QCA8K_FDB_LOAD, -1); -+ -+exit: -+ mutex_unlock(&priv->reg_mutex); -+ return ret; -+} -+ - int qca8k_mib_init(struct qca8k_priv *priv) - { - int ret; -@@ -368,6 +573,15 @@ void qca8k_port_bridge_leave(struct dsa_ - QCA8K_PORT_LOOKUP_MEMBER, BIT(cpu_port)); - } - -+void qca8k_port_fast_age(struct dsa_switch *ds, int port) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ -+ mutex_lock(&priv->reg_mutex); -+ qca8k_fdb_access(priv, QCA8K_FDB_FLUSH_PORT, port); -+ mutex_unlock(&priv->reg_mutex); -+} -+ - int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs) - { - struct qca8k_priv *priv = ds->priv; -@@ -452,3 +666,78 @@ int qca8k_port_max_mtu(struct dsa_switch - { - return QCA8K_MAX_MTU; - } -+ -+int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -+ u16 port_mask, u16 vid) -+{ -+ /* Set the vid to the port vlan id if no vid is set */ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_add(priv, addr, port_mask, vid, -+ QCA8K_ATU_STATUS_STATIC); -+} -+ -+int qca8k_port_fdb_add(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ return qca8k_port_fdb_insert(priv, addr, port_mask, vid); -+} -+ -+int qca8k_port_fdb_del(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ u16 port_mask = BIT(port); -+ -+ if (!vid) -+ vid = QCA8K_PORT_VID_DEF; -+ -+ return qca8k_fdb_del(priv, addr, port_mask, vid); -+} -+ -+int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -+ dsa_fdb_dump_cb_t *cb, void *data) -+{ -+ struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; -+ struct qca8k_fdb _fdb = { 0 }; -+ int cnt = QCA8K_NUM_FDB_RECORDS; -+ bool is_static; -+ int ret = 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ while (cnt-- && !qca8k_fdb_next(priv, &_fdb, port)) { -+ if (!_fdb.aging) -+ break; -+ is_static = (_fdb.aging == QCA8K_ATU_STATUS_STATIC); -+ ret = cb(_fdb.mac, _fdb.vid, is_static, data); -+ if (ret) -+ break; -+ } -+ mutex_unlock(&priv->reg_mutex); -+ -+ return 0; -+} -+ -+int qca8k_port_mdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_insert(priv, BIT(port), addr, vid); -+} -+ -+int qca8k_port_mdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ const u8 *addr = mdb->addr; -+ u16 vid = mdb->vid; -+ -+ return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -430,11 +430,9 @@ int qca8k_read(struct qca8k_priv *priv, - int qca8k_write(struct qca8k_priv *priv, u32 reg, u32 val); - int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); - --int qca8k_bulk_read(struct qca8k_priv *priv, u32 reg, u32 *val, int len); --int qca8k_bulk_write(struct qca8k_priv *priv, u32 reg, u32 *val, int len); -- - /* Common ops function */ - int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); -+void qca8k_fdb_flush(struct qca8k_priv *priv); - - /* Common ethtool stats function */ - void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data); -@@ -463,6 +461,23 @@ int qca8k_port_change_mtu(struct dsa_swi - int qca8k_port_max_mtu(struct dsa_switch *ds, int port); - - /* Common fast age function */ -+void qca8k_port_fast_age(struct dsa_switch *ds, int port); - int qca8k_set_ageing_time(struct dsa_switch *ds, unsigned int msecs); - -+/* Common FDB function */ -+int qca8k_port_fdb_insert(struct qca8k_priv *priv, const u8 *addr, -+ u16 port_mask, u16 vid); -+int qca8k_port_fdb_add(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid); -+int qca8k_port_fdb_del(struct dsa_switch *ds, int port, -+ const unsigned char *addr, u16 vid); -+int qca8k_port_fdb_dump(struct dsa_switch *ds, int port, -+ dsa_fdb_dump_cb_t *cb, void *data); -+ -+/* Common MDB function */ -+int qca8k_port_mdb_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb); -+int qca8k_port_mdb_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_mdb *mdb); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch b/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch deleted file mode 100644 index c1336d4a921..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-11-net-dsa-qca8k-move-port-mirror-functions-to-common-c.patch +++ /dev/null @@ -1,232 +0,0 @@ -From 742d37a84d3f7bb60d9b2d9ada9ad4e599f65ebf Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:20 +0200 -Subject: [PATCH 11/14] net: dsa: qca8k: move port mirror functions to common - code - -The same port mirror functions are used by drivers based on qca8k family -switch. Move them to common code to make them accessible also by other -drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 93 ------------------------------ - drivers/net/dsa/qca/qca8k-common.c | 91 +++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 7 +++ - 3 files changed, 98 insertions(+), 93 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -1838,99 +1838,6 @@ exit: - } - - static int --qca8k_port_mirror_add(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror, -- bool ingress) --{ -- struct qca8k_priv *priv = ds->priv; -- int monitor_port, ret; -- u32 reg, val; -- -- /* Check for existent entry */ -- if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -- return -EEXIST; -- -- ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -- if (ret) -- return ret; -- -- /* QCA83xx can have only one port set to mirror mode. -- * Check that the correct port is requested and return error otherwise. -- * When no mirror port is set, the values is set to 0xF -- */ -- monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -- return -EEXIST; -- -- /* Set the monitor port */ -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -- mirror->to_local_port); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- return ret; -- -- if (ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_update_bits(priv->regmap, reg, val, val); -- if (ret) -- return ret; -- -- /* Track mirror port for tx and rx to decide when the -- * mirror port has to be disabled. -- */ -- if (ingress) -- priv->mirror_rx |= BIT(port); -- else -- priv->mirror_tx |= BIT(port); -- -- return 0; --} -- --static void --qca8k_port_mirror_del(struct dsa_switch *ds, int port, -- struct dsa_mall_mirror_tc_entry *mirror) --{ -- struct qca8k_priv *priv = ds->priv; -- u32 reg, val; -- int ret; -- -- if (mirror->ingress) { -- reg = QCA8K_PORT_LOOKUP_CTRL(port); -- val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -- } else { -- reg = QCA8K_REG_PORT_HOL_CTRL1(port); -- val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -- } -- -- ret = regmap_clear_bits(priv->regmap, reg, val); -- if (ret) -- goto err; -- -- if (mirror->ingress) -- priv->mirror_rx &= ~BIT(port); -- else -- priv->mirror_tx &= ~BIT(port); -- -- /* No port set to send packet to mirror port. Disable mirror port */ -- if (!priv->mirror_rx && !priv->mirror_tx) { -- val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -- QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -- if (ret) -- goto err; -- } --err: -- dev_err(priv->dev, "Failed to del mirror port from %d", port); --} -- --static int - qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack) - { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -741,3 +741,94 @@ int qca8k_port_mdb_del(struct dsa_switch - - return qca8k_fdb_search_and_del(priv, BIT(port), addr, vid); - } -+ -+int qca8k_port_mirror_add(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror, -+ bool ingress) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int monitor_port, ret; -+ u32 reg, val; -+ -+ /* Check for existent entry */ -+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port)) -+ return -EEXIST; -+ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* QCA83xx can have only one port set to mirror mode. -+ * Check that the correct port is requested and return error otherwise. -+ * When no mirror port is set, the values is set to 0xF -+ */ -+ monitor_port = FIELD_GET(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (monitor_port != 0xF && monitor_port != mirror->to_local_port) -+ return -EEXIST; -+ -+ /* Set the monitor port */ -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, -+ mirror->to_local_port); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ return ret; -+ -+ if (ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_update_bits(priv->regmap, reg, val, val); -+ if (ret) -+ return ret; -+ -+ /* Track mirror port for tx and rx to decide when the -+ * mirror port has to be disabled. -+ */ -+ if (ingress) -+ priv->mirror_rx |= BIT(port); -+ else -+ priv->mirror_tx |= BIT(port); -+ -+ return 0; -+} -+ -+void qca8k_port_mirror_del(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ u32 reg, val; -+ int ret; -+ -+ if (mirror->ingress) { -+ reg = QCA8K_PORT_LOOKUP_CTRL(port); -+ val = QCA8K_PORT_LOOKUP_ING_MIRROR_EN; -+ } else { -+ reg = QCA8K_REG_PORT_HOL_CTRL1(port); -+ val = QCA8K_PORT_HOL_CTRL1_EG_MIRROR_EN; -+ } -+ -+ ret = regmap_clear_bits(priv->regmap, reg, val); -+ if (ret) -+ goto err; -+ -+ if (mirror->ingress) -+ priv->mirror_rx &= ~BIT(port); -+ else -+ priv->mirror_tx &= ~BIT(port); -+ -+ /* No port set to send packet to mirror port. Disable mirror port */ -+ if (!priv->mirror_rx && !priv->mirror_tx) { -+ val = FIELD_PREP(QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, 0xF); -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, -+ QCA8K_GLOBAL_FW_CTRL0_MIRROR_PORT_NUM, val); -+ if (ret) -+ goto err; -+ } -+err: -+ dev_err(priv->dev, "Failed to del mirror port from %d", port); -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -480,4 +480,11 @@ int qca8k_port_mdb_add(struct dsa_switch - int qca8k_port_mdb_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb); - -+/* Common port mirror function */ -+int qca8k_port_mirror_add(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror, -+ bool ingress); -+void qca8k_port_mirror_del(struct dsa_switch *ds, int port, -+ struct dsa_mall_mirror_tc_entry *mirror); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch b/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch deleted file mode 100644 index 898010f9509..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-12-net-dsa-qca8k-move-port-VLAN-functions-to-common-cod.patch +++ /dev/null @@ -1,448 +0,0 @@ -From c5290f636624b98e76a82bd63ffec0a8a9daa620 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:21 +0200 -Subject: [PATCH 12/14] net: dsa: qca8k: move port VLAN functions to common - code - -The same port VLAN functions are used by drivers based on qca8k family -switch. Move them to common code to make them accessible also by other -drivers. -Also drop exposing busy_wait and make it static. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 182 ----------------------------- - drivers/net/dsa/qca/qca8k-common.c | 179 +++++++++++++++++++++++++++- - drivers/net/dsa/qca/qca8k.h | 10 +- - 3 files changed, 187 insertions(+), 184 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -15,7 +15,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -442,122 +441,6 @@ static struct regmap_config qca8k_regmap - }; - - static int --qca8k_vlan_access(struct qca8k_priv *priv, enum qca8k_vlan_cmd cmd, u16 vid) --{ -- u32 reg; -- int ret; -- -- /* Set the command and VLAN index */ -- reg = QCA8K_VTU_FUNC1_BUSY; -- reg |= cmd; -- reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -- -- /* Write the function register triggering the table access */ -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -- if (ret) -- return ret; -- -- /* wait for completion */ -- ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -- if (ret) -- return ret; -- -- /* Check for table full violation when adding an entry */ -- if (cmd == QCA8K_VLAN_LOAD) { -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -- if (ret < 0) -- return ret; -- if (reg & QCA8K_VTU_FUNC1_FULL) -- return -ENOMEM; -- } -- -- return 0; --} -- --static int --qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, bool untagged) --{ -- u32 reg; -- int ret; -- -- /* -- We do the right thing with VLAN 0 and treat it as untagged while -- preserving the tag on egress. -- */ -- if (vid == 0) -- return 0; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- if (untagged) -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -- else -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -- -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int --qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) --{ -- u32 reg, mask; -- int ret, i; -- bool del; -- -- mutex_lock(&priv->reg_mutex); -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -- if (ret < 0) -- goto out; -- -- ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -- if (ret < 0) -- goto out; -- reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -- reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -- -- /* Check if we're the last member to be removed */ -- del = true; -- for (i = 0; i < QCA8K_NUM_PORTS; i++) { -- mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -- -- if ((reg & mask) != mask) { -- del = false; -- break; -- } -- } -- -- if (del) { -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -- } else { -- ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -- if (ret) -- goto out; -- ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -- } -- --out: -- mutex_unlock(&priv->reg_mutex); -- -- return ret; --} -- --static int - qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, - struct sk_buff *read_skb, u32 *val) - { -@@ -1836,71 +1719,6 @@ exit: - - return ret; - } -- --static int --qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -- struct netlink_ext_ack *extack) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- if (vlan_filtering) { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -- } else { -- ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -- QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -- QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_add(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan, -- struct netlink_ext_ack *extack) --{ -- bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -- bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -- if (ret) { -- dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -- return ret; -- } -- -- if (pvid) { -- ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -- QCA8K_EGREES_VLAN_PORT_MASK(port), -- QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -- if (ret) -- return ret; -- -- ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -- QCA8K_PORT_VLAN_CVID(vlan->vid) | -- QCA8K_PORT_VLAN_SVID(vlan->vid)); -- } -- -- return ret; --} -- --static int --qca8k_port_vlan_del(struct dsa_switch *ds, int port, -- const struct switchdev_obj_port_vlan *vlan) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret; -- -- ret = qca8k_vlan_del(priv, port, vlan->vid); -- if (ret) -- dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -- -- return ret; --} - - static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) - { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -141,7 +141,7 @@ static int qca8k_bulk_write(struct qca8k - return 0; - } - --int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) -+static int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask) - { - u32 val; - -@@ -354,6 +354,120 @@ exit: - return ret; - } - -+static int qca8k_vlan_access(struct qca8k_priv *priv, -+ enum qca8k_vlan_cmd cmd, u16 vid) -+{ -+ u32 reg; -+ int ret; -+ -+ /* Set the command and VLAN index */ -+ reg = QCA8K_VTU_FUNC1_BUSY; -+ reg |= cmd; -+ reg |= FIELD_PREP(QCA8K_VTU_FUNC1_VID_MASK, vid); -+ -+ /* Write the function register triggering the table access */ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC1, reg); -+ if (ret) -+ return ret; -+ -+ /* wait for completion */ -+ ret = qca8k_busy_wait(priv, QCA8K_REG_VTU_FUNC1, QCA8K_VTU_FUNC1_BUSY); -+ if (ret) -+ return ret; -+ -+ /* Check for table full violation when adding an entry */ -+ if (cmd == QCA8K_VLAN_LOAD) { -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC1, ®); -+ if (ret < 0) -+ return ret; -+ if (reg & QCA8K_VTU_FUNC1_FULL) -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static int qca8k_vlan_add(struct qca8k_priv *priv, u8 port, u16 vid, -+ bool untagged) -+{ -+ u32 reg; -+ int ret; -+ -+ /* We do the right thing with VLAN 0 and treat it as untagged while -+ * preserving the tag on egress. -+ */ -+ if (vid == 0) -+ return 0; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg |= QCA8K_VTU_FUNC0_VALID | QCA8K_VTU_FUNC0_IVL_EN; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ if (untagged) -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_UNTAG(port); -+ else -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_TAG(port); -+ -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ -+static int qca8k_vlan_del(struct qca8k_priv *priv, u8 port, u16 vid) -+{ -+ u32 reg, mask; -+ int ret, i; -+ bool del; -+ -+ mutex_lock(&priv->reg_mutex); -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_READ, vid); -+ if (ret < 0) -+ goto out; -+ -+ ret = qca8k_read(priv, QCA8K_REG_VTU_FUNC0, ®); -+ if (ret < 0) -+ goto out; -+ reg &= ~QCA8K_VTU_FUNC0_EG_MODE_PORT_MASK(port); -+ reg |= QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(port); -+ -+ /* Check if we're the last member to be removed */ -+ del = true; -+ for (i = 0; i < QCA8K_NUM_PORTS; i++) { -+ mask = QCA8K_VTU_FUNC0_EG_MODE_PORT_NOT(i); -+ -+ if ((reg & mask) != mask) { -+ del = false; -+ break; -+ } -+ } -+ -+ if (del) { -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_PURGE, vid); -+ } else { -+ ret = qca8k_write(priv, QCA8K_REG_VTU_FUNC0, reg); -+ if (ret) -+ goto out; -+ ret = qca8k_vlan_access(priv, QCA8K_VLAN_LOAD, vid); -+ } -+ -+out: -+ mutex_unlock(&priv->reg_mutex); -+ -+ return ret; -+} -+ - int qca8k_mib_init(struct qca8k_priv *priv) - { - int ret; -@@ -832,3 +946,66 @@ void qca8k_port_mirror_del(struct dsa_sw - err: - dev_err(priv->dev, "Failed to del mirror port from %d", port); - } -+ -+int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, -+ bool vlan_filtering, -+ struct netlink_ext_ack *extack) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ if (vlan_filtering) { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_SECURE); -+ } else { -+ ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port), -+ QCA8K_PORT_LOOKUP_VLAN_MODE_MASK, -+ QCA8K_PORT_LOOKUP_VLAN_MODE_NONE); -+ } -+ -+ return ret; -+} -+ -+int qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan, -+ struct netlink_ext_ack *extack) -+{ -+ bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; -+ bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_add(priv, port, vlan->vid, untagged); -+ if (ret) { -+ dev_err(priv->dev, "Failed to add VLAN to port %d (%d)", port, ret); -+ return ret; -+ } -+ -+ if (pvid) { -+ ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port), -+ QCA8K_EGREES_VLAN_PORT_MASK(port), -+ QCA8K_EGREES_VLAN_PORT(port, vlan->vid)); -+ if (ret) -+ return ret; -+ -+ ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port), -+ QCA8K_PORT_VLAN_CVID(vlan->vid) | -+ QCA8K_PORT_VLAN_SVID(vlan->vid)); -+ } -+ -+ return ret; -+} -+ -+int qca8k_port_vlan_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret; -+ -+ ret = qca8k_vlan_del(priv, port, vlan->vid); -+ if (ret) -+ dev_err(priv->dev, "Failed to delete VLAN from port %d (%d)", port, ret); -+ -+ return ret; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -431,7 +431,6 @@ int qca8k_write(struct qca8k_priv *priv, - int qca8k_rmw(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val); - - /* Common ops function */ --int qca8k_busy_wait(struct qca8k_priv *priv, u32 reg, u32 mask); - void qca8k_fdb_flush(struct qca8k_priv *priv); - - /* Common ethtool stats function */ -@@ -487,4 +486,13 @@ int qca8k_port_mirror_add(struct dsa_swi - void qca8k_port_mirror_del(struct dsa_switch *ds, int port, - struct dsa_mall_mirror_tc_entry *mirror); - -+/* Common port VLAN function */ -+int qca8k_port_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -+ struct netlink_ext_ack *extack); -+int qca8k_port_vlan_add(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan, -+ struct netlink_ext_ack *extack); -+int qca8k_port_vlan_del(struct dsa_switch *ds, int port, -+ const struct switchdev_obj_port_vlan *vlan); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch b/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch deleted file mode 100644 index 1802b17eaad..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-13-net-dsa-qca8k-move-port-LAG-functions-to-common-code.patch +++ /dev/null @@ -1,384 +0,0 @@ -From e9bbf019af44b204b71ef8edf224002550aab641 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:22 +0200 -Subject: [PATCH 13/14] net: dsa: qca8k: move port LAG functions to common code - -The same port LAG functions are used by drivers based on qca8k family -switch. Move them to common code to make them accessible also by other -drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 168 ----------------------------- - drivers/net/dsa/qca/qca8k-common.c | 165 ++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 6 ++ - 3 files changed, 171 insertions(+), 168 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -1743,178 +1743,6 @@ qca8k_get_tag_protocol(struct dsa_switch - return DSA_TAG_PROTO_QCA; - } - --static bool --qca8k_lag_can_offload(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct dsa_port *dp; -- int id, members = 0; -- -- id = dsa_lag_id(ds->dst, lag); -- if (id < 0 || id >= ds->num_lag_ids) -- return false; -- -- dsa_lag_foreach_port(dp, ds->dst, lag) -- /* Includes the port joining the LAG */ -- members++; -- -- if (members > QCA8K_NUM_PORTS_FOR_LAG) -- return false; -- -- if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -- return false; -- -- if (info->hash_type != NETDEV_LAG_HASH_L2 && -- info->hash_type != NETDEV_LAG_HASH_L23) -- return false; -- -- return true; --} -- --static int --qca8k_lag_setup_hash(struct dsa_switch *ds, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- struct qca8k_priv *priv = ds->priv; -- bool unique_lag = true; -- u32 hash = 0; -- int i, id; -- -- id = dsa_lag_id(ds->dst, lag); -- -- switch (info->hash_type) { -- case NETDEV_LAG_HASH_L23: -- hash |= QCA8K_TRUNK_HASH_SIP_EN; -- hash |= QCA8K_TRUNK_HASH_DIP_EN; -- fallthrough; -- case NETDEV_LAG_HASH_L2: -- hash |= QCA8K_TRUNK_HASH_SA_EN; -- hash |= QCA8K_TRUNK_HASH_DA_EN; -- break; -- default: /* We should NEVER reach this */ -- return -EOPNOTSUPP; -- } -- -- /* Check if we are the unique configured LAG */ -- dsa_lags_foreach_id(i, ds->dst) -- if (i != id && dsa_lag_dev(ds->dst, i)) { -- unique_lag = false; -- break; -- } -- -- /* Hash Mode is global. Make sure the same Hash Mode -- * is set to all the 4 possible lag. -- * If we are the unique LAG we can set whatever hash -- * mode we want. -- * To change hash mode it's needed to remove all LAG -- * and change the mode with the latest. -- */ -- if (unique_lag) { -- priv->lag_hash_mode = hash; -- } else if (priv->lag_hash_mode != hash) { -- netdev_err(lag, "Error: Mismateched Hash Mode across different lag is not supported\n"); -- return -EOPNOTSUPP; -- } -- -- return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -- QCA8K_TRUNK_HASH_MASK, hash); --} -- --static int --qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -- struct net_device *lag, bool delete) --{ -- struct qca8k_priv *priv = ds->priv; -- int ret, id, i; -- u32 val; -- -- id = dsa_lag_id(ds->dst, lag); -- -- /* Read current port member */ -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -- if (ret) -- return ret; -- -- /* Shift val to the correct trunk */ -- val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -- val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -- if (delete) -- val &= ~BIT(port); -- else -- val |= BIT(port); -- -- /* Update port member. With empty portmap disable trunk */ -- ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -- QCA8K_REG_GOL_TRUNK_MEMBER(id) | -- QCA8K_REG_GOL_TRUNK_EN(id), -- !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -- val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -- -- /* Search empty member if adding or port on deleting */ -- for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -- ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -- if (ret) -- return ret; -- -- val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -- -- if (delete) { -- /* If port flagged to be disabled assume this member is -- * empty -- */ -- if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- -- val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -- if (val != port) -- continue; -- } else { -- /* If port flagged to be enabled assume this member is -- * already set -- */ -- if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -- continue; -- } -- -- /* We have found the member to add/remove */ -- break; -- } -- -- /* Set port in the correct port mask or disable port if in delete mode */ -- return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -- QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -- !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -- port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); --} -- --static int --qca8k_port_lag_join(struct dsa_switch *ds, int port, -- struct net_device *lag, -- struct netdev_lag_upper_info *info) --{ -- int ret; -- -- if (!qca8k_lag_can_offload(ds, lag, info)) -- return -EOPNOTSUPP; -- -- ret = qca8k_lag_setup_hash(ds, lag, info); -- if (ret) -- return ret; -- -- return qca8k_lag_refresh_portmap(ds, port, lag, false); --} -- --static int --qca8k_port_lag_leave(struct dsa_switch *ds, int port, -- struct net_device *lag) --{ -- return qca8k_lag_refresh_portmap(ds, port, lag, true); --} -- - static void - qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, - bool operational) ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -1009,3 +1009,169 @@ int qca8k_port_vlan_del(struct dsa_switc - - return ret; - } -+ -+static bool qca8k_lag_can_offload(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct dsa_port *dp; -+ int id, members = 0; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ if (id < 0 || id >= ds->num_lag_ids) -+ return false; -+ -+ dsa_lag_foreach_port(dp, ds->dst, lag) -+ /* Includes the port joining the LAG */ -+ members++; -+ -+ if (members > QCA8K_NUM_PORTS_FOR_LAG) -+ return false; -+ -+ if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) -+ return false; -+ -+ if (info->hash_type != NETDEV_LAG_HASH_L2 && -+ info->hash_type != NETDEV_LAG_HASH_L23) -+ return false; -+ -+ return true; -+} -+ -+static int qca8k_lag_setup_hash(struct dsa_switch *ds, -+ struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ bool unique_lag = true; -+ u32 hash = 0; -+ int i, id; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ switch (info->hash_type) { -+ case NETDEV_LAG_HASH_L23: -+ hash |= QCA8K_TRUNK_HASH_SIP_EN; -+ hash |= QCA8K_TRUNK_HASH_DIP_EN; -+ fallthrough; -+ case NETDEV_LAG_HASH_L2: -+ hash |= QCA8K_TRUNK_HASH_SA_EN; -+ hash |= QCA8K_TRUNK_HASH_DA_EN; -+ break; -+ default: /* We should NEVER reach this */ -+ return -EOPNOTSUPP; -+ } -+ -+ /* Check if we are the unique configured LAG */ -+ dsa_lags_foreach_id(i, ds->dst) -+ if (i != id && dsa_lag_dev(ds->dst, i)) { -+ unique_lag = false; -+ break; -+ } -+ -+ /* Hash Mode is global. Make sure the same Hash Mode -+ * is set to all the 4 possible lag. -+ * If we are the unique LAG we can set whatever hash -+ * mode we want. -+ * To change hash mode it's needed to remove all LAG -+ * and change the mode with the latest. -+ */ -+ if (unique_lag) { -+ priv->lag_hash_mode = hash; -+ } else if (priv->lag_hash_mode != hash) { -+ netdev_err(lag, "Error: Mismatched Hash Mode across different lag is not supported\n"); -+ return -EOPNOTSUPP; -+ } -+ -+ return regmap_update_bits(priv->regmap, QCA8K_TRUNK_HASH_EN_CTRL, -+ QCA8K_TRUNK_HASH_MASK, hash); -+} -+ -+static int qca8k_lag_refresh_portmap(struct dsa_switch *ds, int port, -+ struct net_device *lag, bool delete) -+{ -+ struct qca8k_priv *priv = ds->priv; -+ int ret, id, i; -+ u32 val; -+ -+ id = dsa_lag_id(ds->dst, lag); -+ -+ /* Read current port member */ -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, &val); -+ if (ret) -+ return ret; -+ -+ /* Shift val to the correct trunk */ -+ val >>= QCA8K_REG_GOL_TRUNK_SHIFT(id); -+ val &= QCA8K_REG_GOL_TRUNK_MEMBER_MASK; -+ if (delete) -+ val &= ~BIT(port); -+ else -+ val |= BIT(port); -+ -+ /* Update port member. With empty portmap disable trunk */ -+ ret = regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL0, -+ QCA8K_REG_GOL_TRUNK_MEMBER(id) | -+ QCA8K_REG_GOL_TRUNK_EN(id), -+ !val << QCA8K_REG_GOL_TRUNK_SHIFT(id) | -+ val << QCA8K_REG_GOL_TRUNK_SHIFT(id)); -+ -+ /* Search empty member if adding or port on deleting */ -+ for (i = 0; i < QCA8K_NUM_PORTS_FOR_LAG; i++) { -+ ret = regmap_read(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), &val); -+ if (ret) -+ return ret; -+ -+ val >>= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i); -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_MASK; -+ -+ if (delete) { -+ /* If port flagged to be disabled assume this member is -+ * empty -+ */ -+ if (val != QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ -+ val &= QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT_MASK; -+ if (val != port) -+ continue; -+ } else { -+ /* If port flagged to be enabled assume this member is -+ * already set -+ */ -+ if (val == QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN_MASK) -+ continue; -+ } -+ -+ /* We have found the member to add/remove */ -+ break; -+ } -+ -+ /* Set port in the correct port mask or disable port if in delete mode */ -+ return regmap_update_bits(priv->regmap, QCA8K_REG_GOL_TRUNK_CTRL(id), -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_EN(id, i) | -+ QCA8K_REG_GOL_TRUNK_ID_MEM_ID_PORT(id, i), -+ !delete << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i) | -+ port << QCA8K_REG_GOL_TRUNK_ID_MEM_ID_SHIFT(id, i)); -+} -+ -+int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag, -+ struct netdev_lag_upper_info *info) -+{ -+ int ret; -+ -+ if (!qca8k_lag_can_offload(ds, lag, info)) -+ return -EOPNOTSUPP; -+ -+ ret = qca8k_lag_setup_hash(ds, lag, info); -+ if (ret) -+ return ret; -+ -+ return qca8k_lag_refresh_portmap(ds, port, lag, false); -+} -+ -+int qca8k_port_lag_leave(struct dsa_switch *ds, int port, -+ struct net_device *lag) -+{ -+ return qca8k_lag_refresh_portmap(ds, port, lag, true); -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -495,4 +495,10 @@ int qca8k_port_vlan_add(struct dsa_switc - int qca8k_port_vlan_del(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan); - -+/* Common port LAG function */ -+int qca8k_port_lag_join(struct dsa_switch *ds, int port, struct net_device *lag, -+ struct netdev_lag_upper_info *info); -+int qca8k_port_lag_leave(struct dsa_switch *ds, int port, -+ struct net_device *lag); -+ - #endif /* __QCA8K_H */ diff --git a/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch b/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch deleted file mode 100644 index d6ec8b77e0c..00000000000 --- a/target/linux/generic/backport-6.1/771-v6.0-14-net-dsa-qca8k-move-read_switch_id-function-to-common.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 9d1bcb1f293f1391302a109c9819c3705c804700 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 27 Jul 2022 13:35:23 +0200 -Subject: [PATCH 14/14] net: dsa: qca8k: move read_switch_id function to common - code - -The same function to read the switch id is used by drivers based on -qca8k family switch. Move them to common code to make them accessible -also by other drivers. - -Signed-off-by: Christian Marangi -Reviewed-by: Vladimir Oltean -Signed-off-by: Jakub Kicinski ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 29 ----------------------------- - drivers/net/dsa/qca/qca8k-common.c | 29 +++++++++++++++++++++++++++++ - drivers/net/dsa/qca/qca8k.h | 1 + - 3 files changed, 30 insertions(+), 29 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -1822,35 +1822,6 @@ static const struct dsa_switch_ops qca8k - .connect_tag_protocol = qca8k_connect_tag_protocol, - }; - --static int qca8k_read_switch_id(struct qca8k_priv *priv) --{ -- u32 val; -- u8 id; -- int ret; -- -- if (!priv->info) -- return -ENODEV; -- -- ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -- if (ret < 0) -- return -ENODEV; -- -- id = QCA8K_MASK_CTRL_DEVICE_ID(val); -- if (id != priv->info->id) { -- dev_err(priv->dev, -- "Switch id detected %x but expected %x", -- id, priv->info->id); -- return -ENODEV; -- } -- -- priv->switch_id = id; -- -- /* Save revision to communicate to the internal PHY driver */ -- priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -- -- return 0; --} -- - static int - qca8k_sw_probe(struct mdio_device *mdiodev) - { ---- a/drivers/net/dsa/qca/qca8k-common.c -+++ b/drivers/net/dsa/qca/qca8k-common.c -@@ -1175,3 +1175,32 @@ int qca8k_port_lag_leave(struct dsa_swit - { - return qca8k_lag_refresh_portmap(ds, port, lag, true); - } -+ -+int qca8k_read_switch_id(struct qca8k_priv *priv) -+{ -+ u32 val; -+ u8 id; -+ int ret; -+ -+ if (!priv->info) -+ return -ENODEV; -+ -+ ret = qca8k_read(priv, QCA8K_REG_MASK_CTRL, &val); -+ if (ret < 0) -+ return -ENODEV; -+ -+ id = QCA8K_MASK_CTRL_DEVICE_ID(val); -+ if (id != priv->info->id) { -+ dev_err(priv->dev, -+ "Switch id detected %x but expected %x", -+ id, priv->info->id); -+ return -ENODEV; -+ } -+ -+ priv->switch_id = id; -+ -+ /* Save revision to communicate to the internal PHY driver */ -+ priv->switch_revision = QCA8K_MASK_CTRL_REV_ID(val); -+ -+ return 0; -+} ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -424,6 +424,7 @@ extern const struct qca8k_mib_desc ar832 - extern const struct regmap_access_table qca8k_readable_table; - int qca8k_mib_init(struct qca8k_priv *priv); - void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable); -+int qca8k_read_switch_id(struct qca8k_priv *priv); - - /* Common read/write/rmw function */ - int qca8k_read(struct qca8k_priv *priv, u32 reg, u32 *val); diff --git a/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch b/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch deleted file mode 100644 index 0cca2788f6d..00000000000 --- a/target/linux/generic/backport-6.1/772-v6.0-net-dsa-qca8k-fix-NULL-pointer-dereference-for-of_de.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 057bcf15db8e625276ddf02b2b7c668a3cb43f81 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sun, 4 Sep 2022 23:46:24 +0200 -Subject: [net PATCH] net: dsa: qca8k: fix NULL pointer dereference for - of_device_get_match_data - -of_device_get_match_data is called on priv->dev before priv->dev is -actually set. Move of_device_get_match_data after priv->dev is correctly -set to fix this kernel panic. - -Fixes: 3bb0844e7bcd ("net: dsa: qca8k: cache match data to speed up access") -Signed-off-by: Christian Marangi ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -1835,9 +1835,9 @@ qca8k_sw_probe(struct mdio_device *mdiod - if (!priv) - return -ENOMEM; - -- priv->info = of_device_get_match_data(priv->dev); - priv->bus = mdiodev->bus; - priv->dev = &mdiodev->dev; -+ priv->info = of_device_get_match_data(priv->dev); - - priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", - GPIOD_ASIS); diff --git a/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch b/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch deleted file mode 100644 index 44093eab95b..00000000000 --- a/target/linux/generic/backport-6.1/773-v5.18-1-net-dsa-Move-VLAN-filtering-syncing-out-of-dsa_switc.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 381a730182f1d174e1950cd4e63e885b1c302051 Mon Sep 17 00:00:00 2001 -From: Tobias Waldekranz -Date: Mon, 24 Jan 2022 22:09:43 +0100 -Subject: net: dsa: Move VLAN filtering syncing out of dsa_switch_bridge_leave - -Most of dsa_switch_bridge_leave was, in fact, dealing with the syncing -of VLAN filtering for switches on which that is a global -setting. Separate the two phases to prepare for the cross-chip related -bugfix in the following commit. - -Signed-off-by: Tobias Waldekranz -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - net/dsa/switch.c | 38 +++++++++++++++++++++++++------------- - 1 file changed, 25 insertions(+), 13 deletions(-) - ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -113,25 +113,14 @@ static int dsa_switch_bridge_join(struct - return dsa_tag_8021q_bridge_join(ds, info); - } - --static int dsa_switch_bridge_leave(struct dsa_switch *ds, -- struct dsa_notifier_bridge_info *info) -+static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds, -+ struct dsa_notifier_bridge_info *info) - { -- struct dsa_switch_tree *dst = ds->dst; - struct netlink_ext_ack extack = {0}; - bool change_vlan_filtering = false; - bool vlan_filtering; - int err, port; - -- if (dst->index == info->tree_index && ds->index == info->sw_index && -- ds->ops->port_bridge_leave) -- ds->ops->port_bridge_leave(ds, info->port, info->br); -- -- if ((dst->index != info->tree_index || ds->index != info->sw_index) && -- ds->ops->crosschip_bridge_leave) -- ds->ops->crosschip_bridge_leave(ds, info->tree_index, -- info->sw_index, info->port, -- info->br); -- - if (ds->needs_standalone_vlan_filtering && !br_vlan_enabled(info->br)) { - change_vlan_filtering = true; - vlan_filtering = true; -@@ -172,6 +161,29 @@ static int dsa_switch_bridge_leave(struc - return err; - } - -+ return 0; -+} -+ -+static int dsa_switch_bridge_leave(struct dsa_switch *ds, -+ struct dsa_notifier_bridge_info *info) -+{ -+ struct dsa_switch_tree *dst = ds->dst; -+ int err; -+ -+ if (dst->index == info->tree_index && ds->index == info->sw_index && -+ ds->ops->port_bridge_leave) -+ ds->ops->port_bridge_leave(ds, info->port, info->br); -+ -+ if ((dst->index != info->tree_index || ds->index != info->sw_index) && -+ ds->ops->crosschip_bridge_leave) -+ ds->ops->crosschip_bridge_leave(ds, info->tree_index, -+ info->sw_index, info->port, -+ info->br); -+ -+ err = dsa_switch_sync_vlan_filtering(ds, info); -+ if (err) -+ return err; -+ - return dsa_tag_8021q_bridge_leave(ds, info); - } - diff --git a/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch b/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch deleted file mode 100644 index cdddbcf14ee..00000000000 --- a/target/linux/generic/backport-6.1/773-v5.18-2-net-dsa-Avoid-cross-chip-syncing-of-VLAN-filtering.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 108dc8741c203e9d6ce4e973367f1bac20c7192b Mon Sep 17 00:00:00 2001 -From: Tobias Waldekranz -Date: Mon, 24 Jan 2022 22:09:44 +0100 -Subject: net: dsa: Avoid cross-chip syncing of VLAN filtering - -Changes to VLAN filtering are not applicable to cross-chip -notifications. - -On a system like this: - -.-----. .-----. .-----. -| sw1 +---+ sw2 +---+ sw3 | -'-1-2-' '-1-2-' '-1-2-' - -Before this change, upon sw1p1 leaving a bridge, a call to -dsa_port_vlan_filtering would also be made to sw2p1 and sw3p1. - -In this scenario: - -.---------. .-----. .-----. -| sw1 +---+ sw2 +---+ sw3 | -'-1-2-3-4-' '-1-2-' '-1-2-' - -When sw1p4 would leave a bridge, dsa_port_vlan_filtering would be -called for sw2 and sw3 with a non-existing port - leading to array -out-of-bounds accesses and crashes on mv88e6xxx. - -Fixes: d371b7c92d19 ("net: dsa: Unset vlan_filtering when ports leave the bridge") -Signed-off-by: Tobias Waldekranz -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - net/dsa/switch.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - ---- a/net/dsa/switch.c -+++ b/net/dsa/switch.c -@@ -180,9 +180,11 @@ static int dsa_switch_bridge_leave(struc - info->sw_index, info->port, - info->br); - -- err = dsa_switch_sync_vlan_filtering(ds, info); -- if (err) -- return err; -+ if (ds->dst->index == info->tree_index && ds->index == info->sw_index) { -+ err = dsa_switch_sync_vlan_filtering(ds, info); -+ if (err) -+ return err; -+ } - - return dsa_tag_8021q_bridge_leave(ds, info); - } diff --git a/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch b/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch deleted file mode 100644 index 78570c5e6e3..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-01-net-dsa-rtl8366rb-Support-bridge-offloading.patch +++ /dev/null @@ -1,141 +0,0 @@ -From c9111895fd38dadf125e07be627778a9950d8d77 Mon Sep 17 00:00:00 2001 -From: DENG Qingfang -Date: Sun, 26 Sep 2021 00:59:24 +0200 -Subject: [PATCH 01/11] net: dsa: rtl8366rb: Support bridge offloading -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use port isolation registers to configure bridge offloading. - -Tested on the D-Link DIR-685, switching between ports and -sniffing ports to make sure no packets leak. - -Cc: Vladimir Oltean -Cc: Mauri Sandberg -Reviewed-by: Vladimir Oltean -Reviewed-by: Alvin Šipraga -Reviewed-by: Florian Fainelli -Signed-off-by: DENG Qingfang -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366rb.c | 86 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 86 insertions(+) - ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -300,6 +300,13 @@ - #define RTL8366RB_INTERRUPT_STATUS_REG 0x0442 - #define RTL8366RB_NUM_INTERRUPT 14 /* 0..13 */ - -+/* Port isolation registers */ -+#define RTL8366RB_PORT_ISO_BASE 0x0F08 -+#define RTL8366RB_PORT_ISO(pnum) (RTL8366RB_PORT_ISO_BASE + (pnum)) -+#define RTL8366RB_PORT_ISO_EN BIT(0) -+#define RTL8366RB_PORT_ISO_PORTS_MASK GENMASK(7, 1) -+#define RTL8366RB_PORT_ISO_PORTS(pmask) ((pmask) << 1) -+ - /* bits 0..5 enable force when cleared */ - #define RTL8366RB_MAC_FORCE_CTRL_REG 0x0F11 - -@@ -835,6 +842,21 @@ static int rtl8366rb_setup(struct dsa_sw - if (ret) - return ret; - -+ /* Isolate all user ports so they can only send packets to itself and the CPU port */ -+ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { -+ ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(i), -+ RTL8366RB_PORT_ISO_PORTS(BIT(RTL8366RB_PORT_NUM_CPU)) | -+ RTL8366RB_PORT_ISO_EN); -+ if (ret) -+ return ret; -+ } -+ /* CPU port can send packets to all ports */ -+ ret = regmap_write(smi->map, RTL8366RB_PORT_ISO(RTL8366RB_PORT_NUM_CPU), -+ RTL8366RB_PORT_ISO_PORTS(dsa_user_ports(ds)) | -+ RTL8366RB_PORT_ISO_EN); -+ if (ret) -+ return ret; -+ - /* Set up the "green ethernet" feature */ - ret = rtl8366rb_jam_table(rtl8366rb_green_jam, - ARRAY_SIZE(rtl8366rb_green_jam), smi, false); -@@ -1127,6 +1149,68 @@ rtl8366rb_port_disable(struct dsa_switch - rb8366rb_set_port_led(smi, port, false); - } - -+static int -+rtl8366rb_port_bridge_join(struct dsa_switch *ds, int port, -+ struct net_device *bridge) -+{ -+ struct realtek_smi *smi = ds->priv; -+ unsigned int port_bitmap = 0; -+ int ret, i; -+ -+ /* Loop over all other ports than the current one */ -+ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { -+ /* Current port handled last */ -+ if (i == port) -+ continue; -+ /* Not on this bridge */ -+ if (dsa_to_port(ds, i)->bridge_dev != bridge) -+ continue; -+ /* Join this port to each other port on the bridge */ -+ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), -+ RTL8366RB_PORT_ISO_PORTS(BIT(port)), -+ RTL8366RB_PORT_ISO_PORTS(BIT(port))); -+ if (ret) -+ dev_err(smi->dev, "failed to join port %d\n", port); -+ -+ port_bitmap |= BIT(i); -+ } -+ -+ /* Set the bits for the ports we can access */ -+ return regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), -+ RTL8366RB_PORT_ISO_PORTS(port_bitmap), -+ RTL8366RB_PORT_ISO_PORTS(port_bitmap)); -+} -+ -+static void -+rtl8366rb_port_bridge_leave(struct dsa_switch *ds, int port, -+ struct net_device *bridge) -+{ -+ struct realtek_smi *smi = ds->priv; -+ unsigned int port_bitmap = 0; -+ int ret, i; -+ -+ /* Loop over all other ports than this one */ -+ for (i = 0; i < RTL8366RB_PORT_NUM_CPU; i++) { -+ /* Current port handled last */ -+ if (i == port) -+ continue; -+ /* Not on this bridge */ -+ if (dsa_to_port(ds, i)->bridge_dev != bridge) -+ continue; -+ /* Remove this port from any other port on the bridge */ -+ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(i), -+ RTL8366RB_PORT_ISO_PORTS(BIT(port)), 0); -+ if (ret) -+ dev_err(smi->dev, "failed to leave port %d\n", port); -+ -+ port_bitmap |= BIT(i); -+ } -+ -+ /* Clear the bits for the ports we can not access, leave ourselves */ -+ regmap_update_bits(smi->map, RTL8366RB_PORT_ISO(port), -+ RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); -+} -+ - static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) - { - struct realtek_smi *smi = ds->priv; -@@ -1510,6 +1594,8 @@ static const struct dsa_switch_ops rtl83 - .get_strings = rtl8366_get_strings, - .get_ethtool_stats = rtl8366_get_ethtool_stats, - .get_sset_count = rtl8366_get_sset_count, -+ .port_bridge_join = rtl8366rb_port_bridge_join, -+ .port_bridge_leave = rtl8366rb_port_bridge_leave, - .port_vlan_filtering = rtl8366_vlan_filtering, - .port_vlan_add = rtl8366_vlan_add, - .port_vlan_del = rtl8366_vlan_del, diff --git a/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch b/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch deleted file mode 100644 index e61349a32ca..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-02-net-dsa-rtl8366-Drop-custom-VLAN-set-up.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 96cf10a8e7297065459473c081a6fb6432a22312 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 26 Sep 2021 00:59:25 +0200 -Subject: [PATCH 02/11] net: dsa: rtl8366: Drop custom VLAN set-up -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This hacky default VLAN setup was done in order to direct -packets to the right ports and provide port isolation, both -which we now support properly using custom tags and proper -bridge port isolation. - -We can drop the custom VLAN code and leave all VLAN handling -alone, as users expect things to be. We can also drop -ds->configure_vlan_while_not_filtering = false; and let -the core deal with any VLANs it wants. - -Cc: Mauri Sandberg -Cc: DENG Qingfang -Reviewed-by: Vladimir Oltean -Reviewed-by: Alvin Šipraga -Reviewed-by: Florian Fainelli -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/realtek-smi-core.h | 1 - - drivers/net/dsa/rtl8366.c | 48 ------------------------------ - drivers/net/dsa/rtl8366rb.c | 4 +-- - 3 files changed, 1 insertion(+), 52 deletions(-) - ---- a/drivers/net/dsa/realtek-smi-core.h -+++ b/drivers/net/dsa/realtek-smi-core.h -@@ -129,7 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi - int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); - int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); - int rtl8366_reset_vlan(struct realtek_smi *smi); --int rtl8366_init_vlan(struct realtek_smi *smi); - int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack); - int rtl8366_vlan_add(struct dsa_switch *ds, int port, ---- a/drivers/net/dsa/rtl8366.c -+++ b/drivers/net/dsa/rtl8366.c -@@ -292,54 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm - } - EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); - --int rtl8366_init_vlan(struct realtek_smi *smi) --{ -- int port; -- int ret; -- -- ret = rtl8366_reset_vlan(smi); -- if (ret) -- return ret; -- -- /* Loop over the available ports, for each port, associate -- * it with the VLAN (port+1) -- */ -- for (port = 0; port < smi->num_ports; port++) { -- u32 mask; -- -- if (port == smi->cpu_port) -- /* For the CPU port, make all ports members of this -- * VLAN. -- */ -- mask = GENMASK((int)smi->num_ports - 1, 0); -- else -- /* For all other ports, enable itself plus the -- * CPU port. -- */ -- mask = BIT(port) | BIT(smi->cpu_port); -- -- /* For each port, set the port as member of VLAN (port+1) -- * and untagged, except for the CPU port: the CPU port (5) is -- * member of VLAN 6 and so are ALL the other ports as well. -- * Use filter 0 (no filter). -- */ -- dev_info(smi->dev, "VLAN%d port mask for port %d, %08x\n", -- (port + 1), port, mask); -- ret = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); -- if (ret) -- return ret; -- -- dev_info(smi->dev, "VLAN%d port %d, PVID set to %d\n", -- (port + 1), port, (port + 1)); -- ret = rtl8366_set_pvid(smi, port, (port + 1)); -- if (ret) -- return ret; -- } -- -- return rtl8366_enable_vlan(smi, true); --} --EXPORT_SYMBOL_GPL(rtl8366_init_vlan); -- - int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, - struct netlink_ext_ack *extack) - { ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -985,7 +985,7 @@ static int rtl8366rb_setup(struct dsa_sw - return ret; - } - -- ret = rtl8366_init_vlan(smi); -+ ret = rtl8366_reset_vlan(smi); - if (ret) - return ret; - -@@ -999,8 +999,6 @@ static int rtl8366rb_setup(struct dsa_sw - return -ENODEV; - } - -- ds->configure_vlan_while_not_filtering = false; -- - return 0; - } - diff --git a/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch b/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch deleted file mode 100644 index 2b197523994..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-03-net-dsa-rtl8366rb-Rewrite-weird-VLAN-filering-enable.patch +++ /dev/null @@ -1,270 +0,0 @@ -From 7028f54b620f8df344b18e46e4a78e266091ab45 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 26 Sep 2021 00:59:26 +0200 -Subject: [PATCH 03/11] net: dsa: rtl8366rb: Rewrite weird VLAN filering - enablement -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -While we were defining one VLAN per port for isolating the ports -the port_vlan_filtering() callback was implemented to enable a -VLAN on the port + 1. This function makes no sense, not only is -it incomplete as it only enables the VLAN, it doesn't do what -the callback is supposed to do, which is to selectively enable -and disable filtering on a certain port. - -Implement the correct callback: we have two registers dealing -with filtering on the RTL9366RB, so we implement an ASIC-specific -callback and implement filering using the register bit that makes -the switch drop frames if the port is not in the VLAN member set. - -The DSA documentation Documentation/networking/switchdev.rst states: - - When the bridge has VLAN filtering enabled and a PVID is not - configured on the ingress port, untagged and 802.1p tagged - packets must be dropped. When the bridge has VLAN filtering - enabled and a PVID exists on the ingress port, untagged and - priority-tagged packets must be accepted and forwarded according - to the bridge's port membership of the PVID VLAN. When the - bridge has VLAN filtering disabled, the presence/lack of a - PVID should not influence the packet forwarding decision. - -To comply with this, we add two arrays of bool in the RTL8366RB -state that keeps track of if filtering and PVID is enabled or -not for each port. We then add code such that whenever filtering -or PVID changes, we update the filter according to the -specification. - -Cc: Vladimir Oltean -Cc: Mauri Sandberg -Cc: Alvin Šipraga -Cc: Florian Fainelli -Cc: DENG Qingfang -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/realtek-smi-core.h | 2 - - drivers/net/dsa/rtl8366.c | 35 ---------- - drivers/net/dsa/rtl8366rb.c | 102 +++++++++++++++++++++++++++-- - 3 files changed, 95 insertions(+), 44 deletions(-) - ---- a/drivers/net/dsa/realtek-smi-core.h -+++ b/drivers/net/dsa/realtek-smi-core.h -@@ -129,8 +129,6 @@ int rtl8366_set_pvid(struct realtek_smi - int rtl8366_enable_vlan4k(struct realtek_smi *smi, bool enable); - int rtl8366_enable_vlan(struct realtek_smi *smi, bool enable); - int rtl8366_reset_vlan(struct realtek_smi *smi); --int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -- struct netlink_ext_ack *extack); - int rtl8366_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct netlink_ext_ack *extack); ---- a/drivers/net/dsa/rtl8366.c -+++ b/drivers/net/dsa/rtl8366.c -@@ -292,41 +292,6 @@ int rtl8366_reset_vlan(struct realtek_sm - } - EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); - --int rtl8366_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering, -- struct netlink_ext_ack *extack) --{ -- struct realtek_smi *smi = ds->priv; -- struct rtl8366_vlan_4k vlan4k; -- int ret; -- -- /* Use VLAN nr port + 1 since VLAN0 is not valid */ -- if (!smi->ops->is_vlan_valid(smi, port + 1)) -- return -EINVAL; -- -- dev_info(smi->dev, "%s filtering on port %d\n", -- vlan_filtering ? "enable" : "disable", -- port); -- -- /* TODO: -- * The hardware support filter ID (FID) 0..7, I have no clue how to -- * support this in the driver when the callback only says on/off. -- */ -- ret = smi->ops->get_vlan_4k(smi, port + 1, &vlan4k); -- if (ret) -- return ret; -- -- /* Just set the filter to FID 1 for now then */ -- ret = rtl8366_set_vlan(smi, port + 1, -- vlan4k.member, -- vlan4k.untag, -- 1); -- if (ret) -- return ret; -- -- return 0; --} --EXPORT_SYMBOL_GPL(rtl8366_vlan_filtering); -- - int rtl8366_vlan_add(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct netlink_ext_ack *extack) ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -143,6 +143,21 @@ - #define RTL8366RB_PHY_NO_OFFSET 9 - #define RTL8366RB_PHY_NO_MASK (0x1f << 9) - -+/* VLAN Ingress Control Register 1, one bit per port. -+ * bit 0 .. 5 will make the switch drop ingress frames without -+ * VID such as untagged or priority-tagged frames for respective -+ * port. -+ * bit 6 .. 11 will make the switch drop ingress frames carrying -+ * a C-tag with VID != 0 for respective port. -+ */ -+#define RTL8366RB_VLAN_INGRESS_CTRL1_REG 0x037E -+#define RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) (BIT((port)) | BIT((port) + 6)) -+ -+/* VLAN Ingress Control Register 2, one bit per port. -+ * bit0 .. bit5 will make the switch drop all ingress frames with -+ * a VLAN classification that does not include the port is in its -+ * member set. -+ */ - #define RTL8366RB_VLAN_INGRESS_CTRL2_REG 0x037f - - /* LED control registers */ -@@ -321,9 +336,13 @@ - /** - * struct rtl8366rb - RTL8366RB-specific data - * @max_mtu: per-port max MTU setting -+ * @pvid_enabled: if PVID is set for respective port -+ * @vlan_filtering: if VLAN filtering is enabled for respective port - */ - struct rtl8366rb { - unsigned int max_mtu[RTL8366RB_NUM_PORTS]; -+ bool pvid_enabled[RTL8366RB_NUM_PORTS]; -+ bool vlan_filtering[RTL8366RB_NUM_PORTS]; - }; - - static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { -@@ -933,11 +952,13 @@ static int rtl8366rb_setup(struct dsa_sw - if (ret) - return ret; - -- /* Discard VLAN tagged packets if the port is not a member of -- * the VLAN with which the packets is associated. -- */ -+ /* Accept all packets by default, we enable filtering on-demand */ -+ ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, -+ 0); -+ if (ret) -+ return ret; - ret = regmap_write(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, -- RTL8366RB_PORT_ALL); -+ 0); - if (ret) - return ret; - -@@ -1209,6 +1230,53 @@ rtl8366rb_port_bridge_leave(struct dsa_s - RTL8366RB_PORT_ISO_PORTS(port_bitmap), 0); - } - -+/** -+ * rtl8366rb_drop_untagged() - make the switch drop untagged and C-tagged frames -+ * @smi: SMI state container -+ * @port: the port to drop untagged and C-tagged frames on -+ * @drop: whether to drop or pass untagged and C-tagged frames -+ */ -+static int rtl8366rb_drop_untagged(struct realtek_smi *smi, int port, bool drop) -+{ -+ return regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL1_REG, -+ RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port), -+ drop ? RTL8366RB_VLAN_INGRESS_CTRL1_DROP(port) : 0); -+} -+ -+static int rtl8366rb_vlan_filtering(struct dsa_switch *ds, int port, -+ bool vlan_filtering, -+ struct netlink_ext_ack *extack) -+{ -+ struct realtek_smi *smi = ds->priv; -+ struct rtl8366rb *rb; -+ int ret; -+ -+ rb = smi->chip_data; -+ -+ dev_dbg(smi->dev, "port %d: %s VLAN filtering\n", port, -+ vlan_filtering ? "enable" : "disable"); -+ -+ /* If the port is not in the member set, the frame will be dropped */ -+ ret = regmap_update_bits(smi->map, RTL8366RB_VLAN_INGRESS_CTRL2_REG, -+ BIT(port), vlan_filtering ? BIT(port) : 0); -+ if (ret) -+ return ret; -+ -+ /* Keep track if filtering is enabled on each port */ -+ rb->vlan_filtering[port] = vlan_filtering; -+ -+ /* If VLAN filtering is enabled and PVID is also enabled, we must -+ * not drop any untagged or C-tagged frames. If we turn off VLAN -+ * filtering on a port, we need ti accept any frames. -+ */ -+ if (vlan_filtering) -+ ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); -+ else -+ ret = rtl8366rb_drop_untagged(smi, port, false); -+ -+ return ret; -+} -+ - static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) - { - struct realtek_smi *smi = ds->priv; -@@ -1420,14 +1488,34 @@ static int rtl8366rb_get_mc_index(struct - - static int rtl8366rb_set_mc_index(struct realtek_smi *smi, int port, int index) - { -+ struct rtl8366rb *rb; -+ bool pvid_enabled; -+ int ret; -+ -+ rb = smi->chip_data; -+ pvid_enabled = !!index; -+ - if (port >= smi->num_ports || index >= RTL8366RB_NUM_VLANS) - return -EINVAL; - -- return regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), -+ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_VLAN_CTRL_REG(port), - RTL8366RB_PORT_VLAN_CTRL_MASK << - RTL8366RB_PORT_VLAN_CTRL_SHIFT(port), - (index & RTL8366RB_PORT_VLAN_CTRL_MASK) << - RTL8366RB_PORT_VLAN_CTRL_SHIFT(port)); -+ if (ret) -+ return ret; -+ -+ rb->pvid_enabled[port] = pvid_enabled; -+ -+ /* If VLAN filtering is enabled and PVID is also enabled, we must -+ * not drop any untagged or C-tagged frames. Make sure to update the -+ * filtering setting. -+ */ -+ if (rb->vlan_filtering[port]) -+ ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled); -+ -+ return ret; - } - - static bool rtl8366rb_is_vlan_valid(struct realtek_smi *smi, unsigned int vlan) -@@ -1437,7 +1525,7 @@ static bool rtl8366rb_is_vlan_valid(stru - if (smi->vlan4k_enabled) - max = RTL8366RB_NUM_VIDS - 1; - -- if (vlan == 0 || vlan > max) -+ if (vlan > max) - return false; - - return true; -@@ -1594,7 +1682,7 @@ static const struct dsa_switch_ops rtl83 - .get_sset_count = rtl8366_get_sset_count, - .port_bridge_join = rtl8366rb_port_bridge_join, - .port_bridge_leave = rtl8366rb_port_bridge_leave, -- .port_vlan_filtering = rtl8366_vlan_filtering, -+ .port_vlan_filtering = rtl8366rb_vlan_filtering, - .port_vlan_add = rtl8366_vlan_add, - .port_vlan_del = rtl8366_vlan_del, - .port_enable = rtl8366rb_port_enable, diff --git a/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch b/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch deleted file mode 100644 index b56032c366b..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-06-net-dsa-rtl8366-Drop-and-depromote-pointless-prints.patch +++ /dev/null @@ -1,51 +0,0 @@ -From ddb59a5dc42714999c335dab4bf256125ba3120c Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Sun, 26 Sep 2021 00:59:29 +0200 -Subject: [PATCH 06/11] net: dsa: rtl8366: Drop and depromote pointless prints -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We don't need a message for every VLAN association, dbg -is fine. The message about adding the DSA or CPU -port to a VLAN is directly misleading, this is perfectly -fine. - -Cc: Vladimir Oltean -Cc: Mauri Sandberg -Cc: DENG Qingfang -Reviewed-by: Alvin Šipraga -Reviewed-by: Florian Fainelli -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366.c | 11 ++++------- - 1 file changed, 4 insertions(+), 7 deletions(-) - ---- a/drivers/net/dsa/rtl8366.c -+++ b/drivers/net/dsa/rtl8366.c -@@ -318,12 +318,9 @@ int rtl8366_vlan_add(struct dsa_switch * - return ret; - } - -- dev_info(smi->dev, "add VLAN %d on port %d, %s, %s\n", -- vlan->vid, port, untagged ? "untagged" : "tagged", -- pvid ? " PVID" : "no PVID"); -- -- if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port)) -- dev_err(smi->dev, "port is DSA or CPU port\n"); -+ dev_dbg(smi->dev, "add VLAN %d on port %d, %s, %s\n", -+ vlan->vid, port, untagged ? "untagged" : "tagged", -+ pvid ? "PVID" : "no PVID"); - - member |= BIT(port); - -@@ -356,7 +353,7 @@ int rtl8366_vlan_del(struct dsa_switch * - struct realtek_smi *smi = ds->priv; - int ret, i; - -- dev_info(smi->dev, "del VLAN %04x on port %d\n", vlan->vid, port); -+ dev_dbg(smi->dev, "del VLAN %d on port %d\n", vlan->vid, port); - - for (i = 0; i < smi->num_vlan_mc; i++) { - struct rtl8366_vlan_mc vlanmc; diff --git a/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch b/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch deleted file mode 100644 index 8cd1df97f24..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-07-net-dsa-rtl8366rb-Use-core-filtering-tracking.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 5c9b66f3c8a3f72fa2a58e89a57c6d7afd550bf0 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Wed, 29 Sep 2021 13:23:22 +0200 -Subject: [PATCH 07/11] net: dsa: rtl8366rb: Use core filtering tracking -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -We added a state variable to track whether a certain port -was VLAN filtering or not, but we can just inquire the DSA -core about this. - -Cc: Vladimir Oltean -Cc: Mauri Sandberg -Cc: DENG Qingfang -Cc: Alvin Šipraga -Cc: Reviewed-by: Florian Fainelli -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366rb.c | 9 ++------- - 1 file changed, 2 insertions(+), 7 deletions(-) - ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -337,12 +337,10 @@ - * struct rtl8366rb - RTL8366RB-specific data - * @max_mtu: per-port max MTU setting - * @pvid_enabled: if PVID is set for respective port -- * @vlan_filtering: if VLAN filtering is enabled for respective port - */ - struct rtl8366rb { - unsigned int max_mtu[RTL8366RB_NUM_PORTS]; - bool pvid_enabled[RTL8366RB_NUM_PORTS]; -- bool vlan_filtering[RTL8366RB_NUM_PORTS]; - }; - - static struct rtl8366_mib_counter rtl8366rb_mib_counters[] = { -@@ -1262,12 +1260,9 @@ static int rtl8366rb_vlan_filtering(stru - if (ret) - return ret; - -- /* Keep track if filtering is enabled on each port */ -- rb->vlan_filtering[port] = vlan_filtering; -- - /* If VLAN filtering is enabled and PVID is also enabled, we must - * not drop any untagged or C-tagged frames. If we turn off VLAN -- * filtering on a port, we need ti accept any frames. -+ * filtering on a port, we need to accept any frames. - */ - if (vlan_filtering) - ret = rtl8366rb_drop_untagged(smi, port, !rb->pvid_enabled[port]); -@@ -1512,7 +1507,7 @@ static int rtl8366rb_set_mc_index(struct - * not drop any untagged or C-tagged frames. Make sure to update the - * filtering setting. - */ -- if (rb->vlan_filtering[port]) -+ if (dsa_port_is_vlan_filtering(dsa_to_port(smi->ds, port))) - ret = rtl8366rb_drop_untagged(smi, port, !pvid_enabled); - - return ret; diff --git a/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch b/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch deleted file mode 100644 index 8306eb5aefa..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-08-net-dsa-rtl8366rb-Support-disabling-learning.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 831a3d26bea0d14f8563eecf96def660a74a3000 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Tue, 5 Oct 2021 21:47:02 +0200 -Subject: [PATCH 08/11] net: dsa: rtl8366rb: Support disabling learning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The RTL8366RB hardware supports disabling learning per-port -so let's make use of this feature. Rename some unfortunately -named registers in the process. - -Suggested-by: Vladimir Oltean -Cc: Alvin Šipraga -Cc: Mauri Sandberg -Cc: Florian Fainelli -Cc: DENG Qingfang -Reviewed-by: Vladimir Oltean -Signed-off-by: Linus Walleij -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366rb.c | 50 ++++++++++++++++++++++++++++++++----- - 1 file changed, 44 insertions(+), 6 deletions(-) - ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -14,6 +14,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -42,9 +43,12 @@ - /* Port Enable Control register */ - #define RTL8366RB_PECR 0x0001 - --/* Switch Security Control registers */ --#define RTL8366RB_SSCR0 0x0002 --#define RTL8366RB_SSCR1 0x0003 -+/* Switch per-port learning disablement register */ -+#define RTL8366RB_PORT_LEARNDIS_CTRL 0x0002 -+ -+/* Security control, actually aging register */ -+#define RTL8366RB_SECURITY_CTRL 0x0003 -+ - #define RTL8366RB_SSCR2 0x0004 - #define RTL8366RB_SSCR2_DROP_UNKNOWN_DA BIT(0) - -@@ -927,13 +931,14 @@ static int rtl8366rb_setup(struct dsa_sw - /* layer 2 size, see rtl8366rb_change_mtu() */ - rb->max_mtu[i] = 1532; - -- /* Enable learning for all ports */ -- ret = regmap_write(smi->map, RTL8366RB_SSCR0, 0); -+ /* Disable learning for all ports */ -+ ret = regmap_write(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, -+ RTL8366RB_PORT_ALL); - if (ret) - return ret; - - /* Enable auto ageing for all ports */ -- ret = regmap_write(smi->map, RTL8366RB_SSCR1, 0); -+ ret = regmap_write(smi->map, RTL8366RB_SECURITY_CTRL, 0); - if (ret) - return ret; - -@@ -1272,6 +1277,37 @@ static int rtl8366rb_vlan_filtering(stru - return ret; - } - -+static int -+rtl8366rb_port_pre_bridge_flags(struct dsa_switch *ds, int port, -+ struct switchdev_brport_flags flags, -+ struct netlink_ext_ack *extack) -+{ -+ /* We support enabling/disabling learning */ -+ if (flags.mask & ~(BR_LEARNING)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int -+rtl8366rb_port_bridge_flags(struct dsa_switch *ds, int port, -+ struct switchdev_brport_flags flags, -+ struct netlink_ext_ack *extack) -+{ -+ struct realtek_smi *smi = ds->priv; -+ int ret; -+ -+ if (flags.mask & BR_LEARNING) { -+ ret = regmap_update_bits(smi->map, RTL8366RB_PORT_LEARNDIS_CTRL, -+ BIT(port), -+ (flags.val & BR_LEARNING) ? 0 : BIT(port)); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ - static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) - { - struct realtek_smi *smi = ds->priv; -@@ -1682,6 +1718,8 @@ static const struct dsa_switch_ops rtl83 - .port_vlan_del = rtl8366_vlan_del, - .port_enable = rtl8366rb_port_enable, - .port_disable = rtl8366rb_port_disable, -+ .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, -+ .port_bridge_flags = rtl8366rb_port_bridge_flags, - .port_change_mtu = rtl8366rb_change_mtu, - .port_max_mtu = rtl8366rb_max_mtu, - }; diff --git a/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch b/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch deleted file mode 100644 index a74108e23db..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-09-net-dsa-rtl8366rb-Support-fast-aging.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 8eb13420eb9ab4a4e2ebd612bf5dc9dba0039236 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Tue, 5 Oct 2021 21:47:03 +0200 -Subject: [PATCH 09/11] net: dsa: rtl8366rb: Support fast aging -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This implements fast aging per-port using the special "security" -register, which will flush any learned L2 LUT entries on a port. - -The vendor API just enabled setting and clearing this bit, so -we set it to age out any entries on the port and then we clear -it again. - -Suggested-by: Vladimir Oltean -Cc: Mauri Sandberg -Cc: DENG Qingfang -Cc: Florian Fainelli -Reviewed-by: Alvin Šipraga -Signed-off-by: Linus Walleij -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366rb.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -1308,6 +1308,19 @@ rtl8366rb_port_bridge_flags(struct dsa_s - return 0; - } - -+static void -+rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) -+{ -+ struct realtek_smi *smi = ds->priv; -+ -+ /* This will age out any learned L2 entries */ -+ regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, -+ BIT(port), BIT(port)); -+ /* Restore the normal state of things */ -+ regmap_update_bits(smi->map, RTL8366RB_SECURITY_CTRL, -+ BIT(port), 0); -+} -+ - static int rtl8366rb_change_mtu(struct dsa_switch *ds, int port, int new_mtu) - { - struct realtek_smi *smi = ds->priv; -@@ -1720,6 +1733,7 @@ static const struct dsa_switch_ops rtl83 - .port_disable = rtl8366rb_port_disable, - .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, - .port_bridge_flags = rtl8366rb_port_bridge_flags, -+ .port_fast_age = rtl8366rb_port_fast_age, - .port_change_mtu = rtl8366rb_change_mtu, - .port_max_mtu = rtl8366rb_max_mtu, - }; diff --git a/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch b/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch deleted file mode 100644 index e787ce94811..00000000000 --- a/target/linux/generic/backport-6.1/774-v5.16-10-net-dsa-rtl8366rb-Support-setting-STP-state.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 90c855471a89d3e05ecf5b6464bd04abf2c83b70 Mon Sep 17 00:00:00 2001 -From: Linus Walleij -Date: Tue, 5 Oct 2021 21:47:04 +0200 -Subject: [PATCH 10/11] net: dsa: rtl8366rb: Support setting STP state -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds support for setting the STP state to the RTL8366RB -DSA switch. This rids the following message from the kernel on -e.g. OpenWrt: - -DSA: failed to set STP state 3 (-95) - -Since the RTL8366RB has one STP state register per FID with -two bit per port in each, we simply loop over all the FIDs -and set the state on all of them. - -Cc: Vladimir Oltean -Cc: Alvin Šipraga -Cc: Mauri Sandberg -Cc: DENG Qingfang -Signed-off-by: Linus Walleij -Reviewed-by: Vladimir Oltean -Signed-off-by: David S. Miller ---- - drivers/net/dsa/rtl8366rb.c | 48 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 48 insertions(+) - ---- a/drivers/net/dsa/rtl8366rb.c -+++ b/drivers/net/dsa/rtl8366rb.c -@@ -110,6 +110,18 @@ - - #define RTL8366RB_POWER_SAVING_REG 0x0021 - -+/* Spanning tree status (STP) control, two bits per port per FID */ -+#define RTL8366RB_STP_STATE_BASE 0x0050 /* 0x0050..0x0057 */ -+#define RTL8366RB_STP_STATE_DISABLED 0x0 -+#define RTL8366RB_STP_STATE_BLOCKING 0x1 -+#define RTL8366RB_STP_STATE_LEARNING 0x2 -+#define RTL8366RB_STP_STATE_FORWARDING 0x3 -+#define RTL8366RB_STP_MASK GENMASK(1, 0) -+#define RTL8366RB_STP_STATE(port, state) \ -+ ((state) << ((port) * 2)) -+#define RTL8366RB_STP_STATE_MASK(port) \ -+ RTL8366RB_STP_STATE((port), RTL8366RB_STP_MASK) -+ - /* CPU port control reg */ - #define RTL8368RB_CPU_CTRL_REG 0x0061 - #define RTL8368RB_CPU_PORTS_MSK 0x00FF -@@ -234,6 +246,7 @@ - #define RTL8366RB_NUM_LEDGROUPS 4 - #define RTL8366RB_NUM_VIDS 4096 - #define RTL8366RB_PRIORITYMAX 7 -+#define RTL8366RB_NUM_FIDS 8 - #define RTL8366RB_FIDMAX 7 - - #define RTL8366RB_PORT_1 BIT(0) /* In userspace port 0 */ -@@ -1309,6 +1322,40 @@ rtl8366rb_port_bridge_flags(struct dsa_s - } - - static void -+rtl8366rb_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) -+{ -+ struct realtek_smi *smi = ds->priv; -+ u32 val; -+ int i; -+ -+ switch (state) { -+ case BR_STATE_DISABLED: -+ val = RTL8366RB_STP_STATE_DISABLED; -+ break; -+ case BR_STATE_BLOCKING: -+ case BR_STATE_LISTENING: -+ val = RTL8366RB_STP_STATE_BLOCKING; -+ break; -+ case BR_STATE_LEARNING: -+ val = RTL8366RB_STP_STATE_LEARNING; -+ break; -+ case BR_STATE_FORWARDING: -+ val = RTL8366RB_STP_STATE_FORWARDING; -+ break; -+ default: -+ dev_err(smi->dev, "unknown bridge state requested\n"); -+ return; -+ }; -+ -+ /* Set the same status for the port on all the FIDs */ -+ for (i = 0; i < RTL8366RB_NUM_FIDS; i++) { -+ regmap_update_bits(smi->map, RTL8366RB_STP_STATE_BASE + i, -+ RTL8366RB_STP_STATE_MASK(port), -+ RTL8366RB_STP_STATE(port, val)); -+ } -+} -+ -+static void - rtl8366rb_port_fast_age(struct dsa_switch *ds, int port) - { - struct realtek_smi *smi = ds->priv; -@@ -1733,6 +1780,7 @@ static const struct dsa_switch_ops rtl83 - .port_disable = rtl8366rb_port_disable, - .port_pre_bridge_flags = rtl8366rb_port_pre_bridge_flags, - .port_bridge_flags = rtl8366rb_port_bridge_flags, -+ .port_stp_state_set = rtl8366rb_port_stp_state_set, - .port_fast_age = rtl8366rb_port_fast_age, - .port_change_mtu = rtl8366rb_change_mtu, - .port_max_mtu = rtl8366rb_max_mtu, diff --git a/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch b/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch deleted file mode 100644 index 9b9ab04af6c..00000000000 --- a/target/linux/generic/backport-6.1/775-v6.0-01-net-ethernet-stmicro-stmmac-move-queue-reset-to-dedi.patch +++ /dev/null @@ -1,142 +0,0 @@ -From f9ec5723c3dbfcede9c7b0dcdf85e401ce16316c Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 23 Jul 2022 16:29:29 +0200 -Subject: [PATCH 1/5] net: ethernet: stmicro: stmmac: move queue reset to - dedicated functions - -Move queue reset to dedicated functions. This aside from a simple -cleanup is also required to allocate a dma conf without resetting the tx -queue while the device is temporarily detached as now the reset is not -part of the dma init function and can be done later in the code flow. - -Signed-off-by: Christian Marangi -Signed-off-by: Jakub Kicinski ---- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 59 ++++++++++--------- - 1 file changed, 31 insertions(+), 28 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -130,6 +130,9 @@ static irqreturn_t stmmac_mac_interrupt( - static irqreturn_t stmmac_safety_interrupt(int irq, void *dev_id); - static irqreturn_t stmmac_msi_intr_tx(int irq, void *data); - static irqreturn_t stmmac_msi_intr_rx(int irq, void *data); -+static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue); -+static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue); -+static void stmmac_reset_queues_param(struct stmmac_priv *priv); - static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue); - static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue); - -@@ -1712,9 +1715,6 @@ static int __init_dma_rx_desc_rings(stru - return -ENOMEM; - } - -- rx_q->cur_rx = 0; -- rx_q->dirty_rx = 0; -- - /* Setup the chained descriptor addresses */ - if (priv->mode == STMMAC_CHAIN_MODE) { - if (priv->extend_desc) -@@ -1820,12 +1820,6 @@ static int __init_dma_tx_desc_rings(stru - tx_q->tx_skbuff[i] = NULL; - } - -- tx_q->dirty_tx = 0; -- tx_q->cur_tx = 0; -- tx_q->mss = 0; -- -- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); -- - return 0; - } - -@@ -2694,10 +2688,7 @@ static void stmmac_tx_err(struct stmmac_ - stmmac_stop_tx_dma(priv, chan); - dma_free_tx_skbufs(priv, chan); - stmmac_clear_tx_descriptors(priv, chan); -- tx_q->dirty_tx = 0; -- tx_q->cur_tx = 0; -- tx_q->mss = 0; -- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, chan)); -+ stmmac_reset_tx_queue(priv, chan); - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - tx_q->dma_tx_phy, chan); - stmmac_start_tx_dma(priv, chan); -@@ -3781,6 +3772,8 @@ static int stmmac_open(struct net_device - } - } - -+ stmmac_reset_queues_param(priv); -+ - ret = stmmac_hw_setup(dev, true); - if (ret < 0) { - netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); -@@ -6430,6 +6423,7 @@ void stmmac_enable_rx_queue(struct stmma - return; - } - -+ stmmac_reset_rx_queue(priv, queue); - stmmac_clear_rx_descriptors(priv, queue); - - stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, -@@ -6491,6 +6485,7 @@ void stmmac_enable_tx_queue(struct stmma - return; - } - -+ stmmac_reset_tx_queue(priv, queue); - stmmac_clear_tx_descriptors(priv, queue); - - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, -@@ -7417,6 +7412,25 @@ int stmmac_suspend(struct device *dev) - } - EXPORT_SYMBOL_GPL(stmmac_suspend); - -+static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue) -+{ -+ struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ -+ rx_q->cur_rx = 0; -+ rx_q->dirty_rx = 0; -+} -+ -+static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue) -+{ -+ struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ -+ tx_q->cur_tx = 0; -+ tx_q->dirty_tx = 0; -+ tx_q->mss = 0; -+ -+ netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); -+} -+ - /** - * stmmac_reset_queues_param - reset queue parameters - * @priv: device pointer -@@ -7427,22 +7441,11 @@ static void stmmac_reset_queues_param(st - u32 tx_cnt = priv->plat->tx_queues_to_use; - u32 queue; - -- for (queue = 0; queue < rx_cnt; queue++) { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ for (queue = 0; queue < rx_cnt; queue++) -+ stmmac_reset_rx_queue(priv, queue); - -- rx_q->cur_rx = 0; -- rx_q->dirty_rx = 0; -- } -- -- for (queue = 0; queue < tx_cnt; queue++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -- -- tx_q->cur_tx = 0; -- tx_q->dirty_tx = 0; -- tx_q->mss = 0; -- -- netdev_tx_reset_queue(netdev_get_tx_queue(priv->dev, queue)); -- } -+ for (queue = 0; queue < tx_cnt; queue++) -+ stmmac_reset_tx_queue(priv, queue); - } - - /** diff --git a/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch b/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch deleted file mode 100644 index 8eca92a5c54..00000000000 --- a/target/linux/generic/backport-6.1/775-v6.0-02-net-ethernet-stmicro-stmmac-first-disable-all-queues.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 7028471edb646bfc532fec0973e50e784cdcb7c6 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 23 Jul 2022 16:29:30 +0200 -Subject: [PATCH 2/5] net: ethernet: stmicro: stmmac: first disable all queues - and disconnect in release - -Disable all queues and disconnect before tx_disable in stmmac_release to -prevent a corner case where packet may be still queued at the same time -tx_disable is called resulting in kernel panic if some packet still has -to be processed. - -Signed-off-by: Christian Marangi -Signed-off-by: Jakub Kicinski ---- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -3833,8 +3833,6 @@ static int stmmac_release(struct net_dev - struct stmmac_priv *priv = netdev_priv(dev); - u32 chan; - -- netif_tx_disable(dev); -- - if (device_may_wakeup(priv->device)) - phylink_speed_down(priv->phylink, false); - /* Stop and disconnect the PHY */ -@@ -3846,6 +3844,8 @@ static int stmmac_release(struct net_dev - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) - hrtimer_cancel(&priv->tx_queue[chan].txtimer); - -+ netif_tx_disable(dev); -+ - /* Free the IRQ lines */ - stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); - diff --git a/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch b/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch deleted file mode 100644 index d4c2567a1fd..00000000000 --- a/target/linux/generic/backport-6.1/775-v6.0-03-net-ethernet-stmicro-stmmac-move-dma-conf-to-dedicat.patch +++ /dev/null @@ -1,1289 +0,0 @@ -From 8531c80800c10e8ef7952022326c2f983e1314bf Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 23 Jul 2022 16:29:31 +0200 -Subject: [PATCH 3/5] net: ethernet: stmicro: stmmac: move dma conf to - dedicated struct - -Move dma buf conf to dedicated struct. This in preparation for code -rework that will permit to allocate separate dma_conf without affecting -the priv struct. - -Signed-off-by: Christian Marangi -Signed-off-by: Jakub Kicinski ---- - .../net/ethernet/stmicro/stmmac/chain_mode.c | 6 +- - .../net/ethernet/stmicro/stmmac/ring_mode.c | 4 +- - drivers/net/ethernet/stmicro/stmmac/stmmac.h | 21 +- - .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 4 +- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 286 +++++++++--------- - .../stmicro/stmmac/stmmac_selftests.c | 8 +- - .../net/ethernet/stmicro/stmmac/stmmac_tc.c | 6 +- - 7 files changed, 172 insertions(+), 163 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c -+++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c -@@ -46,7 +46,7 @@ static int jumbo_frm(void *p, struct sk_ - - while (len != 0) { - tx_q->tx_skbuff[entry] = NULL; -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - desc = tx_q->dma_tx + entry; - - if (len > bmax) { -@@ -137,7 +137,7 @@ static void refill_desc3(void *priv_ptr, - */ - p->des3 = cpu_to_le32((unsigned int)(rx_q->dma_rx_phy + - (((rx_q->dirty_rx) + 1) % -- priv->dma_rx_size) * -+ priv->dma_conf.dma_rx_size) * - sizeof(struct dma_desc))); - } - -@@ -155,7 +155,7 @@ static void clean_desc3(void *priv_ptr, - */ - p->des3 = cpu_to_le32((unsigned int)((tx_q->dma_tx_phy + - ((tx_q->dirty_tx + 1) % -- priv->dma_tx_size)) -+ priv->dma_conf.dma_tx_size)) - * sizeof(struct dma_desc))); - } - ---- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c -+++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c -@@ -51,7 +51,7 @@ static int jumbo_frm(void *p, struct sk_ - stmmac_prepare_tx_desc(priv, desc, 1, bmax, csum, - STMMAC_RING_MODE, 0, false, skb->len); - tx_q->tx_skbuff[entry] = NULL; -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - - if (priv->extend_desc) - desc = (struct dma_desc *)(tx_q->dma_etx + entry); -@@ -107,7 +107,7 @@ static void refill_desc3(void *priv_ptr, - struct stmmac_priv *priv = rx_q->priv_data; - - /* Fill DES3 in case of RING mode */ -- if (priv->dma_buf_sz == BUF_SIZE_16KiB) -+ if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) - p->des3 = cpu_to_le32(le32_to_cpu(p->des2) + BUF_SIZE_8KiB); - } - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h -@@ -185,6 +185,18 @@ struct stmmac_rfs_entry { - int tc; - }; - -+struct stmmac_dma_conf { -+ unsigned int dma_buf_sz; -+ -+ /* RX Queue */ -+ struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES]; -+ unsigned int dma_rx_size; -+ -+ /* TX Queue */ -+ struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; -+ unsigned int dma_tx_size; -+}; -+ - struct stmmac_priv { - /* Frequently used values are kept adjacent for cache effect */ - u32 tx_coal_frames[MTL_MAX_TX_QUEUES]; -@@ -199,7 +211,6 @@ struct stmmac_priv { - int sph_cap; - u32 sarc_type; - -- unsigned int dma_buf_sz; - unsigned int rx_copybreak; - u32 rx_riwt[MTL_MAX_TX_QUEUES]; - int hwts_rx_en; -@@ -211,13 +222,7 @@ struct stmmac_priv { - int (*hwif_quirks)(struct stmmac_priv *priv); - struct mutex lock; - -- /* RX Queue */ -- struct stmmac_rx_queue rx_queue[MTL_MAX_RX_QUEUES]; -- unsigned int dma_rx_size; -- -- /* TX Queue */ -- struct stmmac_tx_queue tx_queue[MTL_MAX_TX_QUEUES]; -- unsigned int dma_tx_size; -+ struct stmmac_dma_conf dma_conf; - - /* Generic channel for NAPI */ - struct stmmac_channel channel[STMMAC_CH_MAX]; ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c -@@ -484,8 +484,8 @@ static void stmmac_get_ringparam(struct - - ring->rx_max_pending = DMA_MAX_RX_SIZE; - ring->tx_max_pending = DMA_MAX_TX_SIZE; -- ring->rx_pending = priv->dma_rx_size; -- ring->tx_pending = priv->dma_tx_size; -+ ring->rx_pending = priv->dma_conf.dma_rx_size; -+ ring->tx_pending = priv->dma_conf.dma_tx_size; - } - - static int stmmac_set_ringparam(struct net_device *netdev, ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -74,8 +74,8 @@ static int phyaddr = -1; - module_param(phyaddr, int, 0444); - MODULE_PARM_DESC(phyaddr, "Physical device address"); - --#define STMMAC_TX_THRESH(x) ((x)->dma_tx_size / 4) --#define STMMAC_RX_THRESH(x) ((x)->dma_rx_size / 4) -+#define STMMAC_TX_THRESH(x) ((x)->dma_conf.dma_tx_size / 4) -+#define STMMAC_RX_THRESH(x) ((x)->dma_conf.dma_rx_size / 4) - - /* Limit to make sure XDP TX and slow path can coexist */ - #define STMMAC_XSK_TX_BUDGET_MAX 256 -@@ -232,7 +232,7 @@ static void stmmac_disable_all_queues(st - - /* synchronize_rcu() needed for pending XDP buffers to drain */ - for (queue = 0; queue < rx_queues_cnt; queue++) { -- rx_q = &priv->rx_queue[queue]; -+ rx_q = &priv->dma_conf.rx_queue[queue]; - if (rx_q->xsk_pool) { - synchronize_rcu(); - break; -@@ -358,13 +358,13 @@ static void print_pkt(unsigned char *buf - - static inline u32 stmmac_tx_avail(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - u32 avail; - - if (tx_q->dirty_tx > tx_q->cur_tx) - avail = tx_q->dirty_tx - tx_q->cur_tx - 1; - else -- avail = priv->dma_tx_size - tx_q->cur_tx + tx_q->dirty_tx - 1; -+ avail = priv->dma_conf.dma_tx_size - tx_q->cur_tx + tx_q->dirty_tx - 1; - - return avail; - } -@@ -376,13 +376,13 @@ static inline u32 stmmac_tx_avail(struct - */ - static inline u32 stmmac_rx_dirty(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - u32 dirty; - - if (rx_q->dirty_rx <= rx_q->cur_rx) - dirty = rx_q->cur_rx - rx_q->dirty_rx; - else -- dirty = priv->dma_rx_size - rx_q->dirty_rx + rx_q->cur_rx; -+ dirty = priv->dma_conf.dma_rx_size - rx_q->dirty_rx + rx_q->cur_rx; - - return dirty; - } -@@ -410,7 +410,7 @@ static int stmmac_enable_eee_mode(struct - - /* check if all TX queues have the work finished */ - for (queue = 0; queue < tx_cnt; queue++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - if (tx_q->dirty_tx != tx_q->cur_tx) - return -EBUSY; /* still unfinished work */ -@@ -1309,7 +1309,7 @@ static void stmmac_display_rx_rings(stru - - /* Display RX rings */ - for (queue = 0; queue < rx_cnt; queue++) { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - - pr_info("\tRX Queue %u rings\n", queue); - -@@ -1322,7 +1322,7 @@ static void stmmac_display_rx_rings(stru - } - - /* Display RX ring */ -- stmmac_display_ring(priv, head_rx, priv->dma_rx_size, true, -+ stmmac_display_ring(priv, head_rx, priv->dma_conf.dma_rx_size, true, - rx_q->dma_rx_phy, desc_size); - } - } -@@ -1336,7 +1336,7 @@ static void stmmac_display_tx_rings(stru - - /* Display TX rings */ - for (queue = 0; queue < tx_cnt; queue++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - pr_info("\tTX Queue %d rings\n", queue); - -@@ -1351,7 +1351,7 @@ static void stmmac_display_tx_rings(stru - desc_size = sizeof(struct dma_desc); - } - -- stmmac_display_ring(priv, head_tx, priv->dma_tx_size, false, -+ stmmac_display_ring(priv, head_tx, priv->dma_conf.dma_tx_size, false, - tx_q->dma_tx_phy, desc_size); - } - } -@@ -1392,21 +1392,21 @@ static int stmmac_set_bfsize(int mtu, in - */ - static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int i; - - /* Clear the RX descriptors */ -- for (i = 0; i < priv->dma_rx_size; i++) -+ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) - if (priv->extend_desc) - stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic, - priv->use_riwt, priv->mode, -- (i == priv->dma_rx_size - 1), -- priv->dma_buf_sz); -+ (i == priv->dma_conf.dma_rx_size - 1), -+ priv->dma_conf.dma_buf_sz); - else - stmmac_init_rx_desc(priv, &rx_q->dma_rx[i], - priv->use_riwt, priv->mode, -- (i == priv->dma_rx_size - 1), -- priv->dma_buf_sz); -+ (i == priv->dma_conf.dma_rx_size - 1), -+ priv->dma_conf.dma_buf_sz); - } - - /** -@@ -1418,12 +1418,12 @@ static void stmmac_clear_rx_descriptors( - */ - static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - int i; - - /* Clear the TX descriptors */ -- for (i = 0; i < priv->dma_tx_size; i++) { -- int last = (i == (priv->dma_tx_size - 1)); -+ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { -+ int last = (i == (priv->dma_conf.dma_tx_size - 1)); - struct dma_desc *p; - - if (priv->extend_desc) -@@ -1471,7 +1471,7 @@ static void stmmac_clear_descriptors(str - static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, - int i, gfp_t flags, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (!buf->page) { -@@ -1496,7 +1496,7 @@ static int stmmac_init_rx_buffers(struct - buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; - - stmmac_set_desc_addr(priv, p, buf->addr); -- if (priv->dma_buf_sz == BUF_SIZE_16KiB) -+ if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) - stmmac_init_desc3(priv, p); - - return 0; -@@ -1510,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct - */ - static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (buf->page) -@@ -1530,7 +1530,7 @@ static void stmmac_free_rx_buffer(struct - */ - static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - if (tx_q->tx_skbuff_dma[i].buf && - tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { -@@ -1575,17 +1575,17 @@ static void dma_free_rx_skbufs(struct st - { - int i; - -- for (i = 0; i < priv->dma_rx_size; i++) -+ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) - stmmac_free_rx_buffer(priv, queue, i); - } - - static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, u32 queue, - gfp_t flags) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_rx_size; i++) { -+ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { - struct dma_desc *p; - int ret; - -@@ -1612,10 +1612,10 @@ static int stmmac_alloc_rx_buffers(struc - */ - static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_rx_size; i++) { -+ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (!buf->xdp) -@@ -1628,10 +1628,10 @@ static void dma_free_rx_xskbufs(struct s - - static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_rx_size; i++) { -+ for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { - struct stmmac_rx_buffer *buf; - dma_addr_t dma_addr; - struct dma_desc *p; -@@ -1674,7 +1674,7 @@ static struct xsk_buff_pool *stmmac_get_ - */ - static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int ret; - - netif_dbg(priv, probe, priv->dev, -@@ -1720,11 +1720,11 @@ static int __init_dma_rx_desc_rings(stru - if (priv->extend_desc) - stmmac_mode_init(priv, rx_q->dma_erx, - rx_q->dma_rx_phy, -- priv->dma_rx_size, 1); -+ priv->dma_conf.dma_rx_size, 1); - else - stmmac_mode_init(priv, rx_q->dma_rx, - rx_q->dma_rx_phy, -- priv->dma_rx_size, 0); -+ priv->dma_conf.dma_rx_size, 0); - } - - return 0; -@@ -1751,7 +1751,7 @@ static int init_dma_rx_desc_rings(struct - - err_init_rx_buffers: - while (queue >= 0) { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - - if (rx_q->xsk_pool) - dma_free_rx_xskbufs(priv, queue); -@@ -1780,7 +1780,7 @@ err_init_rx_buffers: - */ - static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - int i; - - netif_dbg(priv, probe, priv->dev, -@@ -1792,16 +1792,16 @@ static int __init_dma_tx_desc_rings(stru - if (priv->extend_desc) - stmmac_mode_init(priv, tx_q->dma_etx, - tx_q->dma_tx_phy, -- priv->dma_tx_size, 1); -+ priv->dma_conf.dma_tx_size, 1); - else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) - stmmac_mode_init(priv, tx_q->dma_tx, - tx_q->dma_tx_phy, -- priv->dma_tx_size, 0); -+ priv->dma_conf.dma_tx_size, 0); - } - - tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue); - -- for (i = 0; i < priv->dma_tx_size; i++) { -+ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { - struct dma_desc *p; - - if (priv->extend_desc) -@@ -1871,12 +1871,12 @@ static int init_dma_desc_rings(struct ne - */ - static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - int i; - - tx_q->xsk_frames_done = 0; - -- for (i = 0; i < priv->dma_tx_size; i++) -+ for (i = 0; i < priv->dma_conf.dma_tx_size; i++) - stmmac_free_tx_buffer(priv, queue, i); - - if (tx_q->xsk_pool && tx_q->xsk_frames_done) { -@@ -1906,7 +1906,7 @@ static void stmmac_free_tx_skbufs(struct - */ - static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - - /* Release the DMA RX socket buffers */ - if (rx_q->xsk_pool) -@@ -1919,11 +1919,11 @@ static void __free_dma_rx_desc_resources - - /* Free DMA regions of consistent memory previously allocated */ - if (!priv->extend_desc) -- dma_free_coherent(priv->device, priv->dma_rx_size * -+ dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * - sizeof(struct dma_desc), - rx_q->dma_rx, rx_q->dma_rx_phy); - else -- dma_free_coherent(priv->device, priv->dma_rx_size * -+ dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * - sizeof(struct dma_extended_desc), - rx_q->dma_erx, rx_q->dma_rx_phy); - -@@ -1952,7 +1952,7 @@ static void free_dma_rx_desc_resources(s - */ - static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - size_t size; - void *addr; - -@@ -1970,7 +1970,7 @@ static void __free_dma_tx_desc_resources - addr = tx_q->dma_tx; - } - -- size *= priv->dma_tx_size; -+ size *= priv->dma_conf.dma_tx_size; - - dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); - -@@ -1999,7 +1999,7 @@ static void free_dma_tx_desc_resources(s - */ - static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_channel *ch = &priv->channel[queue]; - bool xdp_prog = stmmac_xdp_is_enabled(priv); - struct page_pool_params pp_params = { 0 }; -@@ -2011,8 +2011,8 @@ static int __alloc_dma_rx_desc_resources - rx_q->priv_data = priv; - - pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; -- pp_params.pool_size = priv->dma_rx_size; -- num_pages = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE); -+ pp_params.pool_size = priv->dma_conf.dma_rx_size; -+ num_pages = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE); - pp_params.order = ilog2(num_pages); - pp_params.nid = dev_to_node(priv->device); - pp_params.dev = priv->device; -@@ -2027,7 +2027,7 @@ static int __alloc_dma_rx_desc_resources - return ret; - } - -- rx_q->buf_pool = kcalloc(priv->dma_rx_size, -+ rx_q->buf_pool = kcalloc(priv->dma_conf.dma_rx_size, - sizeof(*rx_q->buf_pool), - GFP_KERNEL); - if (!rx_q->buf_pool) -@@ -2035,7 +2035,7 @@ static int __alloc_dma_rx_desc_resources - - if (priv->extend_desc) { - rx_q->dma_erx = dma_alloc_coherent(priv->device, -- priv->dma_rx_size * -+ priv->dma_conf.dma_rx_size * - sizeof(struct dma_extended_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); -@@ -2044,7 +2044,7 @@ static int __alloc_dma_rx_desc_resources - - } else { - rx_q->dma_rx = dma_alloc_coherent(priv->device, -- priv->dma_rx_size * -+ priv->dma_conf.dma_rx_size * - sizeof(struct dma_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); -@@ -2101,20 +2101,20 @@ err_dma: - */ - static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - size_t size; - void *addr; - - tx_q->queue_index = queue; - tx_q->priv_data = priv; - -- tx_q->tx_skbuff_dma = kcalloc(priv->dma_tx_size, -+ tx_q->tx_skbuff_dma = kcalloc(priv->dma_conf.dma_tx_size, - sizeof(*tx_q->tx_skbuff_dma), - GFP_KERNEL); - if (!tx_q->tx_skbuff_dma) - return -ENOMEM; - -- tx_q->tx_skbuff = kcalloc(priv->dma_tx_size, -+ tx_q->tx_skbuff = kcalloc(priv->dma_conf.dma_tx_size, - sizeof(struct sk_buff *), - GFP_KERNEL); - if (!tx_q->tx_skbuff) -@@ -2127,7 +2127,7 @@ static int __alloc_dma_tx_desc_resources - else - size = sizeof(struct dma_desc); - -- size *= priv->dma_tx_size; -+ size *= priv->dma_conf.dma_tx_size; - - addr = dma_alloc_coherent(priv->device, size, - &tx_q->dma_tx_phy, GFP_KERNEL); -@@ -2371,7 +2371,7 @@ static void stmmac_dma_operation_mode(st - - /* configure all channels */ - for (chan = 0; chan < rx_channels_count; chan++) { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; - u32 buf_size; - - qmode = priv->plat->rx_queues_cfg[chan].mode_to_use; -@@ -2386,7 +2386,7 @@ static void stmmac_dma_operation_mode(st - chan); - } else { - stmmac_set_dma_bfsize(priv, priv->ioaddr, -- priv->dma_buf_sz, -+ priv->dma_conf.dma_buf_sz, - chan); - } - } -@@ -2402,7 +2402,7 @@ static void stmmac_dma_operation_mode(st - static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) - { - struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - struct xsk_buff_pool *pool = tx_q->xsk_pool; - unsigned int entry = tx_q->cur_tx; - struct dma_desc *tx_desc = NULL; -@@ -2477,7 +2477,7 @@ static bool stmmac_xdp_xmit_zc(struct st - - stmmac_enable_dma_transmission(priv, priv->ioaddr); - -- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); -+ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); - entry = tx_q->cur_tx; - } - -@@ -2503,7 +2503,7 @@ static bool stmmac_xdp_xmit_zc(struct st - */ - static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - unsigned int bytes_compl = 0, pkts_compl = 0; - unsigned int entry, xmits = 0, count = 0; - -@@ -2516,7 +2516,7 @@ static int stmmac_tx_clean(struct stmmac - entry = tx_q->dirty_tx; - - /* Try to clean all TX complete frame in 1 shot */ -- while ((entry != tx_q->cur_tx) && count < priv->dma_tx_size) { -+ while ((entry != tx_q->cur_tx) && count < priv->dma_conf.dma_tx_size) { - struct xdp_frame *xdpf; - struct sk_buff *skb; - struct dma_desc *p; -@@ -2616,7 +2616,7 @@ static int stmmac_tx_clean(struct stmmac - - stmmac_release_tx_desc(priv, p, priv->mode); - -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - } - tx_q->dirty_tx = entry; - -@@ -2681,7 +2681,7 @@ static int stmmac_tx_clean(struct stmmac - */ - static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - - netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); - -@@ -2748,8 +2748,8 @@ static int stmmac_napi_check(struct stmm - { - int status = stmmac_dma_interrupt_status(priv, priv->ioaddr, - &priv->xstats, chan, dir); -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[chan]; -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - struct stmmac_channel *ch = &priv->channel[chan]; - struct napi_struct *rx_napi; - struct napi_struct *tx_napi; -@@ -2925,7 +2925,7 @@ static int stmmac_init_dma_engine(struct - - /* DMA RX Channel Configuration */ - for (chan = 0; chan < rx_channels_count; chan++) { -- rx_q = &priv->rx_queue[chan]; -+ rx_q = &priv->dma_conf.rx_queue[chan]; - - stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - rx_q->dma_rx_phy, chan); -@@ -2939,7 +2939,7 @@ static int stmmac_init_dma_engine(struct - - /* DMA TX Channel Configuration */ - for (chan = 0; chan < tx_channels_count; chan++) { -- tx_q = &priv->tx_queue[chan]; -+ tx_q = &priv->dma_conf.tx_queue[chan]; - - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - tx_q->dma_tx_phy, chan); -@@ -2954,7 +2954,7 @@ static int stmmac_init_dma_engine(struct - - static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - hrtimer_start(&tx_q->txtimer, - STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), -@@ -3004,7 +3004,7 @@ static void stmmac_init_coalesce(struct - u32 chan; - - for (chan = 0; chan < tx_channel_count; chan++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - - priv->tx_coal_frames[chan] = STMMAC_TX_FRAMES; - priv->tx_coal_timer[chan] = STMMAC_COAL_TX_TIMER; -@@ -3026,12 +3026,12 @@ static void stmmac_set_rings_length(stru - /* set TX ring length */ - for (chan = 0; chan < tx_channels_count; chan++) - stmmac_set_tx_ring_len(priv, priv->ioaddr, -- (priv->dma_tx_size - 1), chan); -+ (priv->dma_conf.dma_tx_size - 1), chan); - - /* set RX ring length */ - for (chan = 0; chan < rx_channels_count; chan++) - stmmac_set_rx_ring_len(priv, priv->ioaddr, -- (priv->dma_rx_size - 1), chan); -+ (priv->dma_conf.dma_rx_size - 1), chan); - } - - /** -@@ -3366,7 +3366,7 @@ static int stmmac_hw_setup(struct net_de - /* Enable TSO */ - if (priv->tso) { - for (chan = 0; chan < tx_cnt; chan++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - - /* TSO and TBS cannot co-exist */ - if (tx_q->tbs & STMMAC_TBS_AVAIL) -@@ -3388,7 +3388,7 @@ static int stmmac_hw_setup(struct net_de - - /* TBS */ - for (chan = 0; chan < tx_cnt; chan++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - int enable = tx_q->tbs & STMMAC_TBS_AVAIL; - - stmmac_enable_tbs(priv, priv->ioaddr, enable, chan); -@@ -3432,7 +3432,7 @@ static void stmmac_free_irq(struct net_d - for (j = irq_idx - 1; j >= 0; j--) { - if (priv->tx_irq[j] > 0) { - irq_set_affinity_hint(priv->tx_irq[j], NULL); -- free_irq(priv->tx_irq[j], &priv->tx_queue[j]); -+ free_irq(priv->tx_irq[j], &priv->dma_conf.tx_queue[j]); - } - } - irq_idx = priv->plat->rx_queues_to_use; -@@ -3441,7 +3441,7 @@ static void stmmac_free_irq(struct net_d - for (j = irq_idx - 1; j >= 0; j--) { - if (priv->rx_irq[j] > 0) { - irq_set_affinity_hint(priv->rx_irq[j], NULL); -- free_irq(priv->rx_irq[j], &priv->rx_queue[j]); -+ free_irq(priv->rx_irq[j], &priv->dma_conf.rx_queue[j]); - } - } - -@@ -3574,7 +3574,7 @@ static int stmmac_request_irq_multi_msi( - sprintf(int_name, "%s:%s-%d", dev->name, "rx", i); - ret = request_irq(priv->rx_irq[i], - stmmac_msi_intr_rx, -- 0, int_name, &priv->rx_queue[i]); -+ 0, int_name, &priv->dma_conf.rx_queue[i]); - if (unlikely(ret < 0)) { - netdev_err(priv->dev, - "%s: alloc rx-%d MSI %d (error: %d)\n", -@@ -3597,7 +3597,7 @@ static int stmmac_request_irq_multi_msi( - sprintf(int_name, "%s:%s-%d", dev->name, "tx", i); - ret = request_irq(priv->tx_irq[i], - stmmac_msi_intr_tx, -- 0, int_name, &priv->tx_queue[i]); -+ 0, int_name, &priv->dma_conf.tx_queue[i]); - if (unlikely(ret < 0)) { - netdev_err(priv->dev, - "%s: alloc tx-%d MSI %d (error: %d)\n", -@@ -3728,21 +3728,21 @@ static int stmmac_open(struct net_device - bfsize = 0; - - if (bfsize < BUF_SIZE_16KiB) -- bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz); -+ bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_conf.dma_buf_sz); - -- priv->dma_buf_sz = bfsize; -+ priv->dma_conf.dma_buf_sz = bfsize; - buf_sz = bfsize; - - priv->rx_copybreak = STMMAC_RX_COPYBREAK; - -- if (!priv->dma_tx_size) -- priv->dma_tx_size = DMA_DEFAULT_TX_SIZE; -- if (!priv->dma_rx_size) -- priv->dma_rx_size = DMA_DEFAULT_RX_SIZE; -+ if (!priv->dma_conf.dma_tx_size) -+ priv->dma_conf.dma_tx_size = DMA_DEFAULT_TX_SIZE; -+ if (!priv->dma_conf.dma_rx_size) -+ priv->dma_conf.dma_rx_size = DMA_DEFAULT_RX_SIZE; - - /* Earlier check for TBS */ - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[chan]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; - int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; - - /* Setup per-TXQ tbs flag before TX descriptor alloc */ -@@ -3800,7 +3800,7 @@ irq_error: - phylink_stop(priv->phylink); - - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) -- hrtimer_cancel(&priv->tx_queue[chan].txtimer); -+ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - - stmmac_hw_teardown(dev); - init_error: -@@ -3842,7 +3842,7 @@ static int stmmac_release(struct net_dev - stmmac_disable_all_queues(priv); - - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) -- hrtimer_cancel(&priv->tx_queue[chan].txtimer); -+ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - - netif_tx_disable(dev); - -@@ -3906,7 +3906,7 @@ static bool stmmac_vlan_insert(struct st - return false; - - stmmac_set_tx_owner(priv, p); -- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); -+ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); - return true; - } - -@@ -3924,7 +3924,7 @@ static bool stmmac_vlan_insert(struct st - static void stmmac_tso_allocator(struct stmmac_priv *priv, dma_addr_t des, - int total_len, bool last_segment, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - struct dma_desc *desc; - u32 buff_size; - int tmp_len; -@@ -3935,7 +3935,7 @@ static void stmmac_tso_allocator(struct - dma_addr_t curr_addr; - - tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, -- priv->dma_tx_size); -+ priv->dma_conf.dma_tx_size); - WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); - - if (tx_q->tbs & STMMAC_TBS_AVAIL) -@@ -3963,7 +3963,7 @@ static void stmmac_tso_allocator(struct - - static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - int desc_size; - - if (likely(priv->extend_desc)) -@@ -4025,7 +4025,7 @@ static netdev_tx_t stmmac_tso_xmit(struc - dma_addr_t des; - int i; - -- tx_q = &priv->tx_queue[queue]; -+ tx_q = &priv->dma_conf.tx_queue[queue]; - first_tx = tx_q->cur_tx; - - /* Compute header lengths */ -@@ -4065,7 +4065,7 @@ static netdev_tx_t stmmac_tso_xmit(struc - stmmac_set_mss(priv, mss_desc, mss); - tx_q->mss = mss; - tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, -- priv->dma_tx_size); -+ priv->dma_conf.dma_tx_size); - WARN_ON(tx_q->tx_skbuff[tx_q->cur_tx]); - } - -@@ -4177,7 +4177,7 @@ static netdev_tx_t stmmac_tso_xmit(struc - * ndo_start_xmit will fill this descriptor the next time it's - * called and stmmac_tx_clean may clean up to this descriptor. - */ -- tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_tx_size); -+ tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); - - if (unlikely(stmmac_tx_avail(priv, queue) <= (MAX_SKB_FRAGS + 1))) { - netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n", -@@ -4265,7 +4265,7 @@ static netdev_tx_t stmmac_xmit(struct sk - int entry, first_tx; - dma_addr_t des; - -- tx_q = &priv->tx_queue[queue]; -+ tx_q = &priv->dma_conf.tx_queue[queue]; - first_tx = tx_q->cur_tx; - - if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) -@@ -4328,7 +4328,7 @@ static netdev_tx_t stmmac_xmit(struct sk - int len = skb_frag_size(frag); - bool last_segment = (i == (nfrags - 1)); - -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - WARN_ON(tx_q->tx_skbuff[entry]); - - if (likely(priv->extend_desc)) -@@ -4399,7 +4399,7 @@ static netdev_tx_t stmmac_xmit(struct sk - * ndo_start_xmit will fill this descriptor the next time it's - * called and stmmac_tx_clean may clean up to this descriptor. - */ -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - tx_q->cur_tx = entry; - - if (netif_msg_pktdata(priv)) { -@@ -4514,7 +4514,7 @@ static void stmmac_rx_vlan(struct net_de - */ - static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - int dirty = stmmac_rx_dirty(priv, queue); - unsigned int entry = rx_q->dirty_rx; - -@@ -4564,7 +4564,7 @@ static inline void stmmac_rx_refill(stru - dma_wmb(); - stmmac_set_rx_owner(priv, p, use_rx_wd); - -- entry = STMMAC_GET_ENTRY(entry, priv->dma_rx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); - } - rx_q->dirty_rx = entry; - rx_q->rx_tail_addr = rx_q->dma_rx_phy + -@@ -4592,12 +4592,12 @@ static unsigned int stmmac_rx_buf1_len(s - - /* First descriptor, not last descriptor and not split header */ - if (status & rx_not_ls) -- return priv->dma_buf_sz; -+ return priv->dma_conf.dma_buf_sz; - - plen = stmmac_get_rx_frame_len(priv, p, coe); - - /* First descriptor and last descriptor and not split header */ -- return min_t(unsigned int, priv->dma_buf_sz, plen); -+ return min_t(unsigned int, priv->dma_conf.dma_buf_sz, plen); - } - - static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, -@@ -4613,7 +4613,7 @@ static unsigned int stmmac_rx_buf2_len(s - - /* Not last descriptor */ - if (status & rx_not_ls) -- return priv->dma_buf_sz; -+ return priv->dma_conf.dma_buf_sz; - - plen = stmmac_get_rx_frame_len(priv, p, coe); - -@@ -4624,7 +4624,7 @@ static unsigned int stmmac_rx_buf2_len(s - static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, - struct xdp_frame *xdpf, bool dma_map) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - unsigned int entry = tx_q->cur_tx; - struct dma_desc *tx_desc; - dma_addr_t dma_addr; -@@ -4687,7 +4687,7 @@ static int stmmac_xdp_xmit_xdpf(struct s - - stmmac_enable_dma_transmission(priv, priv->ioaddr); - -- entry = STMMAC_GET_ENTRY(entry, priv->dma_tx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_tx_size); - tx_q->cur_tx = entry; - - return STMMAC_XDP_TX; -@@ -4861,7 +4861,7 @@ static void stmmac_dispatch_skb_zc(struc - - static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - unsigned int entry = rx_q->dirty_rx; - struct dma_desc *rx_desc = NULL; - bool ret = true; -@@ -4904,7 +4904,7 @@ static bool stmmac_rx_refill_zc(struct s - dma_wmb(); - stmmac_set_rx_owner(priv, rx_desc, use_rx_wd); - -- entry = STMMAC_GET_ENTRY(entry, priv->dma_rx_size); -+ entry = STMMAC_GET_ENTRY(entry, priv->dma_conf.dma_rx_size); - } - - if (rx_desc) { -@@ -4919,7 +4919,7 @@ static bool stmmac_rx_refill_zc(struct s - - static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - unsigned int count = 0, error = 0, len = 0; - int dirty = stmmac_rx_dirty(priv, queue); - unsigned int next_entry = rx_q->cur_rx; -@@ -4941,7 +4941,7 @@ static int stmmac_rx_zc(struct stmmac_pr - desc_size = sizeof(struct dma_desc); - } - -- stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true, -+ stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true, - rx_q->dma_rx_phy, desc_size); - } - while (count < limit) { -@@ -4988,7 +4988,7 @@ read_again: - - /* Prefetch the next RX descriptor */ - rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, -- priv->dma_rx_size); -+ priv->dma_conf.dma_rx_size); - next_entry = rx_q->cur_rx; - - if (priv->extend_desc) -@@ -5109,7 +5109,7 @@ read_again: - */ - static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_channel *ch = &priv->channel[queue]; - unsigned int count = 0, error = 0, len = 0; - int status = 0, coe = priv->hw->rx_csum; -@@ -5122,7 +5122,7 @@ static int stmmac_rx(struct stmmac_priv - int buf_sz; - - dma_dir = page_pool_get_dma_dir(rx_q->page_pool); -- buf_sz = DIV_ROUND_UP(priv->dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; -+ buf_sz = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE) * PAGE_SIZE; - - if (netif_msg_rx_status(priv)) { - void *rx_head; -@@ -5136,7 +5136,7 @@ static int stmmac_rx(struct stmmac_priv - desc_size = sizeof(struct dma_desc); - } - -- stmmac_display_ring(priv, rx_head, priv->dma_rx_size, true, -+ stmmac_display_ring(priv, rx_head, priv->dma_conf.dma_rx_size, true, - rx_q->dma_rx_phy, desc_size); - } - while (count < limit) { -@@ -5180,7 +5180,7 @@ read_again: - break; - - rx_q->cur_rx = STMMAC_GET_ENTRY(rx_q->cur_rx, -- priv->dma_rx_size); -+ priv->dma_conf.dma_rx_size); - next_entry = rx_q->cur_rx; - - if (priv->extend_desc) -@@ -5314,7 +5314,7 @@ read_again: - buf1_len, dma_dir); - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - buf->page, buf->page_offset, buf1_len, -- priv->dma_buf_sz); -+ priv->dma_conf.dma_buf_sz); - - /* Data payload appended into SKB */ - page_pool_release_page(rx_q->page_pool, buf->page); -@@ -5326,7 +5326,7 @@ read_again: - buf2_len, dma_dir); - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, - buf->sec_page, 0, buf2_len, -- priv->dma_buf_sz); -+ priv->dma_conf.dma_buf_sz); - - /* Data payload appended into SKB */ - page_pool_release_page(rx_q->page_pool, buf->sec_page); -@@ -5768,11 +5768,13 @@ static irqreturn_t stmmac_safety_interru - static irqreturn_t stmmac_msi_intr_tx(int irq, void *data) - { - struct stmmac_tx_queue *tx_q = (struct stmmac_tx_queue *)data; -+ struct stmmac_dma_conf *dma_conf; - int chan = tx_q->queue_index; - struct stmmac_priv *priv; - int status; - -- priv = container_of(tx_q, struct stmmac_priv, tx_queue[chan]); -+ dma_conf = container_of(tx_q, struct stmmac_dma_conf, tx_queue[chan]); -+ priv = container_of(dma_conf, struct stmmac_priv, dma_conf); - - if (unlikely(!data)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); -@@ -5812,10 +5814,12 @@ static irqreturn_t stmmac_msi_intr_tx(in - static irqreturn_t stmmac_msi_intr_rx(int irq, void *data) - { - struct stmmac_rx_queue *rx_q = (struct stmmac_rx_queue *)data; -+ struct stmmac_dma_conf *dma_conf; - int chan = rx_q->queue_index; - struct stmmac_priv *priv; - -- priv = container_of(rx_q, struct stmmac_priv, rx_queue[chan]); -+ dma_conf = container_of(rx_q, struct stmmac_dma_conf, rx_queue[chan]); -+ priv = container_of(dma_conf, struct stmmac_priv, dma_conf); - - if (unlikely(!data)) { - netdev_err(priv->dev, "%s: invalid dev pointer\n", __func__); -@@ -5846,10 +5850,10 @@ static void stmmac_poll_controller(struc - - if (priv->plat->multi_msi_en) { - for (i = 0; i < priv->plat->rx_queues_to_use; i++) -- stmmac_msi_intr_rx(0, &priv->rx_queue[i]); -+ stmmac_msi_intr_rx(0, &priv->dma_conf.rx_queue[i]); - - for (i = 0; i < priv->plat->tx_queues_to_use; i++) -- stmmac_msi_intr_tx(0, &priv->tx_queue[i]); -+ stmmac_msi_intr_tx(0, &priv->dma_conf.tx_queue[i]); - } else { - disable_irq(dev->irq); - stmmac_interrupt(dev->irq, dev); -@@ -6030,34 +6034,34 @@ static int stmmac_rings_status_show(stru - return 0; - - for (queue = 0; queue < rx_count; queue++) { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - - seq_printf(seq, "RX Queue %d:\n", queue); - - if (priv->extend_desc) { - seq_printf(seq, "Extended descriptor ring:\n"); - sysfs_display_ring((void *)rx_q->dma_erx, -- priv->dma_rx_size, 1, seq, rx_q->dma_rx_phy); -+ priv->dma_conf.dma_rx_size, 1, seq, rx_q->dma_rx_phy); - } else { - seq_printf(seq, "Descriptor ring:\n"); - sysfs_display_ring((void *)rx_q->dma_rx, -- priv->dma_rx_size, 0, seq, rx_q->dma_rx_phy); -+ priv->dma_conf.dma_rx_size, 0, seq, rx_q->dma_rx_phy); - } - } - - for (queue = 0; queue < tx_count; queue++) { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - seq_printf(seq, "TX Queue %d:\n", queue); - - if (priv->extend_desc) { - seq_printf(seq, "Extended descriptor ring:\n"); - sysfs_display_ring((void *)tx_q->dma_etx, -- priv->dma_tx_size, 1, seq, tx_q->dma_tx_phy); -+ priv->dma_conf.dma_tx_size, 1, seq, tx_q->dma_tx_phy); - } else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) { - seq_printf(seq, "Descriptor ring:\n"); - sysfs_display_ring((void *)tx_q->dma_tx, -- priv->dma_tx_size, 0, seq, tx_q->dma_tx_phy); -+ priv->dma_conf.dma_tx_size, 0, seq, tx_q->dma_tx_phy); - } - } - -@@ -6404,7 +6408,7 @@ void stmmac_disable_rx_queue(struct stmm - - void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_channel *ch = &priv->channel[queue]; - unsigned long flags; - u32 buf_size; -@@ -6441,7 +6445,7 @@ void stmmac_enable_rx_queue(struct stmma - rx_q->queue_index); - } else { - stmmac_set_dma_bfsize(priv, priv->ioaddr, -- priv->dma_buf_sz, -+ priv->dma_conf.dma_buf_sz, - rx_q->queue_index); - } - -@@ -6467,7 +6471,7 @@ void stmmac_disable_tx_queue(struct stmm - - void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - struct stmmac_channel *ch = &priv->channel[queue]; - unsigned long flags; - int ret; -@@ -6517,7 +6521,7 @@ void stmmac_xdp_release(struct net_devic - stmmac_disable_all_queues(priv); - - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) -- hrtimer_cancel(&priv->tx_queue[chan].txtimer); -+ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - - /* Free the IRQ lines */ - stmmac_free_irq(dev, REQ_IRQ_ERR_ALL, 0); -@@ -6576,7 +6580,7 @@ int stmmac_xdp_open(struct net_device *d - - /* DMA RX Channel Configuration */ - for (chan = 0; chan < rx_cnt; chan++) { -- rx_q = &priv->rx_queue[chan]; -+ rx_q = &priv->dma_conf.rx_queue[chan]; - - stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - rx_q->dma_rx_phy, chan); -@@ -6594,7 +6598,7 @@ int stmmac_xdp_open(struct net_device *d - rx_q->queue_index); - } else { - stmmac_set_dma_bfsize(priv, priv->ioaddr, -- priv->dma_buf_sz, -+ priv->dma_conf.dma_buf_sz, - rx_q->queue_index); - } - -@@ -6603,7 +6607,7 @@ int stmmac_xdp_open(struct net_device *d - - /* DMA TX Channel Configuration */ - for (chan = 0; chan < tx_cnt; chan++) { -- tx_q = &priv->tx_queue[chan]; -+ tx_q = &priv->dma_conf.tx_queue[chan]; - - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - tx_q->dma_tx_phy, chan); -@@ -6636,7 +6640,7 @@ int stmmac_xdp_open(struct net_device *d - - irq_error: - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) -- hrtimer_cancel(&priv->tx_queue[chan].txtimer); -+ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - - stmmac_hw_teardown(dev); - init_error: -@@ -6663,8 +6667,8 @@ int stmmac_xsk_wakeup(struct net_device - queue >= priv->plat->tx_queues_to_use) - return -EINVAL; - -- rx_q = &priv->rx_queue[queue]; -- tx_q = &priv->tx_queue[queue]; -+ rx_q = &priv->dma_conf.rx_queue[queue]; -+ tx_q = &priv->dma_conf.tx_queue[queue]; - ch = &priv->channel[queue]; - - if (!rx_q->xsk_pool && !tx_q->xsk_pool) -@@ -6924,8 +6928,8 @@ int stmmac_reinit_ringparam(struct net_d - if (netif_running(dev)) - stmmac_release(dev); - -- priv->dma_rx_size = rx_size; -- priv->dma_tx_size = tx_size; -+ priv->dma_conf.dma_rx_size = rx_size; -+ priv->dma_conf.dma_tx_size = tx_size; - - if (netif_running(dev)) - ret = stmmac_open(dev); -@@ -7363,7 +7367,7 @@ int stmmac_suspend(struct device *dev) - stmmac_disable_all_queues(priv); - - for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) -- hrtimer_cancel(&priv->tx_queue[chan].txtimer); -+ hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - - if (priv->eee_enabled) { - priv->tx_path_in_lpi_mode = false; -@@ -7414,7 +7418,7 @@ EXPORT_SYMBOL_GPL(stmmac_suspend); - - static void stmmac_reset_rx_queue(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - - rx_q->cur_rx = 0; - rx_q->dirty_rx = 0; -@@ -7422,7 +7426,7 @@ static void stmmac_reset_rx_queue(struct - - static void stmmac_reset_tx_queue(struct stmmac_priv *priv, u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; - - tx_q->cur_tx = 0; - tx_q->dirty_tx = 0; ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c -@@ -795,8 +795,8 @@ static int stmmac_test_flowctrl(struct s - struct stmmac_channel *ch = &priv->channel[i]; - u32 tail; - -- tail = priv->rx_queue[i].dma_rx_phy + -- (priv->dma_rx_size * sizeof(struct dma_desc)); -+ tail = priv->dma_conf.rx_queue[i].dma_rx_phy + -+ (priv->dma_conf.dma_rx_size * sizeof(struct dma_desc)); - - stmmac_set_rx_tail_ptr(priv, priv->ioaddr, tail, i); - stmmac_start_rx(priv, priv->ioaddr, i); -@@ -1684,7 +1684,7 @@ cleanup: - static int __stmmac_test_jumbo(struct stmmac_priv *priv, u16 queue) - { - struct stmmac_packet_attrs attr = { }; -- int size = priv->dma_buf_sz; -+ int size = priv->dma_conf.dma_buf_sz; - - attr.dst = priv->dev->dev_addr; - attr.max_size = size - ETH_FCS_LEN; -@@ -1767,7 +1767,7 @@ static int stmmac_test_tbs(struct stmmac - - /* Find first TBS enabled Queue, if any */ - for (i = 0; i < priv->plat->tx_queues_to_use; i++) -- if (priv->tx_queue[i].tbs & STMMAC_TBS_AVAIL) -+ if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_AVAIL) - break; - - if (i >= priv->plat->tx_queues_to_use) ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c -@@ -970,13 +970,13 @@ static int tc_setup_etf(struct stmmac_pr - return -EOPNOTSUPP; - if (qopt->queue >= priv->plat->tx_queues_to_use) - return -EINVAL; -- if (!(priv->tx_queue[qopt->queue].tbs & STMMAC_TBS_AVAIL)) -+ if (!(priv->dma_conf.tx_queue[qopt->queue].tbs & STMMAC_TBS_AVAIL)) - return -EINVAL; - - if (qopt->enable) -- priv->tx_queue[qopt->queue].tbs |= STMMAC_TBS_EN; -+ priv->dma_conf.tx_queue[qopt->queue].tbs |= STMMAC_TBS_EN; - else -- priv->tx_queue[qopt->queue].tbs &= ~STMMAC_TBS_EN; -+ priv->dma_conf.tx_queue[qopt->queue].tbs &= ~STMMAC_TBS_EN; - - netdev_info(priv->dev, "%s ETF for Queue %d\n", - qopt->enable ? "enabled" : "disabled", qopt->queue); diff --git a/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch b/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch deleted file mode 100644 index e84373b4718..00000000000 --- a/target/linux/generic/backport-6.1/775-v6.0-04-net-ethernet-stmicro-stmmac-generate-stmmac-dma-conf.patch +++ /dev/null @@ -1,1161 +0,0 @@ -From ba39b344e9240a4a5fd4ab8178200b85cd1809da Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 23 Jul 2022 16:29:32 +0200 -Subject: [PATCH 4/5] net: ethernet: stmicro: stmmac: generate stmmac dma conf - before open - -Rework the driver to generate the stmmac dma_conf before stmmac_open. -This permits a function to first check if it's possible to allocate a -new dma_config and then pass it directly to __stmmac_open and "open" the -interface with the new configuration. - -Signed-off-by: Christian Marangi -Signed-off-by: Jakub Kicinski ---- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 462 +++++++++++------- - 1 file changed, 289 insertions(+), 173 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -1300,7 +1300,8 @@ static int stmmac_phy_setup(struct stmma - return 0; - } - --static void stmmac_display_rx_rings(struct stmmac_priv *priv) -+static void stmmac_display_rx_rings(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 rx_cnt = priv->plat->rx_queues_to_use; - unsigned int desc_size; -@@ -1309,7 +1310,7 @@ static void stmmac_display_rx_rings(stru - - /* Display RX rings */ - for (queue = 0; queue < rx_cnt; queue++) { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - - pr_info("\tRX Queue %u rings\n", queue); - -@@ -1322,12 +1323,13 @@ static void stmmac_display_rx_rings(stru - } - - /* Display RX ring */ -- stmmac_display_ring(priv, head_rx, priv->dma_conf.dma_rx_size, true, -+ stmmac_display_ring(priv, head_rx, dma_conf->dma_rx_size, true, - rx_q->dma_rx_phy, desc_size); - } - } - --static void stmmac_display_tx_rings(struct stmmac_priv *priv) -+static void stmmac_display_tx_rings(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 tx_cnt = priv->plat->tx_queues_to_use; - unsigned int desc_size; -@@ -1336,7 +1338,7 @@ static void stmmac_display_tx_rings(stru - - /* Display TX rings */ - for (queue = 0; queue < tx_cnt; queue++) { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - - pr_info("\tTX Queue %d rings\n", queue); - -@@ -1351,18 +1353,19 @@ static void stmmac_display_tx_rings(stru - desc_size = sizeof(struct dma_desc); - } - -- stmmac_display_ring(priv, head_tx, priv->dma_conf.dma_tx_size, false, -+ stmmac_display_ring(priv, head_tx, dma_conf->dma_tx_size, false, - tx_q->dma_tx_phy, desc_size); - } - } - --static void stmmac_display_rings(struct stmmac_priv *priv) -+static void stmmac_display_rings(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - /* Display RX ring */ -- stmmac_display_rx_rings(priv); -+ stmmac_display_rx_rings(priv, dma_conf); - - /* Display TX ring */ -- stmmac_display_tx_rings(priv); -+ stmmac_display_tx_rings(priv, dma_conf); - } - - static int stmmac_set_bfsize(int mtu, int bufsize) -@@ -1386,44 +1389,50 @@ static int stmmac_set_bfsize(int mtu, in - /** - * stmmac_clear_rx_descriptors - clear RX descriptors - * @priv: driver private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - * Description: this function is called to clear the RX descriptors - * in case of both basic and extended descriptors are used. - */ --static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, u32 queue) -+static void stmmac_clear_rx_descriptors(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int i; - - /* Clear the RX descriptors */ -- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) -+ for (i = 0; i < dma_conf->dma_rx_size; i++) - if (priv->extend_desc) - stmmac_init_rx_desc(priv, &rx_q->dma_erx[i].basic, - priv->use_riwt, priv->mode, -- (i == priv->dma_conf.dma_rx_size - 1), -- priv->dma_conf.dma_buf_sz); -+ (i == dma_conf->dma_rx_size - 1), -+ dma_conf->dma_buf_sz); - else - stmmac_init_rx_desc(priv, &rx_q->dma_rx[i], - priv->use_riwt, priv->mode, -- (i == priv->dma_conf.dma_rx_size - 1), -- priv->dma_conf.dma_buf_sz); -+ (i == dma_conf->dma_rx_size - 1), -+ dma_conf->dma_buf_sz); - } - - /** - * stmmac_clear_tx_descriptors - clear tx descriptors - * @priv: driver private structure -+ * @dma_conf: structure to take the dma data - * @queue: TX queue index. - * Description: this function is called to clear the TX descriptors - * in case of both basic and extended descriptors are used. - */ --static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, u32 queue) -+static void stmmac_clear_tx_descriptors(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - int i; - - /* Clear the TX descriptors */ -- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { -- int last = (i == (priv->dma_conf.dma_tx_size - 1)); -+ for (i = 0; i < dma_conf->dma_tx_size; i++) { -+ int last = (i == (dma_conf->dma_tx_size - 1)); - struct dma_desc *p; - - if (priv->extend_desc) -@@ -1440,10 +1449,12 @@ static void stmmac_clear_tx_descriptors( - /** - * stmmac_clear_descriptors - clear descriptors - * @priv: driver private structure -+ * @dma_conf: structure to take the dma data - * Description: this function is called to clear the TX and RX descriptors - * in case of both basic and extended descriptors are used. - */ --static void stmmac_clear_descriptors(struct stmmac_priv *priv) -+static void stmmac_clear_descriptors(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 rx_queue_cnt = priv->plat->rx_queues_to_use; - u32 tx_queue_cnt = priv->plat->tx_queues_to_use; -@@ -1451,16 +1462,17 @@ static void stmmac_clear_descriptors(str - - /* Clear the RX descriptors */ - for (queue = 0; queue < rx_queue_cnt; queue++) -- stmmac_clear_rx_descriptors(priv, queue); -+ stmmac_clear_rx_descriptors(priv, dma_conf, queue); - - /* Clear the TX descriptors */ - for (queue = 0; queue < tx_queue_cnt; queue++) -- stmmac_clear_tx_descriptors(priv, queue); -+ stmmac_clear_tx_descriptors(priv, dma_conf, queue); - } - - /** - * stmmac_init_rx_buffers - init the RX descriptor buffer. - * @priv: driver private structure -+ * @dma_conf: structure to take the dma data - * @p: descriptor pointer - * @i: descriptor index - * @flags: gfp flag -@@ -1468,10 +1480,12 @@ static void stmmac_clear_descriptors(str - * Description: this function is called to allocate a receive buffer, perform - * the DMA mapping and init the descriptor. - */ --static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, -+static int stmmac_init_rx_buffers(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ struct dma_desc *p, - int i, gfp_t flags, u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (!buf->page) { -@@ -1496,7 +1510,7 @@ static int stmmac_init_rx_buffers(struct - buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; - - stmmac_set_desc_addr(priv, p, buf->addr); -- if (priv->dma_conf.dma_buf_sz == BUF_SIZE_16KiB) -+ if (dma_conf->dma_buf_sz == BUF_SIZE_16KiB) - stmmac_init_desc3(priv, p); - - return 0; -@@ -1505,12 +1519,13 @@ static int stmmac_init_rx_buffers(struct - /** - * stmmac_free_rx_buffer - free RX dma buffers - * @priv: private structure -- * @queue: RX queue index -+ * @rx_q: RX queue - * @i: buffer index. - */ --static void stmmac_free_rx_buffer(struct stmmac_priv *priv, u32 queue, int i) -+static void stmmac_free_rx_buffer(struct stmmac_priv *priv, -+ struct stmmac_rx_queue *rx_q, -+ int i) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (buf->page) -@@ -1525,12 +1540,15 @@ static void stmmac_free_rx_buffer(struct - /** - * stmmac_free_tx_buffer - free RX dma buffers - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - * @i: buffer index. - */ --static void stmmac_free_tx_buffer(struct stmmac_priv *priv, u32 queue, int i) -+static void stmmac_free_tx_buffer(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue, int i) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - - if (tx_q->tx_skbuff_dma[i].buf && - tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) { -@@ -1569,23 +1587,28 @@ static void stmmac_free_tx_buffer(struct - /** - * dma_free_rx_skbufs - free RX dma buffers - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - */ --static void dma_free_rx_skbufs(struct stmmac_priv *priv, u32 queue) -+static void dma_free_rx_skbufs(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) -- stmmac_free_rx_buffer(priv, queue, i); -+ for (i = 0; i < dma_conf->dma_rx_size; i++) -+ stmmac_free_rx_buffer(priv, rx_q, i); - } - --static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, u32 queue, -- gfp_t flags) -+static int stmmac_alloc_rx_buffers(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue, gfp_t flags) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { -+ for (i = 0; i < dma_conf->dma_rx_size; i++) { - struct dma_desc *p; - int ret; - -@@ -1594,7 +1617,7 @@ static int stmmac_alloc_rx_buffers(struc - else - p = rx_q->dma_rx + i; - -- ret = stmmac_init_rx_buffers(priv, p, i, flags, -+ ret = stmmac_init_rx_buffers(priv, dma_conf, p, i, flags, - queue); - if (ret) - return ret; -@@ -1608,14 +1631,17 @@ static int stmmac_alloc_rx_buffers(struc - /** - * dma_free_rx_xskbufs - free RX dma buffers from XSK pool - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - */ --static void dma_free_rx_xskbufs(struct stmmac_priv *priv, u32 queue) -+static void dma_free_rx_xskbufs(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { -+ for (i = 0; i < dma_conf->dma_rx_size; i++) { - struct stmmac_rx_buffer *buf = &rx_q->buf_pool[i]; - - if (!buf->xdp) -@@ -1626,12 +1652,14 @@ static void dma_free_rx_xskbufs(struct s - } - } - --static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, u32 queue) -+static int stmmac_alloc_rx_buffers_zc(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int i; - -- for (i = 0; i < priv->dma_conf.dma_rx_size; i++) { -+ for (i = 0; i < dma_conf->dma_rx_size; i++) { - struct stmmac_rx_buffer *buf; - dma_addr_t dma_addr; - struct dma_desc *p; -@@ -1666,22 +1694,25 @@ static struct xsk_buff_pool *stmmac_get_ - /** - * __init_dma_rx_desc_rings - init the RX descriptor ring (per queue) - * @priv: driver private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - * @flags: gfp flag. - * Description: this function initializes the DMA RX descriptors - * and allocates the socket buffers. It supports the chained and ring - * modes. - */ --static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, u32 queue, gfp_t flags) -+static int __init_dma_rx_desc_rings(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue, gfp_t flags) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - int ret; - - netif_dbg(priv, probe, priv->dev, - "(%s) dma_rx_phy=0x%08x\n", __func__, - (u32)rx_q->dma_rx_phy); - -- stmmac_clear_rx_descriptors(priv, queue); -+ stmmac_clear_rx_descriptors(priv, dma_conf, queue); - - xdp_rxq_info_unreg_mem_model(&rx_q->xdp_rxq); - -@@ -1708,9 +1739,9 @@ static int __init_dma_rx_desc_rings(stru - /* RX XDP ZC buffer pool may not be populated, e.g. - * xdpsock TX-only. - */ -- stmmac_alloc_rx_buffers_zc(priv, queue); -+ stmmac_alloc_rx_buffers_zc(priv, dma_conf, queue); - } else { -- ret = stmmac_alloc_rx_buffers(priv, queue, flags); -+ ret = stmmac_alloc_rx_buffers(priv, dma_conf, queue, flags); - if (ret < 0) - return -ENOMEM; - } -@@ -1720,17 +1751,19 @@ static int __init_dma_rx_desc_rings(stru - if (priv->extend_desc) - stmmac_mode_init(priv, rx_q->dma_erx, - rx_q->dma_rx_phy, -- priv->dma_conf.dma_rx_size, 1); -+ dma_conf->dma_rx_size, 1); - else - stmmac_mode_init(priv, rx_q->dma_rx, - rx_q->dma_rx_phy, -- priv->dma_conf.dma_rx_size, 0); -+ dma_conf->dma_rx_size, 0); - } - - return 0; - } - --static int init_dma_rx_desc_rings(struct net_device *dev, gfp_t flags) -+static int init_dma_rx_desc_rings(struct net_device *dev, -+ struct stmmac_dma_conf *dma_conf, -+ gfp_t flags) - { - struct stmmac_priv *priv = netdev_priv(dev); - u32 rx_count = priv->plat->rx_queues_to_use; -@@ -1742,7 +1775,7 @@ static int init_dma_rx_desc_rings(struct - "SKB addresses:\nskb\t\tskb data\tdma data\n"); - - for (queue = 0; queue < rx_count; queue++) { -- ret = __init_dma_rx_desc_rings(priv, queue, flags); -+ ret = __init_dma_rx_desc_rings(priv, dma_conf, queue, flags); - if (ret) - goto err_init_rx_buffers; - } -@@ -1751,12 +1784,12 @@ static int init_dma_rx_desc_rings(struct - - err_init_rx_buffers: - while (queue >= 0) { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - - if (rx_q->xsk_pool) -- dma_free_rx_xskbufs(priv, queue); -+ dma_free_rx_xskbufs(priv, dma_conf, queue); - else -- dma_free_rx_skbufs(priv, queue); -+ dma_free_rx_skbufs(priv, dma_conf, queue); - - rx_q->buf_alloc_num = 0; - rx_q->xsk_pool = NULL; -@@ -1773,14 +1806,17 @@ err_init_rx_buffers: - /** - * __init_dma_tx_desc_rings - init the TX descriptor ring (per queue) - * @priv: driver private structure -- * @queue : TX queue index -+ * @dma_conf: structure to take the dma data -+ * @queue: TX queue index - * Description: this function initializes the DMA TX descriptors - * and allocates the socket buffers. It supports the chained and ring - * modes. - */ --static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, u32 queue) -+static int __init_dma_tx_desc_rings(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - int i; - - netif_dbg(priv, probe, priv->dev, -@@ -1792,16 +1828,16 @@ static int __init_dma_tx_desc_rings(stru - if (priv->extend_desc) - stmmac_mode_init(priv, tx_q->dma_etx, - tx_q->dma_tx_phy, -- priv->dma_conf.dma_tx_size, 1); -+ dma_conf->dma_tx_size, 1); - else if (!(tx_q->tbs & STMMAC_TBS_AVAIL)) - stmmac_mode_init(priv, tx_q->dma_tx, - tx_q->dma_tx_phy, -- priv->dma_conf.dma_tx_size, 0); -+ dma_conf->dma_tx_size, 0); - } - - tx_q->xsk_pool = stmmac_get_xsk_pool(priv, queue); - -- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) { -+ for (i = 0; i < dma_conf->dma_tx_size; i++) { - struct dma_desc *p; - - if (priv->extend_desc) -@@ -1823,7 +1859,8 @@ static int __init_dma_tx_desc_rings(stru - return 0; - } - --static int init_dma_tx_desc_rings(struct net_device *dev) -+static int init_dma_tx_desc_rings(struct net_device *dev, -+ struct stmmac_dma_conf *dma_conf) - { - struct stmmac_priv *priv = netdev_priv(dev); - u32 tx_queue_cnt; -@@ -1832,7 +1869,7 @@ static int init_dma_tx_desc_rings(struct - tx_queue_cnt = priv->plat->tx_queues_to_use; - - for (queue = 0; queue < tx_queue_cnt; queue++) -- __init_dma_tx_desc_rings(priv, queue); -+ __init_dma_tx_desc_rings(priv, dma_conf, queue); - - return 0; - } -@@ -1840,26 +1877,29 @@ static int init_dma_tx_desc_rings(struct - /** - * init_dma_desc_rings - init the RX/TX descriptor rings - * @dev: net device structure -+ * @dma_conf: structure to take the dma data - * @flags: gfp flag. - * Description: this function initializes the DMA RX/TX descriptors - * and allocates the socket buffers. It supports the chained and ring - * modes. - */ --static int init_dma_desc_rings(struct net_device *dev, gfp_t flags) -+static int init_dma_desc_rings(struct net_device *dev, -+ struct stmmac_dma_conf *dma_conf, -+ gfp_t flags) - { - struct stmmac_priv *priv = netdev_priv(dev); - int ret; - -- ret = init_dma_rx_desc_rings(dev, flags); -+ ret = init_dma_rx_desc_rings(dev, dma_conf, flags); - if (ret) - return ret; - -- ret = init_dma_tx_desc_rings(dev); -+ ret = init_dma_tx_desc_rings(dev, dma_conf); - -- stmmac_clear_descriptors(priv); -+ stmmac_clear_descriptors(priv, dma_conf); - - if (netif_msg_hw(priv)) -- stmmac_display_rings(priv); -+ stmmac_display_rings(priv, dma_conf); - - return ret; - } -@@ -1867,17 +1907,20 @@ static int init_dma_desc_rings(struct ne - /** - * dma_free_tx_skbufs - free TX dma buffers - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: TX queue index - */ --static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) -+static void dma_free_tx_skbufs(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - int i; - - tx_q->xsk_frames_done = 0; - -- for (i = 0; i < priv->dma_conf.dma_tx_size; i++) -- stmmac_free_tx_buffer(priv, queue, i); -+ for (i = 0; i < dma_conf->dma_tx_size; i++) -+ stmmac_free_tx_buffer(priv, dma_conf, queue, i); - - if (tx_q->xsk_pool && tx_q->xsk_frames_done) { - xsk_tx_completed(tx_q->xsk_pool, tx_q->xsk_frames_done); -@@ -1896,34 +1939,37 @@ static void stmmac_free_tx_skbufs(struct - u32 queue; - - for (queue = 0; queue < tx_queue_cnt; queue++) -- dma_free_tx_skbufs(priv, queue); -+ dma_free_tx_skbufs(priv, &priv->dma_conf, queue); - } - - /** - * __free_dma_rx_desc_resources - free RX dma desc resources (per queue) - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - */ --static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) -+static void __free_dma_rx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - - /* Release the DMA RX socket buffers */ - if (rx_q->xsk_pool) -- dma_free_rx_xskbufs(priv, queue); -+ dma_free_rx_xskbufs(priv, dma_conf, queue); - else -- dma_free_rx_skbufs(priv, queue); -+ dma_free_rx_skbufs(priv, dma_conf, queue); - - rx_q->buf_alloc_num = 0; - rx_q->xsk_pool = NULL; - - /* Free DMA regions of consistent memory previously allocated */ - if (!priv->extend_desc) -- dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * -+ dma_free_coherent(priv->device, dma_conf->dma_rx_size * - sizeof(struct dma_desc), - rx_q->dma_rx, rx_q->dma_rx_phy); - else -- dma_free_coherent(priv->device, priv->dma_conf.dma_rx_size * -+ dma_free_coherent(priv->device, dma_conf->dma_rx_size * - sizeof(struct dma_extended_desc), - rx_q->dma_erx, rx_q->dma_rx_phy); - -@@ -1935,29 +1981,33 @@ static void __free_dma_rx_desc_resources - page_pool_destroy(rx_q->page_pool); - } - --static void free_dma_rx_desc_resources(struct stmmac_priv *priv) -+static void free_dma_rx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 rx_count = priv->plat->rx_queues_to_use; - u32 queue; - - /* Free RX queue resources */ - for (queue = 0; queue < rx_count; queue++) -- __free_dma_rx_desc_resources(priv, queue); -+ __free_dma_rx_desc_resources(priv, dma_conf, queue); - } - - /** - * __free_dma_tx_desc_resources - free TX dma desc resources (per queue) - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: TX queue index - */ --static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) -+static void __free_dma_tx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - size_t size; - void *addr; - - /* Release the DMA TX socket buffers */ -- dma_free_tx_skbufs(priv, queue); -+ dma_free_tx_skbufs(priv, dma_conf, queue); - - if (priv->extend_desc) { - size = sizeof(struct dma_extended_desc); -@@ -1970,7 +2020,7 @@ static void __free_dma_tx_desc_resources - addr = tx_q->dma_tx; - } - -- size *= priv->dma_conf.dma_tx_size; -+ size *= dma_conf->dma_tx_size; - - dma_free_coherent(priv->device, size, addr, tx_q->dma_tx_phy); - -@@ -1978,28 +2028,32 @@ static void __free_dma_tx_desc_resources - kfree(tx_q->tx_skbuff); - } - --static void free_dma_tx_desc_resources(struct stmmac_priv *priv) -+static void free_dma_tx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 tx_count = priv->plat->tx_queues_to_use; - u32 queue; - - /* Free TX queue resources */ - for (queue = 0; queue < tx_count; queue++) -- __free_dma_tx_desc_resources(priv, queue); -+ __free_dma_tx_desc_resources(priv, dma_conf, queue); - } - - /** - * __alloc_dma_rx_desc_resources - alloc RX resources (per queue). - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: RX queue index - * Description: according to which descriptor can be used (extend or basic) - * this function allocates the resources for TX and RX paths. In case of - * reception, for example, it pre-allocated the RX socket buffer in order to - * allow zero-copy mechanism. - */ --static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, u32 queue) -+static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; -+ struct stmmac_rx_queue *rx_q = &dma_conf->rx_queue[queue]; - struct stmmac_channel *ch = &priv->channel[queue]; - bool xdp_prog = stmmac_xdp_is_enabled(priv); - struct page_pool_params pp_params = { 0 }; -@@ -2011,8 +2065,8 @@ static int __alloc_dma_rx_desc_resources - rx_q->priv_data = priv; - - pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; -- pp_params.pool_size = priv->dma_conf.dma_rx_size; -- num_pages = DIV_ROUND_UP(priv->dma_conf.dma_buf_sz, PAGE_SIZE); -+ pp_params.pool_size = dma_conf->dma_rx_size; -+ num_pages = DIV_ROUND_UP(dma_conf->dma_buf_sz, PAGE_SIZE); - pp_params.order = ilog2(num_pages); - pp_params.nid = dev_to_node(priv->device); - pp_params.dev = priv->device; -@@ -2027,7 +2081,7 @@ static int __alloc_dma_rx_desc_resources - return ret; - } - -- rx_q->buf_pool = kcalloc(priv->dma_conf.dma_rx_size, -+ rx_q->buf_pool = kcalloc(dma_conf->dma_rx_size, - sizeof(*rx_q->buf_pool), - GFP_KERNEL); - if (!rx_q->buf_pool) -@@ -2035,7 +2089,7 @@ static int __alloc_dma_rx_desc_resources - - if (priv->extend_desc) { - rx_q->dma_erx = dma_alloc_coherent(priv->device, -- priv->dma_conf.dma_rx_size * -+ dma_conf->dma_rx_size * - sizeof(struct dma_extended_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); -@@ -2044,7 +2098,7 @@ static int __alloc_dma_rx_desc_resources - - } else { - rx_q->dma_rx = dma_alloc_coherent(priv->device, -- priv->dma_conf.dma_rx_size * -+ dma_conf->dma_rx_size * - sizeof(struct dma_desc), - &rx_q->dma_rx_phy, - GFP_KERNEL); -@@ -2069,7 +2123,8 @@ static int __alloc_dma_rx_desc_resources - return 0; - } - --static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv) -+static int alloc_dma_rx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 rx_count = priv->plat->rx_queues_to_use; - u32 queue; -@@ -2077,7 +2132,7 @@ static int alloc_dma_rx_desc_resources(s - - /* RX queues buffers and DMA */ - for (queue = 0; queue < rx_count; queue++) { -- ret = __alloc_dma_rx_desc_resources(priv, queue); -+ ret = __alloc_dma_rx_desc_resources(priv, dma_conf, queue); - if (ret) - goto err_dma; - } -@@ -2085,7 +2140,7 @@ static int alloc_dma_rx_desc_resources(s - return 0; - - err_dma: -- free_dma_rx_desc_resources(priv); -+ free_dma_rx_desc_resources(priv, dma_conf); - - return ret; - } -@@ -2093,28 +2148,31 @@ err_dma: - /** - * __alloc_dma_tx_desc_resources - alloc TX resources (per queue). - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * @queue: TX queue index - * Description: according to which descriptor can be used (extend or basic) - * this function allocates the resources for TX and RX paths. In case of - * reception, for example, it pre-allocated the RX socket buffer in order to - * allow zero-copy mechanism. - */ --static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, u32 queue) -+static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf, -+ u32 queue) - { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue]; - size_t size; - void *addr; - - tx_q->queue_index = queue; - tx_q->priv_data = priv; - -- tx_q->tx_skbuff_dma = kcalloc(priv->dma_conf.dma_tx_size, -+ tx_q->tx_skbuff_dma = kcalloc(dma_conf->dma_tx_size, - sizeof(*tx_q->tx_skbuff_dma), - GFP_KERNEL); - if (!tx_q->tx_skbuff_dma) - return -ENOMEM; - -- tx_q->tx_skbuff = kcalloc(priv->dma_conf.dma_tx_size, -+ tx_q->tx_skbuff = kcalloc(dma_conf->dma_tx_size, - sizeof(struct sk_buff *), - GFP_KERNEL); - if (!tx_q->tx_skbuff) -@@ -2127,7 +2185,7 @@ static int __alloc_dma_tx_desc_resources - else - size = sizeof(struct dma_desc); - -- size *= priv->dma_conf.dma_tx_size; -+ size *= dma_conf->dma_tx_size; - - addr = dma_alloc_coherent(priv->device, size, - &tx_q->dma_tx_phy, GFP_KERNEL); -@@ -2144,7 +2202,8 @@ static int __alloc_dma_tx_desc_resources - return 0; - } - --static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv) -+static int alloc_dma_tx_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - u32 tx_count = priv->plat->tx_queues_to_use; - u32 queue; -@@ -2152,7 +2211,7 @@ static int alloc_dma_tx_desc_resources(s - - /* TX queues buffers and DMA */ - for (queue = 0; queue < tx_count; queue++) { -- ret = __alloc_dma_tx_desc_resources(priv, queue); -+ ret = __alloc_dma_tx_desc_resources(priv, dma_conf, queue); - if (ret) - goto err_dma; - } -@@ -2160,27 +2219,29 @@ static int alloc_dma_tx_desc_resources(s - return 0; - - err_dma: -- free_dma_tx_desc_resources(priv); -+ free_dma_tx_desc_resources(priv, dma_conf); - return ret; - } - - /** - * alloc_dma_desc_resources - alloc TX/RX resources. - * @priv: private structure -+ * @dma_conf: structure to take the dma data - * Description: according to which descriptor can be used (extend or basic) - * this function allocates the resources for TX and RX paths. In case of - * reception, for example, it pre-allocated the RX socket buffer in order to - * allow zero-copy mechanism. - */ --static int alloc_dma_desc_resources(struct stmmac_priv *priv) -+static int alloc_dma_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - /* RX Allocation */ -- int ret = alloc_dma_rx_desc_resources(priv); -+ int ret = alloc_dma_rx_desc_resources(priv, dma_conf); - - if (ret) - return ret; - -- ret = alloc_dma_tx_desc_resources(priv); -+ ret = alloc_dma_tx_desc_resources(priv, dma_conf); - - return ret; - } -@@ -2188,16 +2249,18 @@ static int alloc_dma_desc_resources(stru - /** - * free_dma_desc_resources - free dma desc resources - * @priv: private structure -+ * @dma_conf: structure to take the dma data - */ --static void free_dma_desc_resources(struct stmmac_priv *priv) -+static void free_dma_desc_resources(struct stmmac_priv *priv, -+ struct stmmac_dma_conf *dma_conf) - { - /* Release the DMA TX socket buffers */ -- free_dma_tx_desc_resources(priv); -+ free_dma_tx_desc_resources(priv, dma_conf); - - /* Release the DMA RX socket buffers later - * to ensure all pending XDP_TX buffers are returned. - */ -- free_dma_rx_desc_resources(priv); -+ free_dma_rx_desc_resources(priv, dma_conf); - } - - /** -@@ -2686,8 +2749,8 @@ static void stmmac_tx_err(struct stmmac_ - netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, chan)); - - stmmac_stop_tx_dma(priv, chan); -- dma_free_tx_skbufs(priv, chan); -- stmmac_clear_tx_descriptors(priv, chan); -+ dma_free_tx_skbufs(priv, &priv->dma_conf, chan); -+ stmmac_clear_tx_descriptors(priv, &priv->dma_conf, chan); - stmmac_reset_tx_queue(priv, chan); - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - tx_q->dma_tx_phy, chan); -@@ -3684,19 +3747,93 @@ static int stmmac_request_irq(struct net - } - - /** -- * stmmac_open - open entry point of the driver -+ * stmmac_setup_dma_desc - Generate a dma_conf and allocate DMA queue -+ * @priv: driver private structure -+ * @mtu: MTU to setup the dma queue and buf with -+ * Description: Allocate and generate a dma_conf based on the provided MTU. -+ * Allocate the Tx/Rx DMA queue and init them. -+ * Return value: -+ * the dma_conf allocated struct on success and an appropriate ERR_PTR on failure. -+ */ -+static struct stmmac_dma_conf * -+stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu) -+{ -+ struct stmmac_dma_conf *dma_conf; -+ int chan, bfsize, ret; -+ -+ dma_conf = kzalloc(sizeof(*dma_conf), GFP_KERNEL); -+ if (!dma_conf) { -+ netdev_err(priv->dev, "%s: DMA conf allocation failed\n", -+ __func__); -+ return ERR_PTR(-ENOMEM); -+ } -+ -+ bfsize = stmmac_set_16kib_bfsize(priv, mtu); -+ if (bfsize < 0) -+ bfsize = 0; -+ -+ if (bfsize < BUF_SIZE_16KiB) -+ bfsize = stmmac_set_bfsize(mtu, 0); -+ -+ dma_conf->dma_buf_sz = bfsize; -+ /* Chose the tx/rx size from the already defined one in the -+ * priv struct. (if defined) -+ */ -+ dma_conf->dma_tx_size = priv->dma_conf.dma_tx_size; -+ dma_conf->dma_rx_size = priv->dma_conf.dma_rx_size; -+ -+ if (!dma_conf->dma_tx_size) -+ dma_conf->dma_tx_size = DMA_DEFAULT_TX_SIZE; -+ if (!dma_conf->dma_rx_size) -+ dma_conf->dma_rx_size = DMA_DEFAULT_RX_SIZE; -+ -+ /* Earlier check for TBS */ -+ for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { -+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[chan]; -+ int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; -+ -+ /* Setup per-TXQ tbs flag before TX descriptor alloc */ -+ tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0; -+ } -+ -+ ret = alloc_dma_desc_resources(priv, dma_conf); -+ if (ret < 0) { -+ netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", -+ __func__); -+ goto alloc_error; -+ } -+ -+ ret = init_dma_desc_rings(priv->dev, dma_conf, GFP_KERNEL); -+ if (ret < 0) { -+ netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", -+ __func__); -+ goto init_error; -+ } -+ -+ return dma_conf; -+ -+init_error: -+ free_dma_desc_resources(priv, dma_conf); -+alloc_error: -+ kfree(dma_conf); -+ return ERR_PTR(ret); -+} -+ -+/** -+ * __stmmac_open - open entry point of the driver - * @dev : pointer to the device structure. -+ * @dma_conf : structure to take the dma data - * Description: - * This function is the open entry point of the driver. - * Return value: - * 0 on success and an appropriate (-)ve integer as defined in errno.h - * file on failure. - */ --static int stmmac_open(struct net_device *dev) -+static int __stmmac_open(struct net_device *dev, -+ struct stmmac_dma_conf *dma_conf) - { - struct stmmac_priv *priv = netdev_priv(dev); - int mode = priv->plat->phy_interface; -- int bfsize = 0; - u32 chan; - int ret; - -@@ -3723,45 +3860,10 @@ static int stmmac_open(struct net_device - memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); - priv->xstats.threshold = tc; - -- bfsize = stmmac_set_16kib_bfsize(priv, dev->mtu); -- if (bfsize < 0) -- bfsize = 0; -- -- if (bfsize < BUF_SIZE_16KiB) -- bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_conf.dma_buf_sz); -- -- priv->dma_conf.dma_buf_sz = bfsize; -- buf_sz = bfsize; -- - priv->rx_copybreak = STMMAC_RX_COPYBREAK; - -- if (!priv->dma_conf.dma_tx_size) -- priv->dma_conf.dma_tx_size = DMA_DEFAULT_TX_SIZE; -- if (!priv->dma_conf.dma_rx_size) -- priv->dma_conf.dma_rx_size = DMA_DEFAULT_RX_SIZE; -- -- /* Earlier check for TBS */ -- for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) { -- struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; -- int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en; -- -- /* Setup per-TXQ tbs flag before TX descriptor alloc */ -- tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0; -- } -- -- ret = alloc_dma_desc_resources(priv); -- if (ret < 0) { -- netdev_err(priv->dev, "%s: DMA descriptors allocation failed\n", -- __func__); -- goto dma_desc_error; -- } -- -- ret = init_dma_desc_rings(dev, GFP_KERNEL); -- if (ret < 0) { -- netdev_err(priv->dev, "%s: DMA descriptors initialization failed\n", -- __func__); -- goto init_error; -- } -+ buf_sz = dma_conf->dma_buf_sz; -+ memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf)); - - if (priv->plat->serdes_powerup) { - ret = priv->plat->serdes_powerup(dev, priv->plat->bsp_priv); -@@ -3804,14 +3906,28 @@ irq_error: - - stmmac_hw_teardown(dev); - init_error: -- free_dma_desc_resources(priv); --dma_desc_error: -+ free_dma_desc_resources(priv, &priv->dma_conf); - phylink_disconnect_phy(priv->phylink); - init_phy_error: - pm_runtime_put(priv->device); - return ret; - } - -+static int stmmac_open(struct net_device *dev) -+{ -+ struct stmmac_priv *priv = netdev_priv(dev); -+ struct stmmac_dma_conf *dma_conf; -+ int ret; -+ -+ dma_conf = stmmac_setup_dma_desc(priv, dev->mtu); -+ if (IS_ERR(dma_conf)) -+ return PTR_ERR(dma_conf); -+ -+ ret = __stmmac_open(dev, dma_conf); -+ kfree(dma_conf); -+ return ret; -+} -+ - static void stmmac_fpe_stop_wq(struct stmmac_priv *priv) - { - set_bit(__FPE_REMOVING, &priv->fpe_task_state); -@@ -3858,7 +3974,7 @@ static int stmmac_release(struct net_dev - stmmac_stop_all_dma(priv); - - /* Release and free the Rx/Tx resources */ -- free_dma_desc_resources(priv); -+ free_dma_desc_resources(priv, &priv->dma_conf); - - /* Disable the MAC Rx/Tx */ - stmmac_mac_set(priv, priv->ioaddr, false); -@@ -6403,7 +6519,7 @@ void stmmac_disable_rx_queue(struct stmm - spin_unlock_irqrestore(&ch->lock, flags); - - stmmac_stop_rx_dma(priv, queue); -- __free_dma_rx_desc_resources(priv, queue); -+ __free_dma_rx_desc_resources(priv, &priv->dma_conf, queue); - } - - void stmmac_enable_rx_queue(struct stmmac_priv *priv, u32 queue) -@@ -6414,21 +6530,21 @@ void stmmac_enable_rx_queue(struct stmma - u32 buf_size; - int ret; - -- ret = __alloc_dma_rx_desc_resources(priv, queue); -+ ret = __alloc_dma_rx_desc_resources(priv, &priv->dma_conf, queue); - if (ret) { - netdev_err(priv->dev, "Failed to alloc RX desc.\n"); - return; - } - -- ret = __init_dma_rx_desc_rings(priv, queue, GFP_KERNEL); -+ ret = __init_dma_rx_desc_rings(priv, &priv->dma_conf, queue, GFP_KERNEL); - if (ret) { -- __free_dma_rx_desc_resources(priv, queue); -+ __free_dma_rx_desc_resources(priv, &priv->dma_conf, queue); - netdev_err(priv->dev, "Failed to init RX desc.\n"); - return; - } - - stmmac_reset_rx_queue(priv, queue); -- stmmac_clear_rx_descriptors(priv, queue); -+ stmmac_clear_rx_descriptors(priv, &priv->dma_conf, queue); - - stmmac_init_rx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - rx_q->dma_rx_phy, rx_q->queue_index); -@@ -6466,7 +6582,7 @@ void stmmac_disable_tx_queue(struct stmm - spin_unlock_irqrestore(&ch->lock, flags); - - stmmac_stop_tx_dma(priv, queue); -- __free_dma_tx_desc_resources(priv, queue); -+ __free_dma_tx_desc_resources(priv, &priv->dma_conf, queue); - } - - void stmmac_enable_tx_queue(struct stmmac_priv *priv, u32 queue) -@@ -6476,21 +6592,21 @@ void stmmac_enable_tx_queue(struct stmma - unsigned long flags; - int ret; - -- ret = __alloc_dma_tx_desc_resources(priv, queue); -+ ret = __alloc_dma_tx_desc_resources(priv, &priv->dma_conf, queue); - if (ret) { - netdev_err(priv->dev, "Failed to alloc TX desc.\n"); - return; - } - -- ret = __init_dma_tx_desc_rings(priv, queue); -+ ret = __init_dma_tx_desc_rings(priv, &priv->dma_conf, queue); - if (ret) { -- __free_dma_tx_desc_resources(priv, queue); -+ __free_dma_tx_desc_resources(priv, &priv->dma_conf, queue); - netdev_err(priv->dev, "Failed to init TX desc.\n"); - return; - } - - stmmac_reset_tx_queue(priv, queue); -- stmmac_clear_tx_descriptors(priv, queue); -+ stmmac_clear_tx_descriptors(priv, &priv->dma_conf, queue); - - stmmac_init_tx_chan(priv, priv->ioaddr, priv->plat->dma_cfg, - tx_q->dma_tx_phy, tx_q->queue_index); -@@ -6530,7 +6646,7 @@ void stmmac_xdp_release(struct net_devic - stmmac_stop_all_dma(priv); - - /* Release and free the Rx/Tx resources */ -- free_dma_desc_resources(priv); -+ free_dma_desc_resources(priv, &priv->dma_conf); - - /* Disable the MAC Rx/Tx */ - stmmac_mac_set(priv, priv->ioaddr, false); -@@ -6555,14 +6671,14 @@ int stmmac_xdp_open(struct net_device *d - u32 chan; - int ret; - -- ret = alloc_dma_desc_resources(priv); -+ ret = alloc_dma_desc_resources(priv, &priv->dma_conf); - if (ret < 0) { - netdev_err(dev, "%s: DMA descriptors allocation failed\n", - __func__); - goto dma_desc_error; - } - -- ret = init_dma_desc_rings(dev, GFP_KERNEL); -+ ret = init_dma_desc_rings(dev, &priv->dma_conf, GFP_KERNEL); - if (ret < 0) { - netdev_err(dev, "%s: DMA descriptors initialization failed\n", - __func__); -@@ -6644,7 +6760,7 @@ irq_error: - - stmmac_hw_teardown(dev); - init_error: -- free_dma_desc_resources(priv); -+ free_dma_desc_resources(priv, &priv->dma_conf); - dma_desc_error: - return ret; - } -@@ -7509,7 +7625,7 @@ int stmmac_resume(struct device *dev) - stmmac_reset_queues_param(priv); - - stmmac_free_tx_skbufs(priv); -- stmmac_clear_descriptors(priv); -+ stmmac_clear_descriptors(priv, &priv->dma_conf); - - stmmac_hw_setup(ndev, false); - stmmac_init_coalesce(priv); diff --git a/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch b/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch deleted file mode 100644 index 8fccc716597..00000000000 --- a/target/linux/generic/backport-6.1/775-v6.0-05-net-ethernet-stmicro-stmmac-permit-MTU-change-with-i.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 3470079687448abac42deb62774253be1d6bdef3 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Sat, 23 Jul 2022 16:29:33 +0200 -Subject: [PATCH 5/5] net: ethernet: stmicro: stmmac: permit MTU change with - interface up - -Remove the limitation where the interface needs to be down to change -MTU by releasing and opening the stmmac driver to set the new MTU. -Also call the set_filter function to correctly init the port. -This permits to remove the EBUSY error while the ethernet port is -running permitting a correct MTU change if for example a DSA request -a MTU change for a switch CPU port. - -Signed-off-by: Christian Marangi -Signed-off-by: Jakub Kicinski ---- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 30 +++++++++++++++---- - 1 file changed, 24 insertions(+), 6 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -5626,18 +5626,15 @@ static int stmmac_change_mtu(struct net_ - { - struct stmmac_priv *priv = netdev_priv(dev); - int txfifosz = priv->plat->tx_fifo_size; -+ struct stmmac_dma_conf *dma_conf; - const int mtu = new_mtu; -+ int ret; - - if (txfifosz == 0) - txfifosz = priv->dma_cap.tx_fifo_size; - - txfifosz /= priv->plat->tx_queues_to_use; - -- if (netif_running(dev)) { -- netdev_err(priv->dev, "must be stopped to change its MTU\n"); -- return -EBUSY; -- } -- - if (stmmac_xdp_is_enabled(priv) && new_mtu > ETH_DATA_LEN) { - netdev_dbg(priv->dev, "Jumbo frames not supported for XDP\n"); - return -EINVAL; -@@ -5649,8 +5646,29 @@ static int stmmac_change_mtu(struct net_ - if ((txfifosz < new_mtu) || (new_mtu > BUF_SIZE_16KiB)) - return -EINVAL; - -- dev->mtu = mtu; -+ if (netif_running(dev)) { -+ netdev_dbg(priv->dev, "restarting interface to change its MTU\n"); -+ /* Try to allocate the new DMA conf with the new mtu */ -+ dma_conf = stmmac_setup_dma_desc(priv, mtu); -+ if (IS_ERR(dma_conf)) { -+ netdev_err(priv->dev, "failed allocating new dma conf for new MTU %d\n", -+ mtu); -+ return PTR_ERR(dma_conf); -+ } -+ -+ stmmac_release(dev); -+ -+ ret = __stmmac_open(dev, dma_conf); -+ kfree(dma_conf); -+ if (ret) { -+ netdev_err(priv->dev, "failed reopening the interface after MTU change\n"); -+ return ret; -+ } -+ -+ stmmac_set_rx_mode(dev); -+ } - -+ dev->mtu = mtu; - netdev_update_features(dev); - - return 0; diff --git a/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch b/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch deleted file mode 100644 index 4f0d95f4561..00000000000 --- a/target/linux/generic/backport-6.1/776-v6.1-01-net-dsa-qca8k-fix-inband-mgmt-for-big-endian-systems.patch +++ /dev/null @@ -1,156 +0,0 @@ -From a2550d3ce53c68f54042bc5e468c4d07491ffe0e Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 12 Oct 2022 19:18:36 +0200 -Subject: [PATCH 1/2] net: dsa: qca8k: fix inband mgmt for big-endian systems - -The header and the data of the skb for the inband mgmt requires -to be in little-endian. This is problematic for big-endian system -as the mgmt header is written in the cpu byte order. - -Fix this by converting each value for the mgmt header and data to -little-endian, and convert to cpu byte order the mgmt header and -data sent by the switch. - -Fixes: 5950c7c0a68c ("net: dsa: qca8k: add support for mgmt read/write in Ethernet packet") -Tested-by: Pawel Dembicki -Tested-by: Lech Perczak -Signed-off-by: Christian Marangi -Reviewed-by: Lech Perczak -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 63 ++++++++++++++++++++++++-------- - include/linux/dsa/tag_qca.h | 6 +-- - 2 files changed, 50 insertions(+), 19 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -137,27 +137,42 @@ static void qca8k_rw_reg_ack_handler(str - struct qca8k_mgmt_eth_data *mgmt_eth_data; - struct qca8k_priv *priv = ds->priv; - struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ u32 command; - u8 len, cmd; -+ int i; - - mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); - mgmt_eth_data = &priv->mgmt_eth_data; - -- cmd = FIELD_GET(QCA_HDR_MGMT_CMD, mgmt_ethhdr->command); -- len = FIELD_GET(QCA_HDR_MGMT_LENGTH, mgmt_ethhdr->command); -+ command = get_unaligned_le32(&mgmt_ethhdr->command); -+ cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); -+ len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); - - /* Make sure the seq match the requested packet */ -- if (mgmt_ethhdr->seq == mgmt_eth_data->seq) -+ if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) - mgmt_eth_data->ack = true; - - if (cmd == MDIO_READ) { -- mgmt_eth_data->data[0] = mgmt_ethhdr->mdio_data; -+ u32 *val = mgmt_eth_data->data; -+ -+ *val = get_unaligned_le32(&mgmt_ethhdr->mdio_data); - - /* Get the rest of the 12 byte of data. - * The read/write function will extract the requested data. - */ -- if (len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(mgmt_eth_data->data + 1, skb->data, -- QCA_HDR_MGMT_DATA2_LEN); -+ if (len > QCA_HDR_MGMT_DATA1_LEN) { -+ __le32 *data2 = (__le32 *)skb->data; -+ int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, -+ len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ val++; -+ -+ for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { -+ *val = get_unaligned_le32(data2); -+ val++; -+ data2++; -+ } -+ } - } - - complete(&mgmt_eth_data->rw_done); -@@ -169,8 +184,10 @@ static struct sk_buff *qca8k_alloc_mdio_ - struct qca_mgmt_ethhdr *mgmt_ethhdr; - unsigned int real_len; - struct sk_buff *skb; -- u32 *data2; -+ __le32 *data2; -+ u32 command; - u16 hdr; -+ int i; - - skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); - if (!skb) -@@ -199,20 +216,32 @@ static struct sk_buff *qca8k_alloc_mdio_ - hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); - hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); - -- mgmt_ethhdr->command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -- mgmt_ethhdr->command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, -+ command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); -+ command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); -+ command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); -+ command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, - QCA_HDR_MGMT_CHECK_CODE_VAL); - -+ put_unaligned_le32(command, &mgmt_ethhdr->command); -+ - if (cmd == MDIO_WRITE) -- mgmt_ethhdr->mdio_data = *val; -+ put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data); - - mgmt_ethhdr->hdr = htons(hdr); - - data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); -- if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) -- memcpy(data2, val + 1, len - QCA_HDR_MGMT_DATA1_LEN); -+ if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) { -+ int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, -+ len - QCA_HDR_MGMT_DATA1_LEN); -+ -+ val++; -+ -+ for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { -+ put_unaligned_le32(*val, data2); -+ data2++; -+ val++; -+ } -+ } - - return skb; - } -@@ -220,9 +249,11 @@ static struct sk_buff *qca8k_alloc_mdio_ - static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) - { - struct qca_mgmt_ethhdr *mgmt_ethhdr; -+ u32 seq; - -+ seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); - mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; -- mgmt_ethhdr->seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); -+ put_unaligned_le32(seq, &mgmt_ethhdr->seq); - } - - static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -56,9 +56,9 @@ - - /* Special struct emulating a Ethernet header */ - struct qca_mgmt_ethhdr { -- u32 command; /* command bit 31:0 */ -- u32 seq; /* seq 63:32 */ -- u32 mdio_data; /* first 4byte mdio */ -+ __le32 command; /* command bit 31:0 */ -+ __le32 seq; /* seq 63:32 */ -+ __le32 mdio_data; /* first 4byte mdio */ - __be16 hdr; /* qca hdr */ - } __packed; - diff --git a/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch b/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch deleted file mode 100644 index d13014bf93b..00000000000 --- a/target/linux/generic/backport-6.1/776-v6.1-02-net-dsa-qca8k-fix-ethtool-autocast-mib-for-big-endia.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0d4636f7d72df3179b20a2d32b647881917a5e2a Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 12 Oct 2022 19:18:37 +0200 -Subject: [PATCH 2/2] net: dsa: qca8k: fix ethtool autocast mib for big-endian - systems - -The switch sends autocast mib in little-endian. This is problematic for -big-endian system as the values needs to be converted. - -Fix this by converting each mib value to cpu byte order. - -Fixes: 5c957c7ca78c ("net: dsa: qca8k: add support for mib autocast in Ethernet packet") -Tested-by: Pawel Dembicki -Tested-by: Lech Perczak -Signed-off-by: Christian Marangi -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 20 ++++++++------------ - include/linux/dsa/tag_qca.h | 2 +- - 2 files changed, 9 insertions(+), 13 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -1668,9 +1668,9 @@ static void qca8k_mib_autocast_handler(s - struct qca8k_priv *priv = ds->priv; - const struct qca8k_mib_desc *mib; - struct mib_ethhdr *mib_ethhdr; -- int i, mib_len, offset = 0; -- u64 *data; -+ __le32 *data2; - u8 port; -+ int i; - - mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); - mib_eth_data = &priv->mib_eth_data; -@@ -1682,28 +1682,24 @@ static void qca8k_mib_autocast_handler(s - if (port != mib_eth_data->req_port) - goto exit; - -- data = mib_eth_data->data; -+ data2 = (__le32 *)skb->data; - - for (i = 0; i < priv->info->mib_count; i++) { - mib = &ar8327_mib[i]; - - /* First 3 mib are present in the skb head */ - if (i < 3) { -- data[i] = mib_ethhdr->data[i]; -+ mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i); - continue; - } - -- mib_len = sizeof(uint32_t); -- - /* Some mib are 64 bit wide */ - if (mib->size == 2) -- mib_len = sizeof(uint64_t); -- -- /* Copy the mib value from packet to the */ -- memcpy(data + i, skb->data + offset, mib_len); -+ mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2); -+ else -+ mib_eth_data->data[i] = get_unaligned_le32(data2); - -- /* Set the offset for the next mib */ -- offset += mib_len; -+ data2 += mib->size; - } - - exit: ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -68,7 +68,7 @@ enum mdio_cmd { - }; - - struct mib_ethhdr { -- u32 data[3]; /* first 3 mib counter */ -+ __le32 data[3]; /* first 3 mib counter */ - __be16 hdr; /* qca hdr */ - } __packed; - diff --git a/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch b/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch deleted file mode 100644 index b61e7ede494..00000000000 --- a/target/linux/generic/backport-6.1/777-v6.2-01-net-dsa-qca8k-fix-wrong-length-value-for-mgmt-eth-pa.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 9807ae69746196ee4bbffe7d22d22ab2b61c6ed0 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 29 Dec 2022 17:33:32 +0100 -Subject: [PATCH 1/5] net: dsa: qca8k: fix wrong length value for mgmt eth - packet - -The assumption that Documentation was right about how this value work was -wrong. It was discovered that the length value of the mgmt header is in -step of word size. - -As an example to process 4 byte of data the correct length to set is 2. -To process 8 byte 4, 12 byte 6, 16 byte 8... - -Odd values will always return the next size on the ack packet. -(length of 3 (6 byte) will always return 8 bytes of data) - -This means that a value of 15 (0xf) actually means reading/writing 32 bytes -of data instead of 16 bytes. This behaviour is totally absent and not -documented in the switch Documentation. - -In fact from Documentation the max value that mgmt eth can process is -16 byte of data while in reality it can process 32 bytes at once. - -To handle this we always round up the length after deviding it for word -size. We check if the result is odd and we round another time to align -to what the switch will provide in the ack packet. -The workaround for the length limit of 15 is still needed as the length -reg max value is 0xf(15) - -Reported-by: Ronald Wahl -Tested-by: Ronald Wahl -Fixes: 90386223f44e ("net: dsa: qca8k: add support for larger read/write size with mgmt Ethernet") -Signed-off-by: Christian Marangi -Cc: stable@vger.kernel.org # v5.18+ -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 45 +++++++++++++++++++++++++------- - 1 file changed, 35 insertions(+), 10 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -146,7 +146,16 @@ static void qca8k_rw_reg_ack_handler(str - - command = get_unaligned_le32(&mgmt_ethhdr->command); - cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); -+ - len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); -+ /* Special case for len of 15 as this is the max value for len and needs to -+ * be increased before converting it from word to dword. -+ */ -+ if (len == 15) -+ len++; -+ -+ /* We can ignore odd value, we always round up them in the alloc function. */ -+ len *= sizeof(u16); - - /* Make sure the seq match the requested packet */ - if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) -@@ -193,17 +202,33 @@ static struct sk_buff *qca8k_alloc_mdio_ - if (!skb) - return NULL; - -- /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte -- * Actually for some reason the steps are: -- * 0: nothing -- * 1-4: first 4 byte -- * 5-6: first 12 byte -- * 7-15: all 16 byte -+ /* Hdr mgmt length value is in step of word size. -+ * As an example to process 4 byte of data the correct length to set is 2. -+ * To process 8 byte 4, 12 byte 6, 16 byte 8... -+ * -+ * Odd values will always return the next size on the ack packet. -+ * (length of 3 (6 byte) will always return 8 bytes of data) -+ * -+ * This means that a value of 15 (0xf) actually means reading/writing 32 bytes -+ * of data. -+ * -+ * To correctly calculate the length we devide the requested len by word and -+ * round up. -+ * On the ack function we can skip the odd check as we already handle the -+ * case here. - */ -- if (len == 16) -- real_len = 15; -- else -- real_len = len; -+ real_len = DIV_ROUND_UP(len, sizeof(u16)); -+ -+ /* We check if the result len is odd and we round up another time to -+ * the next size. (length of 3 will be increased to 4 as switch will always -+ * return 8 bytes) -+ */ -+ if (real_len % sizeof(u16) != 0) -+ real_len++; -+ -+ /* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ -+ if (real_len == 16) -+ real_len--; - - skb_reset_mac_header(skb); - skb_set_network_header(skb, skb->len); diff --git a/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch b/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch deleted file mode 100644 index 55ecb1eb42e..00000000000 --- a/target/linux/generic/backport-6.1/777-v6.2-02-net-dsa-tag_qca-fix-wrong-MGMT_DATA2-size.patch +++ /dev/null @@ -1,34 +0,0 @@ -From d9dba91be71f03cc75bcf39fc0d5d99ff33f1ae0 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 29 Dec 2022 17:33:33 +0100 -Subject: [PATCH 2/5] net: dsa: tag_qca: fix wrong MGMT_DATA2 size - -It was discovered that MGMT_DATA2 can contain up to 28 bytes of data -instead of the 12 bytes written in the Documentation by accounting the -limit of 16 bytes declared in Documentation subtracting the first 4 byte -in the packet header. - -Update the define with the real world value. - -Tested-by: Ronald Wahl -Fixes: c2ee8181fddb ("net: dsa: tag_qca: add define for handling mgmt Ethernet packet") -Signed-off-by: Christian Marangi -Cc: stable@vger.kernel.org # v5.18+ -Signed-off-by: David S. Miller ---- - include/linux/dsa/tag_qca.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/include/linux/dsa/tag_qca.h -+++ b/include/linux/dsa/tag_qca.h -@@ -40,8 +40,8 @@ - QCA_HDR_MGMT_COMMAND_LEN + \ - QCA_HDR_MGMT_DATA1_LEN) - --#define QCA_HDR_MGMT_DATA2_LEN 12 /* Other 12 byte for the mdio data */ --#define QCA_HDR_MGMT_PADDING_LEN 34 /* Padding to reach the min Ethernet packet */ -+#define QCA_HDR_MGMT_DATA2_LEN 28 /* Other 28 byte for the mdio data */ -+#define QCA_HDR_MGMT_PADDING_LEN 18 /* Padding to reach the min Ethernet packet */ - - #define QCA_HDR_MGMT_PKT_LEN (QCA_HDR_MGMT_HEADER_LEN + \ - QCA_HDR_LEN + \ diff --git a/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch b/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch deleted file mode 100644 index c8e22fd1b81..00000000000 --- a/target/linux/generic/backport-6.1/777-v6.2-03-Revert-net-dsa-qca8k-cache-lo-and-hi-for-mdio-write.patch +++ /dev/null @@ -1,172 +0,0 @@ -From 03cb9e6d0b32b768e3d9d473c5c4ca1100877664 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 29 Dec 2022 17:33:34 +0100 -Subject: [PATCH 3/5] Revert "net: dsa: qca8k: cache lo and hi for mdio write" - -This reverts commit 2481d206fae7884cd07014fd1318e63af35e99eb. - -The Documentation is very confusing about the topic. -The cache logic for hi and lo is wrong and actually miss some regs to be -actually written. - -What the Documentation actually intended was that it's possible to skip -writing hi OR lo if half of the reg is not needed to be written or read. - -Revert the change in favor of a better and correct implementation. - -Reported-by: Ronald Wahl -Signed-off-by: Christian Marangi -Cc: stable@vger.kernel.org # v5.18+ -Signed-off-by: David S. Miller ---- - drivers/net/dsa/qca/qca8k-8xxx.c | 61 +++++++------------------------- - drivers/net/dsa/qca/qca8k.h | 5 --- - 2 files changed, 12 insertions(+), 54 deletions(-) - ---- a/drivers/net/dsa/qca/qca8k-8xxx.c -+++ b/drivers/net/dsa/qca/qca8k-8xxx.c -@@ -37,44 +37,6 @@ qca8k_split_addr(u32 regaddr, u16 *r1, u - } - - static int --qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) --{ -- u16 *cached_lo = &priv->mdio_cache.lo; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (lo == *cached_lo) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, lo); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit lo register\n"); -- -- *cached_lo = lo; -- return 0; --} -- --static int --qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) --{ -- u16 *cached_hi = &priv->mdio_cache.hi; -- struct mii_bus *bus = priv->bus; -- int ret; -- -- if (hi == *cached_hi) -- return 0; -- -- ret = bus->write(bus, phy_id, regnum, hi); -- if (ret < 0) -- dev_err_ratelimited(&bus->dev, -- "failed to write qca8k 32bit hi register\n"); -- -- *cached_hi = hi; -- return 0; --} -- --static int - qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) - { - int ret; -@@ -97,7 +59,7 @@ qca8k_mii_read32(struct mii_bus *bus, in - } - - static void --qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) -+qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) - { - u16 lo, hi; - int ret; -@@ -105,9 +67,12 @@ qca8k_mii_write32(struct qca8k_priv *pri - lo = val & 0xffff; - hi = (u16)(val >> 16); - -- ret = qca8k_set_lo(priv, phy_id, regnum, lo); -+ ret = bus->write(bus, phy_id, regnum, lo); - if (ret >= 0) -- ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); -+ ret = bus->write(bus, phy_id, regnum + 1, hi); -+ if (ret < 0) -+ dev_err_ratelimited(&bus->dev, -+ "failed to write qca8k 32bit register\n"); - } - - static int -@@ -442,7 +407,7 @@ qca8k_regmap_write(void *ctx, uint32_t r - if (ret < 0) - goto exit; - -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); - - exit: - mutex_unlock(&bus->mdio_lock); -@@ -475,7 +440,7 @@ qca8k_regmap_update_bits(void *ctx, uint - - val &= ~mask; - val |= write_val; -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); - - exit: - mutex_unlock(&bus->mdio_lock); -@@ -750,14 +715,14 @@ qca8k_mdio_write(struct qca8k_priv *priv - if (ret) - goto exit; - -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); - - ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, - QCA8K_MDIO_MASTER_BUSY); - - exit: - /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); - - mutex_unlock(&bus->mdio_lock); - -@@ -787,7 +752,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, - if (ret) - goto exit; - -- qca8k_mii_write32(priv, 0x10 | r2, r1, val); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, val); - - ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, - QCA8K_MDIO_MASTER_BUSY); -@@ -798,7 +763,7 @@ qca8k_mdio_read(struct qca8k_priv *priv, - - exit: - /* even if the busy_wait timeouts try to clear the MASTER_EN */ -- qca8k_mii_write32(priv, 0x10 | r2, r1, 0); -+ qca8k_mii_write32(bus, 0x10 | r2, r1, 0); - - mutex_unlock(&bus->mdio_lock); - -@@ -1914,8 +1879,6 @@ qca8k_sw_probe(struct mdio_device *mdiod - } - - priv->mdio_cache.page = 0xffff; -- priv->mdio_cache.lo = 0xffff; -- priv->mdio_cache.hi = 0xffff; - - /* Check the detected switch id */ - ret = qca8k_read_switch_id(priv); ---- a/drivers/net/dsa/qca/qca8k.h -+++ b/drivers/net/dsa/qca/qca8k.h -@@ -375,11 +375,6 @@ struct qca8k_mdio_cache { - * mdio writes - */ - u16 page; --/* lo and hi can also be cached and from Documentation we can skip one -- * extra mdio write if lo or hi is didn't change. -- */ -- u16 lo; -- u16 hi; - }; - - struct qca8k_priv { diff --git a/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch b/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch deleted file mode 100644 index 7cb21ed00d6..00000000000 --- a/target/linux/generic/backport-6.1/778-v5.18-01-net-phy-at803x-add-fiber-support.patch +++ /dev/null @@ -1,193 +0,0 @@ -From 3265f421887847db9ae2c01a00645e33608556d8 Mon Sep 17 00:00:00 2001 -From: Robert Hancock -Date: Tue, 25 Jan 2022 10:54:09 -0600 -Subject: [PATCH] net: phy: at803x: add fiber support - -Previously this driver always forced the copper page to be selected, -however for AR8031 in 100Base-FX or 1000Base-X modes, the fiber page -needs to be selected. Set the appropriate mode based on the hardware -mode_cfg strap selection. - -Enable the appropriate interrupt bits to detect fiber-side link up -or down events. - -Update config_aneg and read_status methods to use the appropriate -Clause 37 calls when fiber mode is in use. - -Signed-off-by: Robert Hancock -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 76 +++++++++++++++++++++++++++++++++++----- - 1 file changed, 67 insertions(+), 9 deletions(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -48,6 +48,8 @@ - #define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) - #define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) - #define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) -+#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) -+#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) - #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) - #define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) - #define AT803X_INTR_ENABLE_WOL BIT(0) -@@ -82,6 +84,17 @@ - - #define AT803X_MODE_CFG_MASK 0x0F - #define AT803X_MODE_CFG_SGMII 0x01 -+#define AT803X_MODE_CFG_BASET_RGMII 0x00 -+#define AT803X_MODE_CFG_BASET_SGMII 0x01 -+#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 -+#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 -+#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 -+#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 -+#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 -+#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 -+#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B -+#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E -+#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F - - #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ - #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 -@@ -199,6 +212,8 @@ struct at803x_priv { - u16 clk_25m_mask; - u8 smarteee_lpi_tw_1g; - u8 smarteee_lpi_tw_100m; -+ bool is_fiber; -+ bool is_1000basex; - struct regulator_dev *vddio_rdev; - struct regulator_dev *vddh_rdev; - struct regulator *vddio; -@@ -674,7 +689,33 @@ static int at803x_probe(struct phy_devic - return ret; - } - -+ if (phydev->drv->phy_id == ATH8031_PHY_ID) { -+ int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); -+ int mode_cfg; -+ -+ if (ccr < 0) -+ goto err; -+ mode_cfg = ccr & AT803X_MODE_CFG_MASK; -+ -+ switch (mode_cfg) { -+ case AT803X_MODE_CFG_BX1000_RGMII_50OHM: -+ case AT803X_MODE_CFG_BX1000_RGMII_75OHM: -+ priv->is_1000basex = true; -+ fallthrough; -+ case AT803X_MODE_CFG_FX100_RGMII_50OHM: -+ case AT803X_MODE_CFG_FX100_RGMII_75OHM: -+ priv->is_fiber = true; -+ break; -+ } -+ } -+ - return 0; -+ -+err: -+ if (priv->vddio) -+ regulator_disable(priv->vddio); -+ -+ return ret; - } - - static void at803x_remove(struct phy_device *phydev) -@@ -687,6 +728,7 @@ static void at803x_remove(struct phy_dev - - static int at803x_get_features(struct phy_device *phydev) - { -+ struct at803x_priv *priv = phydev->priv; - int err; - - err = genphy_read_abilities(phydev); -@@ -704,12 +746,13 @@ static int at803x_get_features(struct ph - * As a result of that, ESTATUS_1000_XFULL is set - * to 1 even when operating in copper TP mode. - * -- * Remove this mode from the supported link modes, -- * as this driver currently only supports copper -- * operation. -+ * Remove this mode from the supported link modes -+ * when not operating in 1000BaseX mode. - */ -- linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, -- phydev->supported); -+ if (!priv->is_1000basex) -+ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, -+ phydev->supported); -+ - return 0; - } - -@@ -773,15 +816,18 @@ static int at8031_pll_config(struct phy_ - - static int at803x_config_init(struct phy_device *phydev) - { -+ struct at803x_priv *priv = phydev->priv; - int ret; - - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - /* Some bootloaders leave the fiber page selected. -- * Switch to the copper page, as otherwise we read -- * the PHY capabilities from the fiber side. -+ * Switch to the appropriate page (fiber or copper), as otherwise we -+ * read the PHY capabilities from the wrong page. - */ - phy_lock_mdio_bus(phydev); -- ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); -+ ret = at803x_write_page(phydev, -+ priv->is_fiber ? AT803X_PAGE_FIBER : -+ AT803X_PAGE_COPPER); - phy_unlock_mdio_bus(phydev); - if (ret) - return ret; -@@ -840,6 +886,7 @@ static int at803x_ack_interrupt(struct p - - static int at803x_config_intr(struct phy_device *phydev) - { -+ struct at803x_priv *priv = phydev->priv; - int err; - int value; - -@@ -856,6 +903,10 @@ static int at803x_config_intr(struct phy - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; - value |= AT803X_INTR_ENABLE_LINK_FAIL; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; -+ if (priv->is_fiber) { -+ value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; -+ value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; -+ } - - err = phy_write(phydev, AT803X_INTR_ENABLE, value); - } else { -@@ -923,8 +974,12 @@ static void at803x_link_change_notify(st - - static int at803x_read_status(struct phy_device *phydev) - { -+ struct at803x_priv *priv = phydev->priv; - int ss, err, old_link = phydev->link; - -+ if (priv->is_1000basex) -+ return genphy_c37_read_status(phydev); -+ - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); - if (err) -@@ -1023,6 +1078,7 @@ static int at803x_config_mdix(struct phy - - static int at803x_config_aneg(struct phy_device *phydev) - { -+ struct at803x_priv *priv = phydev->priv; - int ret; - - ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); -@@ -1039,6 +1095,9 @@ static int at803x_config_aneg(struct phy - return ret; - } - -+ if (priv->is_1000basex) -+ return genphy_c37_config_aneg(phydev); -+ - return genphy_config_aneg(phydev); - } - diff --git a/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch b/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch deleted file mode 100644 index 8393cb32e89..00000000000 --- a/target/linux/generic/backport-6.1/778-v5.18-02-net-phy-at803x-support-downstream-SFP-cage.patch +++ /dev/null @@ -1,95 +0,0 @@ -From dc4d5fcc5d365c9f70ea3f5c09bdf70e988fad50 Mon Sep 17 00:00:00 2001 -From: Robert Hancock -Date: Tue, 25 Jan 2022 10:54:10 -0600 -Subject: [PATCH] net: phy: at803x: Support downstream SFP cage - -Add support for downstream SFP cages for AR8031 and AR8033. This is -primarily intended for fiber modules or direct-attach cables, however -copper modules which work in 1000Base-X mode may also function. Such -modules are allowed with a warning. - -Signed-off-by: Robert Hancock -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 56 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 56 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -19,6 +19,8 @@ - #include - #include - #include -+#include -+#include - #include - - #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 -@@ -555,6 +557,55 @@ static int at8031_register_regulators(st - return 0; - } - -+static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -+{ -+ struct phy_device *phydev = upstream; -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); -+ __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); -+ phy_interface_t iface; -+ -+ linkmode_zero(phy_support); -+ phylink_set(phy_support, 1000baseX_Full); -+ phylink_set(phy_support, 1000baseT_Full); -+ phylink_set(phy_support, Autoneg); -+ phylink_set(phy_support, Pause); -+ phylink_set(phy_support, Asym_Pause); -+ -+ linkmode_zero(sfp_support); -+ sfp_parse_support(phydev->sfp_bus, id, sfp_support); -+ /* Some modules support 10G modes as well as others we support. -+ * Mask out non-supported modes so the correct interface is picked. -+ */ -+ linkmode_and(sfp_support, phy_support, sfp_support); -+ -+ if (linkmode_empty(sfp_support)) { -+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); -+ return -EINVAL; -+ } -+ -+ iface = sfp_select_interface(phydev->sfp_bus, sfp_support); -+ -+ /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes -+ * interface for use with SFP modules. -+ * However, some copper modules detected as having a preferred SGMII -+ * interface do default to and function in 1000Base-X mode, so just -+ * print a warning and allow such modules, as they may have some chance -+ * of working. -+ */ -+ if (iface == PHY_INTERFACE_MODE_SGMII) -+ dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); -+ else if (iface != PHY_INTERFACE_MODE_1000BASEX) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static const struct sfp_upstream_ops at803x_sfp_ops = { -+ .attach = phy_sfp_attach, -+ .detach = phy_sfp_detach, -+ .module_insert = at803x_sfp_insert, -+}; -+ - static int at803x_parse_dt(struct phy_device *phydev) - { - struct device_node *node = phydev->mdio.dev.of_node; -@@ -662,6 +713,11 @@ static int at803x_parse_dt(struct phy_de - phydev_err(phydev, "failed to get VDDIO regulator\n"); - return PTR_ERR(priv->vddio); - } -+ -+ /* Only AR8031/8033 support 1000Base-X for SFP modules */ -+ ret = phy_sfp_probe(phydev, &at803x_sfp_ops); -+ if (ret < 0) -+ return ret; - } - - return 0; diff --git a/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch b/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch deleted file mode 100644 index de8951db10c..00000000000 --- a/target/linux/generic/backport-6.1/778-v5.18-03-net-phy-at803x-fix-NULL-pointer-dereference-on-AR9331-PHY.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 9926de7315be3d606cc011a305ad9adb9e8e14c9 Mon Sep 17 00:00:00 2001 -From: Oleksij Rempel -Date: Sat, 18 Jun 2022 14:23:33 +0200 -Subject: [PATCH] net: phy: at803x: fix NULL pointer dereference on AR9331 PHY - -Latest kernel will explode on the PHY interrupt config, since it depends -now on allocated priv. So, run probe to allocate priv to fix it. - - ar9331_switch ethernet.1:10 lan0 (uninitialized): PHY [!ahb!ethernet@1a000000!mdio!switch@10:00] driver [Qualcomm Atheros AR9331 built-in PHY] (irq=13) - CPU 0 Unable to handle kernel paging request at virtual address 0000000a, epc == 8050e8a8, ra == 80504b34 - ... - Call Trace: - [<8050e8a8>] at803x_config_intr+0x5c/0xd0 - [<80504b34>] phy_request_interrupt+0xa8/0xd0 - [<8050289c>] phylink_bringup_phy+0x2d8/0x3ac - [<80502b68>] phylink_fwnode_phy_connect+0x118/0x130 - [<8074d8ec>] dsa_slave_create+0x270/0x420 - [<80743b04>] dsa_port_setup+0x12c/0x148 - [<8074580c>] dsa_register_switch+0xaf0/0xcc0 - [<80511344>] ar9331_sw_probe+0x370/0x388 - [<8050cb78>] mdio_probe+0x44/0x70 - [<804df300>] really_probe+0x200/0x424 - [<804df7b4>] __driver_probe_device+0x290/0x298 - [<804df810>] driver_probe_device+0x54/0xe4 - [<804dfd50>] __device_attach_driver+0xe4/0x130 - [<804dcb00>] bus_for_each_drv+0xb4/0xd8 - [<804dfac4>] __device_attach+0x104/0x1a4 - [<804ddd24>] bus_probe_device+0x48/0xc4 - [<804deb44>] deferred_probe_work_func+0xf0/0x10c - [<800a0ffc>] process_one_work+0x314/0x4d4 - [<800a17fc>] worker_thread+0x2a4/0x354 - [<800a9a54>] kthread+0x134/0x13c - [<8006306c>] ret_from_kernel_thread+0x14/0x1c - -Same Issue would affect some other PHYs (QCA8081, QCA9561), so fix it -too. - -Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") -Signed-off-by: Oleksij Rempel -Reviewed-by: Andrew Lunn -Signed-off-by: David S. Miller ---- - drivers/net/phy/at803x.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -1594,6 +1594,8 @@ static struct phy_driver at803x_driver[] - /* ATHEROS AR9331 */ - PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), - .name = "Qualcomm Atheros AR9331 built-in PHY", -+ .probe = at803x_probe, -+ .remove = at803x_remove, - .suspend = at803x_suspend, - .resume = at803x_resume, - .flags = PHY_POLL_CABLE_TEST, diff --git a/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch b/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch deleted file mode 100644 index cdae5b4ca42..00000000000 --- a/target/linux/generic/backport-6.1/778-v5.18-04-net-phy-at803x-fix-error-return-code-in-at803x_probe.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 1f0dd412e34e177621769866bef347f0b22364df Mon Sep 17 00:00:00 2001 -From: Wei Yongjun -Date: Fri, 18 Nov 2022 10:36:35 +0000 -Subject: [PATCH] net: phy: at803x: fix error return code in at803x_probe() - -Fix to return a negative error code from the ccr read error handling -case instead of 0, as done elsewhere in this function. - -Fixes: 3265f4218878 ("net: phy: at803x: add fiber support") -Signed-off-by: Wei Yongjun -Reviewed-by: Andrew Lunn -Link: https://lore.kernel.org/r/20221118103635.254256-1-weiyongjun@huaweicloud.com -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/at803x.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/net/phy/at803x.c -+++ b/drivers/net/phy/at803x.c -@@ -749,8 +749,10 @@ static int at803x_probe(struct phy_devic - int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); - int mode_cfg; - -- if (ccr < 0) -+ if (ccr < 0) { -+ ret = ccr; - goto err; -+ } - mode_cfg = ccr & AT803X_MODE_CFG_MASK; - - switch (mode_cfg) { diff --git a/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch b/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch deleted file mode 100644 index 44f0864e9a8..00000000000 --- a/target/linux/generic/backport-6.1/780-v5.16-bus-mhi-pci_generic-Introduce-Sierra-EM919X-support.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 789d3eeb2367f92193a0882f7cdab03f0f9d6930 Mon Sep 17 00:00:00 2001 -From: Thomas Perrot -Date: Thu, 16 Dec 2021 13:42:27 +0530 -Subject: [PATCH] bus: mhi: pci_generic: Introduce Sierra EM919X support - -Add support for EM919X modems, this modem series is based on SDX55 -qcom chip. - -It is mandatory to use the same ring for control+data and diag events. - -Link: https://lore.kernel.org/r/20211123081541.648426-1-thomas.perrot@bootlin.com -Tested-by: Aleksander Morgado -Reviewed-by: Manivannan Sadhasivam -Signed-off-by: Thomas Perrot -Signed-off-by: Manivannan Sadhasivam -Link: https://lore.kernel.org/r/20211216081227.237749-11-manivannan.sadhasivam@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/bus/mhi/host/pci_generic.c | 43 +++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - ---- a/drivers/bus/mhi/host/pci_generic.c -+++ b/drivers/bus/mhi/host/pci_generic.c -@@ -406,6 +406,46 @@ static const struct mhi_pci_dev_info mhi - .mru_default = 32768, - }; - -+static const struct mhi_channel_config mhi_sierra_em919x_channels[] = { -+ MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), -+ MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 256, 0), -+ MHI_CHANNEL_CONFIG_UL(4, "DIAG", 32, 0), -+ MHI_CHANNEL_CONFIG_DL(5, "DIAG", 32, 0), -+ MHI_CHANNEL_CONFIG_UL(12, "MBIM", 128, 0), -+ MHI_CHANNEL_CONFIG_DL(13, "MBIM", 128, 0), -+ MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), -+ MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), -+ MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), -+ MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), -+ MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 512, 1), -+ MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 512, 2), -+}; -+ -+static struct mhi_event_config modem_sierra_em919x_mhi_events[] = { -+ /* first ring is control+data and DIAG ring */ -+ MHI_EVENT_CONFIG_CTRL(0, 2048), -+ /* Hardware channels request dedicated hardware event rings */ -+ MHI_EVENT_CONFIG_HW_DATA(1, 2048, 100), -+ MHI_EVENT_CONFIG_HW_DATA(2, 2048, 101) -+}; -+ -+static const struct mhi_controller_config modem_sierra_em919x_config = { -+ .max_channels = 128, -+ .timeout_ms = 24000, -+ .num_channels = ARRAY_SIZE(mhi_sierra_em919x_channels), -+ .ch_cfg = mhi_sierra_em919x_channels, -+ .num_events = ARRAY_SIZE(modem_sierra_em919x_mhi_events), -+ .event_cfg = modem_sierra_em919x_mhi_events, -+}; -+ -+static const struct mhi_pci_dev_info mhi_sierra_em919x_info = { -+ .name = "sierra-em919x", -+ .config = &modem_sierra_em919x_config, -+ .bar_num = MHI_PCI_DEFAULT_BAR_NUM, -+ .dma_data_width = 32, -+ .sideband_wake = false, -+}; -+ - static const struct mhi_channel_config mhi_telit_fn980_hw_v1_channels[] = { - MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), - MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), -@@ -480,6 +520,9 @@ static const struct mhi_pci_dev_info mhi - }; - - static const struct pci_device_id mhi_pci_id_table[] = { -+ /* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */ -+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200), -+ .driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info }, - /* Telit FN980 hardware revision v1 */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000), - .driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info }, diff --git a/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch b/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch deleted file mode 100644 index 3c71a27b798..00000000000 --- a/target/linux/generic/backport-6.1/781-v6.1-bus-mhi-host-always-print-detected-modem-name.patch +++ /dev/null @@ -1,37 +0,0 @@ -From f369e9ad52ec9361827e21a631b7198c9fca438e Mon Sep 17 00:00:00 2001 -From: Koen Vandeputte -Date: Wed, 31 Aug 2022 12:03:49 +0200 -Subject: [PATCH] bus: mhi: host: always print detected modem name - -This harmless print provides a very easy way of knowing -if the modem is detected properly during probing. - -Promote it to an informational print so no hassle is required -enabling kernel debugging info to obtain it. - -The rationale here is that: -On a lot of low-storage embedded devices, extensive kernel -debugging info is not always present as this would -increase it's size to much causing partition size issues. - -Signed-off-by: Koen Vandeputte -Reviewed-by: Manivannan Sadhasivam -Reviewed-by: Loic Poulain -Link: https://lore.kernel.org/r/20220831100349.1488762-1-koen.vandeputte@citymesh.com -[mani: added missing review tags] -Signed-off-by: Manivannan Sadhasivam ---- - drivers/bus/mhi/host/pci_generic.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/bus/mhi/host/pci_generic.c -+++ b/drivers/bus/mhi/host/pci_generic.c -@@ -806,7 +806,7 @@ static int mhi_pci_probe(struct pci_dev - struct mhi_controller *mhi_cntrl; - int err; - -- dev_dbg(&pdev->dev, "MHI PCI device found: %s\n", info->name); -+ dev_info(&pdev->dev, "MHI PCI device found: %s\n", info->name); - - /* mhi_pdev.mhi_cntrl must be zero-initialized */ - mhi_pdev = devm_kzalloc(&pdev->dev, sizeof(*mhi_pdev), GFP_KERNEL); diff --git a/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch b/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch deleted file mode 100644 index ebfbaccc9d7..00000000000 --- a/target/linux/generic/backport-6.1/782-v6.1-net-dsa-mt7530-add-support-for-in-band-link-status.patch +++ /dev/null @@ -1,130 +0,0 @@ -From e19de30d20809af3221ef8a2648b8a8a52e02d90 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Wed, 21 Sep 2022 01:23:14 +0100 -Subject: [PATCH 1/1] net: dsa: mt7530: add support for in-band link status - -Read link status from SGMII PCS for in-band managed 2500Base-X and -1000Base-X connection on a MAC port of the MT7531. This is needed to -get the SFP cage working which is connected to SGMII interface of -port 5 of the MT7531 switch IC on the Bananapi BPi-R3 board. -While at it also handle an_complete for both the autoneg and the -non-autoneg codepath. - -Signed-off-by: Daniel Golle -Signed-off-by: David S. Miller ---- - drivers/net/dsa/mt7530.c | 50 +++++++++++++++++++++++++++++----------- - drivers/net/dsa/mt7530.h | 1 + - 2 files changed, 38 insertions(+), 13 deletions(-) - ---- a/drivers/net/dsa/mt7530.c -+++ b/drivers/net/dsa/mt7530.c -@@ -2721,9 +2721,6 @@ mt7531_mac_config(struct dsa_switch *ds, - case PHY_INTERFACE_MODE_NA: - case PHY_INTERFACE_MODE_1000BASEX: - case PHY_INTERFACE_MODE_2500BASEX: -- if (phylink_autoneg_inband(mode)) -- return -EINVAL; -- - return mt7531_sgmii_setup_mode_force(priv, port, interface); - default: - return -EINVAL; -@@ -2799,13 +2796,6 @@ unsupported: - return; - } - -- if (phylink_autoneg_inband(mode) && -- state->interface != PHY_INTERFACE_MODE_SGMII) { -- dev_err(ds->dev, "%s: in-band negotiation unsupported\n", -- __func__); -- return; -- } -- - mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port)); - mcr_new = mcr_cur; - mcr_new &= ~PMCR_LINK_SETTINGS_MASK; -@@ -2942,6 +2932,9 @@ static void mt753x_phylink_get_caps(stru - config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_10 | MAC_100 | MAC_1000FD; - -+ if ((priv->id == ID_MT7531) && mt753x_is_mac_port(port)) -+ config->mac_capabilities |= MAC_2500FD; -+ - /* This driver does not make use of the speed, duplex, pause or the - * advertisement in its mac_config, so it is safe to mark this driver - * as non-legacy. -@@ -3007,6 +3000,7 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 - - status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); - state->link = !!(status & MT7531_SGMII_LINK_STATUS); -+ state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE); - if (state->interface == PHY_INTERFACE_MODE_SGMII && - (status & MT7531_SGMII_AN_ENABLE)) { - val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port)); -@@ -3037,16 +3031,44 @@ mt7531_sgmii_pcs_get_state_an(struct mt7 - return 0; - } - -+static void -+mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port, -+ struct phylink_link_state *state) -+{ -+ unsigned int val; -+ -+ val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port)); -+ state->link = !!(val & MT7531_SGMII_LINK_STATUS); -+ if (!state->link) -+ return; -+ -+ state->an_complete = state->link; -+ -+ if (state->interface == PHY_INTERFACE_MODE_2500BASEX) -+ state->speed = SPEED_2500; -+ else -+ state->speed = SPEED_1000; -+ -+ state->duplex = DUPLEX_FULL; -+ state->pause = MLO_PAUSE_NONE; -+} -+ - static void mt7531_pcs_get_state(struct phylink_pcs *pcs, - struct phylink_link_state *state) - { - struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv; - int port = pcs_to_mt753x_pcs(pcs)->port; - -- if (state->interface == PHY_INTERFACE_MODE_SGMII) -+ if (state->interface == PHY_INTERFACE_MODE_SGMII) { - mt7531_sgmii_pcs_get_state_an(priv, port, state); -- else -- state->link = false; -+ return; -+ } else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) || -+ (state->interface == PHY_INTERFACE_MODE_2500BASEX)) { -+ mt7531_sgmii_pcs_get_state_inband(priv, port, state); -+ return; -+ } -+ -+ state->link = false; - } - - static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, -@@ -3087,6 +3109,8 @@ mt753x_setup(struct dsa_switch *ds) - priv->pcs[i].pcs.ops = priv->info->pcs_ops; - priv->pcs[i].priv = priv; - priv->pcs[i].port = i; -+ if (mt753x_is_mac_port(i)) -+ priv->pcs[i].pcs.poll = 1; - } - - ret = priv->info->sw_setup(ds); ---- a/drivers/net/dsa/mt7530.h -+++ b/drivers/net/dsa/mt7530.h -@@ -373,6 +373,7 @@ enum mt7530_vlan_port_acc_frm { - #define MT7531_SGMII_LINK_STATUS BIT(18) - #define MT7531_SGMII_AN_ENABLE BIT(12) - #define MT7531_SGMII_AN_RESTART BIT(9) -+#define MT7531_SGMII_AN_COMPLETE BIT(21) - - /* Register for SGMII PCS_SPPED_ABILITY */ - #define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08) diff --git a/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch b/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch deleted file mode 100644 index 77cd336d364..00000000000 --- a/target/linux/generic/backport-6.1/783-v6.1-net-sfp-re-implement-soft-state-polling-setup.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 8475c4b70b040f9d8cbc308100f2c4d865f810b3 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 13 Sep 2022 20:06:27 +0100 -Subject: [PATCH 1/1] net: sfp: re-implement soft state polling setup - -Re-implement the decision making for soft state polling. Instead of -generating the soft state mask in sfp_soft_start_poll() by looking at -which GPIOs are available, record their availability in -sfp_sm_mod_probe() in sfp->state_hw_mask. - -This will then allow us to clear bits in sfp->state_hw_mask in module -specific quirks when the hardware signals should not be used, thereby -allowing us to switch to using the software state polling. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++------------ - 1 file changed, 26 insertions(+), 12 deletions(-) - ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -240,6 +240,7 @@ struct sfp { - bool need_poll; - - struct mutex st_mutex; /* Protects state */ -+ unsigned int state_hw_mask; - unsigned int state_soft_mask; - unsigned int state; - struct delayed_work poll; -@@ -505,17 +506,18 @@ static void sfp_soft_set_state(struct sf - static void sfp_soft_start_poll(struct sfp *sfp) - { - const struct sfp_eeprom_id *id = &sfp->id; -+ unsigned int mask = 0; - - sfp->state_soft_mask = 0; -- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE && -- !sfp->gpio[GPIO_TX_DISABLE]) -- sfp->state_soft_mask |= SFP_F_TX_DISABLE; -- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT && -- !sfp->gpio[GPIO_TX_FAULT]) -- sfp->state_soft_mask |= SFP_F_TX_FAULT; -- if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS && -- !sfp->gpio[GPIO_LOS]) -- sfp->state_soft_mask |= SFP_F_LOS; -+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE) -+ mask |= SFP_F_TX_DISABLE; -+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT) -+ mask |= SFP_F_TX_FAULT; -+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS) -+ mask |= SFP_F_LOS; -+ -+ // Poll the soft state for hardware pins we want to ignore -+ sfp->state_soft_mask = ~sfp->state_hw_mask & mask; - - if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) && - !sfp->need_poll) -@@ -529,10 +531,11 @@ static void sfp_soft_stop_poll(struct sf - - static unsigned int sfp_get_state(struct sfp *sfp) - { -- unsigned int state = sfp->get_state(sfp); -+ unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT); -+ unsigned int state; - -- if (state & SFP_F_PRESENT && -- sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT)) -+ state = sfp->get_state(sfp) & sfp->state_hw_mask; -+ if (state & SFP_F_PRESENT && soft) - state |= sfp_soft_get_state(sfp); - - return state; -@@ -1942,6 +1945,15 @@ static int sfp_sm_mod_probe(struct sfp * - if (ret < 0) - return ret; - -+ /* Initialise state bits to use from hardware */ -+ sfp->state_hw_mask = SFP_F_PRESENT; -+ if (sfp->gpio[GPIO_TX_DISABLE]) -+ sfp->state_hw_mask |= SFP_F_TX_DISABLE; -+ if (sfp->gpio[GPIO_TX_FAULT]) -+ sfp->state_hw_mask |= SFP_F_TX_FAULT; -+ if (sfp->gpio[GPIO_LOS]) -+ sfp->state_hw_mask |= SFP_F_LOS; -+ - if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && - !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) - sfp->module_t_start_up = T_START_UP_BAD_GPON; -@@ -2568,6 +2580,8 @@ static int sfp_probe(struct platform_dev - return PTR_ERR(sfp->gpio[i]); - } - -+ sfp->state_hw_mask = SFP_F_PRESENT; -+ - sfp->get_state = sfp_gpio_get_state; - sfp->set_state = sfp_gpio_set_state; - diff --git a/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch b/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch deleted file mode 100644 index 02fa28c5af2..00000000000 --- a/target/linux/generic/backport-6.1/784-v6.1-net-sfp-move-quirk-handling-into-sfp.c.patch +++ /dev/null @@ -1,291 +0,0 @@ -From 23571c7b96437483d28a990c906cc81f5f66374e Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 13 Sep 2022 20:06:32 +0100 -Subject: [PATCH 1/1] net: sfp: move quirk handling into sfp.c - -We need to handle more quirks than just those which affect the link -modes of the module. Move the quirk lookup into sfp.c, and pass the -quirk to sfp-bus.c - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp-bus.c | 98 ++------------------------------------- - drivers/net/phy/sfp.c | 94 ++++++++++++++++++++++++++++++++++++- - drivers/net/phy/sfp.h | 9 +++- - 3 files changed, 104 insertions(+), 97 deletions(-) - ---- a/drivers/net/phy/sfp-bus.c -+++ b/drivers/net/phy/sfp-bus.c -@@ -10,12 +10,6 @@ - - #include "sfp.h" - --struct sfp_quirk { -- const char *vendor; -- const char *part; -- void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); --}; -- - /** - * struct sfp_bus - internal representation of a sfp bus - */ -@@ -38,93 +32,6 @@ struct sfp_bus { - bool started; - }; - --static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, -- unsigned long *modes) --{ -- phylink_set(modes, 2500baseX_Full); --} -- --static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, -- unsigned long *modes) --{ -- /* Ubiquiti U-Fiber Instant module claims that support all transceiver -- * types including 10G Ethernet which is not truth. So clear all claimed -- * modes and set only one mode which module supports: 1000baseX_Full. -- */ -- phylink_zero(modes); -- phylink_set(modes, 1000baseX_Full); --} -- --static const struct sfp_quirk sfp_quirks[] = { -- { -- // Alcatel Lucent G-010S-P can operate at 2500base-X, but -- // incorrectly report 2500MBd NRZ in their EEPROM -- .vendor = "ALCATELLUCENT", -- .part = "G010SP", -- .modes = sfp_quirk_2500basex, -- }, { -- // Alcatel Lucent G-010S-A can operate at 2500base-X, but -- // report 3.2GBd NRZ in their EEPROM -- .vendor = "ALCATELLUCENT", -- .part = "3FE46541AA", -- .modes = sfp_quirk_2500basex, -- }, { -- // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd -- // NRZ in their EEPROM -- .vendor = "HUAWEI", -- .part = "MA5671A", -- .modes = sfp_quirk_2500basex, -- }, { -- // Lantech 8330-262D-E can operate at 2500base-X, but -- // incorrectly report 2500MBd NRZ in their EEPROM -- .vendor = "Lantech", -- .part = "8330-262D-E", -- .modes = sfp_quirk_2500basex, -- }, { -- .vendor = "UBNT", -- .part = "UF-INSTANT", -- .modes = sfp_quirk_ubnt_uf_instant, -- }, --}; -- --static size_t sfp_strlen(const char *str, size_t maxlen) --{ -- size_t size, i; -- -- /* Trailing characters should be filled with space chars */ -- for (i = 0, size = 0; i < maxlen; i++) -- if (str[i] != ' ') -- size = i + 1; -- -- return size; --} -- --static bool sfp_match(const char *qs, const char *str, size_t len) --{ -- if (!qs) -- return true; -- if (strlen(qs) != len) -- return false; -- return !strncmp(qs, str, len); --} -- --static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id) --{ -- const struct sfp_quirk *q; -- unsigned int i; -- size_t vs, ps; -- -- vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name)); -- ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn)); -- -- for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++) -- if (sfp_match(q->vendor, id->base.vendor_name, vs) && -- sfp_match(q->part, id->base.vendor_pn, ps)) -- return q; -- -- return NULL; --} -- - /** - * sfp_parse_port() - Parse the EEPROM base ID, setting the port type - * @bus: a pointer to the &struct sfp_bus structure for the sfp module -@@ -786,12 +693,13 @@ void sfp_link_down(struct sfp_bus *bus) - } - EXPORT_SYMBOL_GPL(sfp_link_down); - --int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id) -+int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ const struct sfp_quirk *quirk) - { - const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); - int ret = 0; - -- bus->sfp_quirk = sfp_lookup_quirk(id); -+ bus->sfp_quirk = quirk; - - if (ops && ops->module_insert) - ret = ops->module_insert(bus->upstream, id); ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -259,6 +259,8 @@ struct sfp { - unsigned int module_t_start_up; - bool tx_fault_ignore; - -+ const struct sfp_quirk *quirk; -+ - #if IS_ENABLED(CONFIG_HWMON) - struct sfp_diag diag; - struct delayed_work hwmon_probe; -@@ -315,6 +317,93 @@ static const struct of_device_id sfp_of_ - }; - MODULE_DEVICE_TABLE(of, sfp_of_match); - -+static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, -+ unsigned long *modes) -+{ -+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, modes); -+} -+ -+static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, -+ unsigned long *modes) -+{ -+ /* Ubiquiti U-Fiber Instant module claims that support all transceiver -+ * types including 10G Ethernet which is not truth. So clear all claimed -+ * modes and set only one mode which module supports: 1000baseX_Full. -+ */ -+ linkmode_zero(modes); -+ linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, modes); -+} -+ -+static const struct sfp_quirk sfp_quirks[] = { -+ { -+ // Alcatel Lucent G-010S-P can operate at 2500base-X, but -+ // incorrectly report 2500MBd NRZ in their EEPROM -+ .vendor = "ALCATELLUCENT", -+ .part = "G010SP", -+ .modes = sfp_quirk_2500basex, -+ }, { -+ // Alcatel Lucent G-010S-A can operate at 2500base-X, but -+ // report 3.2GBd NRZ in their EEPROM -+ .vendor = "ALCATELLUCENT", -+ .part = "3FE46541AA", -+ .modes = sfp_quirk_2500basex, -+ }, { -+ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd -+ // NRZ in their EEPROM -+ .vendor = "HUAWEI", -+ .part = "MA5671A", -+ .modes = sfp_quirk_2500basex, -+ }, { -+ // Lantech 8330-262D-E can operate at 2500base-X, but -+ // incorrectly report 2500MBd NRZ in their EEPROM -+ .vendor = "Lantech", -+ .part = "8330-262D-E", -+ .modes = sfp_quirk_2500basex, -+ }, { -+ .vendor = "UBNT", -+ .part = "UF-INSTANT", -+ .modes = sfp_quirk_ubnt_uf_instant, -+ }, -+}; -+ -+static size_t sfp_strlen(const char *str, size_t maxlen) -+{ -+ size_t size, i; -+ -+ /* Trailing characters should be filled with space chars */ -+ for (i = 0, size = 0; i < maxlen; i++) -+ if (str[i] != ' ') -+ size = i + 1; -+ -+ return size; -+} -+ -+static bool sfp_match(const char *qs, const char *str, size_t len) -+{ -+ if (!qs) -+ return true; -+ if (strlen(qs) != len) -+ return false; -+ return !strncmp(qs, str, len); -+} -+ -+static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id) -+{ -+ const struct sfp_quirk *q; -+ unsigned int i; -+ size_t vs, ps; -+ -+ vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name)); -+ ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn)); -+ -+ for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++) -+ if (sfp_match(q->vendor, id->base.vendor_name, vs) && -+ sfp_match(q->part, id->base.vendor_pn, ps)) -+ return q; -+ -+ return NULL; -+} -+ - static unsigned long poll_jiffies; - - static unsigned int sfp_gpio_get_state(struct sfp *sfp) -@@ -1966,6 +2055,8 @@ static int sfp_sm_mod_probe(struct sfp * - else - sfp->tx_fault_ignore = false; - -+ sfp->quirk = sfp_lookup_quirk(&id); -+ - return 0; - } - -@@ -2077,7 +2168,8 @@ static void sfp_sm_module(struct sfp *sf - break; - - /* Report the module insertion to the upstream device */ -- err = sfp_module_insert(sfp->sfp_bus, &sfp->id); -+ err = sfp_module_insert(sfp->sfp_bus, &sfp->id, -+ sfp->quirk); - if (err < 0) { - sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0); - break; ---- a/drivers/net/phy/sfp.h -+++ b/drivers/net/phy/sfp.h -@@ -6,6 +6,12 @@ - - struct sfp; - -+struct sfp_quirk { -+ const char *vendor; -+ const char *part; -+ void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); -+}; -+ - struct sfp_socket_ops { - void (*attach)(struct sfp *sfp); - void (*detach)(struct sfp *sfp); -@@ -23,7 +29,8 @@ int sfp_add_phy(struct sfp_bus *bus, str - void sfp_remove_phy(struct sfp_bus *bus); - void sfp_link_up(struct sfp_bus *bus); - void sfp_link_down(struct sfp_bus *bus); --int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id); -+int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id, -+ const struct sfp_quirk *quirk); - void sfp_module_remove(struct sfp_bus *bus); - int sfp_module_start(struct sfp_bus *bus); - void sfp_module_stop(struct sfp_bus *bus); diff --git a/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch b/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch deleted file mode 100644 index b076676cff6..00000000000 --- a/target/linux/generic/backport-6.1/785-v6.1-net-sfp-move-Alcatel-Lucent-3FE46541AA-fixup.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 275416754e9a262c97a1ad6f806a4bc6e0464aa2 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 13 Sep 2022 20:06:37 +0100 -Subject: [PATCH 1/1] net: sfp: move Alcatel Lucent 3FE46541AA fixup - -Add a new fixup mechanism to the SFP quirks, and use it for this -module. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp.c | 14 +++++++++----- - drivers/net/phy/sfp.h | 1 + - 2 files changed, 10 insertions(+), 5 deletions(-) - ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -317,6 +317,11 @@ static const struct of_device_id sfp_of_ - }; - MODULE_DEVICE_TABLE(of, sfp_of_match); - -+static void sfp_fixup_long_startup(struct sfp *sfp) -+{ -+ sfp->module_t_start_up = T_START_UP_BAD_GPON; -+} -+ - static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, - unsigned long *modes) - { -@@ -347,6 +352,7 @@ static const struct sfp_quirk sfp_quirks - .vendor = "ALCATELLUCENT", - .part = "3FE46541AA", - .modes = sfp_quirk_2500basex, -+ .fixup = sfp_fixup_long_startup, - }, { - // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd - // NRZ in their EEPROM -@@ -2043,11 +2049,7 @@ static int sfp_sm_mod_probe(struct sfp * - if (sfp->gpio[GPIO_LOS]) - sfp->state_hw_mask |= SFP_F_LOS; - -- if (!memcmp(id.base.vendor_name, "ALCATELLUCENT ", 16) && -- !memcmp(id.base.vendor_pn, "3FE46541AA ", 16)) -- sfp->module_t_start_up = T_START_UP_BAD_GPON; -- else -- sfp->module_t_start_up = T_START_UP; -+ sfp->module_t_start_up = T_START_UP; - - if (!memcmp(id.base.vendor_name, "HUAWEI ", 16) && - !memcmp(id.base.vendor_pn, "MA5671A ", 16)) -@@ -2056,6 +2058,8 @@ static int sfp_sm_mod_probe(struct sfp * - sfp->tx_fault_ignore = false; - - sfp->quirk = sfp_lookup_quirk(&id); -+ if (sfp->quirk && sfp->quirk->fixup) -+ sfp->quirk->fixup(sfp); - - return 0; - } ---- a/drivers/net/phy/sfp.h -+++ b/drivers/net/phy/sfp.h -@@ -10,6 +10,7 @@ struct sfp_quirk { - const char *vendor; - const char *part; - void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes); -+ void (*fixup)(struct sfp *sfp); - }; - - struct sfp_socket_ops { diff --git a/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch b/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch deleted file mode 100644 index 7f856e5b5be..00000000000 --- a/target/linux/generic/backport-6.1/786-v6.1-net-sfp-move-Huawei-MA5671A-fixup.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 5029be761161374a3624aa7b4670174c35449bf5 Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 13 Sep 2022 20:06:42 +0100 -Subject: [PATCH 1/1] net: sfp: move Huawei MA5671A fixup - -Move this module over to the new fixup mechanism. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -322,6 +322,11 @@ static void sfp_fixup_long_startup(struc - sfp->module_t_start_up = T_START_UP_BAD_GPON; - } - -+static void sfp_fixup_ignore_tx_fault(struct sfp *sfp) -+{ -+ sfp->tx_fault_ignore = true; -+} -+ - static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, - unsigned long *modes) - { -@@ -359,6 +364,7 @@ static const struct sfp_quirk sfp_quirks - .vendor = "HUAWEI", - .part = "MA5671A", - .modes = sfp_quirk_2500basex, -+ .fixup = sfp_fixup_ignore_tx_fault, - }, { - // Lantech 8330-262D-E can operate at 2500base-X, but - // incorrectly report 2500MBd NRZ in their EEPROM -@@ -2051,11 +2057,7 @@ static int sfp_sm_mod_probe(struct sfp * - - sfp->module_t_start_up = T_START_UP; - -- if (!memcmp(id.base.vendor_name, "HUAWEI ", 16) && -- !memcmp(id.base.vendor_pn, "MA5671A ", 16)) -- sfp->tx_fault_ignore = true; -- else -- sfp->tx_fault_ignore = false; -+ sfp->tx_fault_ignore = false; - - sfp->quirk = sfp_lookup_quirk(&id); - if (sfp->quirk && sfp->quirk->fixup) diff --git a/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch b/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch deleted file mode 100644 index 81108e19c16..00000000000 --- a/target/linux/generic/backport-6.1/787-v6.1-net-sfp-add-support-for-HALNy-GPON-SFP.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 73472c830eae5fce2107f7f086f1e6827d215caf Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Tue, 13 Sep 2022 20:06:48 +0100 -Subject: [PATCH 1/1] net: sfp: add support for HALNy GPON SFP - -Add a quirk for the HALNy HL-GSFP module, which appears to have an -inverted RX_LOS signal, and maybe uses TX_FAULT as a serial port -transmit pin. Rather than use these hardware signals, switch to -using software polling for these status signals. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: Jakub Kicinski ---- - drivers/net/phy/sfp-bus.c | 2 +- - drivers/net/phy/sfp.c | 21 ++++++++++++++++++--- - 2 files changed, 19 insertions(+), 4 deletions(-) - ---- a/drivers/net/phy/sfp-bus.c -+++ b/drivers/net/phy/sfp-bus.c -@@ -283,7 +283,7 @@ void sfp_parse_support(struct sfp_bus *b - phylink_set(modes, 2500baseX_Full); - } - -- if (bus->sfp_quirk) -+ if (bus->sfp_quirk && bus->sfp_quirk->modes) - bus->sfp_quirk->modes(id, modes); - - linkmode_or(support, support, modes); ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -327,6 +327,15 @@ static void sfp_fixup_ignore_tx_fault(st - sfp->tx_fault_ignore = true; - } - -+static void sfp_fixup_halny_gsfp(struct sfp *sfp) -+{ -+ /* Ignore the TX_FAULT and LOS signals on this module. -+ * these are possibly used for other purposes on this -+ * module, e.g. a serial port. -+ */ -+ sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS); -+} -+ - static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id, - unsigned long *modes) - { -@@ -359,6 +368,10 @@ static const struct sfp_quirk sfp_quirks - .modes = sfp_quirk_2500basex, - .fixup = sfp_fixup_long_startup, - }, { -+ .vendor = "HALNy", -+ .part = "HL-GSFP", -+ .fixup = sfp_fixup_halny_gsfp, -+ }, { - // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd - // NRZ in their EEPROM - .vendor = "HUAWEI", -@@ -375,16 +388,18 @@ static const struct sfp_quirk sfp_quirks - .vendor = "UBNT", - .part = "UF-INSTANT", - .modes = sfp_quirk_ubnt_uf_instant, -- }, -+ } - }; - - static size_t sfp_strlen(const char *str, size_t maxlen) - { - size_t size, i; - -- /* Trailing characters should be filled with space chars */ -+ /* Trailing characters should be filled with space chars, but -+ * some manufacturers can't read SFF-8472 and use NUL. -+ */ - for (i = 0, size = 0; i < maxlen; i++) -- if (str[i] != ' ') -+ if (str[i] != ' ' && str[i] != '\0') - size = i + 1; - - return size; diff --git a/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch b/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch deleted file mode 100644 index 413c73f5478..00000000000 --- a/target/linux/generic/backport-6.1/789-v6.3-net-sfp-add-quirk-enabling-2500Base-x-for-HG-MXPD-48.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ad651d68cee75e9ac20002254c4e5d09ee67a84b Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sun, 2 Apr 2023 12:44:37 +0100 -Subject: [PATCH] net: sfp: add quirk enabling 2500Base-x for HG MXPD-483II - -The HG MXPD-483II 1310nm SFP module is meant to operate with 2500Base-X, -however, in their EEPROM they incorrectly specify: - Transceiver type : Ethernet: 1000BASE-LX - ... - BR, Nominal : 2600MBd - -Use sfp_quirk_2500basex for this module to allow 2500Base-X mode anyway. - -https://forum.banana-pi.org/t/bpi-r3-sfp-module-compatibility/14573/60 - -Reported-by: chowtom -Tested-by: chowtom -Signed-off-by: Daniel Golle -Reviewed-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - drivers/net/phy/sfp.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -372,6 +372,10 @@ static const struct sfp_quirk sfp_quirks - .part = "HL-GSFP", - .fixup = sfp_fixup_halny_gsfp, - }, { -+ .vendor = "HG GENUINE", -+ .part = "MXPD-483II", -+ .modes = sfp_quirk_2500basex, -+ }, { - // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd - // NRZ in their EEPROM - .vendor = "HUAWEI", diff --git a/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch b/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch deleted file mode 100644 index 87d7ff6154d..00000000000 --- a/target/linux/generic/backport-6.1/790-v6.0-net-mii-add-mii_bmcr_encode_fixed.patch +++ /dev/null @@ -1,55 +0,0 @@ -From bdb6cfe7512f7a214815a3092f0be50963dcacbc Mon Sep 17 00:00:00 2001 -From: "Russell King (Oracle)" -Date: Sat, 18 Jun 2022 11:28:32 +0100 -Subject: [PATCH] net: mii: add mii_bmcr_encode_fixed() - -Add a function to encode a fixed speed/duplex to a BMCR value. - -Signed-off-by: Russell King (Oracle) -Signed-off-by: David S. Miller ---- - include/linux/mii.h | 35 +++++++++++++++++++++++++++++++++++ - 1 file changed, 35 insertions(+) - ---- a/include/linux/mii.h -+++ b/include/linux/mii.h -@@ -595,4 +595,39 @@ static inline u8 mii_resolve_flowctrl_fd - return cap; - } - -+/** -+ * mii_bmcr_encode_fixed - encode fixed speed/duplex settings to a BMCR value -+ * @speed: a SPEED_* value -+ * @duplex: a DUPLEX_* value -+ * -+ * Encode the speed and duplex to a BMCR value. 2500, 1000, 100 and 10 Mbps are -+ * supported. 2500Mbps is encoded to 1000Mbps. Other speeds are encoded as 10 -+ * Mbps. Unknown duplex values are encoded to half-duplex. -+ */ -+static inline u16 mii_bmcr_encode_fixed(int speed, int duplex) -+{ -+ u16 bmcr; -+ -+ switch (speed) { -+ case SPEED_2500: -+ case SPEED_1000: -+ bmcr = BMCR_SPEED1000; -+ break; -+ -+ case SPEED_100: -+ bmcr = BMCR_SPEED100; -+ break; -+ -+ case SPEED_10: -+ default: -+ bmcr = BMCR_SPEED10; -+ break; -+ } -+ -+ if (duplex == DUPLEX_FULL) -+ bmcr |= BMCR_FULLDPLX; -+ -+ return bmcr; -+} -+ - #endif /* __LINUX_MII_H__ */ diff --git a/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch b/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch deleted file mode 100644 index a2168aaba5f..00000000000 --- a/target/linux/generic/backport-6.1/797-v5.17-net-usb-ax88179_178a-add-TSO-feature.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 16b1c4e01c89ba07367461e0bc4cb84993c2d027 Mon Sep 17 00:00:00 2001 -From: Jacky Chou -Date: Mon, 15 Nov 2021 11:49:41 +0800 -Subject: [PATCH] net: usb: ax88179_178a: add TSO feature - -On low-effciency embedded platforms, transmission performance is poor -due to on Bulk-out with single packet. -Adding TSO feature improves the transmission performance and reduces -the number of interrupt caused by Bulk-out complete. - -Reference to module, net: usb: aqc111. - -Signed-off-by: Jacky Chou -Signed-off-by: David S. Miller ---- - drivers/net/usb/ax88179_178a.c | 17 +++++++++++------ - 1 file changed, 11 insertions(+), 6 deletions(-) - ---- a/drivers/net/usb/ax88179_178a.c -+++ b/drivers/net/usb/ax88179_178a.c -@@ -1377,11 +1377,12 @@ static int ax88179_bind(struct usbnet *d - dev->mii.phy_id = 0x03; - dev->mii.supports_gmii = 1; - -- dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | -- NETIF_F_RXCSUM; -+ dev->net->features |= NETIF_F_SG | NETIF_F_IP_CSUM | -+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM | NETIF_F_TSO; - -- dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | -- NETIF_F_RXCSUM; -+ dev->net->hw_features |= dev->net->features; -+ -+ netif_set_gso_max_size(dev->net, 16384); - - /* Enable checksum offload */ - *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP | -@@ -1587,17 +1588,19 @@ ax88179_tx_fixup(struct usbnet *dev, str - { - u32 tx_hdr1, tx_hdr2; - int frame_size = dev->maxpacket; -- int mss = skb_shinfo(skb)->gso_size; - int headroom; - void *ptr; - - tx_hdr1 = skb->len; -- tx_hdr2 = mss; -+ tx_hdr2 = skb_shinfo(skb)->gso_size; /* Set TSO mss */ - if (((skb->len + 8) % frame_size) == 0) - tx_hdr2 |= 0x80008000; /* Enable padding */ - - headroom = skb_headroom(skb) - 8; - -+ if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb)) -+ return NULL; -+ - if ((skb_header_cloned(skb) || headroom < 0) && - pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { - dev_kfree_skb_any(skb); -@@ -1608,6 +1611,8 @@ ax88179_tx_fixup(struct usbnet *dev, str - put_unaligned_le32(tx_hdr1, ptr); - put_unaligned_le32(tx_hdr2, ptr + 4); - -+ usbnet_set_skb_tx_stats(skb, (skb_shinfo(skb)->gso_segs ?: 1), 0); -+ - return skb; - } - diff --git a/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch b/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch deleted file mode 100644 index b1072ce6408..00000000000 --- a/target/linux/generic/backport-6.1/800-v6.0-0001-dt-bindings-leds-add-Broadcom-s-BCM63138-controller.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 13344f8ce8a0d98aa7f5d69ce3b47393c73a343b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Mon, 27 Dec 2021 15:59:04 +0100 -Subject: [PATCH] dt-bindings: leds: add Broadcom's BCM63138 controller -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Broadcom used 2 LEDs hardware blocks for their BCM63xx SoCs: -1. Older one (BCM6318, BCM6328, BCM6362, BCM63268, BCM6838) -2. Newer one (BCM6848, BCM6858, BCM63138, BCM63148, BCM63381, BCM68360) - -The newer one was also later also used on BCM4908 SoC. - -Old block is already documented in the leds-bcm6328.yaml. This binding -documents the new one which uses different registers & programming. It's -first used in BCM63138 thus the binding name. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Rob Herring -Reviewed-by: Florian Fainelli -Signed-off-by: Pavel Machek ---- - .../bindings/leds/leds-bcm63138.yaml | 95 +++++++++++++++++++ - 1 file changed, 95 insertions(+) - create mode 100644 Documentation/devicetree/bindings/leds/leds-bcm63138.yaml - ---- /dev/null -+++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml -@@ -0,0 +1,95 @@ -+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/leds/leds-bcm63138.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Broadcom's BCM63138 LEDs controller -+ -+maintainers: -+ - Rafał Miłecki -+ -+description: | -+ This LEDs controller was first used on BCM63138 and later reused on BCM4908, -+ BCM6848, BCM6858, BCM63138, BCM63148, BCM63381 and BCM68360 SoCs. -+ -+ It supports up to 32 LEDs that can be connected parallelly or serially. It -+ also includes limited support for hardware blinking. -+ -+ Binding serially connected LEDs isn't documented yet. -+ -+properties: -+ compatible: -+ oneOf: -+ - items: -+ - enum: -+ - brcm,bcm4908-leds -+ - brcm,bcm6848-leds -+ - brcm,bcm6858-leds -+ - brcm,bcm63148-leds -+ - brcm,bcm63381-leds -+ - brcm,bcm68360-leds -+ - const: brcm,bcm63138-leds -+ - const: brcm,bcm63138-leds -+ -+ reg: -+ maxItems: 1 -+ -+ "#address-cells": -+ const: 1 -+ -+ "#size-cells": -+ const: 0 -+ -+patternProperties: -+ "^led@[a-f0-9]+$": -+ type: object -+ -+ $ref: common.yaml# -+ -+ properties: -+ reg: -+ maxItems: 1 -+ description: LED pin number -+ -+ active-low: -+ type: boolean -+ description: Makes LED active low. -+ -+ required: -+ - reg -+ -+ unevaluatedProperties: false -+ -+required: -+ - reg -+ - "#address-cells" -+ - "#size-cells" -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ -+ leds@ff800800 { -+ compatible = "brcm,bcm4908-leds", "brcm,bcm63138-leds"; -+ reg = <0xff800800 0xdc>; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ led@0 { -+ reg = <0x0>; -+ function = LED_FUNCTION_POWER; -+ color = ; -+ default-state = "on"; -+ }; -+ -+ led@3 { -+ reg = <0x3>; -+ function = LED_FUNCTION_STATUS; -+ color = ; -+ active-low; -+ }; -+ }; diff --git a/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch b/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch deleted file mode 100644 index 376584574fc..00000000000 --- a/target/linux/generic/backport-6.1/800-v6.0-0002-leds-bcm63138-add-support-for-BCM63138-controller.patch +++ /dev/null @@ -1,356 +0,0 @@ -From a0ba692072d89075d0a75c7ad9df31f2c1ee9a1c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Mon, 27 Dec 2021 15:59:05 +0100 -Subject: [PATCH] leds: bcm63138: add support for BCM63138 controller -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It's a new controller first introduced in BCM63138 SoC. Later it was -also used in BCM4908, some BCM68xx and some BCM63xxx SoCs. - -Signed-off-by: Rafał Miłecki -Reviewed-by: Florian Fainelli -Signed-off-by: Pavel Machek ---- - drivers/leds/blink/Kconfig | 12 ++ - drivers/leds/blink/Makefile | 1 + - drivers/leds/blink/leds-bcm63138.c | 308 +++++++++++++++++++++++++++++ - 3 files changed, 321 insertions(+) - create mode 100644 drivers/leds/blink/leds-bcm63138.c - ---- a/drivers/leds/blink/Kconfig -+++ b/drivers/leds/blink/Kconfig -@@ -1,3 +1,15 @@ -+config LEDS_BCM63138 -+ tristate "LED Support for Broadcom BCM63138 SoC" -+ depends on LEDS_CLASS -+ depends on ARCH_BCM4908 || ARCH_BCM_5301X || BCM63XX || COMPILE_TEST -+ depends on HAS_IOMEM -+ depends on OF -+ default ARCH_BCM4908 -+ help -+ This option enables support for LED controller that is part of -+ BCM63138 SoC. The same hardware block is known to be also used -+ in BCM4908, BCM6848, BCM6858, BCM63148, BCM63381 and BCM68360. -+ - config LEDS_LGM - tristate "LED support for LGM SoC series" - depends on X86 || COMPILE_TEST ---- a/drivers/leds/blink/Makefile -+++ b/drivers/leds/blink/Makefile -@@ -1,2 +1,3 @@ - # SPDX-License-Identifier: GPL-2.0 -+obj-$(CONFIG_LEDS_BCM63138) += leds-bcm63138.o - obj-$(CONFIG_LEDS_LGM) += leds-lgm-sso.o ---- /dev/null -+++ b/drivers/leds/blink/leds-bcm63138.c -@@ -0,0 +1,308 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (C) 2021 Rafał Miłecki -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define BCM63138_MAX_LEDS 32 -+#define BCM63138_MAX_BRIGHTNESS 9 -+ -+#define BCM63138_LED_BITS 4 /* how many bits control a single LED */ -+#define BCM63138_LED_MASK ((1 << BCM63138_LED_BITS) - 1) /* 0xf */ -+#define BCM63138_LEDS_PER_REG (32 / BCM63138_LED_BITS) /* 8 */ -+ -+#define BCM63138_GLB_CTRL 0x00 -+#define BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL 0x00000002 -+#define BCM63138_GLB_CTRL_SERIAL_LED_EN_POL 0x00000008 -+#define BCM63138_MASK 0x04 -+#define BCM63138_HW_LED_EN 0x08 -+#define BCM63138_SERIAL_LED_SHIFT_SEL 0x0c -+#define BCM63138_FLASH_RATE_CTRL1 0x10 -+#define BCM63138_FLASH_RATE_CTRL2 0x14 -+#define BCM63138_FLASH_RATE_CTRL3 0x18 -+#define BCM63138_FLASH_RATE_CTRL4 0x1c -+#define BCM63138_BRIGHT_CTRL1 0x20 -+#define BCM63138_BRIGHT_CTRL2 0x24 -+#define BCM63138_BRIGHT_CTRL3 0x28 -+#define BCM63138_BRIGHT_CTRL4 0x2c -+#define BCM63138_POWER_LED_CFG 0x30 -+#define BCM63138_HW_POLARITY 0xb4 -+#define BCM63138_SW_DATA 0xb8 -+#define BCM63138_SW_POLARITY 0xbc -+#define BCM63138_PARALLEL_LED_POLARITY 0xc0 -+#define BCM63138_SERIAL_LED_POLARITY 0xc4 -+#define BCM63138_HW_LED_STATUS 0xc8 -+#define BCM63138_FLASH_CTRL_STATUS 0xcc -+#define BCM63138_FLASH_BRT_CTRL 0xd0 -+#define BCM63138_FLASH_P_LED_OUT_STATUS 0xd4 -+#define BCM63138_FLASH_S_LED_OUT_STATUS 0xd8 -+ -+struct bcm63138_leds { -+ struct device *dev; -+ void __iomem *base; -+ spinlock_t lock; -+}; -+ -+struct bcm63138_led { -+ struct bcm63138_leds *leds; -+ struct led_classdev cdev; -+ u32 pin; -+ bool active_low; -+}; -+ -+/* -+ * I/O access -+ */ -+ -+static void bcm63138_leds_write(struct bcm63138_leds *leds, unsigned int reg, -+ u32 data) -+{ -+ writel(data, leds->base + reg); -+} -+ -+static unsigned long bcm63138_leds_read(struct bcm63138_leds *leds, -+ unsigned int reg) -+{ -+ return readl(leds->base + reg); -+} -+ -+static void bcm63138_leds_update_bits(struct bcm63138_leds *leds, -+ unsigned int reg, u32 mask, u32 val) -+{ -+ WARN_ON(val & ~mask); -+ -+ bcm63138_leds_write(leds, reg, (bcm63138_leds_read(leds, reg) & ~mask) | (val & mask)); -+} -+ -+/* -+ * Helpers -+ */ -+ -+static void bcm63138_leds_set_flash_rate(struct bcm63138_leds *leds, -+ struct bcm63138_led *led, -+ u8 value) -+{ -+ int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4; -+ int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS; -+ -+ bcm63138_leds_update_bits(leds, BCM63138_FLASH_RATE_CTRL1 + reg_offset, -+ BCM63138_LED_MASK << shift, value << shift); -+} -+ -+static void bcm63138_leds_set_bright(struct bcm63138_leds *leds, -+ struct bcm63138_led *led, -+ u8 value) -+{ -+ int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4; -+ int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS; -+ -+ bcm63138_leds_update_bits(leds, BCM63138_BRIGHT_CTRL1 + reg_offset, -+ BCM63138_LED_MASK << shift, value << shift); -+} -+ -+static void bcm63138_leds_enable_led(struct bcm63138_leds *leds, -+ struct bcm63138_led *led, -+ enum led_brightness value) -+{ -+ u32 bit = BIT(led->pin); -+ -+ bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, -+ value == LED_OFF ? 0 : bit); -+} -+ -+/* -+ * API callbacks -+ */ -+ -+static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev, -+ enum led_brightness value) -+{ -+ struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); -+ struct bcm63138_leds *leds = led->leds; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&leds->lock, flags); -+ -+ bcm63138_leds_enable_led(leds, led, value); -+ if (!value) -+ bcm63138_leds_set_flash_rate(leds, led, 0); -+ else -+ bcm63138_leds_set_bright(leds, led, value); -+ -+ spin_unlock_irqrestore(&leds->lock, flags); -+} -+ -+static int bcm63138_leds_blink_set(struct led_classdev *led_cdev, -+ unsigned long *delay_on, -+ unsigned long *delay_off) -+{ -+ struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev); -+ struct bcm63138_leds *leds = led->leds; -+ unsigned long flags; -+ u8 value; -+ -+ if (!*delay_on && !*delay_off) { -+ *delay_on = 640; -+ *delay_off = 640; -+ } -+ -+ if (*delay_on != *delay_off) { -+ dev_dbg(led_cdev->dev, "Blinking at unequal delays is not supported\n"); -+ return -EINVAL; -+ } -+ -+ switch (*delay_on) { -+ case 1152 ... 1408: /* 1280 ms ± 10% */ -+ value = 0x7; -+ break; -+ case 576 ... 704: /* 640 ms ± 10% */ -+ value = 0x6; -+ break; -+ case 288 ... 352: /* 320 ms ± 10% */ -+ value = 0x5; -+ break; -+ case 126 ... 154: /* 140 ms ± 10% */ -+ value = 0x4; -+ break; -+ case 59 ... 72: /* 65 ms ± 10% */ -+ value = 0x3; -+ break; -+ default: -+ dev_dbg(led_cdev->dev, "Blinking delay value %lu is unsupported\n", -+ *delay_on); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&leds->lock, flags); -+ -+ bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS); -+ bcm63138_leds_set_flash_rate(leds, led, value); -+ -+ spin_unlock_irqrestore(&leds->lock, flags); -+ -+ return 0; -+} -+ -+/* -+ * LED driver -+ */ -+ -+static void bcm63138_leds_create_led(struct bcm63138_leds *leds, -+ struct device_node *np) -+{ -+ struct led_init_data init_data = { -+ .fwnode = of_fwnode_handle(np), -+ }; -+ struct device *dev = leds->dev; -+ struct bcm63138_led *led; -+ struct pinctrl *pinctrl; -+ u32 bit; -+ int err; -+ -+ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); -+ if (!led) { -+ dev_err(dev, "Failed to alloc LED\n"); -+ return; -+ } -+ -+ led->leds = leds; -+ -+ if (of_property_read_u32(np, "reg", &led->pin)) { -+ dev_err(dev, "Missing \"reg\" property in %pOF\n", np); -+ goto err_free; -+ } -+ -+ if (led->pin >= BCM63138_MAX_LEDS) { -+ dev_err(dev, "Invalid \"reg\" value %d\n", led->pin); -+ goto err_free; -+ } -+ -+ led->active_low = of_property_read_bool(np, "active-low"); -+ -+ led->cdev.max_brightness = BCM63138_MAX_BRIGHTNESS; -+ led->cdev.brightness_set = bcm63138_leds_brightness_set; -+ led->cdev.blink_set = bcm63138_leds_blink_set; -+ -+ err = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); -+ if (err) { -+ dev_err(dev, "Failed to register LED %pOF: %d\n", np, err); -+ goto err_free; -+ } -+ -+ pinctrl = devm_pinctrl_get_select_default(led->cdev.dev); -+ if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) { -+ dev_warn(led->cdev.dev, "Failed to select %pOF pinctrl: %ld\n", -+ np, PTR_ERR(pinctrl)); -+ } -+ -+ bit = BIT(led->pin); -+ bcm63138_leds_update_bits(leds, BCM63138_PARALLEL_LED_POLARITY, bit, -+ led->active_low ? 0 : bit); -+ bcm63138_leds_update_bits(leds, BCM63138_HW_LED_EN, bit, 0); -+ bcm63138_leds_set_flash_rate(leds, led, 0); -+ bcm63138_leds_enable_led(leds, led, led->cdev.brightness); -+ -+ return; -+ -+err_free: -+ devm_kfree(dev, led); -+} -+ -+static int bcm63138_leds_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = dev_of_node(&pdev->dev); -+ struct device *dev = &pdev->dev; -+ struct bcm63138_leds *leds; -+ struct device_node *child; -+ -+ leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL); -+ if (!leds) -+ return -ENOMEM; -+ -+ leds->dev = dev; -+ -+ leds->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(leds->base)) -+ return PTR_ERR(leds->base); -+ -+ spin_lock_init(&leds->lock); -+ -+ bcm63138_leds_write(leds, BCM63138_GLB_CTRL, -+ BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL | -+ BCM63138_GLB_CTRL_SERIAL_LED_EN_POL); -+ bcm63138_leds_write(leds, BCM63138_HW_LED_EN, 0); -+ bcm63138_leds_write(leds, BCM63138_SERIAL_LED_POLARITY, 0); -+ bcm63138_leds_write(leds, BCM63138_PARALLEL_LED_POLARITY, 0); -+ -+ for_each_available_child_of_node(np, child) { -+ bcm63138_leds_create_led(leds, child); -+ } -+ -+ return 0; -+} -+ -+static const struct of_device_id bcm63138_leds_of_match_table[] = { -+ { .compatible = "brcm,bcm63138-leds", }, -+ { }, -+}; -+ -+static struct platform_driver bcm63138_leds_driver = { -+ .probe = bcm63138_leds_probe, -+ .driver = { -+ .name = "leds-bcm63xxx", -+ .of_match_table = bcm63138_leds_of_match_table, -+ }, -+}; -+ -+module_platform_driver(bcm63138_leds_driver); -+ -+MODULE_AUTHOR("Rafał Miłecki"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table); diff --git a/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch b/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch deleted file mode 100644 index 483826abed5..00000000000 --- a/target/linux/generic/backport-6.1/801-v6.0-0001-dt-bindings-leds-leds-bcm63138-unify-full-stops-in-d.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 13b64a0c19059b38150c79d65d350ae44034c5df Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Sun, 17 Jul 2022 14:42:46 +0200 -Subject: [PATCH] dt-bindings: leds: leds-bcm63138: unify full stops in - descriptions -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Description of "reg" doesn't have full stop at the end. It makes sense -as it's a one-sentence only. Use the same style for "active-low". - -Reported-by: Pavel Machek -Signed-off-by: Rafał Miłecki -Signed-off-by: Pavel Machek ---- - Documentation/devicetree/bindings/leds/leds-bcm63138.yaml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml -+++ b/Documentation/devicetree/bindings/leds/leds-bcm63138.yaml -@@ -54,7 +54,7 @@ patternProperties: - - active-low: - type: boolean -- description: Makes LED active low. -+ description: Makes LED active low - - required: - - reg diff --git a/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch b/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch deleted file mode 100644 index 5430b1f0844..00000000000 --- a/target/linux/generic/backport-6.1/801-v6.0-0002-leds-add-help-info-about-BCM63138-module-name.patch +++ /dev/null @@ -1,28 +0,0 @@ -From bcc607cdbb1f931111196699426f0cb83bfb296a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Sun, 17 Jul 2022 14:42:47 +0200 -Subject: [PATCH] leds: add help info about BCM63138 module name -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -It's what we do for all other LEDs drivers. - -Reported-by: Pavel Machek -Signed-off-by: Rafał Miłecki -Signed-off-by: Pavel Machek ---- - drivers/leds/blink/Kconfig | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/leds/blink/Kconfig -+++ b/drivers/leds/blink/Kconfig -@@ -10,6 +10,8 @@ config LEDS_BCM63138 - BCM63138 SoC. The same hardware block is known to be also used - in BCM4908, BCM6848, BCM6858, BCM63148, BCM63381 and BCM68360. - -+ If compiled as module it will be called leds-bcm63138. -+ - config LEDS_LGM - tristate "LED support for LGM SoC series" - depends on X86 || COMPILE_TEST diff --git a/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch b/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch deleted file mode 100644 index e125a54613b..00000000000 --- a/target/linux/generic/backport-6.1/801-v6.0-0003-leds-leds-bcm63138-get-rid-of-LED_OFF.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 92cfc71ee2ddfb499ed53e21b28bdf8739bc70bc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Sun, 17 Jul 2022 14:42:48 +0200 -Subject: [PATCH] leds: leds-bcm63138: get rid of LED_OFF -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The whole "enum led_brightness" is marked as obsolete. Replace it with a -(non-)zero check. - -Reported-by: Pavel Machek -Signed-off-by: Rafał Miłecki -Signed-off-by: Pavel Machek ---- - drivers/leds/blink/leds-bcm63138.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/leds/blink/leds-bcm63138.c -+++ b/drivers/leds/blink/leds-bcm63138.c -@@ -113,8 +113,7 @@ static void bcm63138_leds_enable_led(str - { - u32 bit = BIT(led->pin); - -- bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, -- value == LED_OFF ? 0 : bit); -+ bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, value ? bit : 0); - } - - /* diff --git a/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch b/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch deleted file mode 100644 index ebab8c7c736..00000000000 --- a/target/linux/generic/backport-6.1/802-v5.16-0001-nvmem-core-rework-nvmem-cell-instance-creation.patch +++ /dev/null @@ -1,456 +0,0 @@ -From 7ae6478b304bc004c3139b422665b0e23b57f05c Mon Sep 17 00:00:00 2001 -From: Srinivas Kandagatla -Date: Wed, 13 Oct 2021 14:19:55 +0100 -Subject: [PATCH] nvmem: core: rework nvmem cell instance creation - -In the existing design, we do not create a instance per nvmem cell consumer -but we directly refer cell from nvmem cell list that are added to provider. - -However this design has some limitations when consumers want to assign name -or connection id the nvmem cell instance, ex: via "nvmem-cell-names" or -id in nvmem_cell_get(id). - -Having a name associated with nvmem cell consumer instance will help -provider drivers in performing post processing of nvmem cell data if required -before data is seen by the consumers. This is pretty normal with some vendors -storing nvmem cells like mac-address in a vendor specific data layouts that -are not directly usable by the consumer drivers. - -With this patch nvmem cell will be created dynamically during nvmem_cell_get -and destroyed in nvmem_cell_put, allowing consumers to associate name with -nvmem cell consumer instance. - -With this patch a new struct nvmem_cell_entry replaces struct nvmem_cell -for storing nvmem cell information within the core. -This patch does not change nvmem-consumer interface based on nvmem_cell. - -Tested-by: Joakim Zhang -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20211013131957.30271-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 165 +++++++++++++++++++++++++++---------------- - 1 file changed, 105 insertions(+), 60 deletions(-) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -45,8 +45,7 @@ struct nvmem_device { - #define to_nvmem_device(d) container_of(d, struct nvmem_device, dev) - - #define FLAG_COMPAT BIT(0) -- --struct nvmem_cell { -+struct nvmem_cell_entry { - const char *name; - int offset; - int bytes; -@@ -57,6 +56,11 @@ struct nvmem_cell { - struct list_head node; - }; - -+struct nvmem_cell { -+ struct nvmem_cell_entry *entry; -+ const char *id; -+}; -+ - static DEFINE_MUTEX(nvmem_mutex); - static DEFINE_IDA(nvmem_ida); - -@@ -424,7 +428,7 @@ static struct bus_type nvmem_bus_type = - .name = "nvmem", - }; - --static void nvmem_cell_drop(struct nvmem_cell *cell) -+static void nvmem_cell_entry_drop(struct nvmem_cell_entry *cell) - { - blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_REMOVE, cell); - mutex_lock(&nvmem_mutex); -@@ -437,13 +441,13 @@ static void nvmem_cell_drop(struct nvmem - - static void nvmem_device_remove_all_cells(const struct nvmem_device *nvmem) - { -- struct nvmem_cell *cell, *p; -+ struct nvmem_cell_entry *cell, *p; - - list_for_each_entry_safe(cell, p, &nvmem->cells, node) -- nvmem_cell_drop(cell); -+ nvmem_cell_entry_drop(cell); - } - --static void nvmem_cell_add(struct nvmem_cell *cell) -+static void nvmem_cell_entry_add(struct nvmem_cell_entry *cell) - { - mutex_lock(&nvmem_mutex); - list_add_tail(&cell->node, &cell->nvmem->cells); -@@ -451,9 +455,9 @@ static void nvmem_cell_add(struct nvmem_ - blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); - } - --static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem, -- const struct nvmem_cell_info *info, -- struct nvmem_cell *cell) -+static int nvmem_cell_info_to_nvmem_cell_entry_nodup(struct nvmem_device *nvmem, -+ const struct nvmem_cell_info *info, -+ struct nvmem_cell_entry *cell) - { - cell->nvmem = nvmem; - cell->offset = info->offset; -@@ -477,13 +481,13 @@ static int nvmem_cell_info_to_nvmem_cell - return 0; - } - --static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, -- const struct nvmem_cell_info *info, -- struct nvmem_cell *cell) -+static int nvmem_cell_info_to_nvmem_cell_entry(struct nvmem_device *nvmem, -+ const struct nvmem_cell_info *info, -+ struct nvmem_cell_entry *cell) - { - int err; - -- err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell); -+ err = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, cell); - if (err) - return err; - -@@ -507,7 +511,7 @@ static int nvmem_add_cells(struct nvmem_ - const struct nvmem_cell_info *info, - int ncells) - { -- struct nvmem_cell **cells; -+ struct nvmem_cell_entry **cells; - int i, rval; - - cells = kcalloc(ncells, sizeof(*cells), GFP_KERNEL); -@@ -521,13 +525,13 @@ static int nvmem_add_cells(struct nvmem_ - goto err; - } - -- rval = nvmem_cell_info_to_nvmem_cell(nvmem, &info[i], cells[i]); -+ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, &info[i], cells[i]); - if (rval) { - kfree(cells[i]); - goto err; - } - -- nvmem_cell_add(cells[i]); -+ nvmem_cell_entry_add(cells[i]); - } - - /* remove tmp array */ -@@ -536,7 +540,7 @@ static int nvmem_add_cells(struct nvmem_ - return 0; - err: - while (i--) -- nvmem_cell_drop(cells[i]); -+ nvmem_cell_entry_drop(cells[i]); - - kfree(cells); - -@@ -573,7 +577,7 @@ static int nvmem_add_cells_from_table(st - { - const struct nvmem_cell_info *info; - struct nvmem_cell_table *table; -- struct nvmem_cell *cell; -+ struct nvmem_cell_entry *cell; - int rval = 0, i; - - mutex_lock(&nvmem_cell_mutex); -@@ -588,15 +592,13 @@ static int nvmem_add_cells_from_table(st - goto out; - } - -- rval = nvmem_cell_info_to_nvmem_cell(nvmem, -- info, -- cell); -+ rval = nvmem_cell_info_to_nvmem_cell_entry(nvmem, info, cell); - if (rval) { - kfree(cell); - goto out; - } - -- nvmem_cell_add(cell); -+ nvmem_cell_entry_add(cell); - } - } - } -@@ -606,10 +608,10 @@ out: - return rval; - } - --static struct nvmem_cell * --nvmem_find_cell_by_name(struct nvmem_device *nvmem, const char *cell_id) -+static struct nvmem_cell_entry * -+nvmem_find_cell_entry_by_name(struct nvmem_device *nvmem, const char *cell_id) - { -- struct nvmem_cell *iter, *cell = NULL; -+ struct nvmem_cell_entry *iter, *cell = NULL; - - mutex_lock(&nvmem_mutex); - list_for_each_entry(iter, &nvmem->cells, node) { -@@ -680,7 +682,7 @@ static int nvmem_add_cells_from_of(struc - { - struct device_node *parent, *child; - struct device *dev = &nvmem->dev; -- struct nvmem_cell *cell; -+ struct nvmem_cell_entry *cell; - const __be32 *addr; - int len; - -@@ -729,7 +731,7 @@ static int nvmem_add_cells_from_of(struc - } - - cell->np = of_node_get(child); -- nvmem_cell_add(cell); -+ nvmem_cell_entry_add(cell); - } - - return 0; -@@ -1142,9 +1144,33 @@ struct nvmem_device *devm_nvmem_device_g - } - EXPORT_SYMBOL_GPL(devm_nvmem_device_get); - -+static struct nvmem_cell *nvmem_create_cell(struct nvmem_cell_entry *entry, const char *id) -+{ -+ struct nvmem_cell *cell; -+ const char *name = NULL; -+ -+ cell = kzalloc(sizeof(*cell), GFP_KERNEL); -+ if (!cell) -+ return ERR_PTR(-ENOMEM); -+ -+ if (id) { -+ name = kstrdup_const(id, GFP_KERNEL); -+ if (!name) { -+ kfree(cell); -+ return ERR_PTR(-ENOMEM); -+ } -+ } -+ -+ cell->id = name; -+ cell->entry = entry; -+ -+ return cell; -+} -+ - static struct nvmem_cell * - nvmem_cell_get_from_lookup(struct device *dev, const char *con_id) - { -+ struct nvmem_cell_entry *cell_entry; - struct nvmem_cell *cell = ERR_PTR(-ENOENT); - struct nvmem_cell_lookup *lookup; - struct nvmem_device *nvmem; -@@ -1169,11 +1195,15 @@ nvmem_cell_get_from_lookup(struct device - break; - } - -- cell = nvmem_find_cell_by_name(nvmem, -- lookup->cell_name); -- if (!cell) { -+ cell_entry = nvmem_find_cell_entry_by_name(nvmem, -+ lookup->cell_name); -+ if (!cell_entry) { - __nvmem_device_put(nvmem); - cell = ERR_PTR(-ENOENT); -+ } else { -+ cell = nvmem_create_cell(cell_entry, con_id); -+ if (IS_ERR(cell)) -+ __nvmem_device_put(nvmem); - } - break; - } -@@ -1184,10 +1214,10 @@ nvmem_cell_get_from_lookup(struct device - } - - #if IS_ENABLED(CONFIG_OF) --static struct nvmem_cell * --nvmem_find_cell_by_node(struct nvmem_device *nvmem, struct device_node *np) -+static struct nvmem_cell_entry * -+nvmem_find_cell_entry_by_node(struct nvmem_device *nvmem, struct device_node *np) - { -- struct nvmem_cell *iter, *cell = NULL; -+ struct nvmem_cell_entry *iter, *cell = NULL; - - mutex_lock(&nvmem_mutex); - list_for_each_entry(iter, &nvmem->cells, node) { -@@ -1217,6 +1247,7 @@ struct nvmem_cell *of_nvmem_cell_get(str - { - struct device_node *cell_np, *nvmem_np; - struct nvmem_device *nvmem; -+ struct nvmem_cell_entry *cell_entry; - struct nvmem_cell *cell; - int index = 0; - -@@ -1237,12 +1268,16 @@ struct nvmem_cell *of_nvmem_cell_get(str - if (IS_ERR(nvmem)) - return ERR_CAST(nvmem); - -- cell = nvmem_find_cell_by_node(nvmem, cell_np); -- if (!cell) { -+ cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); -+ if (!cell_entry) { - __nvmem_device_put(nvmem); - return ERR_PTR(-ENOENT); - } - -+ cell = nvmem_create_cell(cell_entry, id); -+ if (IS_ERR(cell)) -+ __nvmem_device_put(nvmem); -+ - return cell; - } - EXPORT_SYMBOL_GPL(of_nvmem_cell_get); -@@ -1348,13 +1383,17 @@ EXPORT_SYMBOL(devm_nvmem_cell_put); - */ - void nvmem_cell_put(struct nvmem_cell *cell) - { -- struct nvmem_device *nvmem = cell->nvmem; -+ struct nvmem_device *nvmem = cell->entry->nvmem; -+ -+ if (cell->id) -+ kfree_const(cell->id); - -+ kfree(cell); - __nvmem_device_put(nvmem); - } - EXPORT_SYMBOL_GPL(nvmem_cell_put); - --static void nvmem_shift_read_buffer_in_place(struct nvmem_cell *cell, void *buf) -+static void nvmem_shift_read_buffer_in_place(struct nvmem_cell_entry *cell, void *buf) - { - u8 *p, *b; - int i, extra, bit_offset = cell->bit_offset; -@@ -1388,8 +1427,8 @@ static void nvmem_shift_read_buffer_in_p - } - - static int __nvmem_cell_read(struct nvmem_device *nvmem, -- struct nvmem_cell *cell, -- void *buf, size_t *len) -+ struct nvmem_cell_entry *cell, -+ void *buf, size_t *len, const char *id) - { - int rc; - -@@ -1420,18 +1459,18 @@ static int __nvmem_cell_read(struct nvme - */ - void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) - { -- struct nvmem_device *nvmem = cell->nvmem; -+ struct nvmem_device *nvmem = cell->entry->nvmem; - u8 *buf; - int rc; - - if (!nvmem) - return ERR_PTR(-EINVAL); - -- buf = kzalloc(cell->bytes, GFP_KERNEL); -+ buf = kzalloc(cell->entry->bytes, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - -- rc = __nvmem_cell_read(nvmem, cell, buf, len); -+ rc = __nvmem_cell_read(nvmem, cell->entry, buf, len, cell->id); - if (rc) { - kfree(buf); - return ERR_PTR(rc); -@@ -1441,7 +1480,7 @@ void *nvmem_cell_read(struct nvmem_cell - } - EXPORT_SYMBOL_GPL(nvmem_cell_read); - --static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell *cell, -+static void *nvmem_cell_prepare_write_buffer(struct nvmem_cell_entry *cell, - u8 *_buf, int len) - { - struct nvmem_device *nvmem = cell->nvmem; -@@ -1494,16 +1533,7 @@ err: - return ERR_PTR(rc); - } - --/** -- * nvmem_cell_write() - Write to a given nvmem cell -- * -- * @cell: nvmem cell to be written. -- * @buf: Buffer to be written. -- * @len: length of buffer to be written to nvmem cell. -- * -- * Return: length of bytes written or negative on failure. -- */ --int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) -+static int __nvmem_cell_entry_write(struct nvmem_cell_entry *cell, void *buf, size_t len) - { - struct nvmem_device *nvmem = cell->nvmem; - int rc; -@@ -1529,6 +1559,21 @@ int nvmem_cell_write(struct nvmem_cell * - - return len; - } -+ -+/** -+ * nvmem_cell_write() - Write to a given nvmem cell -+ * -+ * @cell: nvmem cell to be written. -+ * @buf: Buffer to be written. -+ * @len: length of buffer to be written to nvmem cell. -+ * -+ * Return: length of bytes written or negative on failure. -+ */ -+int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) -+{ -+ return __nvmem_cell_entry_write(cell->entry, buf, len); -+} -+ - EXPORT_SYMBOL_GPL(nvmem_cell_write); - - static int nvmem_cell_read_common(struct device *dev, const char *cell_id, -@@ -1631,7 +1676,7 @@ static const void *nvmem_cell_read_varia - if (IS_ERR(cell)) - return cell; - -- nbits = cell->nbits; -+ nbits = cell->entry->nbits; - buf = nvmem_cell_read(cell, len); - nvmem_cell_put(cell); - if (IS_ERR(buf)) -@@ -1727,18 +1772,18 @@ EXPORT_SYMBOL_GPL(nvmem_cell_read_variab - ssize_t nvmem_device_cell_read(struct nvmem_device *nvmem, - struct nvmem_cell_info *info, void *buf) - { -- struct nvmem_cell cell; -+ struct nvmem_cell_entry cell; - int rc; - ssize_t len; - - if (!nvmem) - return -EINVAL; - -- rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); -+ rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); - if (rc) - return rc; - -- rc = __nvmem_cell_read(nvmem, &cell, buf, &len); -+ rc = __nvmem_cell_read(nvmem, &cell, buf, &len, NULL); - if (rc) - return rc; - -@@ -1758,17 +1803,17 @@ EXPORT_SYMBOL_GPL(nvmem_device_cell_read - int nvmem_device_cell_write(struct nvmem_device *nvmem, - struct nvmem_cell_info *info, void *buf) - { -- struct nvmem_cell cell; -+ struct nvmem_cell_entry cell; - int rc; - - if (!nvmem) - return -EINVAL; - -- rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); -+ rc = nvmem_cell_info_to_nvmem_cell_entry_nodup(nvmem, info, &cell); - if (rc) - return rc; - -- return nvmem_cell_write(&cell, buf, cell.bytes); -+ return __nvmem_cell_entry_write(&cell, buf, cell.bytes); - } - EXPORT_SYMBOL_GPL(nvmem_device_cell_write); - diff --git a/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch b/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch deleted file mode 100644 index df264add245..00000000000 --- a/target/linux/generic/backport-6.1/802-v5.16-0002-nvmem-core-add-nvmem-cell-post-processing-callback.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 5008062f1c3f5af3acf86164aa6fcc77b0c7bdce Mon Sep 17 00:00:00 2001 -From: Srinivas Kandagatla -Date: Wed, 13 Oct 2021 14:19:56 +0100 -Subject: [PATCH] nvmem: core: add nvmem cell post processing callback - -Some NVMEM providers have certain nvmem cells encoded, which requires -post processing before actually using it. - -For example mac-address is stored in either in ascii or delimited or reverse-order. - -Having a post-process callback hook to provider drivers would enable them to -do this vendor specific post processing before nvmem consumers see it. - -Tested-by: Joakim Zhang -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20211013131957.30271-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 9 +++++++++ - include/linux/nvmem-provider.h | 5 +++++ - 2 files changed, 14 insertions(+) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -38,6 +38,7 @@ struct nvmem_device { - unsigned int nkeepout; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; -+ nvmem_cell_post_process_t cell_post_process; - struct gpio_desc *wp_gpio; - void *priv; - }; -@@ -799,6 +800,7 @@ struct nvmem_device *nvmem_register(cons - nvmem->type = config->type; - nvmem->reg_read = config->reg_read; - nvmem->reg_write = config->reg_write; -+ nvmem->cell_post_process = config->cell_post_process; - nvmem->keepout = config->keepout; - nvmem->nkeepout = config->nkeepout; - if (config->of_node) -@@ -1441,6 +1443,13 @@ static int __nvmem_cell_read(struct nvme - if (cell->bit_offset || cell->nbits) - nvmem_shift_read_buffer_in_place(cell, buf); - -+ if (nvmem->cell_post_process) { -+ rc = nvmem->cell_post_process(nvmem->priv, id, -+ cell->offset, buf, cell->bytes); -+ if (rc) -+ return rc; -+ } -+ - if (len) - *len = cell->bytes; - ---- a/include/linux/nvmem-provider.h -+++ b/include/linux/nvmem-provider.h -@@ -19,6 +19,9 @@ typedef int (*nvmem_reg_read_t)(void *pr - void *val, size_t bytes); - typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset, - void *val, size_t bytes); -+/* used for vendor specific post processing of cell data */ -+typedef int (*nvmem_cell_post_process_t)(void *priv, const char *id, unsigned int offset, -+ void *buf, size_t bytes); - - enum nvmem_type { - NVMEM_TYPE_UNKNOWN = 0, -@@ -62,6 +65,7 @@ struct nvmem_keepout { - * @no_of_node: Device should not use the parent's of_node even if it's !NULL. - * @reg_read: Callback to read data. - * @reg_write: Callback to write data. -+ * @cell_post_process: Callback for vendor specific post processing of cell data - * @size: Device size. - * @word_size: Minimum read/write access granularity. - * @stride: Minimum read/write access stride. -@@ -92,6 +96,7 @@ struct nvmem_config { - bool no_of_node; - nvmem_reg_read_t reg_read; - nvmem_reg_write_t reg_write; -+ nvmem_cell_post_process_t cell_post_process; - int size; - int word_size; - int stride; diff --git a/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch b/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch deleted file mode 100644 index ee19228270d..00000000000 --- a/target/linux/generic/backport-6.1/802-v5.16-0003-nvmem-imx-ocotp-add-support-for-post-processing.patch +++ /dev/null @@ -1,92 +0,0 @@ -From d0221a780cbc99fec6c27a98dba2828dc5735c00 Mon Sep 17 00:00:00 2001 -From: Srinivas Kandagatla -Date: Wed, 13 Oct 2021 14:19:57 +0100 -Subject: [PATCH] nvmem: imx-ocotp: add support for post processing - -Add .cell_post_process callback for imx-ocotp to deal with MAC address, -since MAC address need to be reversed byte for some i.MX SoCs. - -Tested-by: Joakim Zhang -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20211013131957.30271-4-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/imx-ocotp.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - ---- a/drivers/nvmem/imx-ocotp.c -+++ b/drivers/nvmem/imx-ocotp.c -@@ -97,6 +97,7 @@ struct ocotp_params { - unsigned int bank_address_words; - void (*set_timing)(struct ocotp_priv *priv); - struct ocotp_ctrl_reg ctrl; -+ bool reverse_mac_address; - }; - - static int imx_ocotp_wait_for_busy(struct ocotp_priv *priv, u32 flags) -@@ -221,6 +222,25 @@ read_end: - return ret; - } - -+static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset, -+ void *data, size_t bytes) -+{ -+ struct ocotp_priv *priv = context; -+ -+ /* Deal with some post processing of nvmem cell data */ -+ if (id && !strcmp(id, "mac-address")) { -+ if (priv->params->reverse_mac_address) { -+ u8 *buf = data; -+ int i; -+ -+ for (i = 0; i < bytes/2; i++) -+ swap(buf[i], buf[bytes - i - 1]); -+ } -+ } -+ -+ return 0; -+} -+ - static void imx_ocotp_set_imx6_timing(struct ocotp_priv *priv) - { - unsigned long clk_rate; -@@ -468,6 +488,7 @@ static struct nvmem_config imx_ocotp_nvm - .stride = 1, - .reg_read = imx_ocotp_read, - .reg_write = imx_ocotp_write, -+ .cell_post_process = imx_ocotp_cell_pp, - }; - - static const struct ocotp_params imx6q_params = { -@@ -530,6 +551,7 @@ static const struct ocotp_params imx8mq_ - .bank_address_words = 0, - .set_timing = imx_ocotp_set_imx6_timing, - .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, -+ .reverse_mac_address = true, - }; - - static const struct ocotp_params imx8mm_params = { -@@ -537,6 +559,7 @@ static const struct ocotp_params imx8mm_ - .bank_address_words = 0, - .set_timing = imx_ocotp_set_imx6_timing, - .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, -+ .reverse_mac_address = true, - }; - - static const struct ocotp_params imx8mn_params = { -@@ -544,6 +567,7 @@ static const struct ocotp_params imx8mn_ - .bank_address_words = 0, - .set_timing = imx_ocotp_set_imx6_timing, - .ctrl = IMX_OCOTP_BM_CTRL_DEFAULT, -+ .reverse_mac_address = true, - }; - - static const struct ocotp_params imx8mp_params = { -@@ -551,6 +575,7 @@ static const struct ocotp_params imx8mp_ - .bank_address_words = 0, - .set_timing = imx_ocotp_set_imx6_timing, - .ctrl = IMX_OCOTP_BM_CTRL_8MP, -+ .reverse_mac_address = true, - }; - - static const struct of_device_id imx_ocotp_dt_ids[] = { diff --git a/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch b/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch deleted file mode 100644 index 785bfe53f54..00000000000 --- a/target/linux/generic/backport-6.1/803-v5.17-0002-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 98e2c4efae214fb7086cac9117616eb6ea11475d Mon Sep 17 00:00:00 2001 -From: Chunfeng Yun -Date: Thu, 9 Dec 2021 17:42:34 +0000 -Subject: [PATCH] nvmem: mtk-efuse: support minimum one byte access stride and - granularity - -In order to support nvmem bits property, should support minimum 1 byte -read stride and minimum 1 byte read granularity at the same time. - -Signed-off-by: Chunfeng Yun -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20211209174235.14049-4-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/mtk-efuse.c | 13 +++++++------ - 1 file changed, 7 insertions(+), 6 deletions(-) - ---- a/drivers/nvmem/mtk-efuse.c -+++ b/drivers/nvmem/mtk-efuse.c -@@ -19,11 +19,12 @@ static int mtk_reg_read(void *context, - unsigned int reg, void *_val, size_t bytes) - { - struct mtk_efuse_priv *priv = context; -- u32 *val = _val; -- int i = 0, words = bytes / 4; -+ void __iomem *addr = priv->base + reg; -+ u8 *val = _val; -+ int i; - -- while (words--) -- *val++ = readl(priv->base + reg + (i++ * 4)); -+ for (i = 0; i < bytes; i++, val++) -+ *val = readb(addr + i); - - return 0; - } -@@ -45,8 +46,8 @@ static int mtk_efuse_probe(struct platfo - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); - -- econfig.stride = 4; -- econfig.word_size = 4; -+ econfig.stride = 1; -+ econfig.word_size = 1; - econfig.reg_read = mtk_reg_read; - econfig.size = resource_size(res); - econfig.priv = priv; diff --git a/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch b/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch deleted file mode 100644 index ca5357c8d98..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0001-nvmem-core-Remove-unused-devm_nvmem_unregister.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 190fae468592bc2f0efc8b928920f8f712b5831e Mon Sep 17 00:00:00 2001 -From: Andy Shevchenko -Date: Sun, 20 Feb 2022 15:15:15 +0000 -Subject: [PATCH] nvmem: core: Remove unused devm_nvmem_unregister() - -There are no users and seems no will come of the devm_nvmem_unregister(). -Remove the function and remove the unused devm_nvmem_match() along with it. - -Signed-off-by: Andy Shevchenko -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 22 ---------------------- - include/linux/nvmem-provider.h | 8 -------- - 2 files changed, 30 deletions(-) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -943,28 +943,6 @@ struct nvmem_device *devm_nvmem_register - } - EXPORT_SYMBOL_GPL(devm_nvmem_register); - --static int devm_nvmem_match(struct device *dev, void *res, void *data) --{ -- struct nvmem_device **r = res; -- -- return *r == data; --} -- --/** -- * devm_nvmem_unregister() - Unregister previously registered managed nvmem -- * device. -- * -- * @dev: Device that uses the nvmem device. -- * @nvmem: Pointer to previously registered nvmem device. -- * -- * Return: Will be negative on error or zero on success. -- */ --int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) --{ -- return devres_release(dev, devm_nvmem_release, devm_nvmem_match, nvmem); --} --EXPORT_SYMBOL(devm_nvmem_unregister); -- - static struct nvmem_device *__nvmem_device_get(void *data, - int (*match)(struct device *dev, const void *data)) - { ---- a/include/linux/nvmem-provider.h -+++ b/include/linux/nvmem-provider.h -@@ -133,8 +133,6 @@ void nvmem_unregister(struct nvmem_devic - struct nvmem_device *devm_nvmem_register(struct device *dev, - const struct nvmem_config *cfg); - --int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem); -- - void nvmem_add_cell_table(struct nvmem_cell_table *table); - void nvmem_del_cell_table(struct nvmem_cell_table *table); - -@@ -153,12 +151,6 @@ devm_nvmem_register(struct device *dev, - return nvmem_register(c); - } - --static inline int --devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem) --{ -- return -EOPNOTSUPP; --} -- - static inline void nvmem_add_cell_table(struct nvmem_cell_table *table) {} - static inline void nvmem_del_cell_table(struct nvmem_cell_table *table) {} - diff --git a/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch b/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch deleted file mode 100644 index b71a0a365b2..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0002-nvmem-core-Use-devm_add_action_or_reset.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 5825b2c6762611e67ccaf3ccf64485365a120f0b Mon Sep 17 00:00:00 2001 -From: Andy Shevchenko -Date: Sun, 20 Feb 2022 15:15:16 +0000 -Subject: [PATCH] nvmem: core: Use devm_add_action_or_reset() - -Slightly simplify the devm_nvmem_register() by using the -devm_add_action_or_reset(). - -Signed-off-by: Andy Shevchenko -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 22 +++++++++------------- - 1 file changed, 9 insertions(+), 13 deletions(-) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -905,9 +905,9 @@ void nvmem_unregister(struct nvmem_devic - } - EXPORT_SYMBOL_GPL(nvmem_unregister); - --static void devm_nvmem_release(struct device *dev, void *res) -+static void devm_nvmem_unregister(void *nvmem) - { -- nvmem_unregister(*(struct nvmem_device **)res); -+ nvmem_unregister(nvmem); - } - - /** -@@ -924,20 +924,16 @@ static void devm_nvmem_release(struct de - struct nvmem_device *devm_nvmem_register(struct device *dev, - const struct nvmem_config *config) - { -- struct nvmem_device **ptr, *nvmem; -- -- ptr = devres_alloc(devm_nvmem_release, sizeof(*ptr), GFP_KERNEL); -- if (!ptr) -- return ERR_PTR(-ENOMEM); -+ struct nvmem_device *nvmem; -+ int ret; - - nvmem = nvmem_register(config); -+ if (IS_ERR(nvmem)) -+ return nvmem; - -- if (!IS_ERR(nvmem)) { -- *ptr = nvmem; -- devres_add(dev, ptr); -- } else { -- devres_free(ptr); -- } -+ ret = devm_add_action_or_reset(dev, devm_nvmem_unregister, nvmem); -+ if (ret) -+ return ERR_PTR(ret); - - return nvmem; - } diff --git a/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch b/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch deleted file mode 100644 index 4f471f26673..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0003-nvmem-core-Check-input-parameter-for-NULL-in-nvmem_u.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 8c751e0d9a5264376935a84429a2d468c8877d99 Mon Sep 17 00:00:00 2001 -From: Andy Shevchenko -Date: Sun, 20 Feb 2022 15:15:17 +0000 -Subject: [PATCH] nvmem: core: Check input parameter for NULL in - nvmem_unregister() - -nvmem_unregister() frees resources and standard pattern is to allow -caller to not care if it's NULL or not. This will reduce burden on -the callers to perform this check. - -Signed-off-by: Andy Shevchenko -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-4-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -901,7 +901,8 @@ static void nvmem_device_release(struct - */ - void nvmem_unregister(struct nvmem_device *nvmem) - { -- kref_put(&nvmem->refcnt, nvmem_device_release); -+ if (nvmem) -+ kref_put(&nvmem->refcnt, nvmem_device_release); - } - EXPORT_SYMBOL_GPL(nvmem_unregister); - diff --git a/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch b/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch deleted file mode 100644 index c98f8e9d545..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0004-nvmem-qfprom-fix-kerneldoc-warning.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 05196facc052385960028ac634447ecf6c764ec3 Mon Sep 17 00:00:00 2001 -From: Srinivas Kandagatla -Date: Sun, 20 Feb 2022 15:15:18 +0000 -Subject: [PATCH] nvmem: qfprom: fix kerneldoc warning - -This patch fixes below kernel doc warning, -warning: expecting prototype for qfprom_efuse_reg_write(). -Prototype was for qfprom_reg_write() instead - -No code changes. - -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-5-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/qfprom.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/qfprom.c -+++ b/drivers/nvmem/qfprom.c -@@ -244,7 +244,7 @@ err_clk_prepared: - } - - /** -- * qfprom_efuse_reg_write() - Write to fuses. -+ * qfprom_reg_write() - Write to fuses. - * @context: Our driver data. - * @reg: The offset to write at. - * @_val: Pointer to data to write. diff --git a/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch b/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch deleted file mode 100644 index 6aad6af0800..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0005-nvmem-sunxi_sid-Add-support-for-D1-variant.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 07ae4fde9efada7878e1383d6ccc7da70315ca23 Mon Sep 17 00:00:00 2001 -From: Samuel Holland -Date: Sun, 20 Feb 2022 15:15:20 +0000 -Subject: [PATCH] nvmem: sunxi_sid: Add support for D1 variant - -D1 has a smaller eFuse block than some other recent SoCs, and it no -longer requires a workaround to read the eFuse data. - -Signed-off-by: Samuel Holland -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-7-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/sunxi_sid.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/nvmem/sunxi_sid.c -+++ b/drivers/nvmem/sunxi_sid.c -@@ -184,6 +184,11 @@ static const struct sunxi_sid_cfg sun8i_ - .need_register_readout = true, - }; - -+static const struct sunxi_sid_cfg sun20i_d1_cfg = { -+ .value_offset = 0x200, -+ .size = 0x100, -+}; -+ - static const struct sunxi_sid_cfg sun50i_a64_cfg = { - .value_offset = 0x200, - .size = 0x100, -@@ -200,6 +205,7 @@ static const struct of_device_id sunxi_s - { .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg }, - { .compatible = "allwinner,sun8i-a83t-sid", .data = &sun50i_a64_cfg }, - { .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg }, -+ { .compatible = "allwinner,sun20i-d1-sid", .data = &sun20i_d1_cfg }, - { .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg }, - { .compatible = "allwinner,sun50i-h5-sid", .data = &sun50i_a64_cfg }, - { .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg }, diff --git a/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch b/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch deleted file mode 100644 index a73b42c5de3..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0006-nvmem-meson-mx-efuse-replace-unnecessary-devm_kstrdu.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 4dc8d89faed9bb05f116fa1794fc955b14910386 Mon Sep 17 00:00:00 2001 -From: Xiaoke Wang -Date: Sun, 20 Feb 2022 15:15:21 +0000 -Subject: [PATCH] nvmem: meson-mx-efuse: replace unnecessary devm_kstrdup() - -Replace unnecessary devm_kstrdup() so to avoid redundant memory allocation. - -Suggested-by: Martin Blumenstingl -Signed-off-by: Xiaoke Wang -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-8-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/meson-mx-efuse.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/nvmem/meson-mx-efuse.c -+++ b/drivers/nvmem/meson-mx-efuse.c -@@ -209,8 +209,7 @@ static int meson_mx_efuse_probe(struct p - if (IS_ERR(efuse->base)) - return PTR_ERR(efuse->base); - -- efuse->config.name = devm_kstrdup(&pdev->dev, drvdata->name, -- GFP_KERNEL); -+ efuse->config.name = drvdata->name; - efuse->config.owner = THIS_MODULE; - efuse->config.dev = &pdev->dev; - efuse->config.priv = efuse; diff --git a/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch b/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch deleted file mode 100644 index 6afb68b3f91..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0007-nvmem-add-driver-for-Layerscape-SFP-Security-Fuse-Pr.patch +++ /dev/null @@ -1,139 +0,0 @@ -From f78451012b9e159afdba31c3eb69f223a9f42adc Mon Sep 17 00:00:00 2001 -From: Michael Walle -Date: Sun, 20 Feb 2022 15:15:23 +0000 -Subject: [PATCH] nvmem: add driver for Layerscape SFP (Security Fuse - Processor) - -Add support for the Security Fuse Processor found on Layerscape SoCs. -This driver implements basic read access. - -Signed-off-by: Michael Walle -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220220151527.17216-10-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/Kconfig | 12 +++++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/layerscape-sfp.c | 89 ++++++++++++++++++++++++++++++++++ - 3 files changed, 103 insertions(+) - create mode 100644 drivers/nvmem/layerscape-sfp.c - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -300,4 +300,16 @@ config NVMEM_BRCM_NVRAM - This driver provides support for Broadcom's NVRAM that can be accessed - using I/O mapping. - -+config NVMEM_LAYERSCAPE_SFP -+ tristate "Layerscape SFP (Security Fuse Processor) support" -+ depends on ARCH_LAYERSCAPE || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This driver provides support to read the eFuses on Freescale -+ Layerscape SoC's. For example, the vendor provides a per part -+ unique ID there. -+ -+ This driver can also be built as a module. If so, the module -+ will be called layerscape-sfp. -+ - endif ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -61,3 +61,5 @@ obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem. - nvmem-rmem-y := rmem.o - obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o - nvmem_brcm_nvram-y := brcm_nvram.o -+obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o -+nvmem-layerscape-sfp-y := layerscape-sfp.o ---- /dev/null -+++ b/drivers/nvmem/layerscape-sfp.c -@@ -0,0 +1,89 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Layerscape SFP driver -+ * -+ * Copyright (c) 2022 Michael Walle -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 -+ -+struct layerscape_sfp_priv { -+ void __iomem *base; -+}; -+ -+struct layerscape_sfp_data { -+ int size; -+}; -+ -+static int layerscape_sfp_read(void *context, unsigned int offset, void *val, -+ size_t bytes) -+{ -+ struct layerscape_sfp_priv *priv = context; -+ -+ memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset, -+ bytes); -+ -+ return 0; -+} -+ -+static struct nvmem_config layerscape_sfp_nvmem_config = { -+ .name = "fsl-sfp", -+ .reg_read = layerscape_sfp_read, -+}; -+ -+static int layerscape_sfp_probe(struct platform_device *pdev) -+{ -+ const struct layerscape_sfp_data *data; -+ struct layerscape_sfp_priv *priv; -+ struct nvmem_device *nvmem; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(priv->base)) -+ return PTR_ERR(priv->base); -+ -+ data = device_get_match_data(&pdev->dev); -+ -+ layerscape_sfp_nvmem_config.size = data->size; -+ layerscape_sfp_nvmem_config.dev = &pdev->dev; -+ layerscape_sfp_nvmem_config.priv = priv; -+ -+ nvmem = devm_nvmem_register(&pdev->dev, &layerscape_sfp_nvmem_config); -+ -+ return PTR_ERR_OR_ZERO(nvmem); -+} -+ -+static const struct layerscape_sfp_data ls1028a_data = { -+ .size = 0x88, -+}; -+ -+static const struct of_device_id layerscape_sfp_dt_ids[] = { -+ { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, layerscape_sfp_dt_ids); -+ -+static struct platform_driver layerscape_sfp_driver = { -+ .probe = layerscape_sfp_probe, -+ .driver = { -+ .name = "layerscape_sfp", -+ .of_match_table = layerscape_sfp_dt_ids, -+ }, -+}; -+module_platform_driver(layerscape_sfp_driver); -+ -+MODULE_AUTHOR("Michael Walle "); -+MODULE_DESCRIPTION("Layerscape Security Fuse Processor driver"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch b/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch deleted file mode 100644 index 74bd4a7eb67..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0008-nvmem-qfprom-Increase-fuse-blow-timeout-to-prevent-w.patch +++ /dev/null @@ -1,32 +0,0 @@ -From bc5c75e0a5a9400f81a987cc720100ac475fa4d8 Mon Sep 17 00:00:00 2001 -From: Knox Chiou -Date: Wed, 23 Feb 2022 22:35:00 +0000 -Subject: [PATCH] nvmem: qfprom: Increase fuse blow timeout to prevent write - fail - -sc7180 blow fuses got slightly chances to hit qfprom_reg_write timeout. -Current timeout is simply too low. Since blowing fuses is a -very rare operation, so the risk associated with overestimating this -number is low. -Increase fuse blow timeout from 1ms to 10ms. - -Reviewed-by: Douglas Anderson -Signed-off-by: Knox Chiou -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220223223502.29454-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/qfprom.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/qfprom.c -+++ b/drivers/nvmem/qfprom.c -@@ -22,7 +22,7 @@ - - /* Amount of time required to hold charge to blow fuse in micro-seconds */ - #define QFPROM_FUSE_BLOW_POLL_US 100 --#define QFPROM_FUSE_BLOW_TIMEOUT_US 1000 -+#define QFPROM_FUSE_BLOW_TIMEOUT_US 10000 - - #define QFPROM_BLOW_STATUS_OFFSET 0x048 - #define QFPROM_BLOW_STATUS_BUSY 0x1 diff --git a/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch b/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch deleted file mode 100644 index 2a9dc749478..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch +++ /dev/null @@ -1,291 +0,0 @@ -From 8747ec2e9762ed9ae53b3a590938f454b6a1abdf Mon Sep 17 00:00:00 2001 -From: Vincent Shih -Date: Wed, 23 Feb 2022 22:35:01 +0000 -Subject: [PATCH] nvmem: Add driver for OCOTP in Sunplus SP7021 - -Add driver for OCOTP in Sunplus SP7021 - -Signed-off-by: Vincent Shih -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220223223502.29454-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - MAINTAINERS | 5 + - drivers/nvmem/Kconfig | 12 ++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/sunplus-ocotp.c | 228 ++++++++++++++++++++++++++++++++++ - 4 files changed, 247 insertions(+) - create mode 100644 drivers/nvmem/sunplus-ocotp.c - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -17962,6 +17962,11 @@ L: netdev@vger.kernel.org - S: Maintained - F: drivers/net/ethernet/dlink/sundance.c - -+SUNPLUS OCOTP DRIVER -+M: Vincent Shih -+S: Maintained -+F: drivers/nvmem/sunplus-ocotp.c -+ - SUPERH - M: Yoshinori Sato - M: Rich Felker ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -312,4 +312,16 @@ config NVMEM_LAYERSCAPE_SFP - This driver can also be built as a module. If so, the module - will be called layerscape-sfp. - -+config NVMEM_SUNPLUS_OCOTP -+ tristate "Sunplus SoC OTP support" -+ depends on SOC_SP7021 || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This is a driver for the On-chip OTP controller (OCOTP) available -+ on Sunplus SoCs. It provides access to 128 bytes of one-time -+ programmable eFuse. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-sunplus-ocotp. -+ - endif ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -63,3 +63,5 @@ obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_ - nvmem_brcm_nvram-y := brcm_nvram.o - obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o - nvmem-layerscape-sfp-y := layerscape-sfp.o -+obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o -+nvmem_sunplus_ocotp-y := sunplus-ocotp.o ---- /dev/null -+++ b/drivers/nvmem/sunplus-ocotp.c -@@ -0,0 +1,228 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+/* -+ * The OCOTP driver for Sunplus SP7021 -+ * -+ * Copyright (C) 2019 Sunplus Technology Inc., All rights reserved. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * OTP memory -+ * Each bank contains 4 words (32 bits). -+ * Bank 0 starts at offset 0 from the base. -+ */ -+ -+#define OTP_WORDS_PER_BANK 4 -+#define OTP_WORD_SIZE sizeof(u32) -+#define OTP_BIT_ADDR_OF_BANK (8 * OTP_WORD_SIZE * OTP_WORDS_PER_BANK) -+#define QAC628_OTP_NUM_BANKS 8 -+#define QAC628_OTP_SIZE (QAC628_OTP_NUM_BANKS * OTP_WORDS_PER_BANK * OTP_WORD_SIZE) -+#define OTP_READ_TIMEOUT_US 200000 -+ -+/* HB_GPIO */ -+#define ADDRESS_8_DATA 0x20 -+ -+/* OTP_RX */ -+#define OTP_CONTROL_2 0x48 -+#define OTP_RD_PERIOD GENMASK(15, 8) -+#define OTP_RD_PERIOD_MASK ~GENMASK(15, 8) -+#define CPU_CLOCK FIELD_PREP(OTP_RD_PERIOD, 30) -+#define SEL_BAK_KEY2 BIT(5) -+#define SEL_BAK_KEY2_MASK ~BIT(5) -+#define SW_TRIM_EN BIT(4) -+#define SW_TRIM_EN_MASK ~BIT(4) -+#define SEL_BAK_KEY BIT(3) -+#define SEL_BAK_KEY_MASK ~BIT(3) -+#define OTP_READ BIT(2) -+#define OTP_LOAD_SECURE_DATA BIT(1) -+#define OTP_LOAD_SECURE_DATA_MASK ~BIT(1) -+#define OTP_DO_CRC BIT(0) -+#define OTP_DO_CRC_MASK ~BIT(0) -+#define OTP_STATUS 0x4c -+#define OTP_READ_DONE BIT(4) -+#define OTP_READ_DONE_MASK ~BIT(4) -+#define OTP_LOAD_SECURE_DONE_MASK ~BIT(2) -+#define OTP_READ_ADDRESS 0x50 -+ -+enum base_type { -+ HB_GPIO, -+ OTPRX, -+ BASEMAX, -+}; -+ -+struct sp_ocotp_priv { -+ struct device *dev; -+ void __iomem *base[BASEMAX]; -+ struct clk *clk; -+}; -+ -+struct sp_ocotp_data { -+ int size; -+}; -+ -+const struct sp_ocotp_data sp_otp_v0 = { -+ .size = QAC628_OTP_SIZE, -+}; -+ -+static int sp_otp_read_real(struct sp_ocotp_priv *otp, int addr, char *value) -+{ -+ unsigned int addr_data; -+ unsigned int byte_shift; -+ unsigned int status; -+ int ret; -+ -+ addr_data = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); -+ addr_data = addr_data / OTP_WORD_SIZE; -+ -+ byte_shift = addr % (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); -+ byte_shift = byte_shift % OTP_WORD_SIZE; -+ -+ addr = addr / (OTP_WORD_SIZE * OTP_WORDS_PER_BANK); -+ addr = addr * OTP_BIT_ADDR_OF_BANK; -+ -+ writel(readl(otp->base[OTPRX] + OTP_STATUS) & OTP_READ_DONE_MASK & -+ OTP_LOAD_SECURE_DONE_MASK, otp->base[OTPRX] + OTP_STATUS); -+ writel(addr, otp->base[OTPRX] + OTP_READ_ADDRESS); -+ writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) | OTP_READ, -+ otp->base[OTPRX] + OTP_CONTROL_2); -+ writel(readl(otp->base[OTPRX] + OTP_CONTROL_2) & SEL_BAK_KEY2_MASK & SW_TRIM_EN_MASK -+ & SEL_BAK_KEY_MASK & OTP_LOAD_SECURE_DATA_MASK & OTP_DO_CRC_MASK, -+ otp->base[OTPRX] + OTP_CONTROL_2); -+ writel((readl(otp->base[OTPRX] + OTP_CONTROL_2) & OTP_RD_PERIOD_MASK) | CPU_CLOCK, -+ otp->base[OTPRX] + OTP_CONTROL_2); -+ -+ ret = readl_poll_timeout(otp->base[OTPRX] + OTP_STATUS, status, -+ status & OTP_READ_DONE, 10, OTP_READ_TIMEOUT_US); -+ -+ if (ret < 0) -+ return ret; -+ -+ *value = (readl(otp->base[HB_GPIO] + ADDRESS_8_DATA + addr_data * OTP_WORD_SIZE) -+ >> (8 * byte_shift)) & 0xff; -+ -+ return ret; -+} -+ -+static int sp_ocotp_read(void *priv, unsigned int offset, void *value, size_t bytes) -+{ -+ struct sp_ocotp_priv *otp = priv; -+ unsigned int addr; -+ char *buf = value; -+ char val[4]; -+ int ret; -+ -+ ret = clk_enable(otp->clk); -+ if (ret) -+ return ret; -+ -+ *buf = 0; -+ for (addr = offset; addr < (offset + bytes); addr++) { -+ ret = sp_otp_read_real(otp, addr, val); -+ if (ret < 0) { -+ dev_err(otp->dev, "OTP read fail:%d at %d", ret, addr); -+ goto disable_clk; -+ } -+ -+ *buf++ = *val; -+ } -+ -+disable_clk: -+ clk_disable(otp->clk); -+ -+ return ret; -+} -+ -+static struct nvmem_config sp_ocotp_nvmem_config = { -+ .name = "sp-ocotp", -+ .read_only = true, -+ .word_size = 1, -+ .size = QAC628_OTP_SIZE, -+ .stride = 1, -+ .reg_read = sp_ocotp_read, -+ .owner = THIS_MODULE, -+}; -+ -+static int sp_ocotp_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct nvmem_device *nvmem; -+ struct sp_ocotp_priv *otp; -+ struct resource *res; -+ int ret; -+ -+ otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL); -+ if (!otp) -+ return -ENOMEM; -+ -+ otp->dev = dev; -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hb_gpio"); -+ otp->base[HB_GPIO] = devm_ioremap_resource(dev, res); -+ if (IS_ERR(otp->base[HB_GPIO])) -+ return PTR_ERR(otp->base[HB_GPIO]); -+ -+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otprx"); -+ otp->base[OTPRX] = devm_ioremap_resource(dev, res); -+ if (IS_ERR(otp->base[OTPRX])) -+ return PTR_ERR(otp->base[OTPRX]); -+ -+ otp->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(otp->clk)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(otp->clk), -+ "devm_clk_get fail\n"); -+ -+ ret = clk_prepare(otp->clk); -+ if (ret < 0) { -+ dev_err(dev, "failed to prepare clk: %d\n", ret); -+ return ret; -+ } -+ -+ sp_ocotp_nvmem_config.priv = otp; -+ sp_ocotp_nvmem_config.dev = dev; -+ -+ nvmem = devm_nvmem_register(dev, &sp_ocotp_nvmem_config); -+ if (IS_ERR(nvmem)) -+ return dev_err_probe(&pdev->dev, PTR_ERR(nvmem), -+ "register nvmem device fail\n"); -+ -+ platform_set_drvdata(pdev, nvmem); -+ -+ dev_dbg(dev, "banks:%d x wpb:%d x wsize:%d = %d", -+ (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, -+ (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); -+ -+ dev_info(dev, "by Sunplus (C) 2020"); -+ -+ return 0; -+} -+ -+static const struct of_device_id sp_ocotp_dt_ids[] = { -+ { .compatible = "sunplus,sp7021-ocotp", .data = &sp_otp_v0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, sp_ocotp_dt_ids); -+ -+static struct platform_driver sp_otp_driver = { -+ .probe = sp_ocotp_probe, -+ .driver = { -+ .name = "sunplus,sp7021-ocotp", -+ .of_match_table = sp_ocotp_dt_ids, -+ } -+}; -+module_platform_driver(sp_otp_driver); -+ -+MODULE_AUTHOR("Vincent Shih "); -+MODULE_DESCRIPTION("Sunplus On-Chip OTP driver"); -+MODULE_LICENSE("GPL"); -+ diff --git a/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch b/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch deleted file mode 100644 index 99781b3a7b3..00000000000 --- a/target/linux/generic/backport-6.1/804-v5.18-0010-nvmem-brcm_nvram-parse-NVRAM-content-into-NVMEM-cell.patch +++ /dev/null @@ -1,146 +0,0 @@ -From 6e977eaa8280e957b87904b536661550f2a6b3e8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 25 Feb 2022 17:58:20 +0000 -Subject: [PATCH] nvmem: brcm_nvram: parse NVRAM content into NVMEM cells -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -NVRAM consist of header and NUL separated key-value pairs. Parse it and -create NVMEM cell for every key-value entry. - -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220225175822.8293-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/brcm_nvram.c | 90 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 90 insertions(+) - ---- a/drivers/nvmem/brcm_nvram.c -+++ b/drivers/nvmem/brcm_nvram.c -@@ -6,12 +6,26 @@ - #include - #include - #include -+#include - #include - #include -+#include -+ -+#define NVRAM_MAGIC "FLSH" - - struct brcm_nvram { - struct device *dev; - void __iomem *base; -+ struct nvmem_cell_info *cells; -+ int ncells; -+}; -+ -+struct brcm_nvram_header { -+ char magic[4]; -+ __le32 len; -+ __le32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */ -+ __le32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */ -+ __le32 config_ncdl; /* ncdl values for memc */ - }; - - static int brcm_nvram_read(void *context, unsigned int offset, void *val, -@@ -26,6 +40,75 @@ static int brcm_nvram_read(void *context - return 0; - } - -+static int brcm_nvram_add_cells(struct brcm_nvram *priv, uint8_t *data, -+ size_t len) -+{ -+ struct device *dev = priv->dev; -+ char *var, *value, *eq; -+ int idx; -+ -+ priv->ncells = 0; -+ for (var = data + sizeof(struct brcm_nvram_header); -+ var < (char *)data + len && *var; -+ var += strlen(var) + 1) { -+ priv->ncells++; -+ } -+ -+ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL); -+ if (!priv->cells) -+ return -ENOMEM; -+ -+ for (var = data + sizeof(struct brcm_nvram_header), idx = 0; -+ var < (char *)data + len && *var; -+ var = value + strlen(value) + 1, idx++) { -+ eq = strchr(var, '='); -+ if (!eq) -+ break; -+ *eq = '\0'; -+ value = eq + 1; -+ -+ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL); -+ if (!priv->cells[idx].name) -+ return -ENOMEM; -+ priv->cells[idx].offset = value - (char *)data; -+ priv->cells[idx].bytes = strlen(value); -+ } -+ -+ return 0; -+} -+ -+static int brcm_nvram_parse(struct brcm_nvram *priv) -+{ -+ struct device *dev = priv->dev; -+ struct brcm_nvram_header header; -+ uint8_t *data; -+ size_t len; -+ int err; -+ -+ memcpy_fromio(&header, priv->base, sizeof(header)); -+ -+ if (memcmp(header.magic, NVRAM_MAGIC, 4)) { -+ dev_err(dev, "Invalid NVRAM magic\n"); -+ return -EINVAL; -+ } -+ -+ len = le32_to_cpu(header.len); -+ -+ data = kcalloc(1, len, GFP_KERNEL); -+ memcpy_fromio(data, priv->base, len); -+ data[len - 1] = '\0'; -+ -+ err = brcm_nvram_add_cells(priv, data, len); -+ if (err) { -+ dev_err(dev, "Failed to add cells: %d\n", err); -+ return err; -+ } -+ -+ kfree(data); -+ -+ return 0; -+} -+ - static int brcm_nvram_probe(struct platform_device *pdev) - { - struct nvmem_config config = { -@@ -35,6 +118,7 @@ static int brcm_nvram_probe(struct platf - struct device *dev = &pdev->dev; - struct resource *res; - struct brcm_nvram *priv; -+ int err; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) -@@ -46,7 +130,13 @@ static int brcm_nvram_probe(struct platf - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); - -+ err = brcm_nvram_parse(priv); -+ if (err) -+ return err; -+ - config.dev = dev; -+ config.cells = priv->cells; -+ config.ncells = priv->ncells; - config.priv = priv; - config.size = resource_size(res); - diff --git a/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch b/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch deleted file mode 100644 index ef3107db946..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0001-nvmem-bcm-ocotp-mark-ACPI-device-ID-table-as-maybe-u.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 6bd0ffeaa389866089e9573b2298ae58d6359b75 Mon Sep 17 00:00:00 2001 -From: Krzysztof Kozlowski -Date: Mon, 21 Mar 2022 12:03:24 +0100 -Subject: [PATCH] nvmem: bcm-ocotp: mark ACPI device ID table as maybe unused -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -"bcm_otpc_acpi_ids" is used with ACPI_PTR, so a build with !CONFIG_ACPI -has a warning: - - drivers/nvmem/bcm-ocotp.c:247:36: error: - ‘bcm_otpc_acpi_ids’ defined but not used [-Werror=unused-const-variable=] - -Signed-off-by: Krzysztof Kozlowski -Link: https://lore.kernel.org/r/20220321110326.44652-1-krzk@kernel.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/bcm-ocotp.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/bcm-ocotp.c -+++ b/drivers/nvmem/bcm-ocotp.c -@@ -244,7 +244,7 @@ static const struct of_device_id bcm_otp - }; - MODULE_DEVICE_TABLE(of, bcm_otpc_dt_ids); - --static const struct acpi_device_id bcm_otpc_acpi_ids[] = { -+static const struct acpi_device_id bcm_otpc_acpi_ids[] __maybe_unused = { - { .id = "BRCM0700", .driver_data = (kernel_ulong_t)&otp_map }, - { .id = "BRCM0701", .driver_data = (kernel_ulong_t)&otp_map_v2 }, - { /* sentinel */ } diff --git a/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch b/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch deleted file mode 100644 index a84d2316f0c..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0002-nvmem-sunplus-ocotp-staticize-sp_otp_v0.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 1066f8156351fcd997125257cea47cf805ba4f6d Mon Sep 17 00:00:00 2001 -From: Krzysztof Kozlowski -Date: Mon, 21 Mar 2022 12:03:25 +0100 -Subject: [PATCH] nvmem: sunplus-ocotp: staticize sp_otp_v0 - -The "sp_otp_v0" file scope variable is not used outside, so make it -static to fix warning: - - drivers/nvmem/sunplus-ocotp.c:74:29: sparse: - sparse: symbol 'sp_otp_v0' was not declared. Should it be static? - -Reported-by: kernel test robot -Signed-off-by: Krzysztof Kozlowski -Link: https://lore.kernel.org/r/20220321110326.44652-2-krzk@kernel.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/sunplus-ocotp.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/sunplus-ocotp.c -+++ b/drivers/nvmem/sunplus-ocotp.c -@@ -71,7 +71,7 @@ struct sp_ocotp_data { - int size; - }; - --const struct sp_ocotp_data sp_otp_v0 = { -+static const struct sp_ocotp_data sp_otp_v0 = { - .size = QAC628_OTP_SIZE, - }; - diff --git a/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch b/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch deleted file mode 100644 index 886ebc12a9c..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0003-nvmem-sunplus-ocotp-drop-useless-probe-confirmation.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 874dfbcf219ccc42a2cbd187d087c7db82c3024b Mon Sep 17 00:00:00 2001 -From: Krzysztof Kozlowski -Date: Mon, 21 Mar 2022 12:03:26 +0100 -Subject: [PATCH] nvmem: sunplus-ocotp: drop useless probe confirmation - -Printing probe success is discouraged, because we can use tracing for -this purpose. Remove useless print message after Sunplus OCOTP driver -probe. - -Signed-off-by: Krzysztof Kozlowski -Link: https://lore.kernel.org/r/20220321110326.44652-3-krzk@kernel.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/sunplus-ocotp.c | 2 -- - 1 file changed, 2 deletions(-) - ---- a/drivers/nvmem/sunplus-ocotp.c -+++ b/drivers/nvmem/sunplus-ocotp.c -@@ -202,8 +202,6 @@ static int sp_ocotp_probe(struct platfor - (int)QAC628_OTP_NUM_BANKS, (int)OTP_WORDS_PER_BANK, - (int)OTP_WORD_SIZE, (int)QAC628_OTP_SIZE); - -- dev_info(dev, "by Sunplus (C) 2020"); -- - return 0; - } - diff --git a/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch b/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch deleted file mode 100644 index 3b1e76147a8..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0004-nvmem-core-support-passing-DT-node-in-cell-info.patch +++ /dev/null @@ -1,41 +0,0 @@ -From dbc2f62061c6bfba0aee93161ee3194dcee84bd0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 29 Apr 2022 17:26:46 +0100 -Subject: [PATCH] nvmem: core: support passing DT node in cell info -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Some hardware may have NVMEM cells described in Device Tree using -individual nodes. Let drivers pass such nodes to the NVMEM subsystem so -they can be later used by NVMEM consumers. - -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 1 + - include/linux/nvmem-consumer.h | 1 + - 2 files changed, 2 insertions(+) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -467,6 +467,7 @@ static int nvmem_cell_info_to_nvmem_cell - - cell->bit_offset = info->bit_offset; - cell->nbits = info->nbits; -+ cell->np = info->np; - - if (cell->nbits) - cell->bytes = DIV_ROUND_UP(cell->nbits + cell->bit_offset, ---- a/include/linux/nvmem-consumer.h -+++ b/include/linux/nvmem-consumer.h -@@ -25,6 +25,7 @@ struct nvmem_cell_info { - unsigned int bytes; - unsigned int bit_offset; - unsigned int nbits; -+ struct device_node *np; - }; - - /** diff --git a/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch b/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch deleted file mode 100644 index a9eacd9419c..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0005-nvmem-brcm_nvram-find-Device-Tree-nodes-for-NVMEM-ce.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 207775f7e17b8fd0426a2ac4a5b81e4e1d71849e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 29 Apr 2022 17:26:47 +0100 -Subject: [PATCH] nvmem: brcm_nvram: find Device Tree nodes for NVMEM cells -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -DT binding for Broadcom's NVRAM supports specifying NVMEM cells as NVMEM -device (provider) subnodes. Look for such subnodes when collecing NVMEM -cells. This allows NVMEM consumers to use NVRAM variables. - -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/brcm_nvram.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/nvmem/brcm_nvram.c -+++ b/drivers/nvmem/brcm_nvram.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -72,6 +73,7 @@ static int brcm_nvram_add_cells(struct b - return -ENOMEM; - priv->cells[idx].offset = value - (char *)data; - priv->cells[idx].bytes = strlen(value); -+ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); - } - - return 0; diff --git a/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch b/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch deleted file mode 100644 index ebeb6f5ad39..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0006-nvmem-Add-Apple-eFuse-driver.patch +++ /dev/null @@ -1,130 +0,0 @@ -From b6b7ef932ae838209254f016ecf8862d716a5ced Mon Sep 17 00:00:00 2001 -From: Sven Peter -Date: Fri, 29 Apr 2022 17:26:50 +0100 -Subject: [PATCH] nvmem: Add Apple eFuse driver - -Apple SoCs contain eFuses used to store factory-programmed data such -as calibration values for the PCIe or the Type-C PHY. They are organized -as 32bit values exposed as MMIO. - -Signed-off-by: Sven Peter -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-6-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/Kconfig | 12 ++++++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/apple-efuses.c | 80 ++++++++++++++++++++++++++++++++++++ - 3 files changed, 94 insertions(+) - create mode 100644 drivers/nvmem/apple-efuses.c - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -324,4 +324,16 @@ config NVMEM_SUNPLUS_OCOTP - This driver can also be built as a module. If so, the module - will be called nvmem-sunplus-ocotp. - -+config NVMEM_APPLE_EFUSES -+ tristate "Apple eFuse support" -+ depends on ARCH_APPLE || COMPILE_TEST -+ default ARCH_APPLE -+ help -+ Say y here to enable support for reading eFuses on Apple SoCs -+ such as the M1. These are e.g. used to store factory programmed -+ calibration data required for the PCIe or the USB-C PHY. -+ -+ This driver can also be built as a module. If so, the module will -+ be called nvmem-apple-efuses. -+ - endif ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -65,3 +65,5 @@ obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nv - nvmem-layerscape-sfp-y := layerscape-sfp.o - obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o - nvmem_sunplus_ocotp-y := sunplus-ocotp.o -+obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o -+nvmem-apple-efuses-y := apple-efuses.o ---- /dev/null -+++ b/drivers/nvmem/apple-efuses.c -@@ -0,0 +1,80 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Apple SoC eFuse driver -+ * -+ * Copyright (C) The Asahi Linux Contributors -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct apple_efuses_priv { -+ void __iomem *fuses; -+}; -+ -+static int apple_efuses_read(void *context, unsigned int offset, void *val, -+ size_t bytes) -+{ -+ struct apple_efuses_priv *priv = context; -+ u32 *dst = val; -+ -+ while (bytes >= sizeof(u32)) { -+ *dst++ = readl_relaxed(priv->fuses + offset); -+ bytes -= sizeof(u32); -+ offset += sizeof(u32); -+ } -+ -+ return 0; -+} -+ -+static int apple_efuses_probe(struct platform_device *pdev) -+{ -+ struct apple_efuses_priv *priv; -+ struct resource *res; -+ struct nvmem_config config = { -+ .dev = &pdev->dev, -+ .read_only = true, -+ .reg_read = apple_efuses_read, -+ .stride = sizeof(u32), -+ .word_size = sizeof(u32), -+ .name = "apple_efuses_nvmem", -+ .id = NVMEM_DEVID_AUTO, -+ .root_only = true, -+ }; -+ -+ priv = devm_kzalloc(config.dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->fuses = devm_platform_get_and_ioremap_resource(pdev, 0, &res); -+ if (IS_ERR(priv->fuses)) -+ return PTR_ERR(priv->fuses); -+ -+ config.priv = priv; -+ config.size = resource_size(res); -+ -+ return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config)); -+} -+ -+static const struct of_device_id apple_efuses_of_match[] = { -+ { .compatible = "apple,efuses", }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(of, apple_efuses_of_match); -+ -+static struct platform_driver apple_efuses_driver = { -+ .driver = { -+ .name = "apple_efuses", -+ .of_match_table = apple_efuses_of_match, -+ }, -+ .probe = apple_efuses_probe, -+}; -+ -+module_platform_driver(apple_efuses_driver); -+ -+MODULE_AUTHOR("Sven Peter "); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch b/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch deleted file mode 100644 index cd51d970069..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0007-nvmem-qfprom-using-pm_runtime_resume_and_get-instead.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 517f6e2641a2802dce5a5aa0d18c7d37a35678d2 Mon Sep 17 00:00:00 2001 -From: Minghao Chi -Date: Fri, 29 Apr 2022 17:26:54 +0100 -Subject: [PATCH] nvmem: qfprom: using pm_runtime_resume_and_get instead of - pm_runtime_get_sync - -Using pm_runtime_resume_and_get is more appropriate -for simplifing code - -Reported-by: Zeal Robot -Signed-off-by: Minghao Chi -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-10-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/qfprom.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/nvmem/qfprom.c -+++ b/drivers/nvmem/qfprom.c -@@ -217,9 +217,8 @@ static int qfprom_enable_fuse_blowing(co - goto err_clk_rate_set; - } - -- ret = pm_runtime_get_sync(priv->dev); -+ ret = pm_runtime_resume_and_get(priv->dev); - if (ret < 0) { -- pm_runtime_put_noidle(priv->dev); - dev_err(priv->dev, "Failed to enable power-domain\n"); - goto err_reg_enable; - } diff --git a/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch b/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch deleted file mode 100644 index e187238ca38..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0008-nvmem-sfp-Use-regmap.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 943eadbdb11314b41eacbcc484dfb7f93e271ff4 Mon Sep 17 00:00:00 2001 -From: Sean Anderson -Date: Fri, 29 Apr 2022 17:27:00 +0100 -Subject: [PATCH] nvmem: sfp: Use regmap - -This converts the SFP driver to use regmap. This will allow easily -supporting devices with different endians. We disallow byte-level -access, as regmap_bulk_read doesn't support it (and it's unclear what -the correct result would be when we have an endianness difference). - -Signed-off-by: Sean Anderson -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-16-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/Kconfig | 1 + - drivers/nvmem/layerscape-sfp.c | 30 ++++++++++++++++++++++-------- - 2 files changed, 23 insertions(+), 8 deletions(-) - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -304,6 +304,7 @@ config NVMEM_LAYERSCAPE_SFP - tristate "Layerscape SFP (Security Fuse Processor) support" - depends on ARCH_LAYERSCAPE || COMPILE_TEST - depends on HAS_IOMEM -+ select REGMAP_MMIO - help - This driver provides support to read the eFuses on Freescale - Layerscape SoC's. For example, the vendor provides a per part ---- a/drivers/nvmem/layerscape-sfp.c -+++ b/drivers/nvmem/layerscape-sfp.c -@@ -13,15 +13,17 @@ - #include - #include - #include -+#include - - #define LAYERSCAPE_SFP_OTP_OFFSET 0x0200 - - struct layerscape_sfp_priv { -- void __iomem *base; -+ struct regmap *regmap; - }; - - struct layerscape_sfp_data { - int size; -+ enum regmap_endian endian; - }; - - static int layerscape_sfp_read(void *context, unsigned int offset, void *val, -@@ -29,15 +31,16 @@ static int layerscape_sfp_read(void *con - { - struct layerscape_sfp_priv *priv = context; - -- memcpy_fromio(val, priv->base + LAYERSCAPE_SFP_OTP_OFFSET + offset, -- bytes); -- -- return 0; -+ return regmap_bulk_read(priv->regmap, -+ LAYERSCAPE_SFP_OTP_OFFSET + offset, val, -+ bytes / 4); - } - - static struct nvmem_config layerscape_sfp_nvmem_config = { - .name = "fsl-sfp", - .reg_read = layerscape_sfp_read, -+ .word_size = 4, -+ .stride = 4, - }; - - static int layerscape_sfp_probe(struct platform_device *pdev) -@@ -45,16 +48,26 @@ static int layerscape_sfp_probe(struct p - const struct layerscape_sfp_data *data; - struct layerscape_sfp_priv *priv; - struct nvmem_device *nvmem; -+ struct regmap_config config = { 0 }; -+ void __iomem *base; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - -- priv->base = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(priv->base)) -- return PTR_ERR(priv->base); -+ base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); - - data = device_get_match_data(&pdev->dev); -+ config.reg_bits = 32; -+ config.reg_stride = 4; -+ config.val_bits = 32; -+ config.val_format_endian = data->endian; -+ config.max_register = LAYERSCAPE_SFP_OTP_OFFSET + data->size - 4; -+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, &config); -+ if (IS_ERR(priv->regmap)) -+ return PTR_ERR(priv->regmap); - - layerscape_sfp_nvmem_config.size = data->size; - layerscape_sfp_nvmem_config.dev = &pdev->dev; -@@ -67,6 +80,7 @@ static int layerscape_sfp_probe(struct p - - static const struct layerscape_sfp_data ls1028a_data = { - .size = 0x88, -+ .endian = REGMAP_ENDIAN_LITTLE, - }; - - static const struct of_device_id layerscape_sfp_dt_ids[] = { diff --git a/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch b/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch deleted file mode 100644 index ee000986181..00000000000 --- a/target/linux/generic/backport-6.1/805-v5.19-0009-nvmem-sfp-Add-support-for-TA-2.1-devices.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 33a1c6618677fe33f8e84cb7bedc45abbce89a50 Mon Sep 17 00:00:00 2001 -From: Sean Anderson -Date: Fri, 29 Apr 2022 17:27:01 +0100 -Subject: [PATCH] nvmem: sfp: Add support for TA 2.1 devices - -This adds support for Trust Architecture (TA) 2.1 devices to the SFP driver. -There are few differences between TA 2.1 and TA 3.0, especially for -read-only support, so just re-use the existing data. - -Signed-off-by: Sean Anderson -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220429162701.2222-17-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/layerscape-sfp.c | 6 ++++++ - 1 file changed, 6 insertions(+) - ---- a/drivers/nvmem/layerscape-sfp.c -+++ b/drivers/nvmem/layerscape-sfp.c -@@ -78,12 +78,18 @@ static int layerscape_sfp_probe(struct p - return PTR_ERR_OR_ZERO(nvmem); - } - -+static const struct layerscape_sfp_data ls1021a_data = { -+ .size = 0x88, -+ .endian = REGMAP_ENDIAN_BIG, -+}; -+ - static const struct layerscape_sfp_data ls1028a_data = { - .size = 0x88, - .endian = REGMAP_ENDIAN_LITTLE, - }; - - static const struct of_device_id layerscape_sfp_dt_ids[] = { -+ { .compatible = "fsl,ls1021a-sfp", .data = &ls1021a_data }, - { .compatible = "fsl,ls1028a-sfp", .data = &ls1028a_data }, - {}, - }; diff --git a/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch b/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch deleted file mode 100644 index b1855d1f2f2..00000000000 --- a/target/linux/generic/backport-6.1/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch +++ /dev/null @@ -1,389 +0,0 @@ -From 98830350d3fc824c1ff5c338140fe20f041a5916 Mon Sep 17 00:00:00 2001 -From: Claudiu Beznea -Date: Wed, 6 Jul 2022 11:06:22 +0100 -Subject: [PATCH] nvmem: microchip-otpc: add support - -Add support for Microchip OTP controller available on SAMA7G5. The OTPC -controls the access to a non-volatile memory. The memory behind OTPC is -organized into packets, packets are composed by a fixed length header -(4 bytes long) and a variable length payload (payload length is available -in the header). When software request the data at an offset in memory -the OTPC will return (via header + data registers) the whole packet that -has a word at that offset. For the OTP memory layout like below: - -offset OTP Memory layout - - . . - . ... . - . . -0x0E +-----------+ <--- packet X - | header X | -0x12 +-----------+ - | payload X | -0x16 | | - | | -0x1A | | - +-----------+ - . . - . ... . - . . - -if user requests data at address 0x16 the data started at 0x0E will be -returned by controller. User will be able to fetch the whole packet -starting at 0x0E (or parts of the packet) via proper registers. The same -packet will be returned if software request the data at offset 0x0E or -0x12 or 0x1A. - -The OTP will be populated by Microchip with at least 2 packets first one -being boot configuration packet and the 2nd one being temperature -calibration packet. The packet order will be preserved b/w different chip -revisions but the packet sizes may change. - -For the above reasons and to keep the same software able to work on all -chip variants the read function of the driver is working with a packet -id instead of an offset in OTP memory. - -Signed-off-by: Claudiu Beznea -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220706100627.6534-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - MAINTAINERS | 8 + - drivers/nvmem/Kconfig | 7 + - drivers/nvmem/Makefile | 2 + - drivers/nvmem/microchip-otpc.c | 288 +++++++++++++++++++++++++++++++++ - 4 files changed, 305 insertions(+) - create mode 100644 drivers/nvmem/microchip-otpc.c - ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -12361,6 +12361,14 @@ S: Supported - F: Documentation/devicetree/bindings/mtd/atmel-nand.txt - F: drivers/mtd/nand/raw/atmel/* - -+MICROCHIP OTPC DRIVER -+M: Claudiu Beznea -+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -+S: Supported -+F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml -+F: drivers/nvmem/microchip-otpc.c -+F: dt-bindings/nvmem/microchip,sama7g5-otpc.h -+ - MICROCHIP PWM DRIVER - M: Claudiu Beznea - L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -107,6 +107,13 @@ config MTK_EFUSE - This driver can also be built as a module. If so, the module - will be called efuse-mtk. - -+config MICROCHIP_OTPC -+ tristate "Microchip OTPC support" -+ depends on ARCH_AT91 || COMPILE_TEST -+ help -+ This driver enable the OTP controller available on Microchip SAMA7G5 -+ SoCs. It controlls the access to the OTP memory connected to it. -+ - config NVMEM_NINTENDO_OTP - tristate "Nintendo Wii and Wii U OTP Support" - depends on WII || COMPILE_TEST ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -67,3 +67,5 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvm - nvmem_sunplus_ocotp-y := sunplus-ocotp.o - obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o - nvmem-apple-efuses-y := apple-efuses.o -+obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o -+nvmem-microchip-otpc-y := microchip-otpc.o ---- /dev/null -+++ b/drivers/nvmem/microchip-otpc.c -@@ -0,0 +1,288 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * OTP Memory controller -+ * -+ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries -+ * -+ * Author: Claudiu Beznea -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MCHP_OTPC_CR (0x0) -+#define MCHP_OTPC_CR_READ BIT(6) -+#define MCHP_OTPC_MR (0x4) -+#define MCHP_OTPC_MR_ADDR GENMASK(31, 16) -+#define MCHP_OTPC_AR (0x8) -+#define MCHP_OTPC_SR (0xc) -+#define MCHP_OTPC_SR_READ BIT(6) -+#define MCHP_OTPC_HR (0x20) -+#define MCHP_OTPC_HR_SIZE GENMASK(15, 8) -+#define MCHP_OTPC_DR (0x24) -+ -+#define MCHP_OTPC_NAME "mchp-otpc" -+#define MCHP_OTPC_SIZE (11 * 1024) -+ -+/** -+ * struct mchp_otpc - OTPC private data structure -+ * @base: base address -+ * @dev: struct device pointer -+ * @packets: list of packets in OTP memory -+ * @npackets: number of packets in OTP memory -+ */ -+struct mchp_otpc { -+ void __iomem *base; -+ struct device *dev; -+ struct list_head packets; -+ u32 npackets; -+}; -+ -+/** -+ * struct mchp_otpc_packet - OTPC packet data structure -+ * @list: list head -+ * @id: packet ID -+ * @offset: packet offset (in words) in OTP memory -+ */ -+struct mchp_otpc_packet { -+ struct list_head list; -+ u32 id; -+ u32 offset; -+}; -+ -+static struct mchp_otpc_packet *mchp_otpc_id_to_packet(struct mchp_otpc *otpc, -+ u32 id) -+{ -+ struct mchp_otpc_packet *packet; -+ -+ if (id >= otpc->npackets) -+ return NULL; -+ -+ list_for_each_entry(packet, &otpc->packets, list) { -+ if (packet->id == id) -+ return packet; -+ } -+ -+ return NULL; -+} -+ -+static int mchp_otpc_prepare_read(struct mchp_otpc *otpc, -+ unsigned int offset) -+{ -+ u32 tmp; -+ -+ /* Set address. */ -+ tmp = readl_relaxed(otpc->base + MCHP_OTPC_MR); -+ tmp &= ~MCHP_OTPC_MR_ADDR; -+ tmp |= FIELD_PREP(MCHP_OTPC_MR_ADDR, offset); -+ writel_relaxed(tmp, otpc->base + MCHP_OTPC_MR); -+ -+ /* Set read. */ -+ tmp = readl_relaxed(otpc->base + MCHP_OTPC_CR); -+ tmp |= MCHP_OTPC_CR_READ; -+ writel_relaxed(tmp, otpc->base + MCHP_OTPC_CR); -+ -+ /* Wait for packet to be transferred into temporary buffers. */ -+ return read_poll_timeout(readl_relaxed, tmp, !(tmp & MCHP_OTPC_SR_READ), -+ 10000, 2000, false, otpc->base + MCHP_OTPC_SR); -+} -+ -+/* -+ * OTPC memory is organized into packets. Each packets contains a header and -+ * a payload. Header is 4 bytes long and contains the size of the payload. -+ * Payload size varies. The memory footprint is something as follows: -+ * -+ * Memory offset Memory footprint Packet ID -+ * ------------- ---------------- --------- -+ * -+ * 0x0 +------------+ <-- packet 0 -+ * | header 0 | -+ * 0x4 +------------+ -+ * | payload 0 | -+ * . . -+ * . ... . -+ * . . -+ * offset1 +------------+ <-- packet 1 -+ * | header 1 | -+ * offset1 + 0x4 +------------+ -+ * | payload 1 | -+ * . . -+ * . ... . -+ * . . -+ * offset2 +------------+ <-- packet 2 -+ * . . -+ * . ... . -+ * . . -+ * offsetN +------------+ <-- packet N -+ * | header N | -+ * offsetN + 0x4 +------------+ -+ * | payload N | -+ * . . -+ * . ... . -+ * . . -+ * +------------+ -+ * -+ * where offset1, offset2, offsetN depends on the size of payload 0, payload 1, -+ * payload N-1. -+ * -+ * The access to memory is done on a per packet basis: the control registers -+ * need to be updated with an offset address (within a packet range) and the -+ * data registers will be update by controller with information contained by -+ * that packet. E.g. if control registers are updated with any address within -+ * the range [offset1, offset2) the data registers are updated by controller -+ * with packet 1. Header data is accessible though MCHP_OTPC_HR register. -+ * Payload data is accessible though MCHP_OTPC_DR and MCHP_OTPC_AR registers. -+ * There is no direct mapping b/w the offset requested by software and the -+ * offset returned by hardware. -+ * -+ * For this, the read function will return the first requested bytes in the -+ * packet. The user will have to be aware of the memory footprint before doing -+ * the read request. -+ */ -+static int mchp_otpc_read(void *priv, unsigned int off, void *val, -+ size_t bytes) -+{ -+ struct mchp_otpc *otpc = priv; -+ struct mchp_otpc_packet *packet; -+ u32 *buf = val; -+ u32 offset; -+ size_t len = 0; -+ int ret, payload_size; -+ -+ /* -+ * We reach this point with off being multiple of stride = 4 to -+ * be able to cross the subsystem. Inside the driver we use continuous -+ * unsigned integer numbers for packet id, thus devide off by 4 -+ * before passing it to mchp_otpc_id_to_packet(). -+ */ -+ packet = mchp_otpc_id_to_packet(otpc, off / 4); -+ if (!packet) -+ return -EINVAL; -+ offset = packet->offset; -+ -+ while (len < bytes) { -+ ret = mchp_otpc_prepare_read(otpc, offset); -+ if (ret) -+ return ret; -+ -+ /* Read and save header content. */ -+ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_HR); -+ len += sizeof(*buf); -+ offset++; -+ if (len >= bytes) -+ break; -+ -+ /* Read and save payload content. */ -+ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, *(buf - 1)); -+ writel_relaxed(0UL, otpc->base + MCHP_OTPC_AR); -+ do { -+ *buf++ = readl_relaxed(otpc->base + MCHP_OTPC_DR); -+ len += sizeof(*buf); -+ offset++; -+ payload_size--; -+ } while (payload_size >= 0 && len < bytes); -+ } -+ -+ return 0; -+} -+ -+static int mchp_otpc_init_packets_list(struct mchp_otpc *otpc, u32 *size) -+{ -+ struct mchp_otpc_packet *packet; -+ u32 word, word_pos = 0, id = 0, npackets = 0, payload_size; -+ int ret; -+ -+ INIT_LIST_HEAD(&otpc->packets); -+ *size = 0; -+ -+ while (*size < MCHP_OTPC_SIZE) { -+ ret = mchp_otpc_prepare_read(otpc, word_pos); -+ if (ret) -+ return ret; -+ -+ word = readl_relaxed(otpc->base + MCHP_OTPC_HR); -+ payload_size = FIELD_GET(MCHP_OTPC_HR_SIZE, word); -+ if (!payload_size) -+ break; -+ -+ packet = devm_kzalloc(otpc->dev, sizeof(*packet), GFP_KERNEL); -+ if (!packet) -+ return -ENOMEM; -+ -+ packet->id = id++; -+ packet->offset = word_pos; -+ INIT_LIST_HEAD(&packet->list); -+ list_add_tail(&packet->list, &otpc->packets); -+ -+ /* Count size by adding header and paload sizes. */ -+ *size += 4 * (payload_size + 1); -+ /* Next word: this packet (header, payload) position + 1. */ -+ word_pos += payload_size + 2; -+ -+ npackets++; -+ } -+ -+ otpc->npackets = npackets; -+ -+ return 0; -+} -+ -+static struct nvmem_config mchp_nvmem_config = { -+ .name = MCHP_OTPC_NAME, -+ .type = NVMEM_TYPE_OTP, -+ .read_only = true, -+ .word_size = 4, -+ .stride = 4, -+ .reg_read = mchp_otpc_read, -+}; -+ -+static int mchp_otpc_probe(struct platform_device *pdev) -+{ -+ struct nvmem_device *nvmem; -+ struct mchp_otpc *otpc; -+ u32 size; -+ int ret; -+ -+ otpc = devm_kzalloc(&pdev->dev, sizeof(*otpc), GFP_KERNEL); -+ if (!otpc) -+ return -ENOMEM; -+ -+ otpc->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(otpc->base)) -+ return PTR_ERR(otpc->base); -+ -+ otpc->dev = &pdev->dev; -+ ret = mchp_otpc_init_packets_list(otpc, &size); -+ if (ret) -+ return ret; -+ -+ mchp_nvmem_config.dev = otpc->dev; -+ mchp_nvmem_config.size = size; -+ mchp_nvmem_config.priv = otpc; -+ nvmem = devm_nvmem_register(&pdev->dev, &mchp_nvmem_config); -+ -+ return PTR_ERR_OR_ZERO(nvmem); -+} -+ -+static const struct of_device_id __maybe_unused mchp_otpc_ids[] = { -+ { .compatible = "microchip,sama7g5-otpc", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, mchp_otpc_ids); -+ -+static struct platform_driver mchp_otpc_driver = { -+ .probe = mchp_otpc_probe, -+ .driver = { -+ .name = MCHP_OTPC_NAME, -+ .of_match_table = of_match_ptr(mchp_otpc_ids), -+ }, -+}; -+module_platform_driver(mchp_otpc_driver); -+ -+MODULE_AUTHOR("Claudiu Beznea "); -+MODULE_DESCRIPTION("Microchip SAMA7G5 OTPC driver"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch b/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch deleted file mode 100644 index 6a4126b9ded..00000000000 --- a/target/linux/generic/backport-6.1/806-v6.0-0002-nvmem-mtk-efuse-Simplify-with-devm_platform_get_and_.patch +++ /dev/null @@ -1,32 +0,0 @@ -From f5c97da8037b18d1256a58459fa96ed68e50fb41 Mon Sep 17 00:00:00 2001 -From: AngeloGioacchino Del Regno -Date: Wed, 6 Jul 2022 11:06:27 +0100 -Subject: [PATCH] nvmem: mtk-efuse: Simplify with - devm_platform_get_and_ioremap_resource() - -Convert platform_get_resource(), devm_ioremap_resource() to a single -call to devm_platform_get_and_ioremap_resource(), as this is exactly -what this function does. - -No functional changes. - -Signed-off-by: AngeloGioacchino Del Regno -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220706100627.6534-8-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/mtk-efuse.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/nvmem/mtk-efuse.c -+++ b/drivers/nvmem/mtk-efuse.c -@@ -41,8 +41,7 @@ static int mtk_efuse_probe(struct platfo - if (!priv) - return -ENOMEM; - -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- priv->base = devm_ioremap_resource(dev, res); -+ priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); - diff --git a/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch b/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch deleted file mode 100644 index 9138807bc91..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0002-nvmem-add-driver-handling-U-Boot-environment-variabl.patch +++ /dev/null @@ -1,286 +0,0 @@ -From d5542923f200f95bddf524f36fd495f78aa28e3c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 16 Sep 2022 13:20:48 +0100 -Subject: [PATCH] nvmem: add driver handling U-Boot environment variables -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -U-Boot stores its setup as environment variables. It's a list of -key-value pairs stored on flash device with a custom header. - -This commit adds an NVMEM driver that: -1. Provides NVMEM access to environment vars binary data -2. Extracts variables as NVMEM cells - -Current Linux's NVMEM sysfs API allows reading whole NVMEM data block. -It can be used by user-space tools for reading U-Boot env vars block -without the hassle of finding its location. Parsing will still need to -be re-done there. - -Kernel-parsed NVMEM cells can be read however by Linux drivers. This may -be useful for Ethernet drivers for reading device MAC address which is -often stored as U-Boot env variable. - -Reviewed-by: Ahmad Fatoum -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - MAINTAINERS | 1 + - drivers/nvmem/Kconfig | 13 +++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/u-boot-env.c | 218 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 234 insertions(+) - create mode 100644 drivers/nvmem/u-boot-env.c - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -344,4 +344,17 @@ config NVMEM_APPLE_EFUSES - This driver can also be built as a module. If so, the module will - be called nvmem-apple-efuses. - -+config NVMEM_U_BOOT_ENV -+ tristate "U-Boot environment variables support" -+ depends on OF && MTD -+ select CRC32 -+ help -+ U-Boot stores its setup as environment variables. This driver adds -+ support for verifying & exporting such data. It also exposes variables -+ as NVMEM cells so they can be referenced by other drivers. -+ -+ Currently this drivers works only with env variables on top of MTD. -+ -+ If compiled as module it will be called nvmem_u-boot-env. -+ - endif ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -69,3 +69,5 @@ obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvme - nvmem-apple-efuses-y := apple-efuses.o - obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o - nvmem-microchip-otpc-y := microchip-otpc.o -+obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o -+nvmem_u-boot-env-y := u-boot-env.o ---- /dev/null -+++ b/drivers/nvmem/u-boot-env.c -@@ -0,0 +1,218 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * Copyright (C) 2022 Rafał Miłecki -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+enum u_boot_env_format { -+ U_BOOT_FORMAT_SINGLE, -+ U_BOOT_FORMAT_REDUNDANT, -+}; -+ -+struct u_boot_env { -+ struct device *dev; -+ enum u_boot_env_format format; -+ -+ struct mtd_info *mtd; -+ -+ /* Cells */ -+ struct nvmem_cell_info *cells; -+ int ncells; -+}; -+ -+struct u_boot_env_image_single { -+ __le32 crc32; -+ uint8_t data[]; -+} __packed; -+ -+struct u_boot_env_image_redundant { -+ __le32 crc32; -+ u8 mark; -+ uint8_t data[]; -+} __packed; -+ -+static int u_boot_env_read(void *context, unsigned int offset, void *val, -+ size_t bytes) -+{ -+ struct u_boot_env *priv = context; -+ struct device *dev = priv->dev; -+ size_t bytes_read; -+ int err; -+ -+ err = mtd_read(priv->mtd, offset, bytes, &bytes_read, val); -+ if (err && !mtd_is_bitflip(err)) { -+ dev_err(dev, "Failed to read from mtd: %d\n", err); -+ return err; -+ } -+ -+ if (bytes_read != bytes) { -+ dev_err(dev, "Failed to read %zu bytes\n", bytes); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int u_boot_env_add_cells(struct u_boot_env *priv, uint8_t *buf, -+ size_t data_offset, size_t data_len) -+{ -+ struct device *dev = priv->dev; -+ char *data = buf + data_offset; -+ char *var, *value, *eq; -+ int idx; -+ -+ priv->ncells = 0; -+ for (var = data; var < data + data_len && *var; var += strlen(var) + 1) -+ priv->ncells++; -+ -+ priv->cells = devm_kcalloc(dev, priv->ncells, sizeof(*priv->cells), GFP_KERNEL); -+ if (!priv->cells) -+ return -ENOMEM; -+ -+ for (var = data, idx = 0; -+ var < data + data_len && *var; -+ var = value + strlen(value) + 1, idx++) { -+ eq = strchr(var, '='); -+ if (!eq) -+ break; -+ *eq = '\0'; -+ value = eq + 1; -+ -+ priv->cells[idx].name = devm_kstrdup(dev, var, GFP_KERNEL); -+ if (!priv->cells[idx].name) -+ return -ENOMEM; -+ priv->cells[idx].offset = data_offset + value - data; -+ priv->cells[idx].bytes = strlen(value); -+ } -+ -+ if (WARN_ON(idx != priv->ncells)) -+ priv->ncells = idx; -+ -+ return 0; -+} -+ -+static int u_boot_env_parse(struct u_boot_env *priv) -+{ -+ struct device *dev = priv->dev; -+ size_t crc32_data_offset; -+ size_t crc32_data_len; -+ size_t crc32_offset; -+ size_t data_offset; -+ size_t data_len; -+ uint32_t crc32; -+ uint32_t calc; -+ size_t bytes; -+ uint8_t *buf; -+ int err; -+ -+ buf = kcalloc(1, priv->mtd->size, GFP_KERNEL); -+ if (!buf) { -+ err = -ENOMEM; -+ goto err_out; -+ } -+ -+ err = mtd_read(priv->mtd, 0, priv->mtd->size, &bytes, buf); -+ if ((err && !mtd_is_bitflip(err)) || bytes != priv->mtd->size) { -+ dev_err(dev, "Failed to read from mtd: %d\n", err); -+ goto err_kfree; -+ } -+ -+ switch (priv->format) { -+ case U_BOOT_FORMAT_SINGLE: -+ crc32_offset = offsetof(struct u_boot_env_image_single, crc32); -+ crc32_data_offset = offsetof(struct u_boot_env_image_single, data); -+ data_offset = offsetof(struct u_boot_env_image_single, data); -+ break; -+ case U_BOOT_FORMAT_REDUNDANT: -+ crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32); -+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark); -+ data_offset = offsetof(struct u_boot_env_image_redundant, data); -+ break; -+ } -+ crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset)); -+ crc32_data_len = priv->mtd->size - crc32_data_offset; -+ data_len = priv->mtd->size - data_offset; -+ -+ calc = crc32(~0, buf + crc32_data_offset, crc32_data_len) ^ ~0L; -+ if (calc != crc32) { -+ dev_err(dev, "Invalid calculated CRC32: 0x%08x (expected: 0x%08x)\n", calc, crc32); -+ err = -EINVAL; -+ goto err_kfree; -+ } -+ -+ buf[priv->mtd->size - 1] = '\0'; -+ err = u_boot_env_add_cells(priv, buf, data_offset, data_len); -+ if (err) -+ dev_err(dev, "Failed to add cells: %d\n", err); -+ -+err_kfree: -+ kfree(buf); -+err_out: -+ return err; -+} -+ -+static int u_boot_env_probe(struct platform_device *pdev) -+{ -+ struct nvmem_config config = { -+ .name = "u-boot-env", -+ .reg_read = u_boot_env_read, -+ }; -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct u_boot_env *priv; -+ int err; -+ -+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ priv->dev = dev; -+ -+ priv->format = (uintptr_t)of_device_get_match_data(dev); -+ -+ priv->mtd = of_get_mtd_device_by_node(np); -+ if (IS_ERR(priv->mtd)) { -+ dev_err_probe(dev, PTR_ERR(priv->mtd), "Failed to get %pOF MTD\n", np); -+ return PTR_ERR(priv->mtd); -+ } -+ -+ err = u_boot_env_parse(priv); -+ if (err) -+ return err; -+ -+ config.dev = dev; -+ config.cells = priv->cells; -+ config.ncells = priv->ncells; -+ config.priv = priv; -+ config.size = priv->mtd->size; -+ -+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &config)); -+} -+ -+static const struct of_device_id u_boot_env_of_match_table[] = { -+ { .compatible = "u-boot,env", .data = (void *)U_BOOT_FORMAT_SINGLE, }, -+ { .compatible = "u-boot,env-redundant-bool", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, -+ { .compatible = "u-boot,env-redundant-count", .data = (void *)U_BOOT_FORMAT_REDUNDANT, }, -+ {}, -+}; -+ -+static struct platform_driver u_boot_env_driver = { -+ .probe = u_boot_env_probe, -+ .driver = { -+ .name = "u_boot_env", -+ .of_match_table = u_boot_env_of_match_table, -+ }, -+}; -+module_platform_driver(u_boot_env_driver); -+ -+MODULE_AUTHOR("Rafał Miłecki"); -+MODULE_LICENSE("GPL"); -+MODULE_DEVICE_TABLE(of, u_boot_env_of_match_table); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch b/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch deleted file mode 100644 index 48ad63fab5f..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0004-nvmem-brcm_nvram-Use-kzalloc-for-allocating-only-one.patch +++ /dev/null @@ -1,29 +0,0 @@ -From d3524bb5b9a0c567b853a0024526afe87dde01ed Mon Sep 17 00:00:00 2001 -From: Kenneth Lee -Date: Fri, 16 Sep 2022 13:20:52 +0100 -Subject: [PATCH] nvmem: brcm_nvram: Use kzalloc for allocating only one - element - -Use kzalloc(...) rather than kcalloc(1, ...) because the number of -elements we are specifying in this case is 1, so kzalloc would -accomplish the same thing and we can simplify. - -Signed-off-by: Kenneth Lee -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-6-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/brcm_nvram.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/brcm_nvram.c -+++ b/drivers/nvmem/brcm_nvram.c -@@ -96,7 +96,7 @@ static int brcm_nvram_parse(struct brcm_ - - len = le32_to_cpu(header.len); - -- data = kcalloc(1, len, GFP_KERNEL); -+ data = kzalloc(len, GFP_KERNEL); - memcpy_fromio(data, priv->base, len); - data[len - 1] = '\0'; - diff --git a/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch b/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch deleted file mode 100644 index ae02439bd73..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0005-nvmem-prefix-all-symbols-with-NVMEM_.patch +++ /dev/null @@ -1,281 +0,0 @@ -From 28fc7c986f01fdcfd28af648be2597624cac0e27 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 16 Sep 2022 13:20:54 +0100 -Subject: [PATCH] nvmem: prefix all symbols with NVMEM_ -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This unifies all NVMEM symbols. They follow one style now. - -Reviewed-by: Matthias Brugger -Acked-by: Arnd Bergmann -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-8-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - arch/arm/configs/multi_v7_defconfig | 6 +++--- - arch/arm/configs/qcom_defconfig | 2 +- - arch/arm64/configs/defconfig | 10 +++++----- - arch/mips/configs/ci20_defconfig | 2 +- - drivers/cpufreq/Kconfig.arm | 2 +- - drivers/nvmem/Kconfig | 24 ++++++++++++------------ - drivers/nvmem/Makefile | 24 ++++++++++++------------ - drivers/soc/mediatek/Kconfig | 2 +- - drivers/thermal/qcom/Kconfig | 2 +- - 9 files changed, 37 insertions(+), 37 deletions(-) - ---- a/arch/arm/configs/multi_v7_defconfig -+++ b/arch/arm/configs/multi_v7_defconfig -@@ -1125,10 +1125,10 @@ CONFIG_TI_PIPE3=y - CONFIG_TWL4030_USB=m - CONFIG_RAS=y - CONFIG_NVMEM_IMX_OCOTP=y --CONFIG_ROCKCHIP_EFUSE=m -+CONFIG_NVMEM_ROCKCHIP_EFUSE=m - CONFIG_NVMEM_SUNXI_SID=y - CONFIG_NVMEM_VF610_OCOTP=y --CONFIG_MESON_MX_EFUSE=m -+CONFIG_NVMEM_MESON_MX_EFUSE=m - CONFIG_NVMEM_RMEM=m - CONFIG_FSI=m - CONFIG_FSI_MASTER_GPIO=m ---- a/arch/arm/configs/qcom_defconfig -+++ b/arch/arm/configs/qcom_defconfig -@@ -274,7 +274,7 @@ CONFIG_PHY_QCOM_USB_HS=y - CONFIG_PHY_QCOM_USB_HSIC=y - CONFIG_PHY_QCOM_QMP=y - CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y --CONFIG_QCOM_QFPROM=y -+CONFIG_NVMEM_QCOM_QFPROM=y - CONFIG_INTERCONNECT=y - CONFIG_INTERCONNECT_QCOM=y - CONFIG_INTERCONNECT_QCOM_MSM8974=m ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -1135,11 +1135,11 @@ CONFIG_QCOM_L3_PMU=y - CONFIG_NVMEM_IMX_OCOTP=y - CONFIG_NVMEM_IMX_OCOTP_SCU=y - CONFIG_QCOM_QFPROM=y --CONFIG_MTK_EFUSE=y --CONFIG_ROCKCHIP_EFUSE=y -+CONFIG_NVMEM_MTK_EFUSE=y -+CONFIG_NVMEM_ROCKCHIP_EFUSE=y - CONFIG_NVMEM_SUNXI_SID=y --CONFIG_UNIPHIER_EFUSE=y --CONFIG_MESON_EFUSE=m -+CONFIG_NVMEM_UNIPHIER_EFUSE=y -+CONFIG_NVMEM_MESON_EFUSE=m - CONFIG_NVMEM_RMEM=m - CONFIG_FPGA=y - CONFIG_FPGA_MGR_STRATIX10_SOC=m ---- a/arch/mips/configs/ci20_defconfig -+++ b/arch/mips/configs/ci20_defconfig -@@ -137,7 +137,7 @@ CONFIG_MEMORY=y - CONFIG_JZ4780_NEMC=y - CONFIG_PWM=y - CONFIG_PWM_JZ4740=m --CONFIG_JZ4780_EFUSE=y -+CONFIG_NVMEM_JZ4780_EFUSE=y - CONFIG_JZ4770_PHY=y - CONFIG_EXT4_FS=y - # CONFIG_DNOTIFY is not set ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -153,7 +153,7 @@ config ARM_OMAP2PLUS_CPUFREQ - config ARM_QCOM_CPUFREQ_NVMEM - tristate "Qualcomm nvmem based CPUFreq" - depends on ARCH_QCOM -- depends on QCOM_QFPROM -+ depends on NVMEM_QCOM_QFPROM - depends on QCOM_SMEM - select PM_OPP - help ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -52,7 +52,7 @@ config NVMEM_IMX_OCOTP_SCU - This is a driver for the SCU On-Chip OTP Controller (OCOTP) - available on i.MX8 SoCs. - --config JZ4780_EFUSE -+config NVMEM_JZ4780_EFUSE - tristate "JZ4780 EFUSE Memory Support" - depends on MACH_INGENIC || COMPILE_TEST - depends on HAS_IOMEM -@@ -96,7 +96,7 @@ config NVMEM_MXS_OCOTP - This driver can also be built as a module. If so, the module - will be called nvmem-mxs-ocotp. - --config MTK_EFUSE -+config NVMEM_MTK_EFUSE - tristate "Mediatek SoCs EFUSE support" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM -@@ -107,7 +107,7 @@ config MTK_EFUSE - This driver can also be built as a module. If so, the module - will be called efuse-mtk. - --config MICROCHIP_OTPC -+config NVMEM_MICROCHIP_OTPC - tristate "Microchip OTPC support" - depends on ARCH_AT91 || COMPILE_TEST - help -@@ -126,7 +126,7 @@ config NVMEM_NINTENDO_OTP - This driver can also be built as a module. If so, the module - will be called nvmem-nintendo-otp. - --config QCOM_QFPROM -+config NVMEM_QCOM_QFPROM - tristate "QCOM QFPROM Support" - depends on ARCH_QCOM || COMPILE_TEST - depends on HAS_IOMEM -@@ -145,7 +145,7 @@ config NVMEM_SPMI_SDAM - Qualcomm Technologies, Inc. PMICs. It provides the clients - an interface to read/write to the SDAM module's shared memory. - --config ROCKCHIP_EFUSE -+config NVMEM_ROCKCHIP_EFUSE - tristate "Rockchip eFuse Support" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on HAS_IOMEM -@@ -156,7 +156,7 @@ config ROCKCHIP_EFUSE - This driver can also be built as a module. If so, the module - will be called nvmem_rockchip_efuse. - --config ROCKCHIP_OTP -+config NVMEM_ROCKCHIP_OTP - tristate "Rockchip OTP controller support" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on HAS_IOMEM -@@ -199,7 +199,7 @@ config NVMEM_SUNXI_SID - This driver can also be built as a module. If so, the module - will be called nvmem_sunxi_sid. - --config UNIPHIER_EFUSE -+config NVMEM_UNIPHIER_EFUSE - tristate "UniPhier SoCs eFuse support" - depends on ARCH_UNIPHIER || COMPILE_TEST - depends on HAS_IOMEM -@@ -221,7 +221,7 @@ config NVMEM_VF610_OCOTP - This driver can also be build as a module. If so, the module will - be called nvmem-vf610-ocotp. - --config MESON_EFUSE -+config NVMEM_MESON_EFUSE - tristate "Amlogic Meson GX eFuse Support" - depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM - help -@@ -231,7 +231,7 @@ config MESON_EFUSE - This driver can also be built as a module. If so, the module - will be called nvmem_meson_efuse. - --config MESON_MX_EFUSE -+config NVMEM_MESON_MX_EFUSE - tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" - depends on ARCH_MESON || COMPILE_TEST - help -@@ -251,13 +251,13 @@ config NVMEM_SNVS_LPGPR - This driver can also be built as a module. If so, the module - will be called nvmem-snvs-lpgpr. - --config RAVE_SP_EEPROM -+config NVMEM_RAVE_SP_EEPROM - tristate "Rave SP EEPROM Support" - depends on RAVE_SP_CORE - help - Say y here to enable Rave SP EEPROM support. - --config SC27XX_EFUSE -+config NVMEM_SC27XX_EFUSE - tristate "Spreadtrum SC27XX eFuse Support" - depends on MFD_SC27XX_PMIC || COMPILE_TEST - depends on HAS_IOMEM -@@ -278,7 +278,7 @@ config NVMEM_ZYNQMP - - If sure, say yes. If unsure, say no. - --config SPRD_EFUSE -+config NVMEM_SPRD_EFUSE - tristate "Spreadtrum SoC eFuse Support" - depends on ARCH_SPRD || COMPILE_TEST - depends on HAS_IOMEM ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -15,7 +15,7 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-i - nvmem-imx-ocotp-y := imx-ocotp.o - obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o - nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o --obj-$(CONFIG_JZ4780_EFUSE) += nvmem_jz4780_efuse.o -+obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o - nvmem_jz4780_efuse-y := jz4780-efuse.o - obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o - nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o -@@ -25,37 +25,37 @@ obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-m - nvmem-mxs-ocotp-y := mxs-ocotp.o - obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o - nvmem-nintendo-otp-y := nintendo-otp.o --obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o -+obj-$(CONFIG_NVMEM_MTK_EFUSE) += nvmem_mtk-efuse.o - nvmem_mtk-efuse-y := mtk-efuse.o --obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o -+obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o - nvmem_qfprom-y := qfprom.o - obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o - nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o --obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o -+obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o - nvmem_rockchip_efuse-y := rockchip-efuse.o --obj-$(CONFIG_ROCKCHIP_OTP) += nvmem-rockchip-otp.o -+obj-$(CONFIG_NVMEM_ROCKCHIP_OTP) += nvmem-rockchip-otp.o - nvmem-rockchip-otp-y := rockchip-otp.o - obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o - nvmem_stm32_romem-y := stm32-romem.o - obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o - nvmem_sunxi_sid-y := sunxi_sid.o --obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o -+obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o - nvmem-uniphier-efuse-y := uniphier-efuse.o - obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o - nvmem-vf610-ocotp-y := vf610-ocotp.o --obj-$(CONFIG_MESON_EFUSE) += nvmem_meson_efuse.o -+obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o - nvmem_meson_efuse-y := meson-efuse.o --obj-$(CONFIG_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o -+obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o - nvmem_meson_mx_efuse-y := meson-mx-efuse.o - obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o - nvmem_snvs_lpgpr-y := snvs_lpgpr.o --obj-$(CONFIG_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o -+obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o - nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o --obj-$(CONFIG_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o -+obj-$(CONFIG_NVMEM_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o - nvmem-sc27xx-efuse-y := sc27xx-efuse.o - obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o - nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o --obj-$(CONFIG_SPRD_EFUSE) += nvmem_sprd_efuse.o -+obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o - nvmem_sprd_efuse-y := sprd-efuse.o - obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o - nvmem-rmem-y := rmem.o -@@ -67,7 +67,7 @@ obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvm - nvmem_sunplus_ocotp-y := sunplus-ocotp.o - obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o - nvmem-apple-efuses-y := apple-efuses.o --obj-$(CONFIG_MICROCHIP_OTPC) += nvmem-microchip-otpc.o -+obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o - nvmem-microchip-otpc-y := microchip-otpc.o - obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o - nvmem_u-boot-env-y := u-boot-env.o ---- a/drivers/thermal/qcom/Kconfig -+++ b/drivers/thermal/qcom/Kconfig -@@ -1,7 +1,7 @@ - # SPDX-License-Identifier: GPL-2.0-only - config QCOM_TSENS - tristate "Qualcomm TSENS Temperature Alarm" -- depends on QCOM_QFPROM -+ depends on NVMEM_QCOM_QFPROM - depends on ARCH_QCOM || COMPILE_TEST - help - This enables the thermal sysfs driver for the TSENS device. It shows diff --git a/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch b/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch deleted file mode 100644 index 4e45524bffc..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0006-nvmem-sort-config-symbols-alphabetically.patch +++ /dev/null @@ -1,535 +0,0 @@ -From a06d9e5a63b7c2f622c908cd9600ce735e70f7c6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 16 Sep 2022 13:20:55 +0100 -Subject: [PATCH] nvmem: sort config symbols alphabetically -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -1. Match what most subsystems do -2. Simplify maintenance a bit -3. Reduce amount of conflicts for new drivers patches - -While at it unify indent level in Makefile. - -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-9-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/Kconfig | 300 +++++++++++++++++++++-------------------- - drivers/nvmem/Makefile | 114 ++++++++-------- - 2 files changed, 208 insertions(+), 206 deletions(-) - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -21,6 +21,40 @@ config NVMEM_SYSFS - This interface is mostly used by userspace applications to - read/write directly into nvmem. - -+# Devices -+ -+config NVMEM_APPLE_EFUSES -+ tristate "Apple eFuse support" -+ depends on ARCH_APPLE || COMPILE_TEST -+ default ARCH_APPLE -+ help -+ Say y here to enable support for reading eFuses on Apple SoCs -+ such as the M1. These are e.g. used to store factory programmed -+ calibration data required for the PCIe or the USB-C PHY. -+ -+ This driver can also be built as a module. If so, the module will -+ be called nvmem-apple-efuses. -+ -+config NVMEM_BCM_OCOTP -+ tristate "Broadcom On-Chip OTP Controller support" -+ depends on ARCH_BCM_IPROC || COMPILE_TEST -+ depends on HAS_IOMEM -+ default ARCH_BCM_IPROC -+ help -+ Say y here to enable read/write access to the Broadcom OTP -+ controller. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-bcm-ocotp. -+ -+config NVMEM_BRCM_NVRAM -+ tristate "Broadcom's NVRAM support" -+ depends on ARCH_BCM_5301X || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This driver provides support for Broadcom's NVRAM that can be accessed -+ using I/O mapping. -+ - config NVMEM_IMX_IIM - tristate "i.MX IC Identification Module support" - depends on ARCH_MXC || COMPILE_TEST -@@ -64,6 +98,19 @@ config NVMEM_JZ4780_EFUSE - To compile this driver as a module, choose M here: the module - will be called nvmem_jz4780_efuse. - -+config NVMEM_LAYERSCAPE_SFP -+ tristate "Layerscape SFP (Security Fuse Processor) support" -+ depends on ARCH_LAYERSCAPE || COMPILE_TEST -+ depends on HAS_IOMEM -+ select REGMAP_MMIO -+ help -+ This driver provides support to read the eFuses on Freescale -+ Layerscape SoC's. For example, the vendor provides a per part -+ unique ID there. -+ -+ This driver can also be built as a module. If so, the module -+ will be called layerscape-sfp. -+ - config NVMEM_LPC18XX_EEPROM - tristate "NXP LPC18XX EEPROM Memory Support" - depends on ARCH_LPC18XX || COMPILE_TEST -@@ -84,17 +131,32 @@ config NVMEM_LPC18XX_OTP - To compile this driver as a module, choose M here: the module - will be called nvmem_lpc18xx_otp. - --config NVMEM_MXS_OCOTP -- tristate "Freescale MXS On-Chip OTP Memory Support" -- depends on ARCH_MXS || COMPILE_TEST -- depends on HAS_IOMEM -+config NVMEM_MESON_EFUSE -+ tristate "Amlogic Meson GX eFuse Support" -+ depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM - help -- If you say Y here, you will get readonly access to the -- One Time Programmable memory pages that are stored -- on the Freescale i.MX23/i.MX28 processor. -+ This is a driver to retrieve specific values from the eFuse found on -+ the Amlogic Meson GX SoCs. - - This driver can also be built as a module. If so, the module -- will be called nvmem-mxs-ocotp. -+ will be called nvmem_meson_efuse. -+ -+config NVMEM_MESON_MX_EFUSE -+ tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" -+ depends on ARCH_MESON || COMPILE_TEST -+ help -+ This is a driver to retrieve specific values from the eFuse found on -+ the Amlogic Meson6, Meson8 and Meson8b SoCs. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem_meson_mx_efuse. -+ -+config NVMEM_MICROCHIP_OTPC -+ tristate "Microchip OTPC support" -+ depends on ARCH_AT91 || COMPILE_TEST -+ help -+ This driver enable the OTP controller available on Microchip SAMA7G5 -+ SoCs. It controlls the access to the OTP memory connected to it. - - config NVMEM_MTK_EFUSE - tristate "Mediatek SoCs EFUSE support" -@@ -107,12 +169,17 @@ config NVMEM_MTK_EFUSE - This driver can also be built as a module. If so, the module - will be called efuse-mtk. - --config NVMEM_MICROCHIP_OTPC -- tristate "Microchip OTPC support" -- depends on ARCH_AT91 || COMPILE_TEST -+config NVMEM_MXS_OCOTP -+ tristate "Freescale MXS On-Chip OTP Memory Support" -+ depends on ARCH_MXS || COMPILE_TEST -+ depends on HAS_IOMEM - help -- This driver enable the OTP controller available on Microchip SAMA7G5 -- SoCs. It controlls the access to the OTP memory connected to it. -+ If you say Y here, you will get readonly access to the -+ One Time Programmable memory pages that are stored -+ on the Freescale i.MX23/i.MX28 processor. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-mxs-ocotp. - - config NVMEM_NINTENDO_OTP - tristate "Nintendo Wii and Wii U OTP Support" -@@ -137,13 +204,21 @@ config NVMEM_QCOM_QFPROM - This driver can also be built as a module. If so, the module - will be called nvmem_qfprom. - --config NVMEM_SPMI_SDAM -- tristate "SPMI SDAM Support" -- depends on SPMI -+config NVMEM_RAVE_SP_EEPROM -+ tristate "Rave SP EEPROM Support" -+ depends on RAVE_SP_CORE - help -- This driver supports the Shared Direct Access Memory Module on -- Qualcomm Technologies, Inc. PMICs. It provides the clients -- an interface to read/write to the SDAM module's shared memory. -+ Say y here to enable Rave SP EEPROM support. -+ -+config NVMEM_RMEM -+ tristate "Reserved Memory Based Driver Support" -+ depends on HAS_IOMEM -+ help -+ This driver maps reserved memory into an nvmem device. It might be -+ useful to expose information left by firmware in memory. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-rmem. - - config NVMEM_ROCKCHIP_EFUSE - tristate "Rockchip eFuse Support" -@@ -167,79 +242,16 @@ config NVMEM_ROCKCHIP_OTP - This driver can also be built as a module. If so, the module - will be called nvmem_rockchip_otp. - --config NVMEM_BCM_OCOTP -- tristate "Broadcom On-Chip OTP Controller support" -- depends on ARCH_BCM_IPROC || COMPILE_TEST -- depends on HAS_IOMEM -- default ARCH_BCM_IPROC -- help -- Say y here to enable read/write access to the Broadcom OTP -- controller. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem-bcm-ocotp. -- --config NVMEM_STM32_ROMEM -- tristate "STMicroelectronics STM32 factory-programmed memory support" -- depends on ARCH_STM32 || COMPILE_TEST -- help -- Say y here to enable read-only access for STMicroelectronics STM32 -- factory-programmed memory area. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem-stm32-romem. -- --config NVMEM_SUNXI_SID -- tristate "Allwinner SoCs SID support" -- depends on ARCH_SUNXI -- help -- This is a driver for the 'security ID' available on various Allwinner -- devices. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem_sunxi_sid. -- --config NVMEM_UNIPHIER_EFUSE -- tristate "UniPhier SoCs eFuse support" -- depends on ARCH_UNIPHIER || COMPILE_TEST -- depends on HAS_IOMEM -- help -- This is a simple driver to dump specified values of UniPhier SoC -- from eFuse. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem-uniphier-efuse. -- --config NVMEM_VF610_OCOTP -- tristate "VF610 SoC OCOTP support" -- depends on SOC_VF610 || COMPILE_TEST -+config NVMEM_SC27XX_EFUSE -+ tristate "Spreadtrum SC27XX eFuse Support" -+ depends on MFD_SC27XX_PMIC || COMPILE_TEST - depends on HAS_IOMEM - help -- This is a driver for the 'OCOTP' peripheral available on Vybrid -- devices like VF5xx and VF6xx. -- -- This driver can also be build as a module. If so, the module will -- be called nvmem-vf610-ocotp. -- --config NVMEM_MESON_EFUSE -- tristate "Amlogic Meson GX eFuse Support" -- depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM -- help -- This is a driver to retrieve specific values from the eFuse found on -- the Amlogic Meson GX SoCs. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem_meson_efuse. -- --config NVMEM_MESON_MX_EFUSE -- tristate "Amlogic Meson6/Meson8/Meson8b eFuse Support" -- depends on ARCH_MESON || COMPILE_TEST -- help -- This is a driver to retrieve specific values from the eFuse found on -- the Amlogic Meson6, Meson8 and Meson8b SoCs. -+ This is a simple driver to dump specified values of Spreadtrum -+ SC27XX PMICs from eFuse. - - This driver can also be built as a module. If so, the module -- will be called nvmem_meson_mx_efuse. -+ will be called nvmem-sc27xx-efuse. - - config NVMEM_SNVS_LPGPR - tristate "Support for Low Power General Purpose Register" -@@ -251,32 +263,13 @@ config NVMEM_SNVS_LPGPR - This driver can also be built as a module. If so, the module - will be called nvmem-snvs-lpgpr. - --config NVMEM_RAVE_SP_EEPROM -- tristate "Rave SP EEPROM Support" -- depends on RAVE_SP_CORE -- help -- Say y here to enable Rave SP EEPROM support. -- --config NVMEM_SC27XX_EFUSE -- tristate "Spreadtrum SC27XX eFuse Support" -- depends on MFD_SC27XX_PMIC || COMPILE_TEST -- depends on HAS_IOMEM -- help -- This is a simple driver to dump specified values of Spreadtrum -- SC27XX PMICs from eFuse. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem-sc27xx-efuse. -- --config NVMEM_ZYNQMP -- bool "Xilinx ZYNQMP SoC nvmem firmware support" -- depends on ARCH_ZYNQMP -+config NVMEM_SPMI_SDAM -+ tristate "SPMI SDAM Support" -+ depends on SPMI - help -- This is a driver to access hardware related data like -- soc revision, IDCODE... etc by using the firmware -- interface. -- -- If sure, say yes. If unsure, say no. -+ This driver supports the Shared Direct Access Memory Module on -+ Qualcomm Technologies, Inc. PMICs. It provides the clients -+ an interface to read/write to the SDAM module's shared memory. - - config NVMEM_SPRD_EFUSE - tristate "Spreadtrum SoC eFuse Support" -@@ -289,36 +282,15 @@ config NVMEM_SPRD_EFUSE - This driver can also be built as a module. If so, the module - will be called nvmem-sprd-efuse. - --config NVMEM_RMEM -- tristate "Reserved Memory Based Driver Support" -- depends on HAS_IOMEM -- help -- This driver maps reserved memory into an nvmem device. It might be -- useful to expose information left by firmware in memory. -- -- This driver can also be built as a module. If so, the module -- will be called nvmem-rmem. -- --config NVMEM_BRCM_NVRAM -- tristate "Broadcom's NVRAM support" -- depends on ARCH_BCM_5301X || COMPILE_TEST -- depends on HAS_IOMEM -- help -- This driver provides support for Broadcom's NVRAM that can be accessed -- using I/O mapping. -- --config NVMEM_LAYERSCAPE_SFP -- tristate "Layerscape SFP (Security Fuse Processor) support" -- depends on ARCH_LAYERSCAPE || COMPILE_TEST -- depends on HAS_IOMEM -- select REGMAP_MMIO -+config NVMEM_STM32_ROMEM -+ tristate "STMicroelectronics STM32 factory-programmed memory support" -+ depends on ARCH_STM32 || COMPILE_TEST - help -- This driver provides support to read the eFuses on Freescale -- Layerscape SoC's. For example, the vendor provides a per part -- unique ID there. -+ Say y here to enable read-only access for STMicroelectronics STM32 -+ factory-programmed memory area. - - This driver can also be built as a module. If so, the module -- will be called layerscape-sfp. -+ will be called nvmem-stm32-romem. - - config NVMEM_SUNPLUS_OCOTP - tristate "Sunplus SoC OTP support" -@@ -332,17 +304,15 @@ config NVMEM_SUNPLUS_OCOTP - This driver can also be built as a module. If so, the module - will be called nvmem-sunplus-ocotp. - --config NVMEM_APPLE_EFUSES -- tristate "Apple eFuse support" -- depends on ARCH_APPLE || COMPILE_TEST -- default ARCH_APPLE -+config NVMEM_SUNXI_SID -+ tristate "Allwinner SoCs SID support" -+ depends on ARCH_SUNXI - help -- Say y here to enable support for reading eFuses on Apple SoCs -- such as the M1. These are e.g. used to store factory programmed -- calibration data required for the PCIe or the USB-C PHY. -+ This is a driver for the 'security ID' available on various Allwinner -+ devices. - -- This driver can also be built as a module. If so, the module will -- be called nvmem-apple-efuses. -+ This driver can also be built as a module. If so, the module -+ will be called nvmem_sunxi_sid. - - config NVMEM_U_BOOT_ENV - tristate "U-Boot environment variables support" -@@ -357,4 +327,36 @@ config NVMEM_U_BOOT_ENV - - If compiled as module it will be called nvmem_u-boot-env. - -+config NVMEM_UNIPHIER_EFUSE -+ tristate "UniPhier SoCs eFuse support" -+ depends on ARCH_UNIPHIER || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This is a simple driver to dump specified values of UniPhier SoC -+ from eFuse. -+ -+ This driver can also be built as a module. If so, the module -+ will be called nvmem-uniphier-efuse. -+ -+config NVMEM_VF610_OCOTP -+ tristate "VF610 SoC OCOTP support" -+ depends on SOC_VF610 || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This is a driver for the 'OCOTP' peripheral available on Vybrid -+ devices like VF5xx and VF6xx. -+ -+ This driver can also be build as a module. If so, the module will -+ be called nvmem-vf610-ocotp. -+ -+config NVMEM_ZYNQMP -+ bool "Xilinx ZYNQMP SoC nvmem firmware support" -+ depends on ARCH_ZYNQMP -+ help -+ This is a driver to access hardware related data like -+ soc revision, IDCODE... etc by using the firmware -+ interface. -+ -+ If sure, say yes. If unsure, say no. -+ - endif ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -7,67 +7,67 @@ obj-$(CONFIG_NVMEM) += nvmem_core.o - nvmem_core-y := core.o - - # Devices --obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o --nvmem-bcm-ocotp-y := bcm-ocotp.o --obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o --nvmem-imx-iim-y := imx-iim.o --obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o --nvmem-imx-ocotp-y := imx-ocotp.o -+obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o -+nvmem-apple-efuses-y := apple-efuses.o -+obj-$(CONFIG_NVMEM_BCM_OCOTP) += nvmem-bcm-ocotp.o -+nvmem-bcm-ocotp-y := bcm-ocotp.o -+obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o -+nvmem_brcm_nvram-y := brcm_nvram.o -+obj-$(CONFIG_NVMEM_IMX_IIM) += nvmem-imx-iim.o -+nvmem-imx-iim-y := imx-iim.o -+obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o -+nvmem-imx-ocotp-y := imx-ocotp.o - obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o --nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o --obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o --nvmem_jz4780_efuse-y := jz4780-efuse.o -+nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o -+obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o -+nvmem_jz4780_efuse-y := jz4780-efuse.o -+obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o -+nvmem-layerscape-sfp-y := layerscape-sfp.o - obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o --nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o --obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o --nvmem_lpc18xx_otp-y := lpc18xx_otp.o --obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o --nvmem-mxs-ocotp-y := mxs-ocotp.o --obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o --nvmem-nintendo-otp-y := nintendo-otp.o -+nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o -+obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o -+nvmem_lpc18xx_otp-y := lpc18xx_otp.o -+obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o -+nvmem_meson_efuse-y := meson-efuse.o -+obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o -+nvmem_meson_mx_efuse-y := meson-mx-efuse.o -+obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o -+nvmem-microchip-otpc-y := microchip-otpc.o - obj-$(CONFIG_NVMEM_MTK_EFUSE) += nvmem_mtk-efuse.o --nvmem_mtk-efuse-y := mtk-efuse.o --obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o --nvmem_qfprom-y := qfprom.o --obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o --nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o -+nvmem_mtk-efuse-y := mtk-efuse.o -+obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o -+nvmem-mxs-ocotp-y := mxs-ocotp.o -+obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o -+nvmem-nintendo-otp-y := nintendo-otp.o -+obj-$(CONFIG_NVMEM_QCOM_QFPROM) += nvmem_qfprom.o -+nvmem_qfprom-y := qfprom.o -+obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o -+nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o -+obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o -+nvmem-rmem-y := rmem.o - obj-$(CONFIG_NVMEM_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o --nvmem_rockchip_efuse-y := rockchip-efuse.o -+nvmem_rockchip_efuse-y := rockchip-efuse.o - obj-$(CONFIG_NVMEM_ROCKCHIP_OTP) += nvmem-rockchip-otp.o --nvmem-rockchip-otp-y := rockchip-otp.o --obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o --nvmem_stm32_romem-y := stm32-romem.o --obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o --nvmem_sunxi_sid-y := sunxi_sid.o --obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o --nvmem-uniphier-efuse-y := uniphier-efuse.o --obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o --nvmem-vf610-ocotp-y := vf610-ocotp.o --obj-$(CONFIG_NVMEM_MESON_EFUSE) += nvmem_meson_efuse.o --nvmem_meson_efuse-y := meson-efuse.o --obj-$(CONFIG_NVMEM_MESON_MX_EFUSE) += nvmem_meson_mx_efuse.o --nvmem_meson_mx_efuse-y := meson-mx-efuse.o --obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o --nvmem_snvs_lpgpr-y := snvs_lpgpr.o --obj-$(CONFIG_NVMEM_RAVE_SP_EEPROM) += nvmem-rave-sp-eeprom.o --nvmem-rave-sp-eeprom-y := rave-sp-eeprom.o -+nvmem-rockchip-otp-y := rockchip-otp.o - obj-$(CONFIG_NVMEM_SC27XX_EFUSE) += nvmem-sc27xx-efuse.o --nvmem-sc27xx-efuse-y := sc27xx-efuse.o --obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o --nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o --obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o --nvmem_sprd_efuse-y := sprd-efuse.o --obj-$(CONFIG_NVMEM_RMEM) += nvmem-rmem.o --nvmem-rmem-y := rmem.o --obj-$(CONFIG_NVMEM_BRCM_NVRAM) += nvmem_brcm_nvram.o --nvmem_brcm_nvram-y := brcm_nvram.o --obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o --nvmem-layerscape-sfp-y := layerscape-sfp.o -+nvmem-sc27xx-efuse-y := sc27xx-efuse.o -+obj-$(CONFIG_NVMEM_SNVS_LPGPR) += nvmem_snvs_lpgpr.o -+nvmem_snvs_lpgpr-y := snvs_lpgpr.o -+obj-$(CONFIG_NVMEM_SPMI_SDAM) += nvmem_qcom-spmi-sdam.o -+nvmem_qcom-spmi-sdam-y += qcom-spmi-sdam.o -+obj-$(CONFIG_NVMEM_SPRD_EFUSE) += nvmem_sprd_efuse.o -+nvmem_sprd_efuse-y := sprd-efuse.o -+obj-$(CONFIG_NVMEM_STM32_ROMEM) += nvmem_stm32_romem.o -+nvmem_stm32_romem-y := stm32-romem.o - obj-$(CONFIG_NVMEM_SUNPLUS_OCOTP) += nvmem_sunplus_ocotp.o --nvmem_sunplus_ocotp-y := sunplus-ocotp.o --obj-$(CONFIG_NVMEM_APPLE_EFUSES) += nvmem-apple-efuses.o --nvmem-apple-efuses-y := apple-efuses.o --obj-$(CONFIG_NVMEM_MICROCHIP_OTPC) += nvmem-microchip-otpc.o --nvmem-microchip-otpc-y := microchip-otpc.o --obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o --nvmem_u-boot-env-y := u-boot-env.o -+nvmem_sunplus_ocotp-y := sunplus-ocotp.o -+obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o -+nvmem_sunxi_sid-y := sunxi_sid.o -+obj-$(CONFIG_NVMEM_U_BOOT_ENV) += nvmem_u-boot-env.o -+nvmem_u-boot-env-y := u-boot-env.o -+obj-$(CONFIG_NVMEM_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o -+nvmem-uniphier-efuse-y := uniphier-efuse.o -+obj-$(CONFIG_NVMEM_VF610_OCOTP) += nvmem-vf610-ocotp.o -+nvmem-vf610-ocotp-y := vf610-ocotp.o -+obj-$(CONFIG_NVMEM_ZYNQMP) += nvmem_zynqmp_nvmem.o -+nvmem_zynqmp_nvmem-y := zynqmp_nvmem.o diff --git a/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch b/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch deleted file mode 100644 index e0a082adc45..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0007-nvmem-u-boot-env-find-Device-Tree-nodes-for-NVMEM-ce.patch +++ /dev/null @@ -1,31 +0,0 @@ -From d4d432670f7dee0a5432fcffcfc8699b25181ace Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 16 Sep 2022 13:20:57 +0100 -Subject: [PATCH] nvmem: u-boot-env: find Device Tree nodes for NVMEM cells -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -DT binding allows specifying NVMEM cells as NVMEM device (provider) -subnodes. Looks for such subnodes when building NVMEM cells. - -This allows NVMEM consumers to use U-Boot environment variables. - -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-11-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/u-boot-env.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/nvmem/u-boot-env.c -+++ b/drivers/nvmem/u-boot-env.c -@@ -92,6 +92,7 @@ static int u_boot_env_add_cells(struct u - return -ENOMEM; - priv->cells[idx].offset = data_offset + value - data; - priv->cells[idx].bytes = strlen(value); -+ priv->cells[idx].np = of_get_child_by_name(dev->of_node, priv->cells[idx].name); - } - - if (WARN_ON(idx != priv->ncells)) diff --git a/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch b/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch deleted file mode 100644 index 945c6128ff4..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0008-nvmem-lan9662-otp-add-support.patch +++ /dev/null @@ -1,274 +0,0 @@ -From 9e8f208ad5229ddda97cd4a83ecf89c735d99592 Mon Sep 17 00:00:00 2001 -From: Horatiu Vultur -Date: Fri, 16 Sep 2022 13:20:59 +0100 -Subject: [PATCH] nvmem: lan9662-otp: add support - -Add support for OTP controller available on LAN9662. The OTPC controls -the access to a non-volatile memory. The size of the memory is 8KB. -The OTPC can access the memory based on an offset. -Implement both the read and the write functionality. - -Signed-off-by: Horatiu Vultur -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-13-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/Kconfig | 8 ++ - drivers/nvmem/Makefile | 2 + - drivers/nvmem/lan9662-otpc.c | 222 +++++++++++++++++++++++++++++++++++ - 3 files changed, 232 insertions(+) - create mode 100644 drivers/nvmem/lan9662-otpc.c - ---- a/drivers/nvmem/Kconfig -+++ b/drivers/nvmem/Kconfig -@@ -98,6 +98,14 @@ config NVMEM_JZ4780_EFUSE - To compile this driver as a module, choose M here: the module - will be called nvmem_jz4780_efuse. - -+config NVMEM_LAN9662_OTPC -+ tristate "Microchip LAN9662 OTP controller support" -+ depends on SOC_LAN966 || COMPILE_TEST -+ depends on HAS_IOMEM -+ help -+ This driver enables the OTP controller available on Microchip LAN9662 -+ SoCs. It controls the access to the OTP memory connected to it. -+ - config NVMEM_LAYERSCAPE_SFP - tristate "Layerscape SFP (Security Fuse Processor) support" - depends on ARCH_LAYERSCAPE || COMPILE_TEST ---- a/drivers/nvmem/Makefile -+++ b/drivers/nvmem/Makefile -@@ -21,6 +21,8 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvm - nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o - obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o - nvmem_jz4780_efuse-y := jz4780-efuse.o -+obj-$(CONFIG_NVMEM_LAN9662_OTPC) += nvmem-lan9662-otpc.o -+nvmem-lan9662-otpc-y := lan9662-otpc.o - obj-$(CONFIG_NVMEM_LAYERSCAPE_SFP) += nvmem-layerscape-sfp.o - nvmem-layerscape-sfp-y := layerscape-sfp.o - obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o ---- /dev/null -+++ b/drivers/nvmem/lan9662-otpc.c -@@ -0,0 +1,222 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include -+#include -+#include -+#include -+#include -+ -+#define OTP_OTP_PWR_DN(t) (t + 0x00) -+#define OTP_OTP_PWR_DN_OTP_PWRDN_N BIT(0) -+#define OTP_OTP_ADDR_HI(t) (t + 0x04) -+#define OTP_OTP_ADDR_LO(t) (t + 0x08) -+#define OTP_OTP_PRGM_DATA(t) (t + 0x10) -+#define OTP_OTP_PRGM_MODE(t) (t + 0x14) -+#define OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE BIT(0) -+#define OTP_OTP_RD_DATA(t) (t + 0x18) -+#define OTP_OTP_FUNC_CMD(t) (t + 0x20) -+#define OTP_OTP_FUNC_CMD_OTP_PROGRAM BIT(1) -+#define OTP_OTP_FUNC_CMD_OTP_READ BIT(0) -+#define OTP_OTP_CMD_GO(t) (t + 0x28) -+#define OTP_OTP_CMD_GO_OTP_GO BIT(0) -+#define OTP_OTP_PASS_FAIL(t) (t + 0x2c) -+#define OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED BIT(3) -+#define OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED BIT(2) -+#define OTP_OTP_PASS_FAIL_OTP_FAIL BIT(0) -+#define OTP_OTP_STATUS(t) (t + 0x30) -+#define OTP_OTP_STATUS_OTP_CPUMPEN BIT(1) -+#define OTP_OTP_STATUS_OTP_BUSY BIT(0) -+ -+#define OTP_MEM_SIZE 8192 -+#define OTP_SLEEP_US 10 -+#define OTP_TIMEOUT_US 500000 -+ -+struct lan9662_otp { -+ struct device *dev; -+ void __iomem *base; -+}; -+ -+static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) -+{ -+ u32 val; -+ -+ return readl_poll_timeout(reg, val, !(val & flag), -+ OTP_SLEEP_US, OTP_TIMEOUT_US); -+} -+ -+static int lan9662_otp_power(struct lan9662_otp *otp, bool up) -+{ -+ void __iomem *pwrdn = OTP_OTP_PWR_DN(otp->base); -+ -+ if (up) { -+ writel(readl(pwrdn) & ~OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn); -+ if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base), -+ OTP_OTP_STATUS_OTP_CPUMPEN)) -+ return -ETIMEDOUT; -+ } else { -+ writel(readl(pwrdn) | OTP_OTP_PWR_DN_OTP_PWRDN_N, pwrdn); -+ } -+ -+ return 0; -+} -+ -+static int lan9662_otp_execute(struct lan9662_otp *otp) -+{ -+ if (lan9662_otp_wait_flag_clear(OTP_OTP_CMD_GO(otp->base), -+ OTP_OTP_CMD_GO_OTP_GO)) -+ return -ETIMEDOUT; -+ -+ if (lan9662_otp_wait_flag_clear(OTP_OTP_STATUS(otp->base), -+ OTP_OTP_STATUS_OTP_BUSY)) -+ return -ETIMEDOUT; -+ -+ return 0; -+} -+ -+static void lan9662_otp_set_address(struct lan9662_otp *otp, u32 offset) -+{ -+ writel(0xff & (offset >> 8), OTP_OTP_ADDR_HI(otp->base)); -+ writel(0xff & offset, OTP_OTP_ADDR_LO(otp->base)); -+} -+ -+static int lan9662_otp_read_byte(struct lan9662_otp *otp, u32 offset, u8 *dst) -+{ -+ u32 pass; -+ int rc; -+ -+ lan9662_otp_set_address(otp, offset); -+ writel(OTP_OTP_FUNC_CMD_OTP_READ, OTP_OTP_FUNC_CMD(otp->base)); -+ writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base)); -+ rc = lan9662_otp_execute(otp); -+ if (!rc) { -+ pass = readl(OTP_OTP_PASS_FAIL(otp->base)); -+ if (pass & OTP_OTP_PASS_FAIL_OTP_READ_PROHIBITED) -+ return -EACCES; -+ *dst = (u8) readl(OTP_OTP_RD_DATA(otp->base)); -+ } -+ return rc; -+} -+ -+static int lan9662_otp_write_byte(struct lan9662_otp *otp, u32 offset, u8 data) -+{ -+ u32 pass; -+ int rc; -+ -+ lan9662_otp_set_address(otp, offset); -+ writel(OTP_OTP_PRGM_MODE_OTP_PGM_MODE_BYTE, OTP_OTP_PRGM_MODE(otp->base)); -+ writel(data, OTP_OTP_PRGM_DATA(otp->base)); -+ writel(OTP_OTP_FUNC_CMD_OTP_PROGRAM, OTP_OTP_FUNC_CMD(otp->base)); -+ writel(OTP_OTP_CMD_GO_OTP_GO, OTP_OTP_CMD_GO(otp->base)); -+ -+ rc = lan9662_otp_execute(otp); -+ if (!rc) { -+ pass = readl(OTP_OTP_PASS_FAIL(otp->base)); -+ if (pass & OTP_OTP_PASS_FAIL_OTP_WRITE_PROHIBITED) -+ return -EACCES; -+ if (pass & OTP_OTP_PASS_FAIL_OTP_FAIL) -+ return -EIO; -+ } -+ return rc; -+} -+ -+static int lan9662_otp_read(void *context, unsigned int offset, -+ void *_val, size_t bytes) -+{ -+ struct lan9662_otp *otp = context; -+ u8 *val = _val; -+ uint8_t data; -+ int i, rc = 0; -+ -+ lan9662_otp_power(otp, true); -+ for (i = 0; i < bytes; i++) { -+ rc = lan9662_otp_read_byte(otp, offset + i, &data); -+ if (rc < 0) -+ break; -+ *val++ = data; -+ } -+ lan9662_otp_power(otp, false); -+ -+ return rc; -+} -+ -+static int lan9662_otp_write(void *context, unsigned int offset, -+ void *_val, size_t bytes) -+{ -+ struct lan9662_otp *otp = context; -+ u8 *val = _val; -+ u8 data, newdata; -+ int i, rc = 0; -+ -+ lan9662_otp_power(otp, true); -+ for (i = 0; i < bytes; i++) { -+ /* Skip zero bytes */ -+ if (val[i]) { -+ rc = lan9662_otp_read_byte(otp, offset + i, &data); -+ if (rc < 0) -+ break; -+ -+ newdata = data | val[i]; -+ if (newdata == data) -+ continue; -+ -+ rc = lan9662_otp_write_byte(otp, offset + i, -+ newdata); -+ if (rc < 0) -+ break; -+ } -+ } -+ lan9662_otp_power(otp, false); -+ -+ return rc; -+} -+ -+static struct nvmem_config otp_config = { -+ .name = "lan9662-otp", -+ .stride = 1, -+ .word_size = 1, -+ .reg_read = lan9662_otp_read, -+ .reg_write = lan9662_otp_write, -+ .size = OTP_MEM_SIZE, -+}; -+ -+static int lan9662_otp_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct nvmem_device *nvmem; -+ struct lan9662_otp *otp; -+ -+ otp = devm_kzalloc(&pdev->dev, sizeof(*otp), GFP_KERNEL); -+ if (!otp) -+ return -ENOMEM; -+ -+ otp->dev = dev; -+ otp->base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(otp->base)) -+ return PTR_ERR(otp->base); -+ -+ otp_config.priv = otp; -+ otp_config.dev = dev; -+ -+ nvmem = devm_nvmem_register(dev, &otp_config); -+ -+ return PTR_ERR_OR_ZERO(nvmem); -+} -+ -+static const struct of_device_id lan9662_otp_match[] = { -+ { .compatible = "microchip,lan9662-otp", }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, lan9662_otp_match); -+ -+static struct platform_driver lan9662_otp_driver = { -+ .probe = lan9662_otp_probe, -+ .driver = { -+ .name = "lan9662-otp", -+ .of_match_table = lan9662_otp_match, -+ }, -+}; -+module_platform_driver(lan9662_otp_driver); -+ -+MODULE_AUTHOR("Horatiu Vultur "); -+MODULE_DESCRIPTION("lan9662 OTP driver"); -+MODULE_LICENSE("GPL"); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch b/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch deleted file mode 100644 index 633a668a962..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0009-nvmem-u-boot-env-fix-crc32-casting-type.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 3717ca3e0cc8683f93b41d3f06ca79631eb58715 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= -Date: Fri, 16 Sep 2022 13:21:00 +0100 -Subject: [PATCH] nvmem: u-boot-env: fix crc32 casting type -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This fixes: -drivers/nvmem/u-boot-env.c:141:17: sparse: sparse: cast to restricted __le32 - -Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables") -Reported-by: kernel test robot -Signed-off-by: Rafał Miłecki -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20220916122100.170016-14-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/u-boot-env.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/u-boot-env.c -+++ b/drivers/nvmem/u-boot-env.c -@@ -139,7 +139,7 @@ static int u_boot_env_parse(struct u_boo - data_offset = offsetof(struct u_boot_env_image_redundant, data); - break; - } -- crc32 = le32_to_cpu(*(uint32_t *)(buf + crc32_offset)); -+ crc32 = le32_to_cpu(*(__le32 *)(buf + crc32_offset)); - crc32_data_len = priv->mtd->size - crc32_data_offset; - data_len = priv->mtd->size - data_offset; - diff --git a/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch b/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch deleted file mode 100644 index b663a1328df..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0010-nvmem-lan9662-otp-Fix-compatible-string.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 1aeb122d214b92474c86fde00a03d6e2d69381b5 Mon Sep 17 00:00:00 2001 -From: Horatiu Vultur -Date: Wed, 28 Sep 2022 21:51:12 +0200 -Subject: [PATCH] nvmem: lan9662-otp: Fix compatible string - -The device tree bindings for lan9662-otp expects the compatible string -to be one of following compatible strings: -microchip,lan9662-otpc -microchip,lan9668-otpc - -The problem is that the lan9662-otp driver contains the -microchip,lan9662-otp compatible string instead of -microchip,lan9662-otpc. -Fix this by updating the compatible string in the driver. - -Fixes: 9e8f208ad5229d ("nvmem: lan9662-otp: add support") -Signed-off-by: Horatiu Vultur -Link: https://lore.kernel.org/r/20220928195112.630351-1-horatiu.vultur@microchip.com -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/lan9662-otpc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/lan9662-otpc.c -+++ b/drivers/nvmem/lan9662-otpc.c -@@ -203,7 +203,7 @@ static int lan9662_otp_probe(struct plat - } - - static const struct of_device_id lan9662_otp_match[] = { -- { .compatible = "microchip,lan9662-otp", }, -+ { .compatible = "microchip,lan9662-otpc", }, - { }, - }; - MODULE_DEVICE_TABLE(of, lan9662_otp_match); diff --git a/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch b/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch deleted file mode 100644 index 967e891dbd9..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0011-nvmem-u-boot-env-fix-crc32_data_offset-on-redundant-.patch +++ /dev/null @@ -1,59 +0,0 @@ -From ee424f7d3960152f5f862bbb6943e59828dc7917 Mon Sep 17 00:00:00 2001 -From: Christian Lamparter -Date: Fri, 4 Nov 2022 17:52:03 +0100 -Subject: [PATCH] nvmem: u-boot-env: fix crc32_data_offset on redundant - u-boot-env - -The Western Digital MyBook Live (PowerPC 464/APM82181) -has a set of redundant u-boot-env. Loading up the driver -the following error: - -| u_boot_env: Invalid calculated CRC32: 0x4f8f2c86 (expected: 0x98b14514) -| u_boot_env: probe of partition@1e000 failed with error -22 - -Looking up the userspace libubootenv utilities source [0], -it looks like the "mark" or "flag" is not part of the -crc32 sum... which is unfortunate :( - -|static int libuboot_load(struct uboot_ctx *ctx) -|{ -|[...] -| if (ctx->redundant) { -| [...] -| offsetdata = offsetof(struct uboot_env_redund, data); -| [...] //-----^^ -| } -| usable_envsize = ctx->size - offsetdata; -| buf[0] = malloc(bufsize); -|[...] -| for (i = 0; i < copies; i++) { -| data = (uint8_t *)(buf[i] + offsetdata); -| uint32_t crc; -| -| ret = devread(ctx, i, buf[i]); -| [...] -| crc = *(uint32_t *)(buf[i] + offsetcrc); -| dev->crc = crc32(0, (uint8_t *)data, usable_envsize); -| - -[0] https://github.com/sbabic/libubootenv/blob/master/src/uboot_env.c#L951 - -Fixes: d5542923f200 ("nvmem: add driver handling U-Boot environment variables") -Signed-off-by: Christian Lamparter -Link: https://lore.kernel.org/r/70a16eae113e08db2390b76e174f4837caa135c3.1667580636.git.chunkeey@gmail.com -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/u-boot-env.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/u-boot-env.c -+++ b/drivers/nvmem/u-boot-env.c -@@ -135,7 +135,7 @@ static int u_boot_env_parse(struct u_boo - break; - case U_BOOT_FORMAT_REDUNDANT: - crc32_offset = offsetof(struct u_boot_env_image_redundant, crc32); -- crc32_data_offset = offsetof(struct u_boot_env_image_redundant, mark); -+ crc32_data_offset = offsetof(struct u_boot_env_image_redundant, data); - data_offset = offsetof(struct u_boot_env_image_redundant, data); - break; - } diff --git a/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch b/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch deleted file mode 100644 index 0c842f07932..00000000000 --- a/target/linux/generic/backport-6.1/807-v6.1-0013-nvmem-lan9662-otp-Change-return-type-of-lan9662_otp_.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 022b68f271de0e53024e6d5e96fee8e76d25eb95 Mon Sep 17 00:00:00 2001 -From: Horatiu Vultur -Date: Fri, 18 Nov 2022 06:38:40 +0000 -Subject: [PATCH] nvmem: lan9662-otp: Change return type of - lan9662_otp_wait_flag_clear() - -The blamed commit introduced the following smatch warning in the -function lan9662_otp_wait_flag_clear: -drivers/nvmem/lan9662-otpc.c:43 lan9662_otp_wait_flag_clear() warn: signedness bug returning '(-110)' - -Fix this by changing the return type of the function -lan9662_otp_wait_flag_clear() to be int instead of bool. - -Fixes: 9e8f208ad5229d ("nvmem: lan9662-otp: add support") -Reported-by: kernel test robot -Reported-by: Dan Carpenter -Signed-off-by: Horatiu Vultur -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20221118063840.6357-5-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/lan9662-otpc.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/nvmem/lan9662-otpc.c -+++ b/drivers/nvmem/lan9662-otpc.c -@@ -36,7 +36,7 @@ struct lan9662_otp { - void __iomem *base; - }; - --static bool lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) -+static int lan9662_otp_wait_flag_clear(void __iomem *reg, u32 flag) - { - u32 val; - diff --git a/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch b/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch deleted file mode 100644 index 14108b59276..00000000000 --- a/target/linux/generic/backport-6.1/808-v6.2-0007-nvmem-brcm_nvram-Add-check-for-kzalloc.patch +++ /dev/null @@ -1,30 +0,0 @@ -From b0576ade3aaf24b376ea1a4406ae138e2a22b0c0 Mon Sep 17 00:00:00 2001 -From: Jiasheng Jiang -Date: Fri, 27 Jan 2023 10:40:06 +0000 -Subject: [PATCH] nvmem: brcm_nvram: Add check for kzalloc - -Add the check for the return value of kzalloc in order to avoid -NULL pointer dereference. - -Fixes: 6e977eaa8280 ("nvmem: brcm_nvram: parse NVRAM content into NVMEM cells") -Cc: stable@vger.kernel.org -Signed-off-by: Jiasheng Jiang -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20230127104015.23839-2-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/brcm_nvram.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/nvmem/brcm_nvram.c -+++ b/drivers/nvmem/brcm_nvram.c -@@ -97,6 +97,9 @@ static int brcm_nvram_parse(struct brcm_ - len = le32_to_cpu(header.len); - - data = kzalloc(len, GFP_KERNEL); -+ if (!data) -+ return -ENOMEM; -+ - memcpy_fromio(data, priv->base, len); - data[len - 1] = '\0'; - diff --git a/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch b/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch deleted file mode 100644 index 632b01cb2ac..00000000000 --- a/target/linux/generic/backport-6.1/808-v6.2-0008-nvmem-sunxi_sid-Always-use-32-bit-MMIO-reads.patch +++ /dev/null @@ -1,55 +0,0 @@ -From c151d5ed8e8fe0474bd61dce7f2076ca5916c683 Mon Sep 17 00:00:00 2001 -From: Samuel Holland -Date: Fri, 27 Jan 2023 10:40:07 +0000 -Subject: [PATCH] nvmem: sunxi_sid: Always use 32-bit MMIO reads - -The SID SRAM on at least some SoCs (A64 and D1) returns different values -when read with bus cycles narrower than 32 bits. This is not immediately -obvious, because memcpy_fromio() uses word-size accesses as long as -enough data is being copied. - -The vendor driver always uses 32-bit MMIO reads, so do the same here. -This is faster than the register-based method, which is currently used -as a workaround on A64. And it fixes the values returned on D1, where -the SRAM method was being used. - -The special case for the last word is needed to maintain .word_size == 1 -for sysfs ABI compatibility, as noted previously in commit de2a3eaea552 -("nvmem: sunxi_sid: Optimize register read-out method"). - -Fixes: 07ae4fde9efa ("nvmem: sunxi_sid: Add support for D1 variant") -Cc: stable@vger.kernel.org -Tested-by: Heiko Stuebner -Signed-off-by: Samuel Holland -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20230127104015.23839-3-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/sunxi_sid.c | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - ---- a/drivers/nvmem/sunxi_sid.c -+++ b/drivers/nvmem/sunxi_sid.c -@@ -41,8 +41,21 @@ static int sunxi_sid_read(void *context, - void *val, size_t bytes) - { - struct sunxi_sid *sid = context; -+ u32 word; - -- memcpy_fromio(val, sid->base + sid->value_offset + offset, bytes); -+ /* .stride = 4 so offset is guaranteed to be aligned */ -+ __ioread32_copy(val, sid->base + sid->value_offset + offset, bytes / 4); -+ -+ val += round_down(bytes, 4); -+ offset += round_down(bytes, 4); -+ bytes = bytes % 4; -+ -+ if (!bytes) -+ return 0; -+ -+ /* Handle any trailing bytes */ -+ word = readl_relaxed(sid->base + sid->value_offset + offset); -+ memcpy(val, &word, bytes); - - return 0; - } diff --git a/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch b/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch deleted file mode 100644 index a229c303ad0..00000000000 --- a/target/linux/generic/backport-6.1/808-v6.2-0013-nvmem-core-fix-device-node-refcounting.patch +++ /dev/null @@ -1,48 +0,0 @@ -From edcf2fb660526b5ed29f93bd17328a2b4835c8b2 Mon Sep 17 00:00:00 2001 -From: Michael Walle -Date: Fri, 27 Jan 2023 10:40:12 +0000 -Subject: [PATCH] nvmem: core: fix device node refcounting - -In of_nvmem_cell_get(), of_get_next_parent() is used on cell_np. This -will decrement the refcount on cell_np, but cell_np is still used later -in the code. Use of_get_parent() instead and of_node_put() in the -appropriate places. - -Fixes: 69aba7948cbe ("nvmem: Add a simple NVMEM framework for consumers") -Fixes: 7ae6478b304b ("nvmem: core: rework nvmem cell instance creation") -Cc: stable@vger.kernel.org -Signed-off-by: Michael Walle -Signed-off-by: Srinivas Kandagatla -Link: https://lore.kernel.org/r/20230127104015.23839-8-srinivas.kandagatla@linaro.org -Signed-off-by: Greg Kroah-Hartman ---- - drivers/nvmem/core.c | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - ---- a/drivers/nvmem/core.c -+++ b/drivers/nvmem/core.c -@@ -1237,16 +1237,21 @@ struct nvmem_cell *of_nvmem_cell_get(str - if (!cell_np) - return ERR_PTR(-ENOENT); - -- nvmem_np = of_get_next_parent(cell_np); -- if (!nvmem_np) -+ nvmem_np = of_get_parent(cell_np); -+ if (!nvmem_np) { -+ of_node_put(cell_np); - return ERR_PTR(-EINVAL); -+ } - - nvmem = __nvmem_device_get(nvmem_np, device_match_of_node); - of_node_put(nvmem_np); -- if (IS_ERR(nvmem)) -+ if (IS_ERR(nvmem)) { -+ of_node_put(cell_np); - return ERR_CAST(nvmem); -+ } - - cell_entry = nvmem_find_cell_entry_by_node(nvmem, cell_np); -+ of_node_put(cell_np); - if (!cell_entry) { - __nvmem_device_put(nvmem); - return ERR_PTR(-ENOENT); diff --git a/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch b/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch deleted file mode 100644 index 25802be7e3d..00000000000 --- a/target/linux/generic/backport-6.1/810-v5.17-net-qmi_wwan-add-ZTE-MF286D-modem-19d2-1485.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 078c6a1cbd4cd7496048786beec2e312577bebbf Mon Sep 17 00:00:00 2001 -From: Pawel Dembicki -Date: Tue, 11 Jan 2022 23:11:32 +0100 -Subject: [PATCH 1/1] net: qmi_wwan: add ZTE MF286D modem 19d2:1485 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Modem from ZTE MF286D is an Qualcomm MDM9250 based 3G/4G modem. - -T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=5000 MxCh= 0 -D: Ver= 3.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1 -P: Vendor=19d2 ProdID=1485 Rev=52.87 -S: Manufacturer=ZTE,Incorporated -S: Product=ZTE Technologies MSM -S: SerialNumber=MF286DZTED000000 -C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=896mA -A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=06 Prot=00 -I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=ff Driver=rndis_host -E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms -I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host -E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option -E: Ad=83(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option -E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=84(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option -E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms -E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan -E: Ad=88(I) Atr=03(Int.) MxPS= 8 Ivl=32ms -E: Ad=8e(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=0f(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -I:* If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs -E: Ad=05(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms -E: Ad=89(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms - -Signed-off-by: Pawel Dembicki -Acked-by: Bjørn Mork -Signed-off-by: David S. Miller ---- - drivers/net/usb/qmi_wwan.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/drivers/net/usb/qmi_wwan.c -+++ b/drivers/net/usb/qmi_wwan.c -@@ -1314,6 +1314,7 @@ static const struct usb_device_id produc - {QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */ - {QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */ - {QMI_FIXED_INTF(0x19d2, 0x1432, 3)}, /* ZTE ME3620 */ -+ {QMI_FIXED_INTF(0x19d2, 0x1485, 5)}, /* ZTE MF286D */ - {QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */ - {QMI_FIXED_INTF(0x2001, 0x7e16, 3)}, /* D-Link DWM-221 */ - {QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */ diff --git a/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch b/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch deleted file mode 100644 index 98687126487..00000000000 --- a/target/linux/generic/backport-6.1/821-v5.16-Bluetooth-btusb-Support-public-address-configuration.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 5cb03751455c299b1bf10cb48631bf359cfb11b5 Mon Sep 17 00:00:00 2001 -From: "mark-yw.chen" -Date: Wed, 1 Sep 2021 11:32:25 +0800 -Subject: [PATCH 1/5] Bluetooth: btusb: Support public address configuration - for MediaTek Chip. - -The MediaTek chip support vendor specific HCI command(0xfc1a) to -change the public address. Add hdev->set_bdaddr handler for MediaTek -Chip. After doing a power cycle or MediaTek Bluetooth reset, BD_ADDR -will bring back the original one. - -Signed-off-by: mark-yw.chen -Signed-off-by: Marcel Holtmann ---- - drivers/bluetooth/btusb.c | 18 ++++++++++++++++++ - 1 file changed, 18 insertions(+) - ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -2272,6 +2272,23 @@ struct btmtk_section_map { - }; - } __packed; - -+static int btusb_set_bdaddr_mtk(struct hci_dev *hdev, const bdaddr_t *bdaddr) -+{ -+ struct sk_buff *skb; -+ long ret; -+ -+ skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT); -+ if (IS_ERR(skb)) { -+ ret = PTR_ERR(skb); -+ bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", -+ ret); -+ return ret; -+ } -+ kfree_skb(skb); -+ -+ return 0; -+} -+ - static void btusb_mtk_wmt_recv(struct urb *urb) - { - struct hci_dev *hdev = urb->context; -@@ -3923,6 +3940,7 @@ static int btusb_probe(struct usb_interf - hdev->shutdown = btusb_mtk_shutdown; - hdev->manufacturer = 70; - hdev->cmd_timeout = btusb_mtk_cmd_timeout; -+ hdev->set_bdaddr = btusb_set_bdaddr_mtk; - set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); - data->recv_acl = btusb_recv_acl_mtk; - } diff --git a/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch b/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch deleted file mode 100644 index cff537a8669..00000000000 --- a/target/linux/generic/backport-6.1/822-v5.17-Bluetooth-btusb-Fix-application-of-sizeof-to-pointer.patch +++ /dev/null @@ -1,29 +0,0 @@ -From af774a731f7b4c2a90a8476cd44045ba8d1263ba Mon Sep 17 00:00:00 2001 -From: David Yang -Date: Wed, 13 Oct 2021 08:56:33 +0800 -Subject: [PATCH 2/5] Bluetooth: btusb: Fix application of sizeof to pointer - -The coccinelle check report: -"./drivers/bluetooth/btusb.c:2239:36-42: -ERROR: application of sizeof to pointer". -Using the real size to fix it. - -Fixes: 5a87679ffd443 ("Bluetooth: btusb: Support public address configuration for MediaTek Chip.") -Reported-by: Zeal Robot -Signed-off-by: David Yang -Signed-off-by: Marcel Holtmann ---- - drivers/bluetooth/btusb.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -2277,7 +2277,7 @@ static int btusb_set_bdaddr_mtk(struct h - struct sk_buff *skb; - long ret; - -- skb = __hci_cmd_sync(hdev, 0xfc1a, sizeof(bdaddr), bdaddr, HCI_INIT_TIMEOUT); -+ skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - bt_dev_err(hdev, "changing Mediatek device address failed (%ld)", diff --git a/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch b/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch deleted file mode 100644 index d670195da1f..00000000000 --- a/target/linux/generic/backport-6.1/823-v5.18-Bluetooth-btusb-Add-a-new-PID-VID-13d3-3567-for-MT79.patch +++ /dev/null @@ -1,70 +0,0 @@ -From e57186fc02cedff191c469a26cce615371e41740 Mon Sep 17 00:00:00 2001 -From: Yake Yang -Date: Wed, 23 Feb 2022 07:55:59 +0800 -Subject: [PATCH 3/5] Bluetooth: btusb: Add a new PID/VID 13d3/3567 for MT7921 - -Add VID 13D3 & PID 3567 for MediaTek MT7921 USB Bluetooth chip. - -The information in /sys/kernel/debug/usb/devices about the Bluetooth -device is listed as the below. - -T: Bus=05 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=480 MxCh= 0 -D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 -P: Vendor=13d3 ProdID=3567 Rev= 1.00 -S: Manufacturer=MediaTek Inc. -S: Product=Wireless_Device -S: SerialNumber=000000000 -C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA -A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 -I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us -E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms -I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms -I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms -I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms -I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms -I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms -I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms -I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us -I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us - -Co-developed-by: Sean Wang -Signed-off-by: Sean Wang -Signed-off-by: Yake Yang -Signed-off-by: Marcel Holtmann ---- - drivers/bluetooth/btusb.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -464,6 +464,9 @@ static const struct usb_device_id blackl - { USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, -+ { USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK | -+ BTUSB_WIDEBAND_SPEECH | -+ BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, diff --git a/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch b/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch deleted file mode 100644 index be9dc734215..00000000000 --- a/target/linux/generic/backport-6.1/824-v5.19-Bluetooth-btusb-Add-a-new-PID-VID-0489-e0c8-for-MT79.patch +++ /dev/null @@ -1,68 +0,0 @@ -From e507366cd1e8e1d4eebe537c08fd142cf0b617fa Mon Sep 17 00:00:00 2001 -From: Sean Wang -Date: Thu, 28 Apr 2022 02:38:39 +0800 -Subject: [PATCH 4/5] Bluetooth: btusb: Add a new PID/VID 0489/e0c8 for MT7921 - -Add VID 0489 & PID e0c8 for MediaTek MT7921 USB Bluetooth chip. - -The information in /sys/kernel/debug/usb/devices about the Bluetooth -device is listed as the below. - -T: Bus=01 Lev=01 Prnt=01 Port=13 Cnt=03 Dev#= 4 Spd=480 MxCh= 0 -D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 -P: Vendor=0489 ProdID=e0c8 Rev= 1.00 -S: Manufacturer=MediaTek Inc. -S: Product=Wireless_Device -S: SerialNumber=000000000 -C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA -A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 -I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us -E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms -I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms -I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms -I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms -I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms -I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms -I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms -I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us -I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 512 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 512 Ivl=125us - -Signed-off-by: Sean Wang -Signed-off-by: Marcel Holtmann ---- - drivers/bluetooth/btusb.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -455,6 +455,9 @@ static const struct usb_device_id blackl - BTUSB_VALID_LE_STATES }, - - /* Additional MediaTek MT7921 Bluetooth devices */ -+ { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK | -+ BTUSB_WIDEBAND_SPEECH | -+ BTUSB_VALID_LE_STATES }, - { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, diff --git a/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch b/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch deleted file mode 100644 index 24ec68a2ca5..00000000000 --- a/target/linux/generic/backport-6.1/825-v6.1-Bluetooth-btusb-Add-a-new-VID-PID-0e8d-0608-for-MT79.patch +++ /dev/null @@ -1,66 +0,0 @@ -From be55622ce673f9692cc15d26d77a050cda42a3d3 Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Fri, 9 Sep 2022 21:00:30 +0100 -Subject: [PATCH 1/1] Bluetooth: btusb: Add a new VID/PID 0e8d/0608 for MT7921 - -Add a new PID/VID 0e8d/0608 for MT7921K chip found on AMD RZ608 module. - -From /sys/kernel/debug/usb/devices: -T: Bus=01 Lev=02 Prnt=02 Port=01 Cnt=01 Dev#= 3 Spd=480 MxCh= 0 -D: Ver= 2.10 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1 -P: Vendor=0e8d ProdID=0608 Rev= 1.00 -S: Manufacturer=MediaTek Inc. -S: Product=Wireless_Device -S: SerialNumber=000000000 -C:* #Ifs= 3 Cfg#= 1 Atr=e0 MxPwr=100mA -A: FirstIf#= 0 IfCount= 3 Cls=e0(wlcon) Sub=01 Prot=01 -I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=125us -E: Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms -E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms -I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms -I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms -I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms -I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms -I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms -I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms -I: If#= 1 Alt= 6 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb -E: Ad=83(I) Atr=01(Isoc) MxPS= 63 Ivl=1ms -E: Ad=03(O) Atr=01(Isoc) MxPS= 63 Ivl=1ms -I:* If#= 2 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us -I: If#= 2 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=(none) -E: Ad=8a(I) Atr=03(Int.) MxPS= 64 Ivl=125us -E: Ad=0a(O) Atr=03(Int.) MxPS= 64 Ivl=125us - -Signed-off-by: Daniel Golle -Signed-off-by: Luiz Augusto von Dentz ---- - drivers/bluetooth/btusb.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/drivers/bluetooth/btusb.c -+++ b/drivers/bluetooth/btusb.c -@@ -473,6 +473,9 @@ static const struct usb_device_id blackl - { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK | - BTUSB_WIDEBAND_SPEECH | - BTUSB_VALID_LE_STATES }, -+ { USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK | -+ BTUSB_WIDEBAND_SPEECH | -+ BTUSB_VALID_LE_STATES }, - - /* MediaTek MT7922A Bluetooth devices */ - { USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK | diff --git a/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch b/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch deleted file mode 100644 index b00cf574199..00000000000 --- a/target/linux/generic/backport-6.1/826-v5.17-of-base-make-small-of_parse_phandle-variants-static-.patch +++ /dev/null @@ -1,359 +0,0 @@ -From 66a8f7f04979f4ad739085f01d99c8caf620b4f5 Mon Sep 17 00:00:00 2001 -From: Michael Walle -Date: Tue, 18 Jan 2022 18:35:02 +0100 -Subject: [PATCH] of: base: make small of_parse_phandle() variants static - inline - -Make all the smaller variants of the of_parse_phandle() static inline. -This also let us remove the empty function stubs if CONFIG_OF is not -defined. - -Suggested-by: Rob Herring -Signed-off-by: Michael Walle -[robh: move index < 0 check into __of_parse_phandle_with_args] -Signed-off-by: Rob Herring -Link: https://lore.kernel.org/r/20220118173504.2867523-2-michael@walle.cc ---- - drivers/of/base.c | 131 +++------------------------------------ - include/linux/of.h | 148 ++++++++++++++++++++++++++++++++++++--------- - 2 files changed, 129 insertions(+), 150 deletions(-) - ---- a/drivers/of/base.c -+++ b/drivers/of/base.c -@@ -1371,15 +1371,18 @@ int of_phandle_iterator_args(struct of_p - return count; - } - --static int __of_parse_phandle_with_args(const struct device_node *np, -- const char *list_name, -- const char *cells_name, -- int cell_count, int index, -- struct of_phandle_args *out_args) -+int __of_parse_phandle_with_args(const struct device_node *np, -+ const char *list_name, -+ const char *cells_name, -+ int cell_count, int index, -+ struct of_phandle_args *out_args) - { - struct of_phandle_iterator it; - int rc, cur_index = 0; - -+ if (index < 0) -+ return -EINVAL; -+ - /* Loop over the phandles until all the requested entry is found */ - of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { - /* -@@ -1422,82 +1425,7 @@ static int __of_parse_phandle_with_args( - of_node_put(it.node); - return rc; - } -- --/** -- * of_parse_phandle - Resolve a phandle property to a device_node pointer -- * @np: Pointer to device node holding phandle property -- * @phandle_name: Name of property holding a phandle value -- * @index: For properties holding a table of phandles, this is the index into -- * the table -- * -- * Return: The device_node pointer with refcount incremented. Use -- * of_node_put() on it when done. -- */ --struct device_node *of_parse_phandle(const struct device_node *np, -- const char *phandle_name, int index) --{ -- struct of_phandle_args args; -- -- if (index < 0) -- return NULL; -- -- if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, -- index, &args)) -- return NULL; -- -- return args.np; --} --EXPORT_SYMBOL(of_parse_phandle); -- --/** -- * of_parse_phandle_with_args() - Find a node pointed by phandle in a list -- * @np: pointer to a device tree node containing a list -- * @list_name: property name that contains a list -- * @cells_name: property name that specifies phandles' arguments count -- * @index: index of a phandle to parse out -- * @out_args: optional pointer to output arguments structure (will be filled) -- * -- * This function is useful to parse lists of phandles and their arguments. -- * Returns 0 on success and fills out_args, on error returns appropriate -- * errno value. -- * -- * Caller is responsible to call of_node_put() on the returned out_args->np -- * pointer. -- * -- * Example:: -- * -- * phandle1: node1 { -- * #list-cells = <2>; -- * }; -- * -- * phandle2: node2 { -- * #list-cells = <1>; -- * }; -- * -- * node3 { -- * list = <&phandle1 1 2 &phandle2 3>; -- * }; -- * -- * To get a device_node of the ``node2`` node you may call this: -- * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); -- */ --int of_parse_phandle_with_args(const struct device_node *np, const char *list_name, -- const char *cells_name, int index, -- struct of_phandle_args *out_args) --{ -- int cell_count = -1; -- -- if (index < 0) -- return -EINVAL; -- -- /* If cells_name is NULL we assume a cell count of 0 */ -- if (!cells_name) -- cell_count = 0; -- -- return __of_parse_phandle_with_args(np, list_name, cells_name, -- cell_count, index, out_args); --} --EXPORT_SYMBOL(of_parse_phandle_with_args); -+EXPORT_SYMBOL(__of_parse_phandle_with_args); - - /** - * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it -@@ -1684,47 +1612,6 @@ free: - EXPORT_SYMBOL(of_parse_phandle_with_args_map); - - /** -- * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list -- * @np: pointer to a device tree node containing a list -- * @list_name: property name that contains a list -- * @cell_count: number of argument cells following the phandle -- * @index: index of a phandle to parse out -- * @out_args: optional pointer to output arguments structure (will be filled) -- * -- * This function is useful to parse lists of phandles and their arguments. -- * Returns 0 on success and fills out_args, on error returns appropriate -- * errno value. -- * -- * Caller is responsible to call of_node_put() on the returned out_args->np -- * pointer. -- * -- * Example:: -- * -- * phandle1: node1 { -- * }; -- * -- * phandle2: node2 { -- * }; -- * -- * node3 { -- * list = <&phandle1 0 2 &phandle2 2 3>; -- * }; -- * -- * To get a device_node of the ``node2`` node you may call this: -- * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args); -- */ --int of_parse_phandle_with_fixed_args(const struct device_node *np, -- const char *list_name, int cell_count, -- int index, struct of_phandle_args *out_args) --{ -- if (index < 0) -- return -EINVAL; -- return __of_parse_phandle_with_args(np, list_name, NULL, cell_count, -- index, out_args); --} --EXPORT_SYMBOL(of_parse_phandle_with_fixed_args); -- --/** - * of_count_phandle_with_args() - Find the number of phandles references in a property - * @np: pointer to a device tree node containing a list - * @list_name: property name that contains a list ---- a/include/linux/of.h -+++ b/include/linux/of.h -@@ -363,18 +363,12 @@ extern const struct of_device_id *of_mat - const struct of_device_id *matches, const struct device_node *node); - extern int of_modalias_node(struct device_node *node, char *modalias, int len); - extern void of_print_phandle_args(const char *msg, const struct of_phandle_args *args); --extern struct device_node *of_parse_phandle(const struct device_node *np, -- const char *phandle_name, -- int index); --extern int of_parse_phandle_with_args(const struct device_node *np, -- const char *list_name, const char *cells_name, int index, -- struct of_phandle_args *out_args); -+extern int __of_parse_phandle_with_args(const struct device_node *np, -+ const char *list_name, const char *cells_name, int cell_count, -+ int index, struct of_phandle_args *out_args); - extern int of_parse_phandle_with_args_map(const struct device_node *np, - const char *list_name, const char *stem_name, int index, - struct of_phandle_args *out_args); --extern int of_parse_phandle_with_fixed_args(const struct device_node *np, -- const char *list_name, int cells_count, int index, -- struct of_phandle_args *out_args); - extern int of_count_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name); - -@@ -864,18 +858,12 @@ static inline int of_property_read_strin - return -ENOSYS; - } - --static inline struct device_node *of_parse_phandle(const struct device_node *np, -- const char *phandle_name, -- int index) --{ -- return NULL; --} -- --static inline int of_parse_phandle_with_args(const struct device_node *np, -- const char *list_name, -- const char *cells_name, -- int index, -- struct of_phandle_args *out_args) -+static inline int __of_parse_phandle_with_args(const struct device_node *np, -+ const char *list_name, -+ const char *cells_name, -+ int cell_count, -+ int index, -+ struct of_phandle_args *out_args) - { - return -ENOSYS; - } -@@ -889,13 +877,6 @@ static inline int of_parse_phandle_with_ - return -ENOSYS; - } - --static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, -- const char *list_name, int cells_count, int index, -- struct of_phandle_args *out_args) --{ -- return -ENOSYS; --} -- - static inline int of_count_phandle_with_args(const struct device_node *np, - const char *list_name, - const char *cells_name) -@@ -1077,6 +1058,117 @@ static inline bool of_node_is_type(const - } - - /** -+ * of_parse_phandle - Resolve a phandle property to a device_node pointer -+ * @np: Pointer to device node holding phandle property -+ * @phandle_name: Name of property holding a phandle value -+ * @index: For properties holding a table of phandles, this is the index into -+ * the table -+ * -+ * Return: The device_node pointer with refcount incremented. Use -+ * of_node_put() on it when done. -+ */ -+static inline struct device_node *of_parse_phandle(const struct device_node *np, -+ const char *phandle_name, -+ int index) -+{ -+ struct of_phandle_args args; -+ -+ if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, -+ index, &args)) -+ return NULL; -+ -+ return args.np; -+} -+ -+/** -+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list -+ * @np: pointer to a device tree node containing a list -+ * @list_name: property name that contains a list -+ * @cells_name: property name that specifies phandles' arguments count -+ * @index: index of a phandle to parse out -+ * @out_args: optional pointer to output arguments structure (will be filled) -+ * -+ * This function is useful to parse lists of phandles and their arguments. -+ * Returns 0 on success and fills out_args, on error returns appropriate -+ * errno value. -+ * -+ * Caller is responsible to call of_node_put() on the returned out_args->np -+ * pointer. -+ * -+ * Example:: -+ * -+ * phandle1: node1 { -+ * #list-cells = <2>; -+ * }; -+ * -+ * phandle2: node2 { -+ * #list-cells = <1>; -+ * }; -+ * -+ * node3 { -+ * list = <&phandle1 1 2 &phandle2 3>; -+ * }; -+ * -+ * To get a device_node of the ``node2`` node you may call this: -+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args); -+ */ -+static inline int of_parse_phandle_with_args(const struct device_node *np, -+ const char *list_name, -+ const char *cells_name, -+ int index, -+ struct of_phandle_args *out_args) -+{ -+ int cell_count = -1; -+ -+ /* If cells_name is NULL we assume a cell count of 0 */ -+ if (!cells_name) -+ cell_count = 0; -+ -+ return __of_parse_phandle_with_args(np, list_name, cells_name, -+ cell_count, index, out_args); -+} -+ -+/** -+ * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list -+ * @np: pointer to a device tree node containing a list -+ * @list_name: property name that contains a list -+ * @cell_count: number of argument cells following the phandle -+ * @index: index of a phandle to parse out -+ * @out_args: optional pointer to output arguments structure (will be filled) -+ * -+ * This function is useful to parse lists of phandles and their arguments. -+ * Returns 0 on success and fills out_args, on error returns appropriate -+ * errno value. -+ * -+ * Caller is responsible to call of_node_put() on the returned out_args->np -+ * pointer. -+ * -+ * Example:: -+ * -+ * phandle1: node1 { -+ * }; -+ * -+ * phandle2: node2 { -+ * }; -+ * -+ * node3 { -+ * list = <&phandle1 0 2 &phandle2 2 3>; -+ * }; -+ * -+ * To get a device_node of the ``node2`` node you may call this: -+ * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args); -+ */ -+static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, -+ const char *list_name, -+ int cell_count, -+ int index, -+ struct of_phandle_args *out_args) -+{ -+ return __of_parse_phandle_with_args(np, list_name, NULL, cell_count, -+ index, out_args); -+} -+ -+/** - * of_property_count_u8_elems - Count the number of u8 elements in a property - * - * @np: device node from which the property value is to be read. diff --git a/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch b/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch deleted file mode 100644 index 0d81d24e09c..00000000000 --- a/target/linux/generic/backport-6.1/830-v6.2-ata-ahci-fix-enum-constants-for-gcc-13.patch +++ /dev/null @@ -1,348 +0,0 @@ -From f07788079f515ca4a681c5f595bdad19cfbd7b1d Mon Sep 17 00:00:00 2001 -From: Arnd Bergmann -Date: Sat, 3 Dec 2022 11:54:25 +0100 -Subject: [PATCH] ata: ahci: fix enum constants for gcc-13 - -gcc-13 slightly changes the type of constant expressions that are defined -in an enum, which triggers a compile time sanity check in libata: - -linux/drivers/ata/libahci.c: In function 'ahci_led_store': -linux/include/linux/compiler_types.h:357:45: error: call to '__compiletime_assert_302' declared with attribute error: BUILD_BUG_ON failed: sizeof(_s) > sizeof(long) -357 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) - -The new behavior is that sizeof() returns the same value for the -constant as it does for the enum type, which is generally more sensible -and consistent. - -The problem in libata is that it contains a single enum definition for -lots of unrelated constants, some of which are large positive (unsigned) -integers like 0xffffffff, while others like (1<<31) are interpreted as -negative integers, and this forces the enum type to become 64 bit wide -even though most constants would still fit into a signed 32-bit 'int'. - -Fix this by changing the entire enum definition to use BIT(x) in place -of (1< -Cc: linux-ide@vger.kernel.org -Cc: Damien Le Moal -Cc: stable@vger.kernel.org -Cc: Randy Dunlap -Signed-off-by: Arnd Bergmann -Tested-by: Luis Machado -Signed-off-by: Damien Le Moal ---- - drivers/ata/ahci.h | 245 +++++++++++++++++++++++---------------------- - 1 file changed, 123 insertions(+), 122 deletions(-) - ---- a/drivers/ata/ahci.h -+++ b/drivers/ata/ahci.h -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - - /* Enclosure Management Control */ - #define EM_CTRL_MSG_TYPE 0x000f0000 -@@ -54,12 +55,12 @@ enum { - AHCI_PORT_PRIV_FBS_DMA_SZ = AHCI_CMD_SLOT_SZ + - AHCI_CMD_TBL_AR_SZ + - (AHCI_RX_FIS_SZ * 16), -- AHCI_IRQ_ON_SG = (1 << 31), -- AHCI_CMD_ATAPI = (1 << 5), -- AHCI_CMD_WRITE = (1 << 6), -- AHCI_CMD_PREFETCH = (1 << 7), -- AHCI_CMD_RESET = (1 << 8), -- AHCI_CMD_CLR_BUSY = (1 << 10), -+ AHCI_IRQ_ON_SG = BIT(31), -+ AHCI_CMD_ATAPI = BIT(5), -+ AHCI_CMD_WRITE = BIT(6), -+ AHCI_CMD_PREFETCH = BIT(7), -+ AHCI_CMD_RESET = BIT(8), -+ AHCI_CMD_CLR_BUSY = BIT(10), - - RX_FIS_PIO_SETUP = 0x20, /* offset of PIO Setup FIS data */ - RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ -@@ -77,37 +78,37 @@ enum { - HOST_CAP2 = 0x24, /* host capabilities, extended */ - - /* HOST_CTL bits */ -- HOST_RESET = (1 << 0), /* reset controller; self-clear */ -- HOST_IRQ_EN = (1 << 1), /* global IRQ enable */ -- HOST_MRSM = (1 << 2), /* MSI Revert to Single Message */ -- HOST_AHCI_EN = (1 << 31), /* AHCI enabled */ -+ HOST_RESET = BIT(0), /* reset controller; self-clear */ -+ HOST_IRQ_EN = BIT(1), /* global IRQ enable */ -+ HOST_MRSM = BIT(2), /* MSI Revert to Single Message */ -+ HOST_AHCI_EN = BIT(31), /* AHCI enabled */ - - /* HOST_CAP bits */ -- HOST_CAP_SXS = (1 << 5), /* Supports External SATA */ -- HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */ -- HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */ -- HOST_CAP_PART = (1 << 13), /* Partial state capable */ -- HOST_CAP_SSC = (1 << 14), /* Slumber state capable */ -- HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */ -- HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */ -- HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ -- HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */ -- HOST_CAP_CLO = (1 << 24), /* Command List Override support */ -- HOST_CAP_LED = (1 << 25), /* Supports activity LED */ -- HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ -- HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ -- HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */ -- HOST_CAP_SNTF = (1 << 29), /* SNotification register */ -- HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ -- HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */ -+ HOST_CAP_SXS = BIT(5), /* Supports External SATA */ -+ HOST_CAP_EMS = BIT(6), /* Enclosure Management support */ -+ HOST_CAP_CCC = BIT(7), /* Command Completion Coalescing */ -+ HOST_CAP_PART = BIT(13), /* Partial state capable */ -+ HOST_CAP_SSC = BIT(14), /* Slumber state capable */ -+ HOST_CAP_PIO_MULTI = BIT(15), /* PIO multiple DRQ support */ -+ HOST_CAP_FBS = BIT(16), /* FIS-based switching support */ -+ HOST_CAP_PMP = BIT(17), /* Port Multiplier support */ -+ HOST_CAP_ONLY = BIT(18), /* Supports AHCI mode only */ -+ HOST_CAP_CLO = BIT(24), /* Command List Override support */ -+ HOST_CAP_LED = BIT(25), /* Supports activity LED */ -+ HOST_CAP_ALPM = BIT(26), /* Aggressive Link PM support */ -+ HOST_CAP_SSS = BIT(27), /* Staggered Spin-up */ -+ HOST_CAP_MPS = BIT(28), /* Mechanical presence switch */ -+ HOST_CAP_SNTF = BIT(29), /* SNotification register */ -+ HOST_CAP_NCQ = BIT(30), /* Native Command Queueing */ -+ HOST_CAP_64 = BIT(31), /* PCI DAC (64-bit DMA) support */ - - /* HOST_CAP2 bits */ -- HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */ -- HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */ -- HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */ -- HOST_CAP2_SDS = (1 << 3), /* Support device sleep */ -- HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */ -- HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */ -+ HOST_CAP2_BOH = BIT(0), /* BIOS/OS handoff supported */ -+ HOST_CAP2_NVMHCI = BIT(1), /* NVMHCI supported */ -+ HOST_CAP2_APST = BIT(2), /* Automatic partial to slumber */ -+ HOST_CAP2_SDS = BIT(3), /* Support device sleep */ -+ HOST_CAP2_SADM = BIT(4), /* Support aggressive DevSlp */ -+ HOST_CAP2_DESO = BIT(5), /* DevSlp from slumber only */ - - /* registers for each SATA port */ - PORT_LST_ADDR = 0x00, /* command list DMA addr */ -@@ -129,24 +130,24 @@ enum { - PORT_DEVSLP = 0x44, /* device sleep */ - - /* PORT_IRQ_{STAT,MASK} bits */ -- PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ -- PORT_IRQ_TF_ERR = (1 << 30), /* task file error */ -- PORT_IRQ_HBUS_ERR = (1 << 29), /* host bus fatal error */ -- PORT_IRQ_HBUS_DATA_ERR = (1 << 28), /* host bus data error */ -- PORT_IRQ_IF_ERR = (1 << 27), /* interface fatal error */ -- PORT_IRQ_IF_NONFATAL = (1 << 26), /* interface non-fatal error */ -- PORT_IRQ_OVERFLOW = (1 << 24), /* xfer exhausted available S/G */ -- PORT_IRQ_BAD_PMP = (1 << 23), /* incorrect port multiplier */ -- -- PORT_IRQ_PHYRDY = (1 << 22), /* PhyRdy changed */ -- PORT_IRQ_DEV_ILCK = (1 << 7), /* device interlock */ -- PORT_IRQ_CONNECT = (1 << 6), /* port connect change status */ -- PORT_IRQ_SG_DONE = (1 << 5), /* descriptor processed */ -- PORT_IRQ_UNK_FIS = (1 << 4), /* unknown FIS rx'd */ -- PORT_IRQ_SDB_FIS = (1 << 3), /* Set Device Bits FIS rx'd */ -- PORT_IRQ_DMAS_FIS = (1 << 2), /* DMA Setup FIS rx'd */ -- PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ -- PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ -+ PORT_IRQ_COLD_PRES = BIT(31), /* cold presence detect */ -+ PORT_IRQ_TF_ERR = BIT(30), /* task file error */ -+ PORT_IRQ_HBUS_ERR = BIT(29), /* host bus fatal error */ -+ PORT_IRQ_HBUS_DATA_ERR = BIT(28), /* host bus data error */ -+ PORT_IRQ_IF_ERR = BIT(27), /* interface fatal error */ -+ PORT_IRQ_IF_NONFATAL = BIT(26), /* interface non-fatal error */ -+ PORT_IRQ_OVERFLOW = BIT(24), /* xfer exhausted available S/G */ -+ PORT_IRQ_BAD_PMP = BIT(23), /* incorrect port multiplier */ -+ -+ PORT_IRQ_PHYRDY = BIT(22), /* PhyRdy changed */ -+ PORT_IRQ_DEV_ILCK = BIT(7), /* device interlock */ -+ PORT_IRQ_CONNECT = BIT(6), /* port connect change status */ -+ PORT_IRQ_SG_DONE = BIT(5), /* descriptor processed */ -+ PORT_IRQ_UNK_FIS = BIT(4), /* unknown FIS rx'd */ -+ PORT_IRQ_SDB_FIS = BIT(3), /* Set Device Bits FIS rx'd */ -+ PORT_IRQ_DMAS_FIS = BIT(2), /* DMA Setup FIS rx'd */ -+ PORT_IRQ_PIOS_FIS = BIT(1), /* PIO Setup FIS rx'd */ -+ PORT_IRQ_D2H_REG_FIS = BIT(0), /* D2H Register FIS rx'd */ - - PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | - PORT_IRQ_IF_ERR | -@@ -162,34 +163,34 @@ enum { - PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, - - /* PORT_CMD bits */ -- PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ -- PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ -- PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ -- PORT_CMD_FBSCP = (1 << 22), /* FBS Capable Port */ -- PORT_CMD_ESP = (1 << 21), /* External Sata Port */ -- PORT_CMD_HPCP = (1 << 18), /* HotPlug Capable Port */ -- PORT_CMD_PMP = (1 << 17), /* PMP attached */ -- PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ -- PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ -- PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ -- PORT_CMD_CLO = (1 << 3), /* Command list override */ -- PORT_CMD_POWER_ON = (1 << 2), /* Power up device */ -- PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */ -- PORT_CMD_START = (1 << 0), /* Enable port DMA engine */ -- -- PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */ -- PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */ -- PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */ -- PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */ -+ PORT_CMD_ASP = BIT(27), /* Aggressive Slumber/Partial */ -+ PORT_CMD_ALPE = BIT(26), /* Aggressive Link PM enable */ -+ PORT_CMD_ATAPI = BIT(24), /* Device is ATAPI */ -+ PORT_CMD_FBSCP = BIT(22), /* FBS Capable Port */ -+ PORT_CMD_ESP = BIT(21), /* External Sata Port */ -+ PORT_CMD_HPCP = BIT(18), /* HotPlug Capable Port */ -+ PORT_CMD_PMP = BIT(17), /* PMP attached */ -+ PORT_CMD_LIST_ON = BIT(15), /* cmd list DMA engine running */ -+ PORT_CMD_FIS_ON = BIT(14), /* FIS DMA engine running */ -+ PORT_CMD_FIS_RX = BIT(4), /* Enable FIS receive DMA engine */ -+ PORT_CMD_CLO = BIT(3), /* Command list override */ -+ PORT_CMD_POWER_ON = BIT(2), /* Power up device */ -+ PORT_CMD_SPIN_UP = BIT(1), /* Spin up device */ -+ PORT_CMD_START = BIT(0), /* Enable port DMA engine */ -+ -+ PORT_CMD_ICC_MASK = (0xfu << 28), /* i/f ICC state mask */ -+ PORT_CMD_ICC_ACTIVE = (0x1u << 28), /* Put i/f in active state */ -+ PORT_CMD_ICC_PARTIAL = (0x2u << 28), /* Put i/f in partial state */ -+ PORT_CMD_ICC_SLUMBER = (0x6u << 28), /* Put i/f in slumber state */ - - /* PORT_FBS bits */ - PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */ - PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */ - PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */ - PORT_FBS_DEV_MASK = (0xf << PORT_FBS_DEV_OFFSET), /* FBS.DEV */ -- PORT_FBS_SDE = (1 << 2), /* FBS single device error */ -- PORT_FBS_DEC = (1 << 1), /* FBS device error clear */ -- PORT_FBS_EN = (1 << 0), /* Enable FBS */ -+ PORT_FBS_SDE = BIT(2), /* FBS single device error */ -+ PORT_FBS_DEC = BIT(1), /* FBS device error clear */ -+ PORT_FBS_EN = BIT(0), /* Enable FBS */ - - /* PORT_DEVSLP bits */ - PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */ -@@ -197,50 +198,50 @@ enum { - PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */ - PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */ - PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */ -- PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */ -- PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */ -+ PORT_DEVSLP_DSP = BIT(1), /* DevSlp present */ -+ PORT_DEVSLP_ADSE = BIT(0), /* Aggressive DevSlp enable */ - - /* hpriv->flags bits */ - - #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) - -- AHCI_HFLAG_NO_NCQ = (1 << 0), -- AHCI_HFLAG_IGN_IRQ_IF_ERR = (1 << 1), /* ignore IRQ_IF_ERR */ -- AHCI_HFLAG_IGN_SERR_INTERNAL = (1 << 2), /* ignore SERR_INTERNAL */ -- AHCI_HFLAG_32BIT_ONLY = (1 << 3), /* force 32bit */ -- AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ -- AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ -- AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ -- AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ -- AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ -- AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */ -- AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = (1 << 11), /* treat SRST timeout as -+ AHCI_HFLAG_NO_NCQ = BIT(0), -+ AHCI_HFLAG_IGN_IRQ_IF_ERR = BIT(1), /* ignore IRQ_IF_ERR */ -+ AHCI_HFLAG_IGN_SERR_INTERNAL = BIT(2), /* ignore SERR_INTERNAL */ -+ AHCI_HFLAG_32BIT_ONLY = BIT(3), /* force 32bit */ -+ AHCI_HFLAG_MV_PATA = BIT(4), /* PATA port */ -+ AHCI_HFLAG_NO_MSI = BIT(5), /* no PCI MSI */ -+ AHCI_HFLAG_NO_PMP = BIT(6), /* no PMP */ -+ AHCI_HFLAG_SECT255 = BIT(8), /* max 255 sectors */ -+ AHCI_HFLAG_YES_NCQ = BIT(9), /* force NCQ cap on */ -+ AHCI_HFLAG_NO_SUSPEND = BIT(10), /* don't suspend */ -+ AHCI_HFLAG_SRST_TOUT_IS_OFFLINE = BIT(11), /* treat SRST timeout as - link offline */ -- AHCI_HFLAG_NO_SNTF = (1 << 12), /* no sntf */ -- AHCI_HFLAG_NO_FPDMA_AA = (1 << 13), /* no FPDMA AA */ -- AHCI_HFLAG_YES_FBS = (1 << 14), /* force FBS cap on */ -- AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on -+ AHCI_HFLAG_NO_SNTF = BIT(12), /* no sntf */ -+ AHCI_HFLAG_NO_FPDMA_AA = BIT(13), /* no FPDMA AA */ -+ AHCI_HFLAG_YES_FBS = BIT(14), /* force FBS cap on */ -+ AHCI_HFLAG_DELAY_ENGINE = BIT(15), /* do not start engine on - port start (wait until - error-handling stage) */ -- AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */ -- AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */ -+ AHCI_HFLAG_NO_DEVSLP = BIT(17), /* no device sleep */ -+ AHCI_HFLAG_NO_FBS = BIT(18), /* no FBS */ - - #ifdef CONFIG_PCI_MSI -- AHCI_HFLAG_MULTI_MSI = (1 << 20), /* per-port MSI(-X) */ -+ AHCI_HFLAG_MULTI_MSI = BIT(20), /* per-port MSI(-X) */ - #else - /* compile out MSI infrastructure */ - AHCI_HFLAG_MULTI_MSI = 0, - #endif -- AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ -- AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */ -- AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read -+ AHCI_HFLAG_WAKE_BEFORE_STOP = BIT(22), /* wake before DMA stop */ -+ AHCI_HFLAG_YES_ALPM = BIT(23), /* force ALPM cap on */ -+ AHCI_HFLAG_NO_WRITE_TO_RO = BIT(24), /* don't write to read - only registers */ -- AHCI_HFLAG_IS_MOBILE = (1 << 25), /* mobile chipset, use -+ AHCI_HFLAG_IS_MOBILE = BIT(25), /* mobile chipset, use - SATA_MOBILE_LPM_POLICY - as default lpm_policy */ -- AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during -+ AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during - suspend/resume */ -- AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */ -+ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ - - /* ap->flags bits */ - -@@ -256,22 +257,22 @@ enum { - EM_MAX_RETRY = 5, - - /* em_ctl bits */ -- EM_CTL_RST = (1 << 9), /* Reset */ -- EM_CTL_TM = (1 << 8), /* Transmit Message */ -- EM_CTL_MR = (1 << 0), /* Message Received */ -- EM_CTL_ALHD = (1 << 26), /* Activity LED */ -- EM_CTL_XMT = (1 << 25), /* Transmit Only */ -- EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ -- EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ -- EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ -- EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ -- EM_CTL_LED = (1 << 16), /* LED messages supported */ -+ EM_CTL_RST = BIT(9), /* Reset */ -+ EM_CTL_TM = BIT(8), /* Transmit Message */ -+ EM_CTL_MR = BIT(0), /* Message Received */ -+ EM_CTL_ALHD = BIT(26), /* Activity LED */ -+ EM_CTL_XMT = BIT(25), /* Transmit Only */ -+ EM_CTL_SMB = BIT(24), /* Single Message Buffer */ -+ EM_CTL_SGPIO = BIT(19), /* SGPIO messages supported */ -+ EM_CTL_SES = BIT(18), /* SES-2 messages supported */ -+ EM_CTL_SAFTE = BIT(17), /* SAF-TE messages supported */ -+ EM_CTL_LED = BIT(16), /* LED messages supported */ - - /* em message type */ -- EM_MSG_TYPE_LED = (1 << 0), /* LED */ -- EM_MSG_TYPE_SAFTE = (1 << 1), /* SAF-TE */ -- EM_MSG_TYPE_SES2 = (1 << 2), /* SES-2 */ -- EM_MSG_TYPE_SGPIO = (1 << 3), /* SGPIO */ -+ EM_MSG_TYPE_LED = BIT(0), /* LED */ -+ EM_MSG_TYPE_SAFTE = BIT(1), /* SAF-TE */ -+ EM_MSG_TYPE_SES2 = BIT(2), /* SES-2 */ -+ EM_MSG_TYPE_SGPIO = BIT(3), /* SGPIO */ - }; - - struct ahci_cmd_hdr { diff --git a/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch b/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch deleted file mode 100644 index e9d692b651a..00000000000 --- a/target/linux/generic/backport-6.1/860-v5.17-MIPS-ath79-drop-_machine_restart-again.patch +++ /dev/null @@ -1,49 +0,0 @@ -From d3115128bdafb62628ab41861a4f06f6d02ac320 Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Mon, 10 Jan 2022 23:48:44 +0100 -Subject: MIPS: ath79: drop _machine_restart again - -Commit 81424d0ad0d4 ("MIPS: ath79: Use the reset controller to restart -OF machines") removed setup of _machine_restart on OF machines to use -reset handler in reset controller driver. -While removing remnants of non-OF machines in commit 3a77e0d75eed -("MIPS: ath79: drop machfiles"), this was introduced again, making it -impossible to use additional restart handlers registered through device -tree. Drop setting _machine_restart altogether, and ath79_restart -function, which is no longer used after this. - -Fixes: 3a77e0d75eed ("MIPS: ath79: drop machfiles") -Cc: John Crispin -Cc: Florian Fainelli -Signed-off-by: Lech Perczak -Signed-off-by: Thomas Bogendoerfer ---- - arch/mips/ath79/setup.c | 10 ---------- - 1 file changed, 10 deletions(-) - ---- a/arch/mips/ath79/setup.c -+++ b/arch/mips/ath79/setup.c -@@ -34,15 +34,6 @@ - - static char ath79_sys_type[ATH79_SYS_TYPE_LEN]; - --static void ath79_restart(char *command) --{ -- local_irq_disable(); -- ath79_device_reset_set(AR71XX_RESET_FULL_CHIP); -- for (;;) -- if (cpu_wait) -- cpu_wait(); --} -- - static void ath79_halt(void) - { - while (1) -@@ -234,7 +225,6 @@ void __init plat_mem_setup(void) - - detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX); - -- _machine_restart = ath79_restart; - _machine_halt = ath79_halt; - pm_power_off = ath79_halt; - } diff --git a/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch b/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch deleted file mode 100644 index fabf177628f..00000000000 --- a/target/linux/generic/backport-6.1/870-v5.18-hwmon-lm70-Add-ti-tmp125-support.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 31d8f414e1596ba54a4315418e4c0086fda9e428 Mon Sep 17 00:00:00 2001 -From: Christian Lamparter -Date: Fri, 18 Feb 2022 10:06:43 +0100 -Subject: hwmon: (lm70) Add ti,tmp125 support - -The TMP125 is a 2 degree Celsius accurate Digital -Temperature Sensor with a SPI interface. - -The temperature register is a 16-bit, read-only register. -The MSB (Bit 15) is a leading zero and never set. Bits 14 -to 5 are the 1+9 temperature data bits in a two's -complement format. Bits 4 to 0 are useless copies of -Bit 5 value and therefore ignored. - -Signed-off-by: Christian Lamparter -Link: https://lore.kernel.org/r/43b19cbd4e7f51e9509e561b02b5d8d0e7079fac.1645175187.git.chunkeey@gmail.com -Signed-off-by: Guenter Roeck ---- ---- a/drivers/hwmon/lm70.c -+++ b/drivers/hwmon/lm70.c -@@ -34,6 +34,7 @@ - #define LM70_CHIP_LM71 2 /* NS LM71 */ - #define LM70_CHIP_LM74 3 /* NS LM74 */ - #define LM70_CHIP_TMP122 4 /* TI TMP122/TMP124 */ -+#define LM70_CHIP_TMP125 5 /* TI TMP125 */ - - struct lm70 { - struct spi_device *spi; -@@ -87,6 +88,12 @@ static ssize_t temp1_input_show(struct d - * LM71: - * 14 bits of 2's complement data, discard LSB 2 bits, - * resolution 0.0312 degrees celsius. -+ * -+ * TMP125: -+ * MSB/D15 is a leading zero. D14 is the sign-bit. This is -+ * followed by 9 temperature bits (D13..D5) in 2's complement -+ * data format with a resolution of 0.25 degrees celsius per unit. -+ * LSB 5 bits (D4..D0) share the same value as D5 and get discarded. - */ - switch (p_lm70->chip) { - case LM70_CHIP_LM70: -@@ -102,6 +109,10 @@ static ssize_t temp1_input_show(struct d - case LM70_CHIP_LM71: - val = ((int)raw / 4) * 3125 / 100; - break; -+ -+ case LM70_CHIP_TMP125: -+ val = (sign_extend32(raw, 14) / 32) * 250; -+ break; - } - - status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ -@@ -136,6 +147,10 @@ static const struct of_device_id lm70_of - .data = (void *) LM70_CHIP_TMP122, - }, - { -+ .compatible = "ti,tmp125", -+ .data = (void *) LM70_CHIP_TMP125, -+ }, -+ { - .compatible = "ti,lm71", - .data = (void *) LM70_CHIP_LM71, - }, -@@ -184,6 +199,7 @@ static const struct spi_device_id lm70_i - { "lm70", LM70_CHIP_LM70 }, - { "tmp121", LM70_CHIP_TMP121 }, - { "tmp122", LM70_CHIP_TMP122 }, -+ { "tmp125", LM70_CHIP_TMP125 }, - { "lm71", LM70_CHIP_LM71 }, - { "lm74", LM70_CHIP_LM74 }, - { }, diff --git a/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch b/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch deleted file mode 100644 index 39fdb327733..00000000000 --- a/target/linux/generic/backport-6.1/880-v5.19-cdc_ether-export-usbnet_cdc_zte_rx_fixup.patch +++ /dev/null @@ -1,58 +0,0 @@ -From a79a5613e1907e1bf09bb6ba6fd5ff43b66c1afe Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Fri, 1 Apr 2022 22:03:55 +0200 -Subject: [PATCH 1/3] cdc_ether: export usbnet_cdc_zte_rx_fixup -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Commit bfe9b9d2df66 ("cdc_ether: Improve ZTE MF823/831/910 handling") -introduces a workaround for certain ZTE modems reporting invalid MAC -addresses over CDC-ECM. -The same issue was present on their RNDIS interface,which was fixed in -commit a5a18bdf7453 ("rndis_host: Set valid random MAC on buggy devices"). - -However, internal modem of ZTE MF286R router, on its RNDIS interface, also -exhibits a second issue fixed already in CDC-ECM, of the device not -respecting configured random MAC address. In order to share the fixup for -this with rndis_host driver, export the workaround function, which will -be re-used in the following commit in rndis_host. - -Cc: Kristian Evensen -Cc: Bjørn Mork -Cc: Oliver Neukum -Signed-off-by: Lech Perczak ---- - drivers/net/usb/cdc_ether.c | 3 ++- - include/linux/usb/usbnet.h | 1 + - 2 files changed, 3 insertions(+), 1 deletion(-) - ---- a/drivers/net/usb/cdc_ether.c -+++ b/drivers/net/usb/cdc_ether.c -@@ -479,7 +479,7 @@ static int usbnet_cdc_zte_bind(struct us - * device MAC address has been updated). Always set MAC address to that of the - * device. - */ --static int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb) -+int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - { - if (skb->len < ETH_HLEN || !(skb->data[0] & 0x02)) - return 1; -@@ -489,6 +489,7 @@ static int usbnet_cdc_zte_rx_fixup(struc - - return 1; - } -+EXPORT_SYMBOL_GPL(usbnet_cdc_zte_rx_fixup); - - /* Ensure correct link state - * ---- a/include/linux/usb/usbnet.h -+++ b/include/linux/usb/usbnet.h -@@ -214,6 +214,7 @@ extern int usbnet_ether_cdc_bind(struct - extern int usbnet_cdc_bind(struct usbnet *, struct usb_interface *); - extern void usbnet_cdc_unbind(struct usbnet *, struct usb_interface *); - extern void usbnet_cdc_status(struct usbnet *, struct urb *); -+extern int usbnet_cdc_zte_rx_fixup(struct usbnet *dev, struct sk_buff *skb); - - /* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ - #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ diff --git a/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch b/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch deleted file mode 100644 index 71a6df81020..00000000000 --- a/target/linux/generic/backport-6.1/881-v5.19-rndis_host-enable-the-bogus-MAC-fixup-for-ZTE-device.patch +++ /dev/null @@ -1,118 +0,0 @@ -From aa8aff10e969aca0cb64f5e54ff7489355582667 Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Fri, 1 Apr 2022 22:04:01 +0200 -Subject: [PATCH 2/3] rndis_host: enable the bogus MAC fixup for ZTE devices - from cdc_ether -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Certain ZTE modems, namely: MF823. MF831, MF910, built-in modem from -MF286R, expose both CDC-ECM and RNDIS network interfaces. -They have a trait of ignoring the locally-administered MAC address -configured on the interface both in CDC-ECM and RNDIS part, -and this leads to dropping of incoming traffic by the host. -However, the workaround was only present in CDC-ECM, and MF286R -explicitly requires it in RNDIS mode. - -Re-use the workaround in rndis_host as well, to fix operation of MF286R -module, some versions of which expose only the RNDIS interface. Do so by -introducing new flag, RNDIS_DRIVER_DATA_DST_MAC_FIXUP, and testing for it -in rndis_rx_fixup. This is required, as RNDIS uses frame batching, and all -of the packets inside the batch need the fixup. This might introduce a -performance penalty, because test is done for every returned Ethernet -frame. - -Apply the workaround to both "flavors" of RNDIS interfaces, as older ZTE -modems, like MF823 found in the wild, report the USB_CLASS_COMM class -interfaces, while MF286R reports USB_CLASS_WIRELESS_CONTROLLER. - -Suggested-by: Bjørn Mork -Cc: Kristian Evensen -Cc: Oliver Neukum -Signed-off-by: Lech Perczak ---- - drivers/net/usb/rndis_host.c | 32 ++++++++++++++++++++++++++++++++ - include/linux/usb/rndis_host.h | 1 + - 2 files changed, 33 insertions(+) - ---- a/drivers/net/usb/rndis_host.c -+++ b/drivers/net/usb/rndis_host.c -@@ -486,10 +486,14 @@ EXPORT_SYMBOL_GPL(rndis_unbind); - */ - int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - { -+ bool dst_mac_fixup; -+ - /* This check is no longer done by usbnet */ - if (skb->len < dev->net->hard_header_len) - return 0; - -+ dst_mac_fixup = !!(dev->driver_info->data & RNDIS_DRIVER_DATA_DST_MAC_FIXUP); -+ - /* peripheral may have batched packets to us... */ - while (likely(skb->len)) { - struct rndis_data_hdr *hdr = (void *)skb->data; -@@ -524,10 +528,17 @@ int rndis_rx_fixup(struct usbnet *dev, s - break; - skb_pull(skb, msg_len - sizeof *hdr); - skb_trim(skb2, data_len); -+ -+ if (unlikely(dst_mac_fixup)) -+ usbnet_cdc_zte_rx_fixup(dev, skb2); -+ - usbnet_skb_return(dev, skb2); - } - - /* caller will usbnet_skb_return the remaining packet */ -+ if (unlikely(dst_mac_fixup)) -+ usbnet_cdc_zte_rx_fixup(dev, skb); -+ - return 1; - } - EXPORT_SYMBOL_GPL(rndis_rx_fixup); -@@ -601,6 +612,17 @@ static const struct driver_info rndis_po - .tx_fixup = rndis_tx_fixup, - }; - -+static const struct driver_info zte_rndis_info = { -+ .description = "ZTE RNDIS device", -+ .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, -+ .data = RNDIS_DRIVER_DATA_DST_MAC_FIXUP, -+ .bind = rndis_bind, -+ .unbind = rndis_unbind, -+ .status = rndis_status, -+ .rx_fixup = rndis_rx_fixup, -+ .tx_fixup = rndis_tx_fixup, -+}; -+ - /*-------------------------------------------------------------------------*/ - - static const struct usb_device_id products [] = { -@@ -615,6 +637,16 @@ static const struct usb_device_id produc - USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long)&rndis_info, - }, { -+ /* ZTE WWAN modules */ -+ USB_VENDOR_AND_INTERFACE_INFO(0x19d2, -+ USB_CLASS_WIRELESS_CONTROLLER, 1, 3), -+ .driver_info = (unsigned long)&zte_rndis_info, -+}, { -+ /* ZTE WWAN modules, ACM flavour */ -+ USB_VENDOR_AND_INTERFACE_INFO(0x19d2, -+ USB_CLASS_COMM, 2 /* ACM */, 0x0ff), -+ .driver_info = (unsigned long)&zte_rndis_info, -+}, { - /* RNDIS is MSFT's un-official variant of CDC ACM */ - USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), - .driver_info = (unsigned long) &rndis_info, ---- a/include/linux/usb/rndis_host.h -+++ b/include/linux/usb/rndis_host.h -@@ -197,6 +197,7 @@ struct rndis_keepalive_c { /* IN (option - - /* Flags for driver_info::data */ - #define RNDIS_DRIVER_DATA_POLL_STATUS 1 /* poll status before control */ -+#define RNDIS_DRIVER_DATA_DST_MAC_FIXUP 2 /* device ignores configured MAC address */ - - extern void rndis_status(struct usbnet *dev, struct urb *urb); - extern int diff --git a/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch b/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch deleted file mode 100644 index bdd812cc906..00000000000 --- a/target/linux/generic/backport-6.1/882-v5.19-rndis_host-limit-scope-of-bogus-MAC-address-detectio.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 9bfb4bcda7ba32d73ea322ea56a8ebe32e9247f6 Mon Sep 17 00:00:00 2001 -From: Lech Perczak -Date: Sat, 2 Apr 2022 02:19:57 +0200 -Subject: [PATCH 3/3] rndis_host: limit scope of bogus MAC address detection to - ZTE devices -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Reporting of bogus MAC addresses and ignoring configuration of new -destination address wasn't observed outside of a range of ZTE devices, -among which this seems to be the common bug. Align rndis_host driver -with implementation found in cdc_ether, which also limits this workaround -to ZTE devices. - -Suggested-by: Bjørn Mork -Cc: Kristian Evensen -Cc: Oliver Neukum -Signed-off-by: Lech Perczak ---- - drivers/net/usb/rndis_host.c | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - ---- a/drivers/net/usb/rndis_host.c -+++ b/drivers/net/usb/rndis_host.c -@@ -419,10 +419,7 @@ generic_rndis_bind(struct usbnet *dev, s - goto halt_fail_and_release; - } - -- if (bp[0] & 0x02) -- eth_hw_addr_random(net); -- else -- ether_addr_copy(net->dev_addr, bp); -+ ether_addr_copy(net->dev_addr, bp); - - /* set a nonzero filter to enable data transfers */ - memset(u.set, 0, sizeof *u.set); -@@ -464,6 +461,16 @@ static int rndis_bind(struct usbnet *dev - return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); - } - -+static int zte_rndis_bind(struct usbnet *dev, struct usb_interface *intf) -+{ -+ int status = rndis_bind(dev, intf); -+ -+ if (!status && (dev->net->dev_addr[0] & 0x02)) -+ eth_hw_addr_random(dev->net); -+ -+ return status; -+} -+ - void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) - { - struct rndis_halt *halt; -@@ -616,7 +623,7 @@ static const struct driver_info zte_rndi - .description = "ZTE RNDIS device", - .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, - .data = RNDIS_DRIVER_DATA_DST_MAC_FIXUP, -- .bind = rndis_bind, -+ .bind = zte_rndis_bind, - .unbind = rndis_unbind, - .status = rndis_status, - .rx_fixup = rndis_rx_fixup, diff --git a/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch b/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch deleted file mode 100644 index 38fbc3a3d73..00000000000 --- a/target/linux/generic/backport-6.1/890-v6.1-mtd-spinand-winbond-fix-flash-detection.patch +++ /dev/null @@ -1,40 +0,0 @@ -From dbf70fc204d2fbb0d8ad8f42038a60846502efda Mon Sep 17 00:00:00 2001 -From: Mikhail Kshevetskiy -Date: Mon, 10 Oct 2022 13:51:09 +0300 -Subject: [PATCH] mtd: spinand: winbond: fix flash identification - -Winbond uses 3 bytes to identify flash: vendor_id, dev_id_0, dev_id_1, -but current driver uses only first 2 bytes of it for devices -identification. As result Winbond W25N02KV flash (id_bytes: EF, AA, 22) -is identified as W25N01GV (id_bytes: EF, AA, 21). - -Fix this by adding missed identification bytes. - -Signed-off-by: Mikhail Kshevetskiy -Reviewed-by: Frieder Schrempf -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-1-mikhail.kshevetskiy@iopsys.eu ---- - drivers/mtd/nand/spi/winbond.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/drivers/mtd/nand/spi/winbond.c -+++ b/drivers/mtd/nand/spi/winbond.c -@@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct - - static const struct spinand_info winbond_spinand_table[] = { - SPINAND_INFO("W25M02GV", -- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab), -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), - NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -@@ -86,7 +86,7 @@ static const struct spinand_info winbond - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), - SPINAND_SELECT_TARGET(w25m02gv_select_target)), - SPINAND_INFO("W25N01GV", -- SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa), -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), - NAND_ECCREQ(1, 512), - SPINAND_INFO_OP_VARIANTS(&read_cache_variants, diff --git a/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch b/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch deleted file mode 100644 index d75a1acc57c..00000000000 --- a/target/linux/generic/backport-6.1/891-v6.1-mtd-spinand-winbond-add-W25N02KV.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 6154c7a583483d7b69f53bea868efdc369edd563 Mon Sep 17 00:00:00 2001 -From: Mikhail Kshevetskiy -Date: Mon, 10 Oct 2022 13:51:10 +0300 -Subject: [PATCH] mtd: spinand: winbond: add Winbond W25N02KV flash support - -Add support of Winbond W25N02KV flash - -Signed-off-by: Mikhail Kshevetskiy -Reviewed-by: Frieder Schrempf -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20221010105110.446674-2-mikhail.kshevetskiy@iopsys.eu ---- - drivers/mtd/nand/spi/winbond.c | 75 ++++++++++++++++++++++++++++++++++ - 1 file changed, 75 insertions(+) - ---- a/drivers/mtd/nand/spi/winbond.c -+++ b/drivers/mtd/nand/spi/winbond.c -@@ -74,6 +74,72 @@ static int w25m02gv_select_target(struct - return spi_mem_exec_op(spinand->spimem, &op); - } - -+static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section > 3) -+ return -ERANGE; -+ -+ region->offset = 64 + (16 * section); -+ region->length = 13; -+ -+ return 0; -+} -+ -+static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, -+ struct mtd_oob_region *region) -+{ -+ if (section > 3) -+ return -ERANGE; -+ -+ region->offset = (16 * section) + 2; -+ region->length = 14; -+ -+ return 0; -+} -+ -+static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { -+ .ecc = w25n02kv_ooblayout_ecc, -+ .free = w25n02kv_ooblayout_free, -+}; -+ -+static int w25n02kv_ecc_get_status(struct spinand_device *spinand, -+ u8 status) -+{ -+ struct nand_device *nand = spinand_to_nand(spinand); -+ u8 mbf = 0; -+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); -+ -+ switch (status & STATUS_ECC_MASK) { -+ case STATUS_ECC_NO_BITFLIPS: -+ return 0; -+ -+ case STATUS_ECC_UNCOR_ERROR: -+ return -EBADMSG; -+ -+ case STATUS_ECC_HAS_BITFLIPS: -+ /* -+ * Let's try to retrieve the real maximum number of bitflips -+ * in order to avoid forcing the wear-leveling layer to move -+ * data around if it's not necessary. -+ */ -+ if (spi_mem_exec_op(spinand->spimem, &op)) -+ return nanddev_get_ecc_conf(nand)->strength; -+ -+ mbf >>= 4; -+ -+ if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) -+ return nanddev_get_ecc_conf(nand)->strength; -+ -+ return mbf; -+ -+ default: -+ break; -+ } -+ -+ return -EINVAL; -+} -+ - static const struct spinand_info winbond_spinand_table[] = { - SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), -@@ -94,6 +160,15 @@ static const struct spinand_info winbond - &update_cache_variants), - 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), -+ SPINAND_INFO("W25N02KV", -+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), -+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), -+ NAND_ECCREQ(8, 512), -+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants, -+ &write_cache_variants, -+ &update_cache_variants), -+ 0, -+ SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - }; - - static int winbond_spinand_init(struct spinand_device *spinand) From 9aee67efbb4dbb9f813512f60e80a6d7ade66143 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 00:56:57 +0200 Subject: [PATCH 60/88] generic: 6.1: manually refresh backport patches Refresh backport patches that still needs to be merged for kernel 6.1. Signed-off-by: Christian Marangi --- ...mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch | 4 ++-- .../707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch | 4 ++-- ...net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch | 2 +- ...net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch | 4 ++-- .../828-v6.4-0003-of-Rename-of_modalias_node.patch | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch index 2d89a5db126..017a58ba636 100644 --- a/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch +++ b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch @@ -37,9 +37,9 @@ Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc goto err; } @@ -991,7 +990,7 @@ static int mtd_otp_nvmem_add(struct mtd_ + err: - if (mtd->otp_user_nvmem) - nvmem_unregister(mtd->otp_user_nvmem); + nvmem_unregister(mtd->otp_user_nvmem); - return err; + return dev_err_probe(dev, err, "Failed to register OTP NVMEM device\n"); } diff --git a/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch index 9743a3f2062..6a82d191f90 100644 --- a/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch +++ b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch @@ -64,9 +64,9 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile @@ -5,3 +5,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs. - - obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o + obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o + obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o +obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o --- /dev/null +++ b/drivers/net/pcs/pcs-mtk-lynxi.c diff --git a/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch index b3412df9e0c..13245373841 100644 --- a/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch +++ b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch @@ -102,7 +102,7 @@ Signed-off-by: Felix Fietkau if (ring->buf) { - for (i = 0; i < MTK_DMA_SIZE; i++) + for (i = 0; i < ring->dma_size; i++) - mtk_tx_unmap(eth, &ring->buf[i], false); + mtk_tx_unmap(eth, &ring->buf[i], NULL, false); kfree(ring->buf); ring->buf = NULL; @@ -2247,14 +2253,14 @@ static void mtk_tx_clean(struct mtk_eth diff --git a/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch index 0478cb528e2..5458279fff0 100644 --- a/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch +++ b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch @@ -31,9 +31,9 @@ Signed-off-by: Felix Fietkau --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -20,6 +20,7 @@ - #include + #include + #include #include - #include +#include #include "dsa_priv.h" diff --git a/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch index 6c205217018..f15498c7119 100644 --- a/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch +++ b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch @@ -137,8 +137,8 @@ Signed-off-by: Greg Kroah-Hartman if (!compatible || strlen(compatible) > cplen) return -ENODEV; p = strchr(compatible, ','); -- strlcpy(modalias, p ? p + 1 : compatible, len); -+ strlcpy(alias, p ? p + 1 : compatible, len); +- strscpy(modalias, p ? p + 1 : compatible, len); ++ strscpy(alias, p ? p + 1 : compatible, len); return 0; } -EXPORT_SYMBOL_GPL(of_modalias_node); From fcab78c09fd5c5bcd506afbbf50de37bb839eb2f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:24:43 +0200 Subject: [PATCH 61/88] generic: 6.1: manually refresh pending patches Refresh pending patches for kernel 6.1. Changes: - Refresh mtd patches with new implementation. - Change 191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source as uie_unsupported got dropped and we now set the bit directly. Signed-off-by: Christian Marangi --- .../103-kbuild-export-SUBARCH.patch | 10 +- ...ilicon-Labs-EM3581-device-compatible.patch | 8 +- ...ilicon-Labs-SI3210-device-compatible.patch | 8 +- ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch | 2 +- ...he_alarm_to_be_used_as_wakeup_source.patch | 5 +- .../203-kallsyms_uncompressed.patch | 21 +- .../270-platform-mikrotik-build-bits.patch | 4 +- .../400-mtd-mtdsplit-support.patch | 2 +- .../pending-6.1/420-mtd-redboot_space.patch | 2 +- .../476-mtd-spi-nor-add-eon-en25q128.patch | 17 +- .../477-mtd-spi-nor-add-eon-en25qx128a.patch | 14 +- .../479-mtd-spi-nor-add-xtx-xt25f128b.patch | 9 +- ...r-add-support-for-Gigadevice-GD25D05.patch | 17 +- .../482-mtd-spi-nor-add-gd25q512.patch | 14 +- .../484-mtd-spi-nor-add-esmt-f25l16pa.patch | 13 +- .../485-mtd-spi-nor-add-xmc-xm25qh128c.patch | 13 +- ...nand-add-support-for-ESMT-F50x1G41LB.patch | 10 +- ...nd-Add-support-for-Etron-EM73D044VCx.patch | 8 +- .../488-mtd-spi-nor-add-xmc-xm25qh64c.patch | 19 +- ...mtd-device-named-ubi-or-data-on-boot.patch | 2 +- ...i-nor-locking-support-for-MX25L6405D.patch | 18 +- .../530-jffs2_make_lzma_available.patch | 695 ++++++++++++++++-- .../600-netfilter_conntrack_flush.patch | 8 +- .../pending-6.1/655-increase_skb_pad.patch | 2 +- ...T-skip-GRO-for-foreign-MAC-addresses.patch | 20 +- ...ow_offload-handle-netdevice-events-f.patch | 34 +- ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 12 +- ...detach-callback-to-struct-phy_driver.patch | 4 +- ...d-knob-for-filtering-rx-tx-BPDU-pack.patch | 18 +- ...iatek-ppe-add-support-for-flow-accou.patch | 6 +- ...iatek-fix-ppe-flow-accounting-for-L2.patch | 2 +- ...ional-threading-for-backlog-processi.patch | 35 +- .../811-pci_disable_usb_common_quirks.patch | 2 +- .../pending-6.1/834-ledtrig-libata.patch | 8 +- ...e-main-irq_chip-structure-a-static-d.patch | 8 +- .../pending-6.1/920-mangle_bootargs.patch | 4 +- 36 files changed, 846 insertions(+), 228 deletions(-) diff --git a/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch index 120b6e4cf89..513e394092a 100644 --- a/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch +++ b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch @@ -10,12 +10,12 @@ Signed-off-by: Felix Fietkau --- a/Makefile +++ b/Makefile -@@ -534,7 +534,7 @@ KBUILD_LDFLAGS_MODULE := - KBUILD_LDFLAGS := - CLANG_FLAGS := +@@ -523,7 +523,7 @@ KBUILD_LDFLAGS_MODULE := + # Allows the usage of unstable features in stable compilers. + export RUSTC_BOOTSTRAP := 1 -export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG +export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE LD CC HOSTPKG_CONFIG + export RUSTC RUSTDOC RUSTFMT RUSTC_OR_CLIPPY_QUIET RUSTC_OR_CLIPPY BINDGEN CARGO + export HOSTRUSTC KBUILD_HOSTRUSTFLAGS export CPP AR NM STRIP OBJCOPY OBJDUMP READELF PAHOLE RESOLVE_BTFIDS LEX YACC AWK INSTALLKERNEL - export PERL PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX - export KGZIP KBZIP2 KLZOP LZMA LZ4 XZ ZSTD diff --git a/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch index 5216d6a7068..c2940b601bb 100644 --- a/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch +++ b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch @@ -23,10 +23,10 @@ Signed-off-by: Vincent Tremblay }; MODULE_DEVICE_TABLE(spi, spidev_spi_ids); @@ -705,6 +706,7 @@ static const struct of_device_id spidev_ - { .compatible = "menlo,m53cpld" }, - { .compatible = "cisco,spi-petra" }, - { .compatible = "micron,spi-authenta" }, -+ { .compatible = "silabs,em3581" }, + { .compatible = "menlo,m53cpld", .data = &spidev_of_check }, + { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, + { .compatible = "micron,spi-authenta", .data = &spidev_of_check }, ++ { .compatible = "silabs,em3581", .data = &spidev_of_check }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch index ffbed0c622b..d88e5106c17 100644 --- a/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch +++ b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch @@ -23,10 +23,10 @@ Signed-off-by: Vincent Tremblay }; MODULE_DEVICE_TABLE(spi, spidev_spi_ids); @@ -707,6 +708,7 @@ static const struct of_device_id spidev_ - { .compatible = "cisco,spi-petra" }, - { .compatible = "micron,spi-authenta" }, - { .compatible = "silabs,em3581" }, -+ { .compatible = "silabs,si3210" }, + { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, + { .compatible = "micron,spi-authenta", .data = &spidev_of_check }, + { .compatible = "silabs,em3581", .data = &spidev_of_check }, ++ { .compatible = "silabs,si3210", .data = &spidev_of_check }, {}, }; MODULE_DEVICE_TABLE(of, spidev_dt_ids); diff --git a/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch index ac5e3a69b80..4e347a46710 100644 --- a/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch +++ b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch @@ -71,7 +71,7 @@ Signed-off-by: Tobias Wolf --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7620,7 +7620,7 @@ static void __init alloc_node_mem_map(st +@@ -7556,7 +7556,7 @@ static void __init alloc_node_mem_map(st if (pgdat == NODE_DATA(0)) { mem_map = NODE_DATA(0)->node_mem_map; if (page_to_pfn(mem_map) != pgdat->node_start_pfn) diff --git a/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch index 7e9d0e66c05..a934af402ec 100644 --- a/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch +++ b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch @@ -58,12 +58,13 @@ Signed-off-by: Daniel González Cabanelas rs5c372->rtc = devm_rtc_device_register(&client->dev, rs5c372_driver.driver.name, &rs5c372_rtc_ops, THIS_MODULE); -@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_clie +@@ -761,6 +774,10 @@ static int rs5c372_probe(struct i2c_clie if (err) goto exit; + /* the rs5c372 alarm only supports a minute accuracy */ -+ rs5c372->rtc->uie_unsupported = 1; ++ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rs5c372->rtc->features); ++ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rs5c372->rtc->features); + return 0; diff --git a/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch index 930d0ff0fe4..bc9fdda9f1a 100644 --- a/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch +++ b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch @@ -95,22 +95,21 @@ Signed-off-by: Felix Fietkau /* using the '\0' symbol last allows compress_symbols to use standard * fast string functions */ for (i = 255; i >= 0; i--) { -@@ -773,6 +783,8 @@ int main(int argc, char **argv) - absolute_percpu = 1; - else if (strcmp(argv[i], "--base-relative") == 0) - base_relative = 1; -+ else if (strcmp(argv[i], "--uncompressed") == 0) -+ uncompressed = 1; - else - usage(); - } +@@ -773,6 +783,7 @@ int main(int argc, char **argv) + {"all-symbols", no_argument, &all_symbols, 1}, + {"absolute-percpu", no_argument, &absolute_percpu, 1}, + {"base-relative", no_argument, &base_relative, 1}, ++ {"uncompressed", no_argument, &uncompressed, 1}, + {}, + }; + --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh -@@ -257,6 +257,10 @@ kallsyms() +@@ -266,6 +266,10 @@ kallsyms() kallsymopt="${kallsymopt} --base-relative" fi -+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then ++ if is_enabled CONFIG_KALLSYMS_UNCOMPRESSED; then + kallsymopt="${kallsymopt} --uncompressed" + fi + diff --git a/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch index 99f83bb2c4e..f847db983a2 100644 --- a/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch +++ b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch @@ -17,9 +17,9 @@ Signed-off-by: Thibaut VARÈNE --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -15,3 +15,5 @@ source "drivers/platform/mellanox/Kconfi - source "drivers/platform/olpc/Kconfig" - source "drivers/platform/surface/Kconfig" + + source "drivers/platform/x86/Kconfig" + +source "drivers/platform/mikrotik/Kconfig" --- a/drivers/platform/Makefile diff --git a/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch index 46ef15d127d..2360d6dcd0f 100644 --- a/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch +++ b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch @@ -289,7 +289,7 @@ Subject: [PATCH] mtd: mtdsplit support static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) { if (mtd->writesize_shift) -@@ -693,6 +711,13 @@ extern struct mtd_info *of_get_mtd_devic +@@ -685,6 +703,13 @@ extern void __put_mtd_device(struct mtd_ extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); diff --git a/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch index 5518ea71dd5..fee19365933 100644 --- a/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch +++ b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/parsers/redboot.c +++ b/drivers/mtd/parsers/redboot.c -@@ -278,14 +278,21 @@ nogood: +@@ -277,14 +277,21 @@ nogood: #endif names += strlen(names) + 1; diff --git a/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch index 9383e48856d..4caf97fcf2b 100644 --- a/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch +++ b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch @@ -8,11 +8,12 @@ Signed-off-by: Piotr Dymacz --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c -@@ -25,6 +25,7 @@ static const struct flash_info eon_parts - { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, -+ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) }, - { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ) }, - { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, +@@ -15,6 +15,8 @@ static const struct flash_info eon_parts + { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128) }, + { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128) + NO_SFDP_FLAGS(SECT_4K) }, ++ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256) ++ NO_SFDP_FLAGS(SECT_4K) }, + { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32) diff --git a/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch index 3c579e55e34..e94c836f62a 100644 --- a/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch +++ b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch @@ -12,10 +12,10 @@ Signed-off-by: Christian Marangi --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c @@ -26,6 +26,7 @@ static const struct flash_info eon_parts - { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, - { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, - { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) }, -+ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256, 0) }, - { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16, - SECT_4K | SPI_NOR_DUAL_READ) }, - { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32, + NO_SFDP_FLAGS(SECT_4K) }, + { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256) + NO_SFDP_FLAGS(SECT_4K) }, ++ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256) }, + { "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) }, + { "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32) diff --git a/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch index 5a064b714bf..8eb09596ad1 100644 --- a/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch +++ b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch @@ -31,17 +31,18 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile -@@ -17,6 +17,7 @@ spi-nor-objs += sst.o +@@ -17,7 +17,8 @@ spi-nor-objs += sst.o spi-nor-objs += winbond.o spi-nor-objs += xilinx.o spi-nor-objs += xmc.o +spi-nor-objs += xtx.o + spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o obj-$(CONFIG_MTD_SPI_NOR) += controllers/ --- /dev/null +++ b/drivers/mtd/spi-nor/xtx.c -@@ -0,0 +1,15 @@ +@@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + @@ -49,7 +50,9 @@ Signed-off-by: Felix Fietkau + +static const struct flash_info xtx_parts[] = { + /* XTX Technology (Shenzhen) Limited */ -+ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, ++ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256) ++ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | ++ SPI_NOR_QUAD_READ) }, +}; + +const struct spi_nor_manufacturer spi_nor_xtx = { diff --git a/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch index c32cde559db..764dfd68cb3 100644 --- a/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch +++ b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch @@ -10,13 +10,14 @@ Signed-off-by: Koen Vandeputte --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c -@@ -24,6 +24,9 @@ static struct spi_nor_fixups gd25q256_fi +@@ -24,6 +24,10 @@ static struct spi_nor_fixups gd25q256_fi }; - static const struct flash_info gigadevice_parts[] = { -+ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | -+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, - { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | - SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + static const struct flash_info gigadevice_nor_parts[] = { ++ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1) ++ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) ++ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | ++ SPI_NOR_QUAD_READ) }, + { "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32) + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | diff --git a/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch index 7c8b6862777..614263f190b 100644 --- a/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch +++ b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch @@ -9,13 +9,15 @@ Subject: [PATCH] spi-nor/gigadevic: add gd25q512 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c -@@ -53,6 +53,9 @@ static const struct flash_info gigadevic - SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | - SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) +@@ -53,6 +53,11 @@ static const struct flash_info gigadevic + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) + FIXUP_FLAGS(SPI_NOR_4B_OPCODES) .fixups = &gd25q256_fixups }, -+ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | -+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES) }, ++ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024) ++ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) ++ FIXUP_FLAGS(SPI_NOR_4B_OPCODES) ++ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | ++ SPI_NOR_QUAD_READ) }, }; const struct spi_nor_manufacturer spi_nor_gigadevice = { diff --git a/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch index ab402e622a2..d7223ae8c46 100644 --- a/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch +++ b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch @@ -12,12 +12,13 @@ flash. --- a/drivers/mtd/spi-nor/esmt.c +++ b/drivers/mtd/spi-nor/esmt.c -@@ -10,6 +10,8 @@ +@@ -10,6 +10,9 @@ static const struct flash_info esmt_parts[] = { /* ESMT */ -+ { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32, -+ SECT_4K | SPI_NOR_HAS_LOCK) }, - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) }, - { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, ++ { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32) ++ FLAGS(SPI_NOR_HAS_LOCK) ++ NO_SFDP_FLAGS(SECT_4K) }, + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64) + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + NO_SFDP_FLAGS(SECT_4K) }, diff --git a/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch index 68e373ea236..4020a428bee 100644 --- a/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch +++ b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch @@ -13,12 +13,13 @@ Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c -@@ -14,6 +14,8 @@ static const struct flash_info xmc_parts - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, +@@ -14,6 +14,9 @@ static const struct flash_info xmc_parts + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, ++ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256) ++ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | ++ SPI_NOR_QUAD_READ) }, }; const struct spi_nor_manufacturer spi_nor_xmc = { diff --git a/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch index d117cfe0a3a..8191c3c61dc 100644 --- a/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch +++ b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch @@ -26,15 +26,15 @@ Signed-off-by: Chuanhong Guo +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 --spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o -+spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o +-spinand-objs := core.o ato.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o ++spinand-objs := core.o ato.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -906,6 +906,7 @@ static const struct nand_ops spinand_ops - }; +@@ -896,6 +896,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { + &ato_spinand_manufacturer, + &esmt_c8_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, @@ -134,9 +134,9 @@ Signed-off-by: Chuanhong Guo --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -260,6 +260,7 @@ struct spinand_manufacturer { - }; /* SPI NAND manufacturers */ + extern const struct spinand_manufacturer ato_spinand_manufacturer; +extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; extern const struct spinand_manufacturer macronix_spinand_manufacturer; diff --git a/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch index 7e20e14bb62..00c20e37ca6 100644 --- a/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch +++ b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch @@ -42,19 +42,19 @@ Submitted-by: Daniel Danzberger +++ b/drivers/mtd/nand/spi/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 --spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o -+spinand-objs := core.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o +-spinand-objs := core.o ato.o esmt.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o ++spinand-objs := core.o ato.o esmt.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -908,6 +908,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { + &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, - &gigadevice_spinand_manufacturer, + &etron_spinand_manufacturer, + &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, - ¶gon_spinand_manufacturer, --- /dev/null +++ b/drivers/mtd/nand/spi/etron.c @@ -0,0 +1,98 @@ diff --git a/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch index 236d1c2755f..8c73b6031b7 100644 --- a/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch +++ b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch @@ -11,12 +11,13 @@ Signed-off-by: Joe Mullally --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c -@@ -12,6 +12,8 @@ static const struct flash_info xmc_parts - /* XMC (Wuhan Xinxin Semiconductor Manufacturing Corp.) */ - { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -+ { "XM25QH64C", INFO(0x204017, 0, 64 * 1024, 128, -+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256, - SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256, +@@ -12,6 +12,9 @@ static const struct flash_info xmc_parts + { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, ++ { "XM25QH64C", INFO(0x204017, 0, 64 * 1024, 128) ++ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | ++ SPI_NOR_QUAD_READ) }, + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, diff --git a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch index 2751da541a0..aa6700b0171 100644 --- a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch +++ b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -66,7 +66,7 @@ Signed-off-by: Daniel Golle + + mutex_lock(&ubi_devices_mutex); + pr_notice("UBI: auto-attach mtd%d\n", mtd->index); -+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); ++ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0, false); + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + pr_err("UBI error: cannot attach mtd%d\n", mtd->index); diff --git a/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch index 81de7648760..6c480673c69 100644 --- a/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch +++ b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch @@ -23,12 +23,12 @@ Signed-off-by: Nick Hainke --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c @@ -41,7 +41,8 @@ static const struct flash_info macronix_ - { "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) }, - { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) }, - { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, -- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) }, -+ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K | -+ SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) }, - { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) }, - { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, - SECT_4K | SPI_NOR_DUAL_READ | + { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64) + NO_SFDP_FLAGS(SECT_4K) }, + { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128) +- NO_SFDP_FLAGS(SECT_4K) }, ++ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) ++ NO_SFDP_FLAGS(SECT_4K) }, + { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4) + NO_SFDP_FLAGS(SECT_4K) }, + { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64) diff --git a/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch index ac784d0b0bb..fd6ca784c0f 100644 --- a/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch +++ b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch @@ -356,7 +356,7 @@ Signed-off-by: Alexandros C. Couloumbis +#endif --- /dev/null +++ b/include/linux/lzma/LzFind.h -@@ -0,0 +1,98 @@ +@@ -0,0 +1,115 @@ +/* LzFind.h -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + @@ -414,6 +414,11 @@ Signed-off-by: Alexandros C. Couloumbis + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + ++int MatchFinder_NeedMove(CMatchFinder *p); ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); ++void MatchFinder_MoveBlock(CMatchFinder *p); ++void MatchFinder_ReadIfRequired(CMatchFinder *p); ++ +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: @@ -424,6 +429,12 @@ Signed-off-by: Alexandros C. Couloumbis + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, ++ UInt32 *distances, UInt32 maxLen); + +/* +Conditions: @@ -450,6 +461,12 @@ Signed-off-by: Alexandros C. Couloumbis + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + ++void MatchFinder_Init(CMatchFinder *p); ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); ++ +#ifdef __cplusplus +} +#endif @@ -514,7 +531,7 @@ Signed-off-by: Alexandros C. Couloumbis +#endif --- /dev/null +++ b/include/linux/lzma/LzmaDec.h -@@ -0,0 +1,130 @@ +@@ -0,0 +1,231 @@ +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + @@ -548,6 +565,14 @@ Signed-off-by: Alexandros C. Couloumbis + UInt32 dicSize; +} CLzmaProps; + ++/* LzmaProps_Decode - decodes properties ++Returns: ++ SZ_OK ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); ++ + +/* ---------- LZMA Decoder state ---------- */ + @@ -579,6 +604,8 @@ Signed-off-by: Alexandros C. Couloumbis + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + ++void LzmaDec_Init(CLzmaDec *p); ++ +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ @@ -615,6 +642,97 @@ Signed-off-by: Alexandros C. Couloumbis + +/* ELzmaStatus is used only as output value for function call */ + ++ ++/* ---------- Interfaces ---------- */ ++ ++/* There are 3 levels of interfaces: ++ 1) Dictionary Interface ++ 2) Buffer Interface ++ 3) One Call Interface ++ You can select any of these interfaces, but don't mix functions from different ++ groups for same object. */ ++ ++ ++/* There are two variants to allocate state for Dictionary Interface: ++ 1) LzmaDec_Allocate / LzmaDec_Free ++ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs ++ You can use variant 2, if you set dictionary buffer manually. ++ For Buffer Interface you must always use variant 1. ++ ++LzmaDec_Allocate* can return: ++ SZ_OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_UNSUPPORTED - Unsupported properties ++*/ ++ ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); ++ ++SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); ++void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); ++ ++/* ---------- Dictionary Interface ---------- */ ++ ++/* You can use it, if you want to eliminate the overhead for data copying from ++ dictionary to some other external buffer. ++ You must work with CLzmaDec variables directly in this interface. ++ ++ STEPS: ++ LzmaDec_Constr() ++ LzmaDec_Allocate() ++ for (each new stream) ++ { ++ LzmaDec_Init() ++ while (it needs more decompression) ++ { ++ LzmaDec_DecodeToDic() ++ use data from CLzmaDec::dic and update CLzmaDec::dicPos ++ } ++ } ++ LzmaDec_Free() ++*/ ++ ++/* LzmaDec_DecodeToDic ++ ++ The decoding to internal dictionary buffer (CLzmaDec::dic). ++ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (dicLimit). ++ LZMA_FINISH_ANY - Decode just dicLimit bytes. ++ LZMA_FINISH_END - Stream must be finished after dicLimit. ++ ++Returns: ++ SZ_OK ++ status: ++ LZMA_STATUS_FINISHED_WITH_MARK ++ LZMA_STATUS_NOT_FINISHED ++ LZMA_STATUS_NEEDS_MORE_INPUT ++ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK ++ SZ_ERROR_DATA - Data error ++*/ ++ ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ ++/* ---------- Buffer Interface ---------- */ ++ ++/* It's zlib-like interface. ++ See LzmaDec_DecodeToDic description for information about STEPS and return results, ++ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need ++ to work with CLzmaDec variables manually. ++ ++finishMode: ++ It has meaning only if the decoding reaches output limit (*destLen). ++ LZMA_FINISH_ANY - Decode just destLen bytes. ++ LZMA_FINISH_END - Stream must be finished after (*destLen). ++*/ ++ ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, ++ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); ++ ++ +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode @@ -647,7 +765,7 @@ Signed-off-by: Alexandros C. Couloumbis +#endif --- /dev/null +++ b/include/linux/lzma/LzmaEnc.h -@@ -0,0 +1,60 @@ +@@ -0,0 +1,80 @@ +/* LzmaEnc.h -- LZMA Encoder +2009-02-07 : Igor Pavlov : Public domain */ + @@ -681,6 +799,9 @@ Signed-off-by: Alexandros C. Couloumbis +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); ++void LzmaEncProps_Normalize(CLzmaEncProps *p); ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); ++ + +/* ---------- CLzmaEncHandle Interface ---------- */ + @@ -700,9 +821,26 @@ Signed-off-by: Alexandros C. Couloumbis +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); ++SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + ++/* ---------- One Call Interface ---------- */ ++ ++/* LzmaEncode ++Return code: ++ SZ_OK - OK ++ SZ_ERROR_MEM - Memory allocation error ++ SZ_ERROR_PARAM - Incorrect paramater ++ SZ_ERROR_OUTPUT_EOF - output buffer overflow ++ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) ++*/ ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); ++ +#ifdef __cplusplus +} +#endif @@ -992,7 +1130,7 @@ Signed-off-by: Alexandros C. Couloumbis lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o --- /dev/null +++ b/lib/lzma/LzFind.c -@@ -0,0 +1,522 @@ +@@ -0,0 +1,761 @@ +/* LzFind.c -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + @@ -1009,15 +1147,9 @@ Signed-off-by: Alexandros C. Couloumbis + +#define kStartMaxLen 3 + -+#if 0 -+#define DIRECT_INPUT p->directInput -+#else -+#define DIRECT_INPUT 1 -+#endif -+ +static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) +{ -+ if (!DIRECT_INPUT) ++ if (!p->directInput) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; @@ -1029,7 +1161,7 @@ Signed-off-by: Alexandros C. Couloumbis +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; -+ if (DIRECT_INPUT) ++ if (p->directInput) + { + p->blockSize = blockSize; + return 1; @@ -1043,12 +1175,12 @@ Signed-off-by: Alexandros C. Couloumbis + return (p->bufferBase != 0); +} + -+static Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } -+static Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } ++Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } ++Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + -+static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } ++UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + -+static void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) ++void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; @@ -1059,7 +1191,7 @@ Signed-off-by: Alexandros C. Couloumbis +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; -+ if (DIRECT_INPUT) ++ if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) @@ -1090,7 +1222,7 @@ Signed-off-by: Alexandros C. Couloumbis + } +} + -+static void MatchFinder_MoveBlock(CMatchFinder *p) ++void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, @@ -1098,14 +1230,22 @@ Signed-off-by: Alexandros C. Couloumbis + p->buffer = p->bufferBase + p->keepSizeBefore; +} + -+static int MatchFinder_NeedMove(CMatchFinder *p) ++int MatchFinder_NeedMove(CMatchFinder *p) +{ -+ if (DIRECT_INPUT) ++ if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + ++void MatchFinder_ReadIfRequired(CMatchFinder *p) ++{ ++ if (p->streamEndWasReached) ++ return; ++ if (p->keepSizeAfter >= p->streamPos - p->pos) ++ MatchFinder_ReadBlock(p); ++} ++ +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) @@ -1261,7 +1401,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->posLimit = p->pos + limit; +} + -+static void MatchFinder_Init(CMatchFinder *p) ++void MatchFinder_Init(CMatchFinder *p) +{ + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) @@ -1280,7 +1420,7 @@ Signed-off-by: Alexandros C. Couloumbis + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + -+static void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) ++void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +{ + UInt32 i; + for (i = 0; i < numItems; i++) @@ -1312,7 +1452,38 @@ Signed-off-by: Alexandros C. Couloumbis + MatchFinder_SetLimits(p); +} + -+static UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, ++ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, ++ UInt32 *distances, UInt32 maxLen) ++{ ++ son[_cyclicBufferPos] = curMatch; ++ for (;;) ++ { ++ UInt32 delta = pos - curMatch; ++ if (cutValue-- == 0 || delta >= _cyclicBufferSize) ++ return distances; ++ { ++ const Byte *pb = cur - delta; ++ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; ++ if (pb[maxLen] == cur[maxLen] && *pb == *cur) ++ { ++ UInt32 len = 0; ++ while (++len != lenLimit) ++ if (pb[len] != cur[len]) ++ break; ++ if (maxLen < len) ++ { ++ *distances++ = maxLen = len; ++ *distances++ = delta - 1; ++ if (len == lenLimit) ++ return distances; ++ } ++ } ++ } ++ } ++} ++ ++UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ @@ -1422,9 +1593,9 @@ Signed-off-by: Alexandros C. Couloumbis + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + -+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } ++#define MOVE_POS_RET MOVE_POS return offset; + -+#define MOVE_POS_RET MatchFinder_MovePos(p); return offset; ++static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ @@ -1441,7 +1612,62 @@ Signed-off-by: Alexandros C. Couloumbis + distances + offset, maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ -+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MatchFinder_MovePos(p); ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; ++ ++static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 1) ++} ++ ++UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = 0; ++ GET_MATCHES_FOOTER(offset, 2) ++} ++ ++static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, delta2, maxLen, offset; ++ GET_MATCHES_HEADER(3) ++ ++ HASH3_CALC; ++ ++ delta2 = p->pos - p->hash[hash2Value]; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ ++ ++ maxLen = 2; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[0] = maxLen; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ if (maxLen == lenLimit) ++ { ++ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); ++ MOVE_POS_RET; ++ } ++ } ++ GET_MATCHES_FOOTER(offset, maxLen) ++} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ @@ -1490,6 +1716,108 @@ Signed-off-by: Alexandros C. Couloumbis + GET_MATCHES_FOOTER(offset, maxLen) +} + ++static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; ++ GET_MATCHES_HEADER(4) ++ ++ HASH4_CALC; ++ ++ delta2 = p->pos - p->hash[ hash2Value]; ++ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ ++ maxLen = 1; ++ offset = 0; ++ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) ++ { ++ distances[0] = maxLen = 2; ++ distances[1] = delta2 - 1; ++ offset = 2; ++ } ++ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) ++ { ++ maxLen = 3; ++ distances[offset + 1] = delta3 - 1; ++ offset += 2; ++ delta2 = delta3; ++ } ++ if (offset != 0) ++ { ++ for (; maxLen != lenLimit; maxLen++) ++ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) ++ break; ++ distances[offset - 2] = maxLen; ++ if (maxLen == lenLimit) ++ { ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS_RET; ++ } ++ } ++ if (maxLen < 3) ++ maxLen = 3; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances + offset, maxLen) - (distances)); ++ MOVE_POS_RET ++} ++ ++UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) ++{ ++ UInt32 offset; ++ GET_MATCHES_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), ++ distances, 2) - (distances)); ++ MOVE_POS_RET ++} ++ ++static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(2) ++ HASH2_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ ++static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value; ++ SKIP_HEADER(3) ++ HASH3_CALC; ++ curMatch = p->hash[kFix3HashSize + hashValue]; ++ p->hash[hash2Value] = ++ p->hash[kFix3HashSize + hashValue] = p->pos; ++ SKIP_FOOTER ++ } ++ while (--num != 0); ++} ++ +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do @@ -1506,18 +1834,67 @@ Signed-off-by: Alexandros C. Couloumbis + while (--num != 0); +} + ++static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ UInt32 hash2Value, hash3Value; ++ SKIP_HEADER(4) ++ HASH4_CALC; ++ curMatch = p->hash[kFix4HashSize + hashValue]; ++ p->hash[ hash2Value] = ++ p->hash[kFix3HashSize + hash3Value] = ++ p->hash[kFix4HashSize + hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ ++void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) ++{ ++ do ++ { ++ SKIP_HEADER(3) ++ HASH_ZIP_CALC; ++ curMatch = p->hash[hashValue]; ++ p->hash[hashValue] = p->pos; ++ p->son[p->cyclicBufferPos] = curMatch; ++ MOVE_POS ++ } ++ while (--num != 0); ++} ++ +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; -+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; -+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ if (!p->btMode) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 2) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; ++ } ++ else if (p->numHashBytes == 3) ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; ++ } ++ else ++ { ++ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; ++ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; ++ } +} --- /dev/null +++ b/lib/lzma/LzmaDec.c -@@ -0,0 +1,925 @@ +@@ -0,0 +1,999 @@ +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + @@ -2202,7 +2579,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->needFlush = 0; +} + -+static void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) ++void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; @@ -2218,7 +2595,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->needInitState = 1; +} + -+static void LzmaDec_Init(CLzmaDec *p) ++void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); @@ -2236,7 +2613,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->needInitState = 0; +} + -+static SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ++SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; @@ -2357,13 +2734,65 @@ Signed-off-by: Alexandros C. Couloumbis + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + -+static void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) ++SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) ++{ ++ SizeT outSize = *destLen; ++ SizeT inSize = *srcLen; ++ *srcLen = *destLen = 0; ++ for (;;) ++ { ++ SizeT inSizeCur = inSize, outSizeCur, dicPos; ++ ELzmaFinishMode curFinishMode; ++ SRes res; ++ if (p->dicPos == p->dicBufSize) ++ p->dicPos = 0; ++ dicPos = p->dicPos; ++ if (outSize > p->dicBufSize - dicPos) ++ { ++ outSizeCur = p->dicBufSize; ++ curFinishMode = LZMA_FINISH_ANY; ++ } ++ else ++ { ++ outSizeCur = dicPos + outSize; ++ curFinishMode = finishMode; ++ } ++ ++ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); ++ src += inSizeCur; ++ inSize -= inSizeCur; ++ *srcLen += inSizeCur; ++ outSizeCur = p->dicPos - dicPos; ++ memcpy(dest, p->dic + dicPos, outSizeCur); ++ dest += outSizeCur; ++ outSize -= outSizeCur; ++ *destLen += outSizeCur; ++ if (res != 0) ++ return res; ++ if (outSizeCur == 0 || outSize == 0) ++ return SZ_OK; ++ } ++} ++ ++void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + -+static SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) ++static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ alloc->Free(alloc, p->dic); ++ p->dic = 0; ++} ++ ++void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) ++{ ++ LzmaDec_FreeProbs(p, alloc); ++ LzmaDec_FreeDict(p, alloc); ++} ++ ++SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; @@ -2403,7 +2832,7 @@ Signed-off-by: Alexandros C. Couloumbis + return SZ_OK; +} + -+static SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); @@ -2412,6 +2841,28 @@ Signed-off-by: Alexandros C. Couloumbis + return SZ_OK; +} + ++SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) ++{ ++ CLzmaProps propNew; ++ SizeT dicBufSize; ++ RINOK(LzmaProps_Decode(&propNew, props, propsSize)); ++ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); ++ dicBufSize = propNew.dicSize; ++ if (p->dic == 0 || dicBufSize != p->dicBufSize) ++ { ++ LzmaDec_FreeDict(p, alloc); ++ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); ++ if (p->dic == 0) ++ { ++ LzmaDec_FreeProbs(p, alloc); ++ return SZ_ERROR_MEM; ++ } ++ } ++ p->dicBufSize = dicBufSize; ++ p->prop = propNew; ++ return SZ_OK; ++} ++ +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) @@ -2445,7 +2896,7 @@ Signed-off-by: Alexandros C. Couloumbis +} --- /dev/null +++ b/lib/lzma/LzmaEnc.c -@@ -0,0 +1,2123 @@ +@@ -0,0 +1,2271 @@ +/* LzmaEnc.c -- LZMA Encoder +2009-11-24 : Igor Pavlov : Public domain */ + @@ -2501,7 +2952,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->writeEndMark = 0; +} + -+static void LzmaEncProps_Normalize(CLzmaEncProps *p) ++void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; @@ -2524,7 +2975,7 @@ Signed-off-by: Alexandros C. Couloumbis + #endif +} + -+static UInt32 __maybe_unused LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) ++UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); @@ -2541,7 +2992,7 @@ Signed-off-by: Alexandros C. Couloumbis + +#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + -+static UInt32 GetPosSlot1(UInt32 pos) ++UInt32 GetPosSlot1(UInt32 pos) +{ + UInt32 res; + BSR2_RET(pos, res); @@ -2555,7 +3006,7 @@ Signed-off-by: Alexandros C. Couloumbis +#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + -+static void LzmaEnc_FastPosInit(Byte *g_FastPos) ++void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + int c = 2, slotFast; + g_FastPos[0] = 0; @@ -2787,6 +3238,58 @@ Signed-off-by: Alexandros C. Couloumbis + CSaveState saveState; +} CLzmaEnc; + ++void LzmaEnc_SaveState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ CSaveState *dest = &p->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); ++} ++ ++void LzmaEnc_RestoreState(CLzmaEncHandle pp) ++{ ++ CLzmaEnc *dest = (CLzmaEnc *)pp; ++ const CSaveState *p = &dest->saveState; ++ int i; ++ dest->lenEnc = p->lenEnc; ++ dest->repLenEnc = p->repLenEnc; ++ dest->state = p->state; ++ ++ for (i = 0; i < kNumStates; i++) ++ { ++ memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); ++ memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); ++ } ++ for (i = 0; i < kNumLenToPosStates; i++) ++ memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); ++ memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); ++ memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); ++ memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); ++ memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); ++ memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); ++ memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); ++ memcpy(dest->reps, p->reps, sizeof(p->reps)); ++ memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); ++} ++ +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; @@ -2996,7 +3499,7 @@ Signed-off-by: Alexandros C. Couloumbis + while (symbol < 0x10000); +} + -+static void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) ++void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +{ + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) @@ -4072,7 +4575,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->matchPriceCount = 0; +} + -+static void LzmaEnc_Construct(CLzmaEnc *p) ++void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); @@ -4105,7 +4608,7 @@ Signed-off-by: Alexandros C. Couloumbis + return p; +} + -+static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) ++void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); @@ -4113,7 +4616,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->saveState.litProbs = 0; +} + -+static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) ++void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); @@ -4343,7 +4846,7 @@ Signed-off-by: Alexandros C. Couloumbis + return SZ_OK; +} + -+static void LzmaEnc_Init(CLzmaEnc *p) ++void LzmaEnc_Init(CLzmaEnc *p) +{ + UInt32 i; + p->state = 0; @@ -4401,7 +4904,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->lpMask = (1 << p->lp) - 1; +} + -+static void LzmaEnc_InitPrices(CLzmaEnc *p) ++void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { @@ -4433,6 +4936,26 @@ Signed-off-by: Alexandros C. Couloumbis + return SZ_OK; +} + ++static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ p->rc.outStream = outStream; ++ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); ++} ++ ++SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ++ ISeqInStream *inStream, UInt32 keepWindowSize, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ p->matchFinderBase.stream = inStream; ++ p->needInit = 1; ++ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); ++} ++ +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; @@ -4440,7 +4963,7 @@ Signed-off-by: Alexandros C. Couloumbis + p->matchFinderBase.directInputRem = srcLen; +} + -+static SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, ++SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; @@ -4450,7 +4973,7 @@ Signed-off-by: Alexandros C. Couloumbis + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + -+static void LzmaEnc_Finish(CLzmaEncHandle pp) ++void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; @@ -4483,6 +5006,53 @@ Signed-off-by: Alexandros C. Couloumbis + return size; +} + ++ ++UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); ++} ++ ++const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) ++{ ++ const CLzmaEnc *p = (CLzmaEnc *)pp; ++ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; ++} ++ ++SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, ++ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)pp; ++ UInt64 nowPos64; ++ SRes res; ++ CSeqOutStreamBuf outStream; ++ ++ outStream.funcTable.Write = MyWrite; ++ outStream.data = dest; ++ outStream.rem = *destLen; ++ outStream.overflow = False; ++ ++ p->writeEndMark = False; ++ p->finished = False; ++ p->result = SZ_OK; ++ ++ if (reInit) ++ LzmaEnc_Init(p); ++ LzmaEnc_InitPrices(p); ++ nowPos64 = p->nowPos64; ++ RangeEnc_Init(&p->rc); ++ p->rc.outStream = &outStream.funcTable; ++ ++ res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); ++ ++ *unpackSize = (UInt32)(p->nowPos64 - nowPos64); ++ *destLen -= outStream.rem; ++ if (outStream.overflow) ++ return SZ_ERROR_OUTPUT_EOF; ++ ++ return res; ++} ++ +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; @@ -4513,6 +5083,13 @@ Signed-off-by: Alexandros C. Couloumbis + return res; +} + ++SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ++ ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); ++ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); ++} ++ +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; @@ -4569,6 +5146,28 @@ Signed-off-by: Alexandros C. Couloumbis + return SZ_ERROR_OUTPUT_EOF; + return res; +} ++ ++SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, ++ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ++ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) ++{ ++ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); ++ SRes res; ++ if (p == 0) ++ return SZ_ERROR_MEM; ++ ++ res = LzmaEnc_SetProps(p, props); ++ if (res == SZ_OK) ++ { ++ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); ++ if (res == SZ_OK) ++ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, ++ writeEndMark, progress, alloc, allocBig); ++ } ++ ++ LzmaEnc_Destroy(p, alloc, allocBig); ++ return res; ++} --- /dev/null +++ b/lib/lzma/Makefile @@ -0,0 +1,7 @@ diff --git a/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch index a88e3d7d9a7..d8531ed740a 100644 --- a/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch +++ b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau #include #ifdef CONFIG_SYSCTL #include -@@ -462,6 +463,56 @@ static int ct_cpu_seq_show(struct seq_fi +@@ -462,6 +463,58 @@ static int ct_cpu_seq_show(struct seq_fi return 0; } @@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau +static int ct_file_write(struct file *file, char *buf, size_t count) +{ + struct seq_file *seq = file->private_data; -+ struct net *net = seq_file_net(seq); ++ struct nf_ct_iter_data iter_data; + struct kill_request kr = { }; + + if (count == 0) @@ -66,7 +66,9 @@ Signed-off-by: Felix Fietkau + return -EINVAL; + } + -+ nf_ct_iterate_cleanup_net(net, kill_matching, &kr, 0, 0); ++ iter_data.net = seq_file_net(seq); ++ iter_data.data = &kr; ++ nf_ct_iterate_cleanup_net(kill_matching, &iter_data); + + return 0; +} diff --git a/target/linux/generic/pending-6.1/655-increase_skb_pad.patch b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch index 5d100270a90..f89ee0b8d20 100644 --- a/target/linux/generic/pending-6.1/655-increase_skb_pad.patch +++ b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2821,7 +2821,7 @@ static inline int pskb_network_may_pull( +@@ -2782,7 +2782,7 @@ static inline int pskb_network_may_pull( * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) */ #ifndef NET_SKB_PAD diff --git a/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index 091e65f31e0..e61f59f7561 100644 --- a/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2098,6 +2098,8 @@ struct net_device { +@@ -2075,6 +2075,8 @@ struct net_device { struct netdev_hw_addr_list mc; struct netdev_hw_addr_list dev_addrs; @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau #endif --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -893,6 +893,7 @@ struct sk_buff { +@@ -890,6 +890,7 @@ struct sk_buff { #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif @@ -30,9 +30,9 @@ Signed-off-by: Felix Fietkau __u8 ipvs_property:1; __u8 inner_protocol_type:1; ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -6065,6 +6065,9 @@ static enum gro_result dev_gro_receive(s +--- a/net/core/gro.c ++++ b/net/core/gro.c +@@ -6062,6 +6062,9 @@ static enum gro_result dev_gro_receive(s int same_flow; int grow; @@ -42,7 +42,9 @@ Signed-off-by: Felix Fietkau if (netif_elide_gro(skb->dev)) goto normal; -@@ -8079,6 +8082,48 @@ static void __netdev_adjacent_dev_unlink +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -8076,6 +8079,48 @@ static void __netdev_adjacent_dev_unlink &upper_dev->adj_list.lower); } @@ -91,7 +93,7 @@ Signed-off-by: Felix Fietkau static int __netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev, bool master, void *upper_priv, void *upper_info, -@@ -8130,6 +8175,7 @@ static int __netdev_upper_dev_link(struc +@@ -8127,6 +8172,7 @@ static int __netdev_upper_dev_link(struc if (ret) return ret; @@ -99,7 +101,7 @@ Signed-off-by: Felix Fietkau ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, &changeupper_info.info); ret = notifier_to_errno(ret); -@@ -8226,6 +8272,7 @@ static void __netdev_upper_dev_unlink(st +@@ -8223,6 +8269,7 @@ static void __netdev_upper_dev_unlink(st __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); @@ -107,7 +109,7 @@ Signed-off-by: Felix Fietkau call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, &changeupper_info.info); -@@ -9045,6 +9092,7 @@ int dev_set_mac_address(struct net_devic +@@ -9042,6 +9089,7 @@ int dev_set_mac_address(struct net_devic if (err) return err; dev->addr_assign_type = NET_ADDR_SET; diff --git a/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch index 488c6a8d92c..3de0201f955 100644 --- a/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch +++ b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch @@ -10,9 +10,9 @@ Signed-off-by: Pablo Neira Ayuso --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c -@@ -613,13 +613,41 @@ void nf_flow_table_free(struct nf_flowta - } - EXPORT_SYMBOL_GPL(nf_flow_table_free); +@@ -608,28 +608,52 @@ void nf_flow_table_free(struct nf_flowta + .exit_batch = nf_flow_table_pernet_exit, + }; +static int nf_flow_table_netdev_event(struct notifier_block *this, + unsigned long event, void *ptr) @@ -33,24 +33,34 @@ Signed-off-by: Pablo Neira Ayuso + static int __init nf_flow_table_module_init(void) { -- return nf_flow_table_offload_init(); -+ int ret; -+ -+ ret = nf_flow_table_offload_init(); -+ if (ret) -+ return ret; + int ret; + + ret = register_pernet_subsys(&nf_flow_table_net_ops); + if (ret < 0) + return ret; + + ret = nf_flow_table_offload_init(); + if (ret) + goto out_offload; + + ret = register_netdevice_notifier(&flow_offload_netdev_notifier); + if (ret) -+ nf_flow_table_offload_exit(); -+ -+ return ret; ++ goto out_offload_init; + + return 0; + ++out_offload_init: ++ nf_flow_table_offload_exit(); + out_offload: + unregister_pernet_subsys(&nf_flow_table_net_ops); + return ret; } static void __exit nf_flow_table_module_exit(void) { + unregister_netdevice_notifier(&flow_offload_netdev_notifier); nf_flow_table_offload_exit(); + unregister_pernet_subsys(&nf_flow_table_net_ops); } --- a/net/netfilter/nft_flow_offload.c diff --git a/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index a4e3d265033..649b3010538 100644 --- a/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2992,8 +2992,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -2443,8 +2443,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -3005,8 +3005,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -2456,8 +2456,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,12 +30,12 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -4673,6 +4673,8 @@ static int mtk_probe(struct platform_dev +@@ -3623,6 +3623,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); + eth->dummy_dev.threaded = 1; + strcpy(eth->dummy_dev.name, "mtk_eth"); - netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx, - NAPI_POLL_WEIGHT); - netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx, + netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx); + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx); + diff --git a/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch index 5baccf73cb8..21c322b4f11 100644 --- a/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch +++ b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c -@@ -1748,6 +1748,9 @@ void phy_detach(struct phy_device *phyde +@@ -1738,6 +1738,9 @@ void phy_detach(struct phy_device *phyde struct module *ndev_owner = NULL; struct mii_bus *bus; @@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos sysfs_remove_link(&dev->dev.kobj, "phydev"); --- a/include/linux/phy.h +++ b/include/linux/phy.h -@@ -823,6 +823,12 @@ struct phy_driver { +@@ -789,6 +789,12 @@ struct phy_driver { /** @handle_interrupt: Override default interrupt handling */ irqreturn_t (*handle_interrupt)(struct phy_device *phydev); diff --git a/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch index 2a2ca7f1fae..3aa88066b50 100644 --- a/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch +++ b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch @@ -15,10 +15,10 @@ Signed-off-by: Felix Fietkau --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -58,6 +58,7 @@ struct br_ip_list { - #define BR_MRP_LOST_CONT BIT(18) #define BR_MRP_LOST_IN_CONT BIT(19) #define BR_TX_FWD_OFFLOAD BIT(20) -+#define BR_BPDU_FILTER BIT(21) + #define BR_PORT_LOCKED BIT(21) ++#define BR_BPDU_FILTER BIT(22) #define BR_DEFAULT_AGEING_TIME (300 * HZ) @@ -107,9 +107,9 @@ Signed-off-by: Felix Fietkau --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -536,6 +536,7 @@ enum { - IFLA_BRPORT_MRP_IN_OPEN, IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, + IFLA_BRPORT_LOCKED, + IFLA_BRPORT_BPDU_FILTER, __IFLA_BRPORT_MAX }; @@ -117,19 +117,19 @@ Signed-off-by: Felix Fietkau --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -184,6 +184,7 @@ static inline size_t br_port_info_size(v - + nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */ + nla_total_size(1) /* IFLA_BRPORT_NEIGH_SUPPRESS */ + nla_total_size(1) /* IFLA_BRPORT_ISOLATED */ + + nla_total_size(1) /* IFLA_BRPORT_LOCKED */ + + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */ + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ @@ -269,7 +270,8 @@ static int br_port_fill_attrs(struct sk_ - BR_MRP_LOST_CONT)) || nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, !!(p->flags & BR_MRP_LOST_IN_CONT)) || -- nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) -+ nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || + nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || +- nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED))) ++ nla_put_u8(skb, IFLA_BRPORT_LOCKED, !!(p->flags & BR_PORT_LOCKED)) || + nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER))) return -EMSGSIZE; @@ -143,9 +143,9 @@ Signed-off-by: Felix Fietkau /* Change the state of the port and notify spanning tree */ @@ -893,6 +896,7 @@ static int br_setport(struct net_bridge_ - br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS); br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); + br_set_port_flag(p, tb, IFLA_BRPORT_LOCKED, BR_PORT_LOCKED); + br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER); changed_mask = old_flags ^ p->flags; @@ -153,7 +153,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -55,7 +55,7 @@ - #include + #include "dev.h" #define RTNL_MAX_TYPE 50 -#define RTNL_SLAVE_MAX_TYPE 40 diff --git a/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index 60c32b67057..2071bb0f947 100644 --- a/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -167,9 +167,9 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov { ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); @@ -464,6 +506,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); + mtk_ppe_cache_clear(ppe); + if (ppe->accounting) { + struct mtk_foe_accounting *acct; + @@ -335,10 +335,10 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov -struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, - int version, int index); +struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index); + void mtk_ppe_deinit(struct mtk_eth *eth); void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); - int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); -@@ -358,5 +376,7 @@ int mtk_foe_entry_commit(struct mtk_ppe +@@ -354,5 +373,7 @@ int mtk_foe_entry_commit(struct mtk_ppe void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); diff --git a/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch index fdc3d520c11..26b33351197 100644 --- a/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch +++ b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch @@ -78,9 +78,9 @@ Signed-off-by: Felix Fietkau static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) @@ -508,13 +523,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - hwe->ib1 &= ~MTK_FOE_IB1_STATE; hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); + mtk_ppe_cache_clear(ppe); - if (ppe->accounting) { - struct mtk_foe_accounting *acct; - diff --git a/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch index fc83416b2a9..8dace90b966 100644 --- a/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch +++ b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch @@ -31,9 +31,9 @@ Signed-off-by: Felix Fietkau --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4574,7 +4574,7 @@ static int rps_ipi_queued(struct softnet - #ifdef CONFIG_RPS struct softnet_data *mysd = this_cpu_ptr(&softnet_data); + #ifdef CONFIG_RPS - if (sd != mysd) { + if (sd != mysd && !test_bit(NAPI_STATE_THREADED, &sd->backlog.state)) { sd->rps_ipi_next = mysd->rps_ipi_list; @@ -48,7 +48,7 @@ Signed-off-by: Felix Fietkau struct sk_buff *skb, *tmp; struct softnet_data *sd; -@@ -5770,9 +5772,18 @@ static void flush_backlog(struct work_st +@@ -5770,8 +5772,17 @@ static void flush_backlog(struct work_st input_queue_head_incr(sd); } } @@ -58,8 +58,7 @@ Signed-off-by: Felix Fietkau + !skb_queue_empty_lockless(&sd->process_queue); + if (flush_processq) + process_queue_empty = sd->process_queue_empty; - rps_unlock(sd); - local_irq_enable(); + rps_unlock_irq_enable(sd); + if (threaded) + goto out; @@ -67,7 +66,7 @@ Signed-off-by: Felix Fietkau skb_queue_walk_safe(&sd->process_queue, skb, tmp) { if (skb->dev->reg_state == NETREG_UNREGISTERING) { __skb_unlink(skb, &sd->process_queue); -@@ -5780,7 +5791,18 @@ static void flush_backlog(struct work_st +@@ -5780,7 +5791,16 @@ static void flush_backlog(struct work_st input_queue_head_incr(sd); } } @@ -77,19 +76,17 @@ Signed-off-by: Felix Fietkau + + while (flush_processq) { + msleep(1); -+ local_irq_disable(); -+ rps_lock(sd); ++ rps_lock_irq_disable(sd); + flush_processq = process_queue_empty == sd->process_queue_empty; -+ rps_unlock(sd); -+ local_irq_enable(); ++ rps_unlock_irq_enable(sd); + } } static bool flush_required(int cpu) @@ -6463,6 +6485,7 @@ static int process_backlog(struct napi_s - - local_irq_disable(); - rps_lock(sd); + } + + rps_lock_irq_disable(sd); + sd->process_queue_empty++; if (skb_queue_empty(&sd->input_pkt_queue)) { /* @@ -104,7 +101,7 @@ Signed-off-by: Felix Fietkau again = false; } else { skb_queue_splice_tail_init(&sd->input_pkt_queue, -@@ -6889,6 +6913,57 @@ int dev_set_threaded(struct net_device * +@@ -6889,6 +6913,55 @@ int dev_set_threaded(struct net_device * } EXPORT_SYMBOL(dev_set_threaded); @@ -146,20 +143,18 @@ Signed-off-by: Felix Fietkau + struct napi_struct *n = &sd->backlog; + unsigned long flags; + -+ local_irq_save(flags); -+ rps_lock(sd); ++ rps_lock_irqsave(sd, &flags); + if (threaded) + n->state |= NAPIF_STATE_THREADED; + else + n->state &= ~NAPIF_STATE_THREADED; -+ rps_unlock(sd); -+ local_irq_restore(flags); ++ rps_unlock_irq_restore(sd, &flags); + } + + return err; +} + - void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, int (*poll)(struct napi_struct *, int), int weight) { @@ -11367,6 +11442,9 @@ static int dev_cpu_dead(unsigned int old @@ -187,8 +182,8 @@ Signed-off-by: Felix Fietkau static int min_rcvbuf = SOCK_MIN_RCVBUF; static int max_skb_frags = MAX_SKB_FRAGS; +static int backlog_threaded; - static long long_one __maybe_unused = 1; - static long long_max __maybe_unused = LONG_MAX; + + static int net_msg_warn; /* Unused, but still a sysctl */ @@ -114,6 +115,23 @@ static int rps_sock_flow_sysctl(struct c } diff --git a/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch index b498d9f700a..67406bac84c 100644 --- a/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch +++ b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch @@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau #endif /* __LINUX_USB_PCI_QUIRKS_H */ --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h -@@ -498,7 +498,14 @@ extern int usb_hcd_pci_probe(struct pci_ +@@ -497,7 +497,14 @@ extern int usb_hcd_pci_probe(struct pci_ extern void usb_hcd_pci_remove(struct pci_dev *dev); extern void usb_hcd_pci_shutdown(struct pci_dev *dev); diff --git a/target/linux/generic/pending-6.1/834-ledtrig-libata.patch b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch index 9c85862a4bd..9654f4429a8 100644 --- a/target/linux/generic/pending-6.1/834-ledtrig-libata.patch +++ b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch @@ -65,7 +65,7 @@ Signed-off-by: Daniel Golle /** * ata_build_rw_tf - Build ATA taskfile for given read/write request * @tf: Target ATA taskfile -@@ -4580,6 +4593,9 @@ struct ata_queued_cmd *ata_qc_new_init(s +@@ -4576,6 +4589,9 @@ struct ata_queued_cmd *ata_qc_new_init(s if (tag < 0) return NULL; } @@ -75,7 +75,7 @@ Signed-off-by: Daniel Golle qc = __ata_qc_from_tag(ap, tag); qc->tag = qc->hw_tag = tag; -@@ -5358,6 +5374,9 @@ struct ata_port *ata_port_alloc(struct a +@@ -5354,6 +5370,9 @@ struct ata_port *ata_port_alloc(struct a ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; #endif @@ -85,7 +85,7 @@ Signed-off-by: Daniel Golle ata_sff_port_init(ap); return ap; -@@ -5393,6 +5412,12 @@ static void ata_host_release(struct kref +@@ -5389,6 +5408,12 @@ static void ata_host_release(struct kref kfree(ap->pmp_link); kfree(ap->slave_link); @@ -98,7 +98,7 @@ Signed-off-by: Daniel Golle kfree(ap); host->ports[i] = NULL; } -@@ -5799,7 +5824,23 @@ int ata_host_register(struct ata_host *h +@@ -5795,7 +5820,23 @@ int ata_host_register(struct ata_host *h host->ports[i]->print_id = atomic_inc_return(&ata_print_id); host->ports[i]->local_port_no = i + 1; } diff --git a/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch index e180a385e11..de28ebe73aa 100644 --- a/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch +++ b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch @@ -33,7 +33,7 @@ Signed-off-by: Marek Behún --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c -@@ -275,7 +275,6 @@ struct advk_pcie { +@@ -274,7 +274,6 @@ struct advk_pcie { u8 wins_count; struct irq_domain *rp_irq_domain; struct irq_domain *irq_domain; @@ -41,7 +41,7 @@ Signed-off-by: Marek Behún raw_spinlock_t irq_lock; struct irq_domain *msi_domain; struct irq_domain *msi_inner_domain; -@@ -1345,14 +1344,19 @@ static void advk_pcie_irq_unmask(struct +@@ -1330,14 +1329,19 @@ static void advk_pcie_irq_unmask(struct raw_spin_unlock_irqrestore(&pcie->irq_lock, flags); } @@ -63,7 +63,7 @@ Signed-off-by: Marek Behún irq_set_chip_data(virq, pcie); return 0; -@@ -1411,7 +1415,6 @@ static int advk_pcie_init_irq_domain(str +@@ -1396,7 +1400,6 @@ static int advk_pcie_init_irq_domain(str struct device *dev = &pcie->pdev->dev; struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; @@ -71,7 +71,7 @@ Signed-off-by: Marek Behún int ret = 0; raw_spin_lock_init(&pcie->irq_lock); -@@ -1422,28 +1425,14 @@ static int advk_pcie_init_irq_domain(str +@@ -1407,28 +1410,14 @@ static int advk_pcie_init_irq_domain(str return -ENODEV; } diff --git a/target/linux/generic/pending-6.1/920-mangle_bootargs.patch b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch index 5f0a106ae4e..23784616624 100644 --- a/target/linux/generic/pending-6.1/920-mangle_bootargs.patch +++ b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch @@ -31,7 +31,7 @@ Signed-off-by: Imre Kaloz help --- a/init/main.c +++ b/init/main.c -@@ -616,6 +616,29 @@ static inline void setup_nr_cpu_ids(void +@@ -615,6 +615,29 @@ static inline void setup_nr_cpu_ids(void static inline void smp_prepare_cpus(unsigned int maxcpus) { } #endif @@ -61,7 +61,7 @@ Signed-off-by: Imre Kaloz /* * We need to store the untouched command line for future reference. * We also need to store the touched command line since the parameter -@@ -956,6 +979,7 @@ asmlinkage __visible void __init __no_sa +@@ -955,6 +978,7 @@ asmlinkage __visible void __init __no_sa pr_notice("%s", linux_banner); early_security_init(); setup_arch(&command_line); From 92a0cc7c61d0d532449ccda0fbf2dc622ece17c5 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 02:41:47 +0200 Subject: [PATCH 62/88] generic: 6.1: drop pending patch backported as fixes Drop pending patch backported as fixes in later kernel version. Signed-off-by: Christian Marangi --- ..._eth_soc-add-missing-ppe-cache-flush.patch | 21 ----------- ...pool-and-page-referenced-frags-in-GR.patch | 35 ------------------- 2 files changed, 56 deletions(-) delete mode 100644 target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch delete mode 100644 target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch diff --git a/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch b/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch deleted file mode 100644 index 30839319c7d..00000000000 --- a/target/linux/generic/pending-6.1/736-05-net-ethernet-mtk_eth_soc-add-missing-ppe-cache-flush.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Felix Fietkau -Date: Thu, 23 Mar 2023 11:19:14 +0100 -Subject: [PATCH] net: ethernet: mtk_eth_soc: add missing ppe cache flush when - deleting a flow - -The cache needs to be flushed to ensure that the hardware stops offloading -the flow immediately. - -Signed-off-by: Felix Fietkau ---- - ---- a/drivers/net/ethernet/mediatek/mtk_ppe.c -+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -523,6 +523,7 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp - hwe->ib1 &= ~MTK_FOE_IB1_STATE; - hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); - dma_wmb(); -+ mtk_ppe_cache_clear(ppe); - } - entry->hash = 0xffff; - diff --git a/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch b/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch deleted file mode 100644 index 6f28e19a483..00000000000 --- a/target/linux/generic/pending-6.1/750-skb-Do-mix-page-pool-and-page-referenced-frags-in-GR.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Alexander Duyck -Date: Thu, 26 Jan 2023 11:06:59 -0800 -Subject: [PATCH] skb: Do mix page pool and page referenced frags in GRO - -GSO should not merge page pool recycled frames with standard reference -counted frames. Traditionally this didn't occur, at least not often. -However as we start looking at adding support for wireless adapters there -becomes the potential to mix the two due to A-MSDU repartitioning frames in -the receive path. There are possibly other places where this may have -occurred however I suspect they must be few and far between as we have not -seen this issue until now. - -Fixes: 53e0961da1c7 ("page_pool: add frag page recycling support in page pool") -Reported-by: Felix Fietkau -Signed-off-by: Alexander Duyck ---- - ---- a/net/core/skbuff.c -+++ b/net/core/skbuff.c -@@ -4347,6 +4347,15 @@ int skb_gro_receive(struct sk_buff *p, s - if (unlikely(p->len + len >= 65536 || NAPI_GRO_CB(skb)->flush)) - return -E2BIG; - -+ /* Do not splice page pool based packets w/ non-page pool -+ * packets. This can result in reference count issues as page -+ * pool pages will not decrement the reference count and will -+ * instead be immediately returned to the pool or have frag -+ * count decremented. -+ */ -+ if (p->pp_recycle != skb->pp_recycle) -+ return -ETOOMANYREFS; -+ - lp = NAPI_GRO_CB(p)->last; - pinfo = skb_shinfo(lp); - From 19a246bb6503942fe332c1f744d583e38aeca9c0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:43:43 +0200 Subject: [PATCH 63/88] generic: 6.1: manually refresh hack patches Refresh hack patches for kernel 6.1. Signed-off-by: Christian Marangi --- .../generic/hack-6.1/204-module_strip.patch | 60 +++---- .../hack-6.1/212-tools_portability.patch | 56 +++--- .../generic/hack-6.1/221-module_exports.patch | 6 +- .../hack-6.1/230-openwrt_lzma_options.patch | 10 +- .../hack-6.1/250-netfilter_depends.patch | 4 +- .../generic/hack-6.1/259-regmap_dynamic.patch | 2 +- .../321-powerpc_crtsavres_prereq.patch | 2 +- ...rans-call-add-disks-after-mtd-device.patch | 22 ++- .../410-block-fit-partition-parser.patch | 23 --- .../hack-6.1/430-mtk-bmt-support.patch | 8 +- .../generic/hack-6.1/600-bridge_offload.patch | 26 +-- ...-netfilter-add-xt_FLOWOFFLOAD-target.patch | 68 +------ ...-dsa-mv88e6xxx-disable-ATU-violation.patch | 2 +- .../hack-6.1/720-net-phy-add-aqr-phys.patch | 54 ++---- .../721-net-add-packet-mangeling.patch | 35 ++-- ...hy-aquantia-enable-AQR112-and-AQR412.patch | 35 ++-- ...aquantia-fix-system-side-protocol-mi.patch | 2 +- ...y-aquantia-Add-AQR113-driver-support.patch | 33 ++-- ...ntia-add-PHY_IDs-for-AQR112-variants.patch | 35 ++-- .../765-mxl-gpy-control-LED-reg-from-DT.patch | 8 +- .../780-usb-net-MeigLink_modem_support.patch | 6 +- .../790-SFP-GE-T-ignore-TX_FAULT.patch | 24 ++- .../795-backport-phylink_pcs-helpers.patch | 167 ------------------ .../800-GPIO-add-named-gpio-exports.patch | 2 +- .../hack-6.1/901-debloat_sock_diag.patch | 6 +- .../generic/hack-6.1/902-debloat_proc.patch | 2 +- .../hack-6.1/904-debloat_dma_buf.patch | 12 +- .../hack-6.1/920-device_tree_cmdline.patch | 4 +- 28 files changed, 225 insertions(+), 489 deletions(-) delete mode 100644 target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch diff --git a/target/linux/generic/hack-6.1/204-module_strip.patch b/target/linux/generic/hack-6.1/204-module_strip.patch index dd5d93e2267..ee39d15095d 100644 --- a/target/linux/generic/hack-6.1/204-module_strip.patch +++ b/target/linux/generic/hack-6.1/204-module_strip.patch @@ -86,9 +86,9 @@ Signed-off-by: Felix Fietkau struct kernel_param; ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -2356,6 +2356,13 @@ config UNUSED_KSYMS_WHITELIST +--- a/kernel/module/Kconfig ++++ b/kernel/module/Kconfig +@@ -2352,6 +2352,13 @@ config UNUSED_KSYMS_WHITELIST one per line. The path can be absolute, or relative to the kernel source tree. @@ -102,14 +102,14 @@ Signed-off-by: Felix Fietkau endif # MODULES config MODULES_TREE_LOOKUP ---- a/kernel/module.c -+++ b/kernel/module.c +--- a/kernel/module/main.c ++++ b/kernel/module/main.c @@ -1218,6 +1218,7 @@ static struct module_attribute *modinfo_ static const char vermagic[] = VERMAGIC_STRING; +#if defined(CONFIG_MODVERSIONS) || !defined(CONFIG_MODULE_STRIPPED) - static int try_to_force_load(struct module *mod, const char *reason) + int try_to_force_load(struct module *mod, const char *reason) { #ifdef CONFIG_MODULE_FORCE_LOAD @@ -1229,6 +1230,7 @@ static int try_to_force_load(struct modu @@ -118,8 +118,8 @@ Signed-off-by: Felix Fietkau } +#endif - #ifdef CONFIG_MODVERSIONS - + static char *get_modinfo(const struct load_info *info, const char *tag); + static char *get_next_modinfo(const struct load_info *info, const char *tag, @@ -3266,9 +3268,11 @@ static int setup_load_info(struct load_i static int check_modinfo(struct module *mod, struct load_info *info, int flags) @@ -143,7 +143,7 @@ Signed-off-by: Felix Fietkau --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c -@@ -2036,7 +2036,9 @@ static void read_symbols(const char *mod +@@ -2034,7 +2034,9 @@ static void read_symbols(const char *mod symname = remove_dot(info.strtab + sym->st_name); handle_symbol(mod, &info, sym, symname); @@ -153,7 +153,7 @@ Signed-off-by: Felix Fietkau } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { -@@ -2215,8 +2217,10 @@ static void add_header(struct buffer *b, +@@ -2213,8 +2215,10 @@ static void add_header(struct buffer *b, buf_printf(b, "BUILD_SALT;\n"); buf_printf(b, "BUILD_LTO_INFO;\n"); buf_printf(b, "\n"); @@ -164,29 +164,29 @@ Signed-off-by: Felix Fietkau buf_printf(b, "\n"); buf_printf(b, "__visible struct module __this_module\n"); buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); -@@ -2233,8 +2237,10 @@ static void add_header(struct buffer *b, +@@ -2231,8 +2235,10 @@ static void add_header(struct buffer *b, + buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "};\n"); - static void add_intree_flag(struct buffer *b, int is_intree) - { +#ifndef CONFIG_MODULE_STRIPPED - if (is_intree) + if (!external_module) buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); +#endif - } - /* Cannot check for assembler */ -@@ -2247,8 +2253,10 @@ static void add_retpoline(struct buffer + buf_printf(b, + "\n" +@@ -2245,8 +2251,10 @@ static void add_retpoline(struct buffer + "MODULE_INFO(retpoline, \"Y\");\n" + "#endif\n"); - static void add_staging_flag(struct buffer *b, const char *name) - { +#ifndef CONFIG_MODULE_STRIPPED - if (strstarts(name, "drivers/staging")) + if (strstarts(mod->name, "drivers/staging")) buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); +#endif - } - /** -@@ -2328,11 +2336,13 @@ static void add_depends(struct buffer *b + if (strstarts(mod->name, "tools/testing")) + buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); +@@ -2326,11 +2334,13 @@ static void add_depends(struct buffer *b static void add_srcversion(struct buffer *b, struct module *mod) { @@ -200,13 +200,13 @@ Signed-off-by: Felix Fietkau } static void write_buf(struct buffer *b, const char *fname) -@@ -2581,7 +2591,9 @@ int main(int argc, char **argv) - add_staging_flag(&buf, mod->name); - add_versions(&buf, mod); - add_depends(&buf, mod); +@@ -2579,7 +2589,9 @@ int main(int argc, char **argv) + add_exported_symbols(&buf, mod); + add_versions(&buf, mod); + add_depends(&buf, mod); +#ifndef CONFIG_MODULE_STRIPPED - add_moddevtable(&buf, mod); + add_moddevtable(&buf, mod); +#endif - add_srcversion(&buf, mod); + add_srcversion(&buf, mod); - sprintf(fname, "%s.mod.c", mod->name); + ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name); diff --git a/target/linux/generic/hack-6.1/212-tools_portability.patch b/target/linux/generic/hack-6.1/212-tools_portability.patch index b488155f942..0b908f7c7d1 100644 --- a/target/linux/generic/hack-6.1/212-tools_portability.patch +++ b/target/linux/generic/hack-6.1/212-tools_portability.patch @@ -81,30 +81,40 @@ Signed-off-by: Felix Fietkau struct page; struct kmem_cache; ---- a/tools/perf/pmu-events/jevents.c -+++ b/tools/perf/pmu-events/jevents.c -@@ -1,4 +1,6 @@ -+#ifdef __linux__ - #define _XOPEN_SOURCE 500 /* needed for nftw() */ -+#endif - #define _GNU_SOURCE /* needed for asprintf() */ - - /* Parse event JSON files */ -@@ -35,6 +37,7 @@ - #include - #include +--- a/tools/perf/pmu-events/jevents.py ++++ b/tools/perf/pmu-events/jevents.py +@@ -684,6 +684,7 @@ + #include "util/header.h" + #include "util/pmu.h" #include +#include - #include - #include - #include ---- a/tools/perf/pmu-events/json.c -+++ b/tools/perf/pmu-events/json.c -@@ -38,7 +38,6 @@ - #include - #include "jsmn.h" - #include "json.h" --#include + #include + + struct compact_pmu_event { +# --- a/tools/perf/pmu-events/jevents.c +# +++ b/tools/perf/pmu-events/jevents.c +# @@ -1,4 +1,6 @@ +# +#ifdef __linux__ +# #define _XOPEN_SOURCE 500 /* needed for nftw() */ +# +#endif +# #define _GNU_SOURCE /* needed for asprintf() */ + +# /* Parse event JSON files */ +# @@ -35,6 +37,7 @@ +# #include +# #include +# #include +# +#include +# #include +# #include +# #include +# --- a/tools/perf/pmu-events/json.c +# +++ b/tools/perf/pmu-events/json.c +# @@ -38,7 +38,6 @@ +# #include +# #include "jsmn.h" +# #include "json.h" +# -#include - static char *mapfile(const char *fn, size_t *size) +# static char *mapfile(const char *fn, size_t *size) diff --git a/target/linux/generic/hack-6.1/221-module_exports.patch b/target/linux/generic/hack-6.1/221-module_exports.patch index 87f541b46f2..adc2cefbd2e 100644 --- a/target/linux/generic/hack-6.1/221-module_exports.patch +++ b/target/linux/generic/hack-6.1/221-module_exports.patch @@ -56,10 +56,10 @@ Signed-off-by: Felix Fietkau } \ \ /* __*init sections */ \ -@@ -1022,6 +1032,8 @@ - +@@ -1018,6 +1028,8 @@ #define COMMON_DISCARDS \ SANITIZER_DISCARDS \ + PATCHABLE_DISCARDS \ + SYMTAB_DISCARD \ + SYMTAB_DISCARD_GPL \ *(.discard) \ @@ -81,9 +81,9 @@ Signed-off-by: Felix Fietkau * For every exported symbol, do the following: * @@ -101,7 +107,7 @@ struct kernel_symbol { + extern typeof(sym) sym; \ extern const char __kstrtab_##sym[]; \ extern const char __kstrtabns_##sym[]; \ - __CRC_SYMBOL(sym, sec); \ - asm(" .section \"__ksymtab_strings\",\"aMS\",%progbits,1 \n" \ + asm(" .section \"__ksymtab_strings" __EXPORT_SUFFIX(sym) "\",\"aMS\",%progbits,1 \n" \ "__kstrtab_" #sym ": \n" \ diff --git a/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch index f9361b060bd..a28878427a4 100644 --- a/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch +++ b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch @@ -23,12 +23,16 @@ Signed-off-by: Imre Kaloz { {0x02, 0x21}, "lz4", unlz4 }, --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -402,7 +402,7 @@ quiet_cmd_bzip2 = BZIP2 $@ +@@ -402,10 +402,10 @@ quiet_cmd_bzip2 = BZIP2 $@ # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ -- cmd_lzma = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ -+ cmd_lzma = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ +- cmd_lzma = cat $(real-prereqs) | $(LZMA) -9 > $@ ++ cmd_lzma = cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so > $@ + + quiet_cmd_lzma_with_size = LZMA $@ +- cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) -9; $(size_append); } > $@ ++ cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ quiet_cmd_lzo = LZO $@ cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ diff --git a/target/linux/generic/hack-6.1/250-netfilter_depends.patch b/target/linux/generic/hack-6.1/250-netfilter_depends.patch index d9a2b81d743..495c73ffa88 100644 --- a/target/linux/generic/hack-6.1/250-netfilter_depends.patch +++ b/target/linux/generic/hack-6.1/250-netfilter_depends.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig -@@ -242,7 +242,6 @@ config NF_CONNTRACK_FTP +@@ -243,7 +243,6 @@ config NF_CONNTRACK_FTP config NF_CONNTRACK_H323 tristate "H.323 protocol support" @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau depends on NETFILTER_ADVANCED help H.323 is a VoIP signalling protocol from ITU-T. As one of the most -@@ -1105,7 +1104,6 @@ config NETFILTER_XT_TARGET_SECMARK +@@ -1106,7 +1105,6 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_TCPMSS tristate '"TCPMSS" target support' diff --git a/target/linux/generic/hack-6.1/259-regmap_dynamic.patch b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch index 76a5ace6f31..8cf6c035e50 100644 --- a/target/linux/generic/hack-6.1/259-regmap_dynamic.patch +++ b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch @@ -125,7 +125,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -3358,3 +3359,5 @@ static int __init regmap_initcall(void) +@@ -3348,3 +3349,5 @@ static int __init regmap_initcall(void) return 0; } postcore_initcall(regmap_initcall); diff --git a/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch index f1942e20375..215528a90c5 100644 --- a/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch +++ b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch @@ -16,7 +16,7 @@ Signed-off-by: Alexandros C. Couloumbis --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile -@@ -44,19 +44,6 @@ machine-$(CONFIG_PPC64) += 64 +@@ -61,19 +61,6 @@ machine-$(CONFIG_PPC64) += 64 machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le UTS_MACHINE := $(subst $(space),,$(machine-y)) diff --git a/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch index 32a7fb62664..7999f5ac6d8 100644 --- a/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch +++ b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch @@ -25,11 +25,13 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c -@@ -384,13 +384,6 @@ int add_mtd_blktrans_dev(struct mtd_blkt +@@ -384,19 +384,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt if (new->readonly) set_disk_ro(gd, 1); -- device_add_disk(&new->mtd->dev, gd, NULL); +- ret = device_add_disk(&new->mtd->dev, gd, NULL); +- if (ret) +- goto out_cleanup_disk; - - if (new->disk_attributes) { - ret = sysfs_create_group(&disk_to_dev(gd)->kobj, @@ -38,8 +40,12 @@ Signed-off-by: Daniel Golle - } return 0; +-out_cleanup_disk: +- put_disk(new->disk); out_free_tag_set: -@@ -402,6 +395,27 @@ out_list_del: + blk_mq_free_tag_set(new->tag_set); + out_kfree_tag_set: +@@ -402,6 +395,35 @@ out_list_del: return ret; } @@ -54,7 +60,10 @@ Signed-off-by: Daniel Golle + if (disk_live(dev->disk)) + continue; + -+ device_add_disk(&dev->mtd->dev, dev->disk, NULL); ++ ret = device_add_disk(&dev->mtd->dev, dev->disk, NULL); ++ if (ret) ++ goto out_cleanup_disk; ++ + if (dev->disk_attributes) { + ret = sysfs_create_group(&disk_to_dev(dev->disk)->kobj, + dev->disk_attributes); @@ -62,6 +71,11 @@ Signed-off-by: Daniel Golle + } + } + } ++ ++ return; ++ ++out_cleanup_disk: ++ put_disk(dev->disk); +} + int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) diff --git a/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch index 96c89f41c48..854621bb58f 100644 --- a/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch +++ b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch @@ -179,29 +179,6 @@ Subject: [PATCH] kernel: add block fit partition parser {0, NULL}, }; ---- a/drivers/mtd/mtd_blkdevs.c -+++ b/drivers/mtd/mtd_blkdevs.c -@@ -345,6 +345,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt - gd->first_minor = (new->devnum) << tr->part_bits; - gd->minors = 1 << tr->part_bits; - gd->fops = &mtd_block_ops; -+ if (IS_ENABLED(CONFIG_FIT_PARTITION) && !mtd_type_is_nand(new->mtd)) -+ gd->flags |= GENHD_FL_EXT_DEVT; - - if (tr->part_bits) - if (new->devnum < 26) ---- a/drivers/mtd/ubi/block.c -+++ b/drivers/mtd/ubi/block.c -@@ -428,6 +428,9 @@ int ubiblock_create(struct ubi_volume_in - goto out_cleanup_disk; - } - gd->private_data = dev; -+#ifdef CONFIG_FIT_PARTITION -+ gd->flags |= GENHD_FL_EXT_DEVT; -+#endif - sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id); - set_capacity(gd, disk_capacity); - dev->gd = gd; --- a/include/linux/msdos_partition.h +++ b/include/linux/msdos_partition.h @@ -31,6 +31,7 @@ enum msdos_sys_ind { diff --git a/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch index 2a83f46e0ee..1476f4fd562 100644 --- a/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch +++ b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch @@ -18,15 +18,15 @@ Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table + bool "Support MediaTek NAND Bad-block Management Table" + default n + - endmenu - - endmenu + config MTD_NAND_ECC_MXIC + bool "Macronix external hardware ECC engine" + depends on HAS_IOMEM --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -2,6 +2,7 @@ - nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o + obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o +obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o obj-y += onenand/ diff --git a/target/linux/generic/hack-6.1/600-bridge_offload.patch b/target/linux/generic/hack-6.1/600-bridge_offload.patch index 9d71a741b25..6462044bbe3 100644 --- a/target/linux/generic/hack-6.1/600-bridge_offload.patch +++ b/target/linux/generic/hack-6.1/600-bridge_offload.patch @@ -26,10 +26,10 @@ Subject: [PATCH] net/bridge: add bridge offload --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -59,6 +59,7 @@ struct br_ip_list { - #define BR_MRP_LOST_IN_CONT BIT(19) #define BR_TX_FWD_OFFLOAD BIT(20) - #define BR_BPDU_FILTER BIT(21) -+#define BR_OFFLOAD BIT(22) + #define BR_PORT_LOCKED BIT(21) + #define BR_BPDU_FILTER BIT(22) ++#define BR_OFFLOAD BIT(23) #define BR_DEFAULT_AGEING_TIME (300 * HZ) @@ -103,16 +103,7 @@ Subject: [PATCH] net/bridge: add bridge offload static const struct rhashtable_params br_fdb_rht_params = { .head_offset = offsetof(struct net_bridge_fdb_entry, rhnode), -@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_ - fdb->key.vlan_id = vid; - fdb->flags = flags; - fdb->updated = fdb->used = jiffies; -+ INIT_HLIST_HEAD(&fdb->offload_in); -+ INIT_HLIST_HEAD(&fdb->offload_out); - if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, - &fdb->rhnode, - br_fdb_rht_params)) { -@@ -794,6 +797,8 @@ static void fdb_notify(struct net_bridge +@@ -185,6 +185,8 @@ static void fdb_notify(struct net_bridge struct sk_buff *skb; int err = -ENOBUFS; @@ -121,6 +112,15 @@ Subject: [PATCH] net/bridge: add bridge offload if (swdev_notify) br_switchdev_fdb_notify(br, fdb, type); +@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_ + fdb->key.vlan_id = vid; + fdb->flags = flags; + fdb->updated = fdb->used = jiffies; ++ INIT_HLIST_HEAD(&fdb->offload_in); ++ INIT_HLIST_HEAD(&fdb->offload_out); + err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode, + br_fdb_rht_params); + if (err) { --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -16,6 +16,7 @@ diff --git a/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch index aa6c668558a..476c5948ab0 100644 --- a/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch +++ b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch @@ -6,71 +6,9 @@ Signed-off-by: Felix Fietkau --- create mode 100644 net/netfilter/xt_OFFLOAD.c ---- a/net/ipv4/netfilter/Kconfig -+++ b/net/ipv4/netfilter/Kconfig -@@ -56,8 +56,6 @@ config NF_TABLES_ARP - help - This option enables the ARP support for nf_tables. - --endif # NF_TABLES -- - config NF_FLOW_TABLE_IPV4 - tristate "Netfilter flow table IPv4 module" - depends on NF_FLOW_TABLE -@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4 - - To compile it as a module, choose M here. - -+endif # NF_TABLES -+ - config NF_DUP_IPV4 - tristate "Netfilter IPv4 packet duplication to alternate destination" - depends on !NF_CONNTRACK || NF_CONNTRACK ---- a/net/ipv6/netfilter/Kconfig -+++ b/net/ipv6/netfilter/Kconfig -@@ -45,7 +45,6 @@ config NFT_FIB_IPV6 - multicast or blackhole. - - endif # NF_TABLES_IPV6 --endif # NF_TABLES - - config NF_FLOW_TABLE_IPV6 - tristate "Netfilter flow table IPv6 module" -@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6 - - To compile it as a module, choose M here. - -+endif # NF_TABLES -+ - config NF_DUP_IPV6 - tristate "Netfilter IPv6 packet duplication to alternate destination" - depends on !NF_CONNTRACK || NF_CONNTRACK --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig -@@ -707,8 +707,6 @@ config NFT_REJECT_NETDEV - - endif # NF_TABLES_NETDEV - --endif # NF_TABLES -- - config NF_FLOW_TABLE_INET - tristate "Netfilter flow table mixed IPv4/IPv6 module" - depends on NF_FLOW_TABLE -@@ -717,11 +715,12 @@ config NF_FLOW_TABLE_INET - - To compile it as a module, choose M here. - -+endif # NF_TABLES -+ - config NF_FLOW_TABLE - tristate "Netfilter flow table module" - depends on NETFILTER_INGRESS - depends on NF_CONNTRACK -- depends on NF_TABLES - help - This option adds the flow table core infrastructure. - -@@ -1010,6 +1009,15 @@ config NETFILTER_XT_TARGET_NOTRACK +@@ -1011,6 +1010,15 @@ config NETFILTER_XT_TARGET_NOTRACK depends on NETFILTER_ADVANCED select NETFILTER_XT_TARGET_CT @@ -823,7 +761,7 @@ Signed-off-by: Felix Fietkau } +EXPORT_SYMBOL_GPL(nf_flow_table_iterate); - void nf_flow_table_gc_run(struct nf_flowtable *flow_table) + static void nf_flow_offload_work_gc(struct work_struct *work) { --- /dev/null +++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h @@ -847,7 +785,7 @@ Signed-off-by: Felix Fietkau +#endif /* _XT_FLOWOFFLOAD_H */ --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h -@@ -276,6 +276,11 @@ void nf_flow_table_free(struct nf_flowta +@@ -275,6 +275,11 @@ void nf_flow_table_free(struct nf_flowta void flow_offload_teardown(struct flow_offload *flow); diff --git a/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch index e62f45f3c33..8f2e6e0e0e8 100644 --- a/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch +++ b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch @@ -9,7 +9,7 @@ Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -2985,6 +2985,9 @@ static int mv88e6xxx_setup_port(struct m +@@ -2981,6 +2981,9 @@ static int mv88e6xxx_setup_port(struct m else reg = 1 << port; diff --git a/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch index 29050d38ea2..de6fdb3ceaa 100644 --- a/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch +++ b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch @@ -9,18 +9,15 @@ Signed-off-by: Birger Koblitz --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -20,8 +20,10 @@ - #define PHY_ID_AQR105 0x03a1b4a2 - #define PHY_ID_AQR106 0x03a1b4d0 - #define PHY_ID_AQR107 0x03a1b4e0 -+#define PHY_ID_AQR113C 0x31c31c12 +@@ -20,6 +20,7 @@ #define PHY_ID_AQCS109 0x03a1b5c2 #define PHY_ID_AQR405 0x03a1b4b0 + #define PHY_ID_AQR113C 0x31c31c12 +#define PHY_ID_AQR813 0x31c31cb2 #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -381,6 +383,49 @@ static int aqr107_read_rate(struct phy_d +@@ -372,6 +374,49 @@ static int aqr107_read_rate(struct phy_d return 0; } @@ -70,7 +67,7 @@ Signed-off-by: Birger Koblitz static int aqr107_read_status(struct phy_device *phydev) { int val, ret; -@@ -511,7 +556,7 @@ static void aqr107_chip_info(struct phy_ +@@ -502,7 +547,7 @@ static void aqr107_chip_info(struct phy_ build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); @@ -79,32 +76,16 @@ Signed-off-by: Birger Koblitz fw_major, fw_minor, build_id, prov_id); } -@@ -719,6 +764,24 @@ static struct phy_driver aqr_driver[] = - .link_change_notify = aqr107_link_change_notify, - }, - { -+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), -+ .name = "Aquantia AQR113C", -+ .probe = aqr107_probe, -+ .config_init = aqr107_config_init, -+ .config_aneg = aqr_config_aneg, -+ .config_intr = aqr_config_intr, -+ .handle_interrupt = aqr_handle_interrupt, -+ .read_status = aqr113c_read_status, -+ .get_tunable = aqr107_get_tunable, -+ .set_tunable = aqr107_set_tunable, -+ .suspend = aqr107_suspend, -+ .resume = aqr107_resume, -+ .get_sset_count = aqr107_get_sset_count, -+ .get_strings = aqr107_get_strings, -+ .get_stats = aqr107_get_stats, -+ .link_change_notify = aqr107_link_change_notify, -+}, -+{ - PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), - .name = "Aquantia AQCS109", - .probe = aqr107_probe, -@@ -744,6 +807,24 @@ static struct phy_driver aqr_driver[] = +@@ -706,7 +706,7 @@ static struct phy_driver aqr_driver[] = + .config_aneg = aqr_config_aneg, + .config_intr = aqr_config_intr, + .handle_interrupt = aqr_handle_interrupt, +- .read_status = aqr107_read_status, ++ .read_status = aqr113c_read_status, + .get_tunable = aqr107_get_tunable, + .set_tunable = aqr107_set_tunable, + .suspend = aqr107_suspend, +@@ -708,6 +762,24 @@ static struct phy_driver aqr_driver[] = .handle_interrupt = aqr_handle_interrupt, .read_status = aqr_read_status, }, @@ -129,13 +110,10 @@ Signed-off-by: Birger Koblitz }; module_phy_driver(aqr_driver); -@@ -754,8 +835,10 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, -+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, +@@ -709,6 +790,7 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, { } }; diff --git a/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch index dbdb141c6dc..adb437548ef 100644 --- a/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch @@ -19,34 +19,23 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1679,6 +1679,10 @@ enum netdev_priv_flags { +@@ -1655,6 +1655,7 @@ enum netdev_priv_flags { + IFF_LIVE_RENAME_OK = 1<<30, IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), + IFF_CHANGE_PROTO_DOWN = BIT_ULL(32), ++ IFF_NO_IP_ALIGN = BIT_ULL(33), }; -+enum netdev_extra_priv_flags { -+ IFF_NO_IP_ALIGN = 1<<0, -+}; -+ #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN - #define IFF_EBRIDGE IFF_EBRIDGE - #define IFF_BONDING IFF_BONDING -@@ -1711,6 +1715,7 @@ enum netdev_priv_flags { +@@ -1687,6 +1691,7 @@ enum netdev_priv_flags { #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR -+#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN ++#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN /* Specifies the type of the struct net_device::ml_priv pointer */ enum netdev_ml_priv_type { -@@ -2012,6 +2017,7 @@ struct net_device { - /* Read-mostly cache-line for fast-path access */ - unsigned int flags; - unsigned int priv_flags; -+ unsigned int extra_priv_flags; - const struct net_device_ops *netdev_ops; - int ifindex; - unsigned short gflags; -@@ -2072,6 +2078,11 @@ struct net_device { +@@ -2048,6 +2054,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif @@ -58,7 +47,7 @@ Signed-off-by: Felix Fietkau const struct header_ops *header_ops; unsigned char operstate; -@@ -2146,6 +2157,10 @@ struct net_device { +@@ -2122,6 +2133,10 @@ struct net_device { struct mctp_dev __rcu *mctp_ptr; #endif @@ -71,7 +60,7 @@ Signed-off-by: Felix Fietkau */ --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2855,6 +2855,10 @@ static inline int pskb_trim(struct sk_bu +@@ -2816,6 +2816,10 @@ static inline int pskb_trim(struct sk_bu return (len < skb->len) ? __pskb_trim(skb, len) : 0; } @@ -82,7 +71,7 @@ Signed-off-by: Felix Fietkau /** * pskb_trim_unique - remove end from a paged unique (not cloned) buffer * @skb: buffer to alter -@@ -3005,16 +3009,6 @@ static inline struct sk_buff *dev_alloc_ +@@ -2966,16 +2970,6 @@ static inline struct sk_buff *dev_alloc_ } @@ -126,8 +115,8 @@ Signed-off-by: Felix Fietkau +#endif + len = skb->len; - PRANDOM_ADD_NOISE(skb, dev, txq, len + jiffies); trace_net_dev_start_xmit(skb, dev); + rc = netdev_start_xmit(skb, dev, txq, more); --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -61,6 +61,7 @@ @@ -148,7 +137,7 @@ Signed-off-by: Felix Fietkau + struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); + +#ifdef CONFIG_ETHERNET_PACKET_MANGLE -+ if (dev && (dev->extra_priv_flags & IFF_NO_IP_ALIGN)) ++ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN)) + return skb; +#endif + diff --git a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch index 211696c5688..d4024f1a435 100644 --- a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch +++ b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch @@ -15,21 +15,18 @@ Signed-off-by: Alex Marginean --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -20,9 +20,11 @@ - #define PHY_ID_AQR105 0x03a1b4a2 - #define PHY_ID_AQR106 0x03a1b4d0 - #define PHY_ID_AQR107 0x03a1b4e0 -+#define PHY_ID_AQR112 0x03a1b662 - #define PHY_ID_AQR113C 0x31c31c12 - #define PHY_ID_AQCS109 0x03a1b5c2 +@@ -20,6 +20,8 @@ #define PHY_ID_AQR405 0x03a1b4b0 -+#define PHY_ID_AQR412 0x03a1b712 + #define PHY_ID_AQR113C 0x31c31c12 #define PHY_ID_AQR813 0x31c31cb2 ++#define PHY_ID_AQR112 0x03a1b662 ++#define PHY_ID_AQR412 0x03a1b712 #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 -@@ -135,6 +137,29 @@ - #define AQR107_OP_IN_PROG_SLEEP 1000 - #define AQR107_OP_IN_PROG_TIMEOUT 100000 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +@@ -126,6 +128,29 @@ + #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) + #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) +/* registers in MDIO_MMD_VEND1 region */ +#define AQUANTIA_VND1_GLOBAL_SC 0x000 @@ -57,7 +54,7 @@ Signed-off-by: Alex Marginean struct aqr107_hw_stat { const char *name; int reg; -@@ -266,6 +291,51 @@ static int aqr_config_aneg(struct phy_de +@@ -257,6 +282,51 @@ static int aqr_config_aneg(struct phy_de return genphy_c45_check_and_restart_aneg(phydev, changed); } @@ -109,7 +106,7 @@ Signed-off-by: Alex Marginean static int aqr_config_intr(struct phy_device *phydev) { bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; -@@ -825,6 +895,30 @@ static struct phy_driver aqr_driver[] = +@@ -780,6 +850,30 @@ static struct phy_driver aqr_driver[] = .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, @@ -140,15 +137,11 @@ Signed-off-by: Alex Marginean }; module_phy_driver(aqr_driver); -@@ -835,9 +929,11 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_MODEL(PHY_ID_AQR105) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, -+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, +@@ -790,5 +884,7 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, -+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, ++ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, { } }; diff --git a/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch index 7d16c8aa289..d99b4951b82 100644 --- a/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch +++ b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch @@ -14,7 +14,7 @@ Signed-off-by: Alex Marginean --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -324,10 +324,16 @@ static int aqr_config_aneg_set_prot(stru +@@ -315,10 +315,16 @@ static int aqr_config_aneg_set_prot(stru phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, aquantia_syscfg[if_type].start_rate); diff --git a/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch index d03c3430fae..dd32690048d 100644 --- a/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch +++ b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch @@ -11,17 +11,18 @@ Add a new entry for AQR113 PHY_ID --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c @@ -21,6 +21,7 @@ - #define PHY_ID_AQR106 0x03a1b4d0 - #define PHY_ID_AQR107 0x03a1b4e0 + #define PHY_ID_AQR813 0x31c31cb2 #define PHY_ID_AQR112 0x03a1b662 + #define PHY_ID_AQR412 0x03a1b712 +#define PHY_ID_AQR113 0x31c31c40 - #define PHY_ID_AQR113C 0x31c31c12 - #define PHY_ID_AQCS109 0x03a1b5c2 - #define PHY_ID_AQR405 0x03a1b4b0 -@@ -914,6 +915,14 @@ static struct phy_driver aqr_driver[] = + + #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +@@ -869,6 +870,14 @@ static struct phy_driver aqr_driver[] = + .get_strings = aqr107_get_strings, .get_stats = aqr107_get_stats, }, - { ++{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR113), + .name = "Aquantia AQR113", + .config_aneg = aqr_config_aneg, @@ -29,15 +30,13 @@ Add a new entry for AQR113 PHY_ID + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, +}, -+{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR412), - .name = "Aquantia AQR412", - .probe = aqr107_probe, -@@ -936,6 +945,7 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, + }; + + module_phy_driver(aqr_driver); +@@ -790,5 +884,6 @@ static struct mdio_device_id __maybe_unu + { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, + { } + }; diff --git a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch index 9821c0c86ee..57edfc118e4 100644 --- a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch +++ b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch @@ -13,18 +13,19 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c @@ -21,6 +21,8 @@ - #define PHY_ID_AQR106 0x03a1b4d0 - #define PHY_ID_AQR107 0x03a1b4e0 #define PHY_ID_AQR112 0x03a1b662 + #define PHY_ID_AQR412 0x03a1b712 + #define PHY_ID_AQR113 0x31c31c40 +#define PHY_ID_AQR112C 0x03a1b790 +#define PHY_ID_AQR112R 0x31c31d12 - #define PHY_ID_AQR113 0x31c31c40 - #define PHY_ID_AQR113C 0x31c31c12 - #define PHY_ID_AQCS109 0x03a1b5c2 -@@ -915,6 +917,30 @@ static struct phy_driver aqr_driver[] = - .get_stats = aqr107_get_stats, + + #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 + #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) +@@ -870,6 +872,30 @@ static struct phy_driver aqr_driver[] = + .handle_interrupt = aqr_handle_interrupt, + .read_status = aqr107_read_status, }, - { ++{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR112C), + .name = "Aquantia AQR112C", + .probe = aqr107_probe, @@ -48,16 +49,14 @@ Signed-off-by: Daniel Golle + .get_strings = aqr107_get_strings, + .get_stats = aqr107_get_stats, +}, -+{ - PHY_ID_MATCH_MODEL(PHY_ID_AQR113), - .name = "Aquantia AQR113", - .config_aneg = aqr_config_aneg, -@@ -945,6 +971,8 @@ static struct mdio_device_id __maybe_unu - { PHY_ID_MATCH_MODEL(PHY_ID_AQR106) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR107) }, + }; + + module_phy_driver(aqr_driver); +@@ -900,5 +926,7 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, - { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, + { } + }; diff --git a/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch index 8de3668def2..22fa7289fd3 100644 --- a/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch +++ b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch @@ -24,13 +24,13 @@ Signed-off-by: David Bauer --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -8,6 +8,7 @@ - - #include #include + #include + #include +#include #include + #include #include - @@ -30,6 +31,7 @@ #define PHY_MIISTAT 0x18 /* MII state */ #define PHY_IMASK 0x19 /* interrupt mask */ @@ -46,7 +46,7 @@ Signed-off-by: David Bauer +#define PHY_LED_NUM_LEDS 4 + #define PHY_FWV_REL_MASK BIT(15) - #define PHY_FWV_TYPE_MASK GENMASK(11, 8) + #define PHY_FWV_MAJOR_MASK GENMASK(11, 8) #define PHY_FWV_MINOR_MASK GENMASK(7, 0) +/* LED */ diff --git a/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch index 367d66fc666..e3959658a3c 100644 --- a/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch +++ b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch @@ -10,7 +10,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c -@@ -1086,6 +1086,7 @@ static const struct usb_device_id produc +@@ -1085,6 +1085,7 @@ static const struct usb_device_id produc {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ @@ -29,8 +29,8 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support #define QUECTEL_VENDOR_ID 0x2c7c /* These Quectel products use Quectel's vendor ID */ -@@ -1169,6 +1171,11 @@ static const struct usb_device_id option - .driver_info = ZLP }, +@@ -1133,6 +1135,11 @@ static const struct usb_device_id option + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0, 0) }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), .driver_info = RSVD(4) }, + /* Meiglink products using Qualcomm vendor ID */ diff --git a/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch index 10af22e52e0..7131b61b35f 100644 --- a/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch +++ b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch @@ -26,19 +26,17 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -383,6 +383,11 @@ static const struct sfp_quirk sfp_quirks - .modes = sfp_quirk_2500basex, - .fixup = sfp_fixup_ignore_tx_fault, - }, { -+ // OEM SFP-GE-T is 1000Base-T module -+ .vendor = "OEM", -+ .part = "SFP-GE-T", -+ .fixup = sfp_fixup_ignore_tx_fault, -+ }, { - // Lantech 8330-262D-E can operate at 2500base-X, but - // incorrectly report 2500MBd NRZ in their EEPROM - .vendor = "Lantech", -@@ -2312,7 +2317,8 @@ static void sfp_sm_main(struct sfp *sfp, +@@ -393,6 +393,9 @@ static const struct sfp_quirk sfp_quirks + // their EEPROM + SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, + sfp_fixup_ignore_tx_fault), ++ ++ // OEM SFP-GE-T is 1000Base-T module ++ SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), + + // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report + // 2500MBd NRZ in their EEPROM +@@ -2303,7 +2308,8 @@ static void sfp_sm_main(struct sfp *sfp, * or t_start_up, so assume there is a fault. */ sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, diff --git a/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch b/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch deleted file mode 100644 index b1e7065a8b9..00000000000 --- a/target/linux/generic/hack-6.1/795-backport-phylink_pcs-helpers.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 027586ae8ecacff49757ed854c020f35d24a599c Mon Sep 17 00:00:00 2001 -From: Daniel Golle -Date: Sat, 11 Mar 2023 03:44:41 +0000 -Subject: [PATCH] generic: backport some phylink helper functions - -It isn't feasible to literally backport all upstream phylink_pcs changes -down to Linux 5.15: It's just too many patches, and many downstream -drivers and hacks are likely to break. We are too close to branching off -to risk this, and it's also just too much work. -Instead just add helper functions used by modern PCS drivers while keeping -the original functions instact as well. While this may add a kilobyte or -two of extra kernel size, it has the advantage that we get the best of both -worlds: None of the existing codepaths are touched, but yet we have the -option to backport singular improvements to Ethernet drivers where needed. - -Signed-off-by: Daniel Golle - ---- a/include/linux/phylink.h -+++ b/include/linux/phylink.h -@@ -584,10 +584,37 @@ int phylink_speed_up(struct phylink *pl) - #define phylink_test(bm, mode) __phylink_do_bit(test_bit, bm, mode) - - void phylink_set_port_modes(unsigned long *bits); -+ -+/** -+ * phylink_get_link_timer_ns - return the PCS link timer value -+ * @interface: link &typedef phy_interface_t mode -+ * -+ * Return the PCS link timer setting in nanoseconds for the PHY @interface -+ * mode, or -EINVAL if not appropriate. -+ */ -+static inline int phylink_get_link_timer_ns(phy_interface_t interface) -+{ -+ switch (interface) { -+ case PHY_INTERFACE_MODE_SGMII: -+ return 1600000; -+ -+ case PHY_INTERFACE_MODE_1000BASEX: -+ case PHY_INTERFACE_MODE_2500BASEX: -+ return 10000000; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ - void phylink_helper_basex_speed(struct phylink_link_state *state); - -+void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, -+ u16 bmsr, u16 lpa); - void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, - struct phylink_link_state *state); -+int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, -+ const unsigned long *advertising); - int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, - phy_interface_t interface, - const unsigned long *advertising); ---- a/drivers/net/phy/phylink.c -+++ b/drivers/net/phy/phylink.c -@@ -885,7 +885,6 @@ static int phylink_change_inband_advert( - - return 0; - } -- - static void phylink_mac_pcs_get_state(struct phylink *pl, - struct phylink_link_state *state) - { -@@ -2966,6 +2965,52 @@ void phylink_mii_c22_pcs_get_state(struc - EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); - - /** -+ * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers -+ * @state: a pointer to a &struct phylink_link_state. -+ * @bmsr: The value of the %MII_BMSR register -+ * @lpa: The value of the %MII_LPA register -+ * -+ * Helper for MAC PCS supporting the 802.3 clause 22 register set for -+ * clause 37 negotiation and/or SGMII control. -+ * -+ * Parse the Clause 37 or Cisco SGMII link partner negotiation word into -+ * the phylink @state structure. This is suitable to be used for implementing -+ * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if -+ * accessing @bmsr and @lpa cannot be done with MDIO directly. -+ */ -+void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state, -+ u16 bmsr, u16 lpa) -+{ -+ state->link = !!(bmsr & BMSR_LSTATUS); -+ state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); -+ /* If there is no link or autonegotiation is disabled, the LP advertisement -+ * data is not meaningful, so don't go any further. -+ */ -+ if (!state->link || !state->an_enabled) -+ return; -+ -+ switch (state->interface) { -+ case PHY_INTERFACE_MODE_1000BASEX: -+ phylink_decode_c37_word(state, lpa, SPEED_1000); -+ break; -+ -+ case PHY_INTERFACE_MODE_2500BASEX: -+ phylink_decode_c37_word(state, lpa, SPEED_2500); -+ break; -+ -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_QSGMII: -+ phylink_decode_sgmii_word(state, lpa); -+ break; -+ -+ default: -+ state->link = false; -+ break; -+ } -+} -+EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state); -+ -+/** - * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS - * advertisement - * @pcs: a pointer to a &struct mdio_device. -@@ -3037,6 +3082,46 @@ int phylink_mii_c22_pcs_set_advertisemen - EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); - - /** -+ * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS -+ * advertisement -+ * @interface: the PHY interface mode being configured -+ * @advertising: the ethtool advertisement mask -+ * -+ * Helper for MAC PCS supporting the 802.3 clause 22 register set for -+ * clause 37 negotiation and/or SGMII control. -+ * -+ * Encode the clause 37 PCS advertisement as specified by @interface and -+ * @advertising. -+ * -+ * Return: The new value for @adv, or ``-EINVAL`` if it should not be changed. -+ */ -+int phylink_mii_c22_pcs_encode_advertisement(phy_interface_t interface, -+ const unsigned long *advertising) -+{ -+ u16 adv; -+ -+ switch (interface) { -+ case PHY_INTERFACE_MODE_1000BASEX: -+ case PHY_INTERFACE_MODE_2500BASEX: -+ adv = ADVERTISE_1000XFULL; -+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, -+ advertising)) -+ adv |= ADVERTISE_1000XPAUSE; -+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, -+ advertising)) -+ adv |= ADVERTISE_1000XPSE_ASYM; -+ return adv; -+ case PHY_INTERFACE_MODE_SGMII: -+ case PHY_INTERFACE_MODE_QSGMII: -+ return 0x0001; -+ default: -+ /* Nothing to do for other modes */ -+ return -EINVAL; -+ } -+} -+EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement); -+ -+/** - * phylink_mii_c22_pcs_config() - configure clause 22 PCS - * @pcs: a pointer to a &struct mdio_device. - * @mode: link autonegotiation mode diff --git a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch index 0a2c82cacbc..4c2a37e3475 100644 --- a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch +++ b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch @@ -15,7 +15,7 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1059,3 +1061,72 @@ void of_gpio_dev_init(struct gpio_chip * +@@ -1057,3 +1059,72 @@ void of_gpio_dev_init(struct gpio_chip * else gc->of_node = gdev->dev.of_node; } diff --git a/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch index ac502bdd16d..247eb798b33 100644 --- a/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch +++ b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch @@ -28,13 +28,15 @@ Signed-off-by: Felix Fietkau help --- a/net/core/Makefile +++ b/net/core/Makefile -@@ -10,9 +10,10 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. +@@ -10,11 +10,12 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ - sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ + dev_ioctl.o tso.o sock_reuseport.o \ - fib_notifier.o xdp.o flow_offload.o + fib_notifier.o xdp.o flow_offload.o gro.o + + obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o +obj-$(CONFIG_SOCK_DIAG) += sock_diag.o obj-y += net-sysfs.o diff --git a/target/linux/generic/hack-6.1/902-debloat_proc.patch b/target/linux/generic/hack-6.1/902-debloat_proc.patch index 12e99280289..d729b29015a 100644 --- a/target/linux/generic/hack-6.1/902-debloat_proc.patch +++ b/target/linux/generic/hack-6.1/902-debloat_proc.patch @@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/sock.c +++ b/net/core/sock.c -@@ -3866,6 +3866,8 @@ static __net_initdata struct pernet_oper +@@ -3855,6 +3855,8 @@ static __net_initdata struct pernet_oper static int __init proto_init(void) { diff --git a/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch index 0291a5e9bd8..8eb705341d5 100644 --- a/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch +++ b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch @@ -32,13 +32,13 @@ Signed-off-by: Felix Fietkau +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile -@@ -1,16 +1,20 @@ +@@ -1,18 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ +obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o + +dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ - dma-resv.o seqno-fence.o + dma-fence-unwrap.o dma-resv.o -obj-$(CONFIG_DMABUF_HEAPS) += dma-heap.o -obj-$(CONFIG_DMABUF_HEAPS) += heaps/ -obj-$(CONFIG_SYNC_FILE) += sync_file.o @@ -50,12 +50,14 @@ Signed-off-by: Felix Fietkau +dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o +dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o +dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o -+dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += udmabuf.o ++dma-buf-objs-$(CONFIG_DMABUF_SYSFS_STATS) += dma-buf-sysfs-stats.o dmabuf_selftests-y := \ selftest.o \ st-dma-fence.o \ - st-dma-fence-chain.o + st-dma-fence-chain.o \ + st-dma-fence-unwrap.o \ + st-dma-resv.o -obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o +dma-buf-objs-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o @@ -72,7 +74,7 @@ Signed-off-by: Felix Fietkau +MODULE_LICENSE("GPL"); --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -4216,6 +4216,7 @@ int wake_up_state(struct task_struct *p, +@@ -4175,6 +4175,7 @@ int wake_up_state(struct task_struct *p, { return try_to_wake_up(p, state, 0); } diff --git a/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch index d1f36e716ed..2722266722e 100644 --- a/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch +++ b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch @@ -12,10 +12,10 @@ Subject: [PATCH] of/ftd: add device tree cmdline @@ -1158,6 +1158,9 @@ int __init early_init_dt_scan_chosen(uns p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) - strlcpy(data, p, min(l, COMMAND_LINE_SIZE)); + strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); + p = of_get_flat_dt_prop(node, "bootargs-append", &l); + if (p != NULL && l > 0) -+ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); ++ strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); /* * CONFIG_CMDLINE is meant to be a default in case nothing else From e41466edab3302b5c667341a06b9fead6eb3436a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 02:36:35 +0200 Subject: [PATCH 64/88] generic: 6.1: manually refresh mglru patch with new kernel version Refresh mglru patch for new kernel version due to very fun backport changing name from folio to pages. Signed-off-by: Christian Marangi --- .../020-v6.3-19-mm-add-vma_has_recency.patch | 30 ++---- ...-rename-lru_gen_struct-to-lru_gen_pa.patch | 100 +++++++++--------- ...-rename-lrugen-lists-to-lrugen-pages.patch | 88 +++++++-------- ...U-remove-eviction-fairness-safeguard.patch | 29 +++-- ...-LRU-remove-aging-fairness-safeguard.patch | 16 +-- ...lti-gen-LRU-shuffle-should_run_aging.patch | 8 +- ...-gen-LRU-per-node-lru_gen_page-lists.patch | 32 +++--- ...i-gen-LRU-clarify-scan_control-flags.patch | 28 ++--- ...m-multi-gen-LRU-avoid-futile-retries.patch | 2 +- 9 files changed, 162 insertions(+), 171 deletions(-) diff --git a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch index d740c5bd1d5..eb0181301c5 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch @@ -58,9 +58,9 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -333,4 +333,13 @@ static __always_inline void del_page_fro - update_lru_size(lruvec, page_lru(page), page_zonenum(page), - -thp_nr_pages(page)); +@@ -606,5 +606,13 @@ static __always_inline void del_page_fro + make_pte_marker(PTE_MARKER_UFFD_WP)); + #endif } + +static inline bool vma_has_recency(struct vm_area_struct *vma) @@ -70,18 +70,10 @@ Signed-off-by: Andrew Morton + + return true; +} -+ + #endif --- a/mm/memory.c +++ b/mm/memory.c -@@ -41,6 +41,7 @@ - - #include - #include -+#include - #include - #include - #include @@ -1353,8 +1354,7 @@ again: force_flush = 1; set_page_dirty(page); @@ -121,10 +113,10 @@ Signed-off-by: Andrew Morton - /* - * Don't treat a reference through - * a sequentially read mapping as such. -- * If the page has been used in another mapping, +- * If the folio has been used in another mapping, - * we will catch it; if this other mapping is - * already gone, the unmap path will have set -- * PG_referenced or activated the page. +- * the referenced flag or activated the folio. - */ - if (likely(!(vma->vm_flags & VM_SEQ_READ))) - referenced++; @@ -157,10 +149,10 @@ Signed-off-by: Andrew Morton return false; @@ -876,6 +878,7 @@ int page_referenced(struct page *page, - .rmap_one = page_referenced_one, .arg = (void *)&pra, - .anon_lock = page_lock_anon_vma_read, -+ .invalid_vma = invalid_page_referenced_vma, + .anon_lock = folio_lock_anon_vma_read, + .try_lock = true, ++ .invalid_vma = invalid_folio_referenced_vma, }; *vm_flags = 0; @@ -174,10 +166,10 @@ Signed-off-by: Andrew Morton - * cgroups - */ - if (memcg) { -- rwc.invalid_vma = invalid_page_referenced_vma; +- rwc.invalid_vma = invalid_folio_referenced_vma; - } - - rmap_walk(page, &rwc); + rmap_walk(folio, &rwc); *vm_flags = pra.vm_flags; --- a/mm/vmscan.c diff --git a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch index 4e09173681f..960661a0e65 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch @@ -2,7 +2,7 @@ From 348fdbada9fb3f0bf1a53651be46319105af187f Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:18:59 -0700 Subject: [PATCH 21/29] mm: multi-gen LRU: rename lru_gen_struct to - lru_gen_page + lru_gen_folio Patch series "mm: multi-gen LRU: memcg LRU", v3. @@ -10,7 +10,7 @@ Overview ======== An memcg LRU is a per-node LRU of memcgs. It is also an LRU of LRUs, -since each node and memcg combination has an LRU of pages (see +since each node and memcg combination has an LRU of folios (see mem_cgroup_lruvec()). Its goal is to improve the scalability of global reclaim, which is @@ -24,7 +24,7 @@ the worst-case complexity O(n). Therefore, on average, it has a sublinear complexity in contrast to the current linear complexity. The basic structure of an memcg LRU can be understood by an analogy to -the active/inactive LRU (of pages): +the active/inactive LRU (of folios): 1. It has the young and the old (generations), i.e., the counterparts to the active and the inactive; 2. The increment of max_seq triggers promotion, i.e., the counterpart @@ -101,7 +101,7 @@ The following is a simple test to quickly verify its effectiveness. This patch (of 8): -The new name lru_gen_page will be more distinct from the coming +The new name lru_gen_folio will be more distinct from the coming lru_gen_memcg. Link: https://lkml.kernel.org/r/20221222041905.2431096-1-yuzhao@google.com @@ -125,31 +125,31 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h @@ -168,7 +168,7 @@ static inline void lru_gen_update_size(s - int zone = page_zonenum(page); - int delta = thp_nr_pages(page); + int zone = folio_zonenum(folio); + int delta = thp_nr_folios(folio); enum lru_list lru = type * LRU_INACTIVE_FILE; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); -@@ -214,7 +214,7 @@ static inline bool lru_gen_add_page(stru - int gen = page_lru_gen(page); - int type = page_is_file_lru(page); - int zone = page_zonenum(page); +@@ -214,7 +214,7 @@ static inline bool lru_gen_add_folio(stru + int gen = folio_lru_gen(folio); + int type = folio_is_file_lru(folio); + int zone = folio_zonenum(folio); - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; - VM_WARN_ON_ONCE_PAGE(gen != -1, page); + VM_WARN_ON_ONCE_FOLIO(gen != -1, folio); --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -394,7 +394,7 @@ enum { - * The number of pages in each generation is eventually consistent and therefore + * The number of folios in each generation is eventually consistent and therefore * can be transiently negative when reset_batch_size() is pending. */ -struct lru_gen_struct { -+struct lru_gen_page { ++struct lru_gen_folio { /* the aging increments the youngest generation number */ unsigned long max_seq; /* the eviction increments the oldest generation numbers */ @@ -158,7 +158,7 @@ Signed-off-by: Andrew Morton /* the lruvec under reclaim */ struct lruvec *lruvec; - /* unstable max_seq from lru_gen_struct */ -+ /* unstable max_seq from lru_gen_page */ ++ /* unstable max_seq from lru_gen_folio */ unsigned long max_seq; /* the next address within an mm to scan */ unsigned long next_addr; @@ -167,7 +167,7 @@ Signed-off-by: Andrew Morton #ifdef CONFIG_LRU_GEN /* evictable pages divided into generations */ - struct lru_gen_struct lrugen; -+ struct lru_gen_page lrugen; ++ struct lru_gen_folio lrugen; /* to concurrently iterate lru_gen_mm_list */ struct lru_gen_mm_state mm_state; #endif @@ -178,7 +178,7 @@ Signed-off-by: Andrew Morton static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) { - /* see the comment on lru_gen_struct */ -+ /* see the comment on lru_gen_page */ ++ /* see the comment on lru_gen_folio */ return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; @@ -187,7 +187,7 @@ Signed-off-by: Andrew Morton struct ctrl_pos *pos) { - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; int hist = lru_hist_from_seq(lrugen->min_seq[type]); pos->refaulted = lrugen->avg_refaulted[type][tier] + @@ -196,25 +196,25 @@ Signed-off-by: Andrew Morton { int hist, tier; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; -@@ -3408,7 +3408,7 @@ static int page_update_gen(struct page * - static int page_inc_gen(struct lruvec *lruvec, struct page *page, bool reclaiming) +@@ -3408,7 +3408,7 @@ static int folio_update_gen(struct folio * + static int folio_inc_gen(struct lruvec *lruvec, struct folio *folio, bool reclaiming) { - int type = page_is_file_lru(page); + int type = folio_is_file_lru(folio); - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); - unsigned long new_flags, old_flags = READ_ONCE(page->flags); + unsigned long new_flags, old_flags = READ_ONCE(folio->flags); @@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) { int gen, type, zone; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; walk->batched = 0; @@ -223,7 +223,7 @@ Signed-off-by: Andrew Morton int zone; int remaining = MAX_LRU_BATCH; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); if (type == LRU_GEN_ANON && !can_swap) @@ -232,7 +232,7 @@ Signed-off-by: Andrew Morton int gen, type, zone; bool success = false; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; DEFINE_MIN_SEQ(lruvec); VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); @@ -241,7 +241,7 @@ Signed-off-by: Andrew Morton } - /* see the comment on lru_gen_struct */ -+ /* see the comment on lru_gen_page */ ++ /* see the comment on lru_gen_folio */ if (can_swap) { min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); @@ -250,7 +250,7 @@ Signed-off-by: Andrew Morton int prev, next; int type, zone; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; spin_lock_irq(&lruvec->lru_lock); @@ -259,7 +259,7 @@ Signed-off-by: Andrew Morton struct lru_gen_mm_walk *walk; struct mm_struct *mm = NULL; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); @@ -268,25 +268,25 @@ Signed-off-by: Andrew Morton unsigned long young = 0; unsigned long total = 0; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); for (type = !can_swap; type < ANON_AND_FILE; type++) { -@@ -4466,7 +4466,7 @@ static bool sort_page(struct lruvec *lru - int delta = thp_nr_pages(page); - int refs = page_lru_refs(page); +@@ -4466,7 +4466,7 @@ static bool sort_folio(struct lruvec *lru + int delta = thp_nr_folios(folio); + int refs = folio_lru_refs(folio); int tier = lru_tier_from_refs(refs); - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; - VM_WARN_ON_ONCE_PAGE(gen >= MAX_NR_GENS, page); + VM_WARN_ON_ONCE_folio(gen >= MAX_NR_GENS, folio); -@@ -4566,7 +4566,7 @@ static int scan_pages(struct lruvec *lru +@@ -4566,7 +4566,7 @@ static int scan_folios(struct lruvec *lru int scanned = 0; int isolated = 0; int remaining = MAX_LRU_BATCH; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); VM_WARN_ON_ONCE(!list_empty(list)); @@ -295,7 +295,7 @@ Signed-off-by: Andrew Morton static bool __maybe_unused state_is_valid(struct lruvec *lruvec) { - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; if (lrugen->enabled) { enum lru_list lru; @@ -304,7 +304,7 @@ Signed-off-by: Andrew Morton int type, tier; int hist = lru_hist_from_seq(seq); - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; for (tier = 0; tier < MAX_NR_TIERS; tier++) { seq_printf(m, " %10d", tier); @@ -313,7 +313,7 @@ Signed-off-by: Andrew Morton bool full = !debugfs_real_fops(m->file)->write; struct lruvec *lruvec = v; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; int nid = lruvec_pgdat(lruvec)->node_id; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); @@ -322,7 +322,7 @@ Signed-off-by: Andrew Morton int i; int gen, type, zone; - struct lru_gen_struct *lrugen = &lruvec->lrugen; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; lrugen->max_seq = MIN_NR_GENS + 1; lrugen->enabled = lru_gen_enabled(); @@ -333,16 +333,16 @@ Signed-off-by: Andrew Morton unsigned long min_seq; struct lruvec *lruvec; - struct lru_gen_struct *lrugen; -+ struct lru_gen_page *lrugen; - int type = page_is_file_lru(page); - int delta = thp_nr_pages(page); - int refs = page_lru_refs(page); -@@ -252,7 +252,7 @@ static void lru_gen_refault(struct page ++ struct lru_gen_folio *lrugen; + int type = folio_is_file_lru(folio); + int delta = thp_nr_folios(folio); + int refs = folio_lru_refs(folio); +@@ -252,7 +252,7 @@ static void lru_gen_refault(struct folio unsigned long token; unsigned long min_seq; struct lruvec *lruvec; - struct lru_gen_struct *lrugen; -+ struct lru_gen_page *lrugen; ++ struct lru_gen_folio *lrugen; struct mem_cgroup *memcg; struct pglist_data *pgdat; - int type = page_is_file_lru(page); + int type = folio_is_file_lru(folio); diff --git a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch index b548c1c8b3d..32b7b39f69a 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch @@ -2,9 +2,9 @@ From afd37e73db04c7e6b47411120ac5f6a7eca51fec Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:00 -0700 Subject: [PATCH 22/29] mm: multi-gen LRU: rename lrugen->lists[] to - lrugen->pages[] + lrugen->folios[] -lru_gen_page will be chained into per-node lists by the coming +lru_gen_folio will be chained into per-node lists by the coming lrugen->list. Link: https://lkml.kernel.org/r/20221222041905.2431096-3-yuzhao@google.com @@ -25,15 +25,15 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -246,9 +246,9 @@ static inline bool lru_gen_add_page(stru - lru_gen_update_size(lruvec, page, -1, gen); - /* for rotate_reclaimable_page() */ +@@ -246,9 +246,9 @@ static inline bool lru_gen_add_folio(stru + lru_gen_update_size(lruvec, folio, -1, gen); + /* for rotate_reclaimable_folio() */ if (reclaiming) -- list_add_tail(&page->lru, &lrugen->lists[gen][type][zone]); -+ list_add_tail(&page->lru, &lrugen->pages[gen][type][zone]); +- list_add_tail(&folio->lru, &lrugen->lists[gen][type][zone]); ++ list_add_tail(&folio->lru, &lrugen->folios[gen][type][zone]); else -- list_add(&page->lru, &lrugen->lists[gen][type][zone]); -+ list_add(&page->lru, &lrugen->pages[gen][type][zone]); +- list_add(&folio->lru, &lrugen->lists[gen][type][zone]); ++ list_add(&folio->lru, &lrugen->folios[gen][type][zone]); return true; } @@ -42,31 +42,31 @@ Signed-off-by: Andrew Morton @@ -302,7 +302,7 @@ enum lruvec_flags { * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the - * corresponding generation. The gen counter in page->flags stores gen+1 while + * corresponding generation. The gen counter in folio->flags stores gen+1 while - * a page is on one of lrugen->lists[]. Otherwise it stores 0. -+ * a page is on one of lrugen->pages[]. Otherwise it stores 0. ++ * a page is on one of lrugen->folios[]. Otherwise it stores 0. * - * A page is added to the youngest generation on faulting. The aging needs to - * check the accessed bit at least twice before handing this page over to the + * A folio is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this folio over to the @@ -314,8 +314,8 @@ enum lruvec_flags { * rest of generations, if they exist, are considered inactive. See * lru_gen_is_active(). * - * PG_active is always cleared while a page is on one of lrugen->lists[] so that - * the aging needs not to worry about it. And it's set again when a page -+ * PG_active is always cleared while a page is on one of lrugen->pages[] so ++ * PG_active is always cleared while a page is on one of lrugen->folios[] so + * that the aging needs not to worry about it. And it's set again when a page * considered active is isolated for non-reclaiming purposes, e.g., migration. - * See lru_gen_add_page() and lru_gen_del_page(). + * See lru_gen_add_folio() and lru_gen_del_folio(). * -@@ -402,7 +402,7 @@ struct lru_gen_page { +@@ -402,7 +402,7 @@ struct lru_gen_folio { /* the birth time of each generation in jiffies */ unsigned long timestamps[MAX_NR_GENS]; /* the multi-gen LRU lists, lazily sorted on eviction */ - struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; -+ struct list_head pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; ++ struct list_head folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the multi-gen LRU sizes, eventually consistent */ - long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + long nr_folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the exponential moving average of refaulted */ --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -75,16 +75,16 @@ Signed-off-by: Andrew Morton /* prevent cold/hot inversion if force_scan is true */ for (zone = 0; zone < MAX_NR_ZONES; zone++) { - struct list_head *head = &lrugen->lists[old_gen][type][zone]; -+ struct list_head *head = &lrugen->pages[old_gen][type][zone]; ++ struct list_head *head = &lrugen->folios[old_gen][type][zone]; while (!list_empty(head)) { - struct page *page = lru_to_page(head); + struct folio *folio = lru_to_folio(head); @@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *l - VM_WARN_ON_ONCE_PAGE(page_zonenum(page) != zone, page); + VM_WARN_ON_ONCE_folio(folio_zonenum(folio) != zone, folio); - new_gen = page_inc_gen(lruvec, page, false); -- list_move_tail(&page->lru, &lrugen->lists[new_gen][type][zone]); -+ list_move_tail(&page->lru, &lrugen->pages[new_gen][type][zone]); + new_gen = folio_inc_gen(lruvec, folio, false); +- list_move_tail(&folio->lru, &lrugen->lists[new_gen][type][zone]); ++ list_move_tail(&folio->lru, &lrugen->folios[new_gen][type][zone]); if (!--remaining) return false; @@ -93,52 +93,52 @@ Signed-off-by: Andrew Morton for (zone = 0; zone < MAX_NR_ZONES; zone++) { - if (!list_empty(&lrugen->lists[gen][type][zone])) -+ if (!list_empty(&lrugen->pages[gen][type][zone])) ++ if (!list_empty(&lrugen->folios[gen][type][zone])) goto next; } -@@ -4491,7 +4491,7 @@ static bool sort_page(struct lruvec *lru +@@ -4491,7 +4491,7 @@ static bool sort_folio(struct lruvec *lru /* promoted */ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { -- list_move(&page->lru, &lrugen->lists[gen][type][zone]); -+ list_move(&page->lru, &lrugen->pages[gen][type][zone]); +- list_move(&folio->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&folio->lru, &lrugen->folios[gen][type][zone]); return true; } -@@ -4500,7 +4500,7 @@ static bool sort_page(struct lruvec *lru +@@ -4500,7 +4500,7 @@ static bool sort_folio(struct lruvec *lru int hist = lru_hist_from_seq(lrugen->min_seq[type]); - gen = page_inc_gen(lruvec, page, false); -- list_move_tail(&page->lru, &lrugen->lists[gen][type][zone]); -+ list_move_tail(&page->lru, &lrugen->pages[gen][type][zone]); + gen = folio_inc_gen(lruvec, folio, false); +- list_move_tail(&folio->lru, &lrugen->lists[gen][type][zone]); ++ list_move_tail(&folio->lru, &lrugen->folios[gen][type][zone]); WRITE_ONCE(lrugen->protected[hist][type][tier - 1], lrugen->protected[hist][type][tier - 1] + delta); -@@ -4512,7 +4512,7 @@ static bool sort_page(struct lruvec *lru - if (PageLocked(page) || PageWriteback(page) || - (type == LRU_GEN_FILE && PageDirty(page))) { - gen = page_inc_gen(lruvec, page, true); -- list_move(&page->lru, &lrugen->lists[gen][type][zone]); -+ list_move(&page->lru, &lrugen->pages[gen][type][zone]); +@@ -4512,7 +4512,7 @@ static bool sort_folio(struct lruvec *lru + if (folioLocked(folio) || folioWriteback(folio) || + (type == LRU_GEN_FILE && folioDirty(folio))) { + gen = folio_inc_gen(lruvec, folio, true); +- list_move(&folio->lru, &lrugen->lists[gen][type][zone]); ++ list_move(&folio->lru, &lrugen->folios[gen][type][zone]); return true; } -@@ -4579,7 +4579,7 @@ static int scan_pages(struct lruvec *lru +@@ -4579,7 +4579,7 @@ static int scan_folios(struct lruvec *lru for (zone = sc->reclaim_idx; zone >= 0; zone--) { LIST_HEAD(moved); int skipped = 0; - struct list_head *head = &lrugen->lists[gen][type][zone]; -+ struct list_head *head = &lrugen->pages[gen][type][zone]; ++ struct list_head *head = &lrugen->folios[gen][type][zone]; while (!list_empty(head)) { - struct page *page = lru_to_page(head); + struct folio *folio = lru_to_folio(head); @@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_vali int gen, type, zone; for_each_gen_type_zone(gen, type, zone) { - if (!list_empty(&lrugen->lists[gen][type][zone])) -+ if (!list_empty(&lrugen->pages[gen][type][zone])) ++ if (!list_empty(&lrugen->folios[gen][type][zone])) return false; } } @@ -147,7 +147,7 @@ Signed-off-by: Andrew Morton for_each_gen_type_zone(gen, type, zone) { - struct list_head *head = &lruvec->lrugen.lists[gen][type][zone]; -+ struct list_head *head = &lruvec->lrugen.pages[gen][type][zone]; ++ struct list_head *head = &lruvec->lrugen.folios[gen][type][zone]; while (!list_empty(head)) { bool success; @@ -156,7 +156,7 @@ Signed-off-by: Andrew Morton for_each_gen_type_zone(gen, type, zone) - INIT_LIST_HEAD(&lrugen->lists[gen][type][zone]); -+ INIT_LIST_HEAD(&lrugen->pages[gen][type][zone]); ++ INIT_LIST_HEAD(&lrugen->folios[gen][type][zone]); lruvec->mm_state.seq = MIN_NR_GENS; init_waitqueue_head(&lruvec->mm_state.wait); diff --git a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch index 2bb6e12a5ae..01babfecb1e 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch @@ -4,7 +4,7 @@ Date: Wed, 21 Dec 2022 21:19:01 -0700 Subject: [PATCH 23/29] mm: multi-gen LRU: remove eviction fairness safeguard Recall that the eviction consumes the oldest generation: first it -bucket-sorts pages whose gen counters were updated by the aging and +bucket-sorts folios whose gen counters were updated by the aging and reclaims the rest; then it increments lrugen->min_seq. The current eviction fairness safeguard for global reclaim has a @@ -61,13 +61,13 @@ Signed-off-by: Andrew Morton static bool writeback_throttling_sane(struct scan_control *sc) { return true; -@@ -4722,8 +4732,7 @@ static int isolate_pages(struct lruvec * +@@ -4722,8 +4732,7 @@ static int isolate_folios(struct lruvec * return scanned; } --static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness, -- bool *need_swapping) -+static int evict_pages(struct lruvec *lruvec, struct scan_control *sc, int swappiness) +-static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swappiness, +- bool *need_swapping) ++static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swappiness) { int type; int scanned; @@ -81,7 +81,7 @@ Signed-off-by: Andrew Morton return scanned; } -@@ -4853,68 +4859,26 @@ done: +@@ -4853,67 +4859,26 @@ done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } @@ -93,7 +93,7 @@ Signed-off-by: Andrew Morton - DEFINE_MAX_SEQ(lruvec); - - if (!current_is_kswapd()) { -- /* age each memcg once to ensure fairness */ +- /* age each memcg at most once to ensure fairness */ - if (max_seq - seq > 1) - return true; - @@ -118,10 +118,9 @@ Signed-off-by: Andrew Morton - - /* - * A minimum amount of work was done under global memory pressure. For -- * kswapd, it may be overshooting. For direct reclaim, the target isn't -- * met, and yet the allocation may still succeed, since kswapd may have -- * caught up. In either case, it's better to stop now, and restart if -- * necessary. +- * kswapd, it may be overshooting. For direct reclaim, the allocation +- * may succeed if all suitable zones are somewhat safe. In either case, +- * it's better to stop now, and restart later if necessary. - */ - for (i = 0; i <= sc->reclaim_idx; i++) { - unsigned long wmark; @@ -163,8 +162,8 @@ Signed-off-by: Andrew Morton if (!nr_to_scan) goto done; -- delta = evict_pages(lruvec, sc, swappiness, &need_swapping); -+ delta = evict_pages(lruvec, sc, swappiness); +- delta = evict_folios(lruvec, sc, swappiness, &need_swapping); ++ delta = evict_folios(lruvec, sc, swappiness); if (!delta) goto done; @@ -181,8 +180,8 @@ Signed-off-by: Andrew Morton if (sc->nr_reclaimed >= nr_to_reclaim) return 0; -- if (!evict_pages(lruvec, sc, swappiness, NULL)) -+ if (!evict_pages(lruvec, sc, swappiness)) +- if (!evict_folios(lruvec, sc, swappiness, NULL)) ++ if (!evict_folios(lruvec, sc, swappiness)) return 0; cond_resched(); diff --git a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch index 316217ed028..2f4fb911f5b 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch @@ -4,13 +4,13 @@ Date: Wed, 21 Dec 2022 21:19:02 -0700 Subject: [PATCH 24/29] mm: multi-gen LRU: remove aging fairness safeguard Recall that the aging produces the youngest generation: first it scans -for accessed pages and updates their gen counters; then it increments +for accessed folios and updates their gen counters; then it increments lrugen->max_seq. The current aging fairness safeguard for kswapd uses two passes to ensure the fairness to multiple eligible memcgs. On the first pass, which is shared with the eviction, it checks whether all eligible -memcgs are low on cold pages. If so, it requires a second pass, on +memcgs are low on cold folios. If so, it requires a second pass, on which it ages all those memcgs at the same time. With memcg LRU, the aging, while ensuring eventual fairness, will run @@ -56,11 +56,11 @@ Signed-off-by: Andrew Morton int gen, type, zone; @@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruv unsigned long total = 0; - struct lru_gen_page *lrugen = &lruvec->lrugen; + struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MIN_SEQ(lruvec); + -+ /* whether this lruvec is completely out of cold pages */ ++ /* whether this lruvec is completely out of cold folios */ + if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { + *nr_to_scan = 0; + return true; @@ -90,7 +90,7 @@ Signed-off-by: Andrew Morton + int gen, type, zone; + unsigned long total = 0; + bool can_swap = get_swappiness(lruvec, sc); -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); DEFINE_MIN_SEQ(lruvec); @@ -134,7 +134,7 @@ Signed-off-by: Andrew Morton - if (!nr_to_scan && sc->priority != DEF_PRIORITY) - return false; - } -+ /* see the comment on lru_gen_page */ ++ /* see the comment on lru_gen_folio */ + gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); + birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); @@ -242,7 +242,7 @@ Signed-off-by: Andrew Morton - return nr_to_scan; -done: - return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; -+ /* skip this lruvec as it's low on cold pages */ ++ /* skip this lruvec as it's low on cold folios */ + return 0; } @@ -267,7 +267,7 @@ Signed-off-by: Andrew Morton - goto done; + break; - delta = evict_pages(lruvec, sc, swappiness); + delta = evict_folios(lruvec, sc, swappiness); if (!delta) - goto done; + break; diff --git a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch index 391ee6e67ce..2e6b8b9c9b2 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -32,11 +32,11 @@ Signed-off-by: Andrew Morton - unsigned long old = 0; - unsigned long young = 0; - unsigned long total = 0; -- struct lru_gen_page *lrugen = &lruvec->lrugen; +- struct lru_gen_folio *lrugen = &lruvec->lrugen; - struct mem_cgroup *memcg = lruvec_memcg(lruvec); - DEFINE_MIN_SEQ(lruvec); - -- /* whether this lruvec is completely out of cold pages */ +- /* whether this lruvec is completely out of cold folios */ - if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { - *nr_to_scan = 0; - return true; @@ -101,11 +101,11 @@ Signed-off-by: Andrew Morton + unsigned long old = 0; + unsigned long young = 0; + unsigned long total = 0; -+ struct lru_gen_page *lrugen = &lruvec->lrugen; ++ struct lru_gen_folio *lrugen = &lruvec->lrugen; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + DEFINE_MIN_SEQ(lruvec); + -+ /* whether this lruvec is completely out of cold pages */ ++ /* whether this lruvec is completely out of cold folios */ + if (min_seq[!can_swap] + MIN_NR_GENS > max_seq) { + *nr_to_scan = 0; + return true; diff --git a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch index f54e828de10..5aa7473c21b 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch @@ -1,7 +1,7 @@ From fa6363828d314e837c5f79e97ea5e8c0d2f7f062 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:04 -0700 -Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_page lists +Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_folio lists For each node, memcgs are divided into two generations: the old and the young. For each generation, memcgs are randomly sharded into @@ -63,7 +63,7 @@ Signed-off-by: Andrew Morton include/linux/mm_inline.h | 17 ++ include/linux/mmzone.h | 117 +++++++++++- mm/memcontrol.c | 16 ++ - mm/page_alloc.c | 1 + + mm/folio_alloc.c | 1 + mm/vmscan.c | 373 +++++++++++++++++++++++++++++++++---- 6 files changed, 499 insertions(+), 35 deletions(-) @@ -123,7 +123,7 @@ Signed-off-by: Andrew Morton + return 0; +} + - static inline bool lru_gen_add_page(struct lruvec *lruvec, struct page *page, bool reclaiming) + static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, bool reclaiming) { return false; --- a/include/linux/mmzone.h @@ -136,7 +136,7 @@ Signed-off-by: Andrew Morton #include #include #include -@@ -357,6 +358,15 @@ struct page_vma_mapped_walk; +@@ -357,6 +358,15 @@ struct folio_vma_mapped_walk; #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) @@ -152,16 +152,16 @@ Signed-off-by: Andrew Morton #ifdef CONFIG_LRU_GEN enum { -@@ -416,6 +426,14 @@ struct lru_gen_page { +@@ -416,6 +426,14 @@ struct lru_gen_folio { atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; /* whether the multi-gen LRU is enabled */ bool enabled; +#ifdef CONFIG_MEMCG -+ /* the memcg generation this lru_gen_page belongs to */ ++ /* the memcg generation this lru_gen_folio belongs to */ + u8 gen; -+ /* the list segment this lru_gen_page belongs to */ ++ /* the list segment this lru_gen_folio belongs to */ + u8 seg; -+ /* per-node lru_gen_page list for global reclaim */ ++ /* per-node lru_gen_folio list for global reclaim */ + struct hlist_nulls_node list; +#endif }; @@ -216,9 +216,9 @@ Signed-off-by: Andrew Morton +struct lru_gen_memcg { + /* the per-node memcg generation counter */ + unsigned long seq; -+ /* each memcg has one lru_gen_page per node */ ++ /* each memcg has one lru_gen_folio per node */ + unsigned long nr_memcgs[MEMCG_NR_GENS]; -+ /* per-node lru_gen_page list for global reclaim */ ++ /* per-node lru_gen_folio list for global reclaim */ + struct hlist_nulls_head fifo[MEMCG_NR_GENS][MEMCG_NR_BINS]; + /* protects the above */ + spinlock_t lock; @@ -294,7 +294,7 @@ Signed-off-by: Andrew Morton #ifdef CONFIG_LRU_GEN /* kswap mm walk data */ struct lru_gen_mm_walk mm_walk; -+ /* lru_gen_page list */ ++ /* lru_gen_folio list */ + struct lru_gen_memcg memcg_lru; #endif @@ -306,7 +306,7 @@ Signed-off-by: Andrew Morton struct mem_cgroup_tree_per_node *mctz; + if (lru_gen_enabled()) { -+ struct lruvec *lruvec = &mem_cgroup_page_nodeinfo(memcg, page)->lruvec; ++ struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; + + /* see the comment on MEMCG_NR_GENS */ + if (soft_limit_excess(memcg) && lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) @@ -315,7 +315,7 @@ Signed-off-by: Andrew Morton + return; + } + - mctz = soft_limit_tree_from_page(page); + mctz = soft_limit_tree.rb_tree_per_node[nid]; if (!mctz) return; @@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_recl @@ -430,7 +430,7 @@ Signed-off-by: Andrew Morton - try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false); - - /* skip this lruvec as it's low on cold pages */ + /* skip this lruvec as it's low on cold folios */ - return 0; + return try_to_inc_max_seq(lruvec, max_seq, sc, can_swap, false) ? -1 : 0; } @@ -476,7 +476,7 @@ Signed-off-by: Andrew Morton + if (nr_to_scan <= 0) break; - delta = evict_pages(lruvec, sc, swappiness); + delta = evict_folios(lruvec, sc, swappiness); @@ -4912,10 +4895,250 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } @@ -532,7 +532,7 @@ Signed-off-by: Andrew Morton + int bin; + int first_bin; + struct lruvec *lruvec; -+ struct lru_gen_page *lrugen; ++ struct lru_gen_folio *lrugen; + const struct hlist_nulls_node *pos; + int op = 0; + struct mem_cgroup *memcg = NULL; diff --git a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch index 882f29e9892..029141b2d3e 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -10,10 +10,10 @@ Among the flags in scan_control: opportunistically skip the aging path, since it is considered less latency sensitive. 3. !(sc->gfp_mask & __GFP_IO), which indicates IO constraint, lowers - swappiness to prioritize file LRU, since clean file pages are more + swappiness to prioritize file LRU, since clean file folios are more likely to exist. -4. sc->may_writepage and sc->may_unmap, which indicates opportunistic - reclaim, are rejected, since unmapped clean pages are already +4. sc->may_writefolio and sc->may_unmap, which indicates opportunistic + reclaim, are rejected, since unmapped clean folios are already prioritized. Scanning for more of them is likely futile and can cause high reclaim latency when there is a large number of memcgs. @@ -43,7 +43,7 @@ Signed-off-by: Andrew Morton + return 0; + if (!can_demote(pgdat->node_id, sc) && - mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) + mem_cgroup_get_nr_swap_folios(memcg) < MIN_LRU_BATCH) return 0; @@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruve } while (err == -EAGAIN); @@ -78,24 +78,24 @@ Signed-off-by: Andrew Morton - VM_WARN_ON_ONCE(sc->memcg_low_reclaim); - - /* see the comment on lru_gen_page */ + /* see the comment on lru_gen_folio */ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -@@ -4472,12 +4473,8 @@ static bool isolate_page(struct lruvec * +@@ -4472,12 +4473,8 @@ static bool isolate_folio(struct lruvec * { bool success; - /* unmapping inhibited */ -- if (!sc->may_unmap && page_mapped(page)) +- if (!sc->may_unmap && folio_mapped(folio)) - return false; - /* swapping inhibited */ - if (!(sc->may_writepage && (sc->gfp_mask & __GFP_IO)) && + if (!(sc->gfp_mask & __GFP_IO) && - (PageDirty(page) || - (PageAnon(page) && !PageSwapCache(page)))) + (folio_test_dirty(folio) || + (folio_test_anon(folio) && !folio_test_swapcache(folio)))) return false; -@@ -4574,9 +4571,8 @@ static int scan_pages(struct lruvec *lru +@@ -4574,9 +4571,8 @@ static int scan_folios(struct lruvec *lru __count_vm_events(PGSCAN_ANON + type, isolated); /* @@ -123,7 +123,7 @@ Signed-off-by: Andrew Morton unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + int swappiness = get_swappiness(lruvec, sc); + -+ /* clean file pages are more likely to exist */ ++ /* clean file folios are more likely to exist */ + if (swappiness && !(sc->gfp_mask & __GFP_IO)) + swappiness = 1; @@ -151,7 +151,7 @@ Signed-off-by: Andrew Morton blk_start_plug(&plug); - set_mm_walk(lruvec_pgdat(lruvec)); -+ set_mm_walk(NULL, false); ++ set_mm_walk(NULL, sc->proactive); if (try_to_shrink_lruvec(lruvec, sc)) lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); @@ -160,7 +160,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(!global_reclaim(sc)); + /* -+ * Unmapped clean pages are already prioritized. Scanning for more of ++ * Unmapped clean folios are already prioritized. Scanning for more of + * them is likely futile and can cause high reclaim latency when there + * is a large number of memcgs. + */ @@ -172,7 +172,7 @@ Signed-off-by: Andrew Morton blk_start_plug(&plug); - set_mm_walk(pgdat); -+ set_mm_walk(pgdat, false); ++ set_mm_walk(NULL, sc->proactive); set_initial_priority(pgdat, sc); diff --git a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch index 2d19d0d7da1..62904e16553 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -34,7 +34,7 @@ Signed-off-by: Andrew Morton int bin; int first_bin; struct lruvec *lruvec; - struct lru_gen_page *lrugen; + struct lru_gen_folio *lrugen; + struct mem_cgroup *memcg; const struct hlist_nulls_node *pos; - int op = 0; From 7f7ee27d5ffabd26fb9aba09c2c2df2c91b56185 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 20 Oct 2022 03:45:31 +0200 Subject: [PATCH 65/88] generic: 6.1: add patch to compile ieee8211 headers With kernel 6.1 ieee2111_ptr is not compiled by default. Add pending patch to restore this to make backports project compatible. Signed-off-by: Christian Marangi --- target/linux/generic/config-6.1 | 1 + ...0211_ptr-even-with-no-CFG82111-suppo.patch | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index f13af8ba268..83ce378c05c 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -876,6 +876,7 @@ CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y # CONFIG_CEPH_FS is not set # CONFIG_CEPH_LIB is not set # CONFIG_CFG80211 is not set +CONFIG_CFG80211_HEADERS=y # CONFIG_CFG80211_CERTIFICATION_ONUS is not set # CONFIG_CGROUPS is not set # CONFIG_CGROUP_MISC is not set diff --git a/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch b/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch new file mode 100644 index 00000000000..b736ecc75a3 --- /dev/null +++ b/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch @@ -0,0 +1,68 @@ +From 686c603f67ae87bf21a61b5e4b1564443f41c3ee Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 20 Oct 2022 03:34:43 +0200 +Subject: [PATCH] net: permit ieee80211_ptr even with no CFG82111 support + +Introduce a new flag CONFIG_CFG80211_HEADERS to compile in ieee80211_ptr +even if CFG80211 support is not compiled in. This is needed for the +backports project and for any downstream wireless driver that loads in +the kernel dynamically. + +Signed-off-by: Christian Marangi +--- + include/linux/netdevice.h | 2 +- + net/batman-adv/hard-interface.c | 2 +- + net/wireless/Kconfig | 4 ++++ + 3 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h +index eddf8ee270e7..1ac7390772de 100644 +--- a/include/linux/netdevice.h ++++ b/include/linux/netdevice.h +@@ -2156,7 +2156,7 @@ struct net_device { + #if IS_ENABLED(CONFIG_AX25) + void *ax25_ptr; + #endif +-#if IS_ENABLED(CONFIG_CFG80211) ++#if IS_ENABLED(CONFIG_CFG80211_HEADERS) + struct wireless_dev *ieee80211_ptr; + #endif + #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN) +diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c +index 41c1ad33d009..58a1c5999b44 100644 +--- a/net/batman-adv/hard-interface.c ++++ b/net/batman-adv/hard-interface.c +@@ -308,7 +308,7 @@ static bool batadv_is_cfg80211_netdev(struct net_device *net_device) + if (!net_device) + return false; + +-#if IS_ENABLED(CONFIG_CFG80211) ++#if IS_ENABLED(CONFIG_CFG80211_HEADERS) + /* cfg80211 drivers have to set ieee80211_ptr */ + if (net_device->ieee80211_ptr) + return true; +diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig +index f620acd2a0f5..9f1aa9ec9fa3 100644 +--- a/net/wireless/Kconfig ++++ b/net/wireless/Kconfig +@@ -26,6 +26,7 @@ config CFG80211 + # using a different algorithm, though right now they shouldn't + # (this is here rather than below to allow it to be a module) + select CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS ++ select CFG80211_HEADERS + help + cfg80211 is the Linux wireless LAN (802.11) configuration API. + Enable this if you have a wireless device. +@@ -36,6 +37,9 @@ config CFG80211 + + When built as a module it will be called cfg80211. + ++config CFG80211_HEADERS ++ bool "cfg80211 - headers support" ++ + if CFG80211 + + config NL80211_TESTMODE +-- +2.37.2 + From ce345dd0df8a0c5cdef09a8a8d6f0a1e3188e7d0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 01:12:04 +0200 Subject: [PATCH 66/88] generic: 6.1: add pending OPP set opp improvement patch Add pending OPP set opp improvement patch to better handle _set_opp function in clock scaling. Signed-off-by: Christian Marangi --- ...e-old-opp-to-config_clks-on-_set_opp.patch | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch diff --git a/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch b/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch new file mode 100644 index 00000000000..477b10c7f29 --- /dev/null +++ b/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch @@ -0,0 +1,117 @@ +From fd59b838dd90452f61a17dc9e5ff175205003068 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 15 Sep 2022 18:49:43 +0200 +Subject: [PATCH] OPP: Provide old opp to config_clks on _set_opp + +With the target opp, also pass the old opp to config_clks function. +This can be useful when a driver needs to take decision on what fequency +to set based on what is the current frequency without using a +clk_get_freq call. +Update the only user of custom config_clks (tegra30 devfreq driver) to +this new implementation. + +Signed-off-by: Christian Marangi +--- + drivers/devfreq/tegra30-devfreq.c | 5 +++-- + drivers/opp/core.c | 11 ++++++----- + include/linux/pm_opp.h | 11 ++++++----- + 3 files changed, 15 insertions(+), 12 deletions(-) + +diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c +index 503376b894b6..92cdb6bf9a89 100644 +--- a/drivers/devfreq/tegra30-devfreq.c ++++ b/drivers/devfreq/tegra30-devfreq.c +@@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(struct device *dev, + + static int tegra_devfreq_config_clks_nop(struct device *dev, + struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, ++ void *data, bool scaling_down) + { + /* We want to skip clk configuration via dev_pm_opp_set_opp() */ + return 0; +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index e87567dbe99f..2f44ceaf8d3c 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -816,7 +816,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, + + static int + _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, +- struct dev_pm_opp *opp, void *data, bool scaling_down) ++ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, ++ void *data, bool scaling_down) + { + unsigned long *target = data; + unsigned long freq; +@@ -848,8 +849,8 @@ _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, + * the order in which they are present in the array while scaling up. + */ + int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down) + { + int ret, i; + +@@ -1121,7 +1122,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, + } + + if (opp_table->config_clks) { +- ret = opp_table->config_clks(dev, opp_table, opp, clk_data, scaling_down); ++ ret = opp_table->config_clks(dev, opp_table, old_opp, opp, clk_data, scaling_down); + if (ret) + return ret; + } +@@ -1196,7 +1197,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) + * equivalent to a clk_set_rate() + */ + if (!_get_opp_count(opp_table)) { +- ret = opp_table->config_clks(dev, opp_table, NULL, ++ ret = opp_table->config_clks(dev, opp_table, NULL, NULL, + &target_freq, false); + goto put_opp_table; + } +diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h +index dc1fb5890792..6c24a4f9fc49 100644 +--- a/include/linux/pm_opp.h ++++ b/include/linux/pm_opp.h +@@ -61,7 +61,8 @@ typedef int (*config_regulators_t)(struct device *dev, + struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp, + struct regulator **regulators, unsigned int count); + +-typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table, ++typedef int (*config_clks_t)(struct device *dev, ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, + struct dev_pm_opp *opp, void *data, bool scaling_down); + + /** +@@ -160,8 +161,8 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); + int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); + void dev_pm_opp_clear_config(int token); + int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down); ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down); + + struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); + int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); +@@ -346,8 +347,8 @@ static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_c + static inline void dev_pm_opp_clear_config(int token) {} + + static inline int dev_pm_opp_config_clks_simple(struct device *dev, +- struct opp_table *opp_table, struct dev_pm_opp *opp, void *data, +- bool scaling_down) ++ struct opp_table *opp_table, struct dev_pm_opp *old_opp, ++ struct dev_pm_opp *opp, void *data, bool scaling_down) + { + return -EOPNOTSUPP; + } +-- +2.37.2 + From f79af593830ef766f54e7931a0fad28134ae44c9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 18:06:14 +0200 Subject: [PATCH 67/88] generic: 6.1: refresh backport patches Refresh backport patches with make target/linux/refresh. Signed-off-by: Christian Marangi --- .../020-v6.3-19-mm-add-vma_has_recency.patch | 23 +++-- ...6.3-20-mm-support-POSIX_FADV_NOREUSE.patch | 10 +-- ...-rename-lru_gen_struct-to-lru_gen_pa.patch | 56 ++++++------ ...-rename-lrugen-lists-to-lrugen-pages.patch | 42 ++++----- ...U-remove-eviction-fairness-safeguard.patch | 16 ++-- ...-LRU-remove-aging-fairness-safeguard.patch | 20 ++--- ...lti-gen-LRU-shuffle-should_run_aging.patch | 4 +- ...-gen-LRU-per-node-lru_gen_page-lists.patch | 74 ++++++++-------- ...i-gen-LRU-clarify-scan_control-flags.patch | 28 +++--- ...-simplify-arch_has_hw_pte_young-chec.patch | 2 +- ...m-multi-gen-LRU-avoid-futile-retries.patch | 6 +- ...y-a-bit-code-find-partition-matching.patch | 4 +- ...find-OF-node-for-every-MTD-partition.patch | 4 +- ...T_DEV-for-partitions-marked-as-rootf.patch | 2 +- ...TP-Link-SafeLoader-partitions-table-.patch | 4 +- ...-mtd_otp_nvmem_add-to-handle-EPROBE_.patch | 6 +- ...net-page_pool-use-in_softirq-instead.patch | 8 +- ...611-v6.3-net-add-helper-eth_addr_add.patch | 2 +- ...cs-add-driver-for-MediaTek-SGMII-PCS.patch | 10 +-- ...net-mtk_wed-introduce-wed-wo-support.patch | 2 +- ..._wed-rename-tx_wdma-array-in-rx_wdma.patch | 6 +- ...mtk_wed-add-configure-wed-wo-support.patch | 48 +++++------ ..._eth_soc-remove-cpu_relax-in-mtk_pen.patch | 4 +- ..._wed-add-wcid-overwritten-support-fo.patch | 4 +- ..._wed-return-status-value-in-mtk_wdma.patch | 2 +- ...ethernet-mtk_wed-update-mtk_wed_stop.patch | 2 +- ...mtk_wed-add-mtk_wed_rx_reset-routine.patch | 14 +-- ..._wed-add-reset-to-tx_ring_setup-call.patch | 10 +-- ..._eth_soc-introduce-mtk_hw_reset-util.patch | 4 +- ..._eth_soc-introduce-mtk_hw_warm_reset.patch | 8 +- ..._eth_soc-align-reset-procedure-to-ve.patch | 14 +-- ..._eth_soc-add-dma-checks-to-mtk_hw_re.patch | 24 +++--- ..._wed-add-reset-reset_complete-callba.patch | 4 +- ..._wed-add-reset-to-rx_ring_setup-call.patch | 8 +- ..._eth_soc-increase-tx-ring-side-for-Q.patch | 14 +-- ..._eth_soc-avoid-port_mg-assignment-on.patch | 4 +- ..._eth_soc-implement-multi-queue-suppo.patch | 86 +++++++++---------- ...iatek-ppe-assign-per-port-queues-for.patch | 4 +- ..._eth_soc-compile-out-netsys-v2-code-.patch | 2 +- ...ort-for-DSA-rx-offloading-via-metada.patch | 8 +- ..._eth_soc-fix-VLAN-rx-hardware-accele.patch | 12 +-- ..._eth_soc-disable-hardware-DSA-untagg.patch | 4 +- ..._eth_soc-enable-special-tag-when-any.patch | 6 +- ..._eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch | 4 +- ..._wed-No-need-to-clear-memory-after-a.patch | 2 +- ..._wed-fix-possible-deadlock-if-mtk_we.patch | 2 +- ..._eth_soc-fix-tx-throughput-regressio.patch | 2 +- ...-mtk_eth_soc-add-definitions-for-PCS.patch | 4 +- ...ii-ensure-the-SGMII-PHY-is-powered-d.patch | 2 +- ...iatek-sgmii-fix-duplex-configuration.patch | 2 +- ...ethernet-mtk_eth_soc-reset-PCS-state.patch | 2 +- ...t-mtk_eth_soc-add-support-for-MT7981.patch | 16 ++-- ..._eth_soc-set-MDIO-bus-clock-frequenc.patch | 4 +- ..._eth_soc-switch-to-external-PCS-driv.patch | 24 +++--- ...t-dsa-mt7530-use-external-PCS-driver.patch | 22 ++--- ...or-Motorcomm-yt8521-gigabit-ethernet.patch | 4 +- ...net-phy-add-Motorcomm-YT8531S-phy-id.patch | 2 +- ...or-Motorcomm-yt8531-gigabit-ethernet.patch | 2 +- ...2-nvmem-core-introduce-NVMEM-layouts.patch | 2 +- ...p-Use-devm_platform_ioremap_resource.patch | 4 +- ...-of_parse_phandle_with_optional_args.patch | 2 +- ...ke-.-cells-optional-for-simple-props.patch | 2 +- ...operty-add-nvmem-cell-cells-property.patch | 2 +- ...vice-Ignore-modalias-of-reused-nodes.patch | 4 +- ...-ignore-error-code-in-of_device_ueve.patch | 2 +- ...002-of-Update-of_device_get_modalias.patch | 12 +-- ...v6.4-0003-of-Rename-of_modalias_node.patch | 10 +-- ...0004-of-Move-of_modalias-to-module.c.patch | 6 +- ...uest-module-helper-logic-to-module.c.patch | 6 +- 69 files changed, 380 insertions(+), 381 deletions(-) diff --git a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch index eb0181301c5..5335b804880 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch @@ -58,11 +58,10 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -606,5 +606,13 @@ static __always_inline void del_page_fro - make_pte_marker(PTE_MARKER_UFFD_WP)); +@@ -578,4 +578,12 @@ pte_install_uffd_wp_if_needed(struct vm_ #endif } -+ + +static inline bool vma_has_recency(struct vm_area_struct *vma) +{ + if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) @@ -70,11 +69,11 @@ Signed-off-by: Andrew Morton + + return true; +} - ++ #endif --- a/mm/memory.c +++ b/mm/memory.c -@@ -1353,8 +1354,7 @@ again: +@@ -1435,8 +1435,7 @@ again: force_flush = 1; set_page_dirty(page); } @@ -84,7 +83,7 @@ Signed-off-by: Andrew Morton mark_page_accessed(page); } rss[mm_counter(page)]--; -@@ -4795,8 +4795,8 @@ static inline void mm_account_fault(stru +@@ -5170,8 +5169,8 @@ static inline void mm_account_fault(stru #ifdef CONFIG_LRU_GEN static void lru_gen_enter_fault(struct vm_area_struct *vma) { @@ -97,7 +96,7 @@ Signed-off-by: Andrew Morton static void lru_gen_exit_fault(void) --- a/mm/rmap.c +++ b/mm/rmap.c -@@ -794,25 +794,14 @@ static bool page_referenced_one(struct p +@@ -823,25 +823,14 @@ static bool folio_referenced_one(struct } if (pvmw.pte) { @@ -126,8 +125,8 @@ Signed-off-by: Andrew Morton } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { if (pmdp_clear_flush_young_notify(vma, address, pvmw.pmd)) -@@ -846,7 +835,20 @@ static bool invalid_page_referenced_vma( - struct page_referenced_arg *pra = arg; +@@ -875,7 +864,20 @@ static bool invalid_folio_referenced_vma + struct folio_referenced_arg *pra = arg; struct mem_cgroup *memcg = pra->memcg; - if (!mm_match_cgroup(vma->vm_mm, memcg)) @@ -148,7 +147,7 @@ Signed-off-by: Andrew Morton return true; return false; -@@ -876,6 +878,7 @@ int page_referenced(struct page *page, +@@ -906,6 +908,7 @@ int folio_referenced(struct folio *folio .arg = (void *)&pra, .anon_lock = folio_lock_anon_vma_read, .try_lock = true, @@ -156,7 +155,7 @@ Signed-off-by: Andrew Morton }; *vm_flags = 0; -@@ -891,15 +894,6 @@ int page_referenced(struct page *page, +@@ -921,15 +924,6 @@ int folio_referenced(struct folio *folio return 1; } @@ -174,7 +173,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3486,7 +3486,10 @@ static int should_skip_vma(unsigned long +@@ -3766,7 +3766,10 @@ static int should_skip_vma(unsigned long if (is_vm_hugetlb_page(vma)) return true; diff --git a/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch b/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch index 3bb075bf367..b2b7c605ca5 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch @@ -81,9 +81,9 @@ Signed-off-by: Andrew Morton --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -167,6 +167,8 @@ typedef int (dio_iodone_t)(struct kiocb - /* File is stream-like */ - #define FMODE_STREAM ((__force fmode_t)0x200000) +@@ -166,6 +166,8 @@ typedef int (dio_iodone_t)(struct kiocb + /* File supports DIRECT IO */ + #define FMODE_CAN_ODIRECT ((__force fmode_t)0x400000) +#define FMODE_NOREUSE ((__force fmode_t)0x400000) + @@ -92,7 +92,7 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -339,6 +339,9 @@ static inline bool vma_has_recency(struc +@@ -583,6 +583,9 @@ static inline bool vma_has_recency(struc if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) return false; @@ -122,4 +122,4 @@ Signed-off-by: Andrew Morton + spin_unlock(&file->f_lock); break; case POSIX_FADV_DONTNEED: - if (!inode_write_congested(mapping->host)) + __filemap_fdatawrite_range(mapping, offset, endbyte, diff --git a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch index 960661a0e65..881ef4e528f 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch @@ -124,16 +124,16 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -168,7 +168,7 @@ static inline void lru_gen_update_size(s +@@ -178,7 +178,7 @@ static inline void lru_gen_update_size(s int zone = folio_zonenum(folio); - int delta = thp_nr_folios(folio); + int delta = folio_nr_pages(folio); enum lru_list lru = type * LRU_INACTIVE_FILE; - struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct lru_gen_folio *lrugen = &lruvec->lrugen; VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); -@@ -214,7 +214,7 @@ static inline bool lru_gen_add_folio(stru +@@ -224,7 +224,7 @@ static inline bool lru_gen_add_folio(str int gen = folio_lru_gen(folio); int type = folio_is_file_lru(folio); int zone = folio_zonenum(folio); @@ -144,8 +144,8 @@ Signed-off-by: Andrew Morton --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h -@@ -394,7 +394,7 @@ enum { - * The number of folios in each generation is eventually consistent and therefore +@@ -404,7 +404,7 @@ enum { + * The number of pages in each generation is eventually consistent and therefore * can be transiently negative when reset_batch_size() is pending. */ -struct lru_gen_struct { @@ -153,7 +153,7 @@ Signed-off-by: Andrew Morton /* the aging increments the youngest generation number */ unsigned long max_seq; /* the eviction increments the oldest generation numbers */ -@@ -451,7 +451,7 @@ struct lru_gen_mm_state { +@@ -461,7 +461,7 @@ struct lru_gen_mm_state { struct lru_gen_mm_walk { /* the lruvec under reclaim */ struct lruvec *lruvec; @@ -162,7 +162,7 @@ Signed-off-by: Andrew Morton unsigned long max_seq; /* the next address within an mm to scan */ unsigned long next_addr; -@@ -514,7 +514,7 @@ struct lruvec { +@@ -524,7 +524,7 @@ struct lruvec { unsigned long flags; #ifdef CONFIG_LRU_GEN /* evictable pages divided into generations */ @@ -173,7 +173,7 @@ Signed-off-by: Andrew Morton #endif --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2910,7 +2910,7 @@ static int get_nr_gens(struct lruvec *lr +@@ -3190,7 +3190,7 @@ static int get_nr_gens(struct lruvec *lr static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) { @@ -182,7 +182,7 @@ Signed-off-by: Andrew Morton return get_nr_gens(lruvec, LRU_GEN_FILE) >= MIN_NR_GENS && get_nr_gens(lruvec, LRU_GEN_FILE) <= get_nr_gens(lruvec, LRU_GEN_ANON) && get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; -@@ -3316,7 +3316,7 @@ struct ctrl_pos { +@@ -3596,7 +3596,7 @@ struct ctrl_pos { static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, struct ctrl_pos *pos) { @@ -191,7 +191,7 @@ Signed-off-by: Andrew Morton int hist = lru_hist_from_seq(lrugen->min_seq[type]); pos->refaulted = lrugen->avg_refaulted[type][tier] + -@@ -3331,7 +3331,7 @@ static void read_ctrl_pos(struct lruvec +@@ -3611,7 +3611,7 @@ static void read_ctrl_pos(struct lruvec static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) { int hist, tier; @@ -200,7 +200,7 @@ Signed-off-by: Andrew Morton bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; -@@ -3408,7 +3408,7 @@ static int folio_update_gen(struct folio * +@@ -3688,7 +3688,7 @@ static int folio_update_gen(struct folio static int folio_inc_gen(struct lruvec *lruvec, struct folio *folio, bool reclaiming) { int type = folio_is_file_lru(folio); @@ -209,7 +209,7 @@ Signed-off-by: Andrew Morton int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); unsigned long new_flags, old_flags = READ_ONCE(folio->flags); -@@ -3453,7 +3453,7 @@ static void update_batch_size(struct lru +@@ -3733,7 +3733,7 @@ static void update_batch_size(struct lru static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) { int gen, type, zone; @@ -218,7 +218,7 @@ Signed-off-by: Andrew Morton walk->batched = 0; -@@ -3979,7 +3979,7 @@ static bool inc_min_seq(struct lruvec *l +@@ -4253,7 +4253,7 @@ static bool inc_min_seq(struct lruvec *l { int zone; int remaining = MAX_LRU_BATCH; @@ -227,7 +227,7 @@ Signed-off-by: Andrew Morton int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); if (type == LRU_GEN_ANON && !can_swap) -@@ -4015,7 +4015,7 @@ static bool try_to_inc_min_seq(struct lr +@@ -4289,7 +4289,7 @@ static bool try_to_inc_min_seq(struct lr { int gen, type, zone; bool success = false; @@ -236,7 +236,7 @@ Signed-off-by: Andrew Morton DEFINE_MIN_SEQ(lruvec); VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -@@ -4036,7 +4036,7 @@ next: +@@ -4310,7 +4310,7 @@ next: ; } @@ -245,7 +245,7 @@ Signed-off-by: Andrew Morton if (can_swap) { min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); -@@ -4058,7 +4058,7 @@ static void inc_max_seq(struct lruvec *l +@@ -4332,7 +4332,7 @@ static void inc_max_seq(struct lruvec *l { int prev, next; int type, zone; @@ -254,7 +254,7 @@ Signed-off-by: Andrew Morton spin_lock_irq(&lruvec->lru_lock); -@@ -4116,7 +4116,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4390,7 +4390,7 @@ static bool try_to_inc_max_seq(struct lr bool success; struct lru_gen_mm_walk *walk; struct mm_struct *mm = NULL; @@ -263,7 +263,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); -@@ -4181,7 +4181,7 @@ static bool should_run_aging(struct lruv +@@ -4455,7 +4455,7 @@ static bool should_run_aging(struct lruv unsigned long old = 0; unsigned long young = 0; unsigned long total = 0; @@ -272,16 +272,16 @@ Signed-off-by: Andrew Morton struct mem_cgroup *memcg = lruvec_memcg(lruvec); for (type = !can_swap; type < ANON_AND_FILE; type++) { -@@ -4466,7 +4466,7 @@ static bool sort_folio(struct lruvec *lru - int delta = thp_nr_folios(folio); +@@ -4740,7 +4740,7 @@ static bool sort_folio(struct lruvec *lr + int delta = folio_nr_pages(folio); int refs = folio_lru_refs(folio); int tier = lru_tier_from_refs(refs); - struct lru_gen_struct *lrugen = &lruvec->lrugen; + struct lru_gen_folio *lrugen = &lruvec->lrugen; - VM_WARN_ON_ONCE_folio(gen >= MAX_NR_GENS, folio); + VM_WARN_ON_ONCE_FOLIO(gen >= MAX_NR_GENS, folio); -@@ -4566,7 +4566,7 @@ static int scan_folios(struct lruvec *lru +@@ -4840,7 +4840,7 @@ static int scan_folios(struct lruvec *lr int scanned = 0; int isolated = 0; int remaining = MAX_LRU_BATCH; @@ -290,7 +290,7 @@ Signed-off-by: Andrew Morton struct mem_cgroup *memcg = lruvec_memcg(lruvec); VM_WARN_ON_ONCE(!list_empty(list)); -@@ -4967,7 +4967,7 @@ done: +@@ -5240,7 +5240,7 @@ done: static bool __maybe_unused state_is_valid(struct lruvec *lruvec) { @@ -299,7 +299,7 @@ Signed-off-by: Andrew Morton if (lrugen->enabled) { enum lru_list lru; -@@ -5247,7 +5247,7 @@ static void lru_gen_seq_show_full(struct +@@ -5522,7 +5522,7 @@ static void lru_gen_seq_show_full(struct int i; int type, tier; int hist = lru_hist_from_seq(seq); @@ -308,7 +308,7 @@ Signed-off-by: Andrew Morton for (tier = 0; tier < MAX_NR_TIERS; tier++) { seq_printf(m, " %10d", tier); -@@ -5296,7 +5296,7 @@ static int lru_gen_seq_show(struct seq_f +@@ -5572,7 +5572,7 @@ static int lru_gen_seq_show(struct seq_f unsigned long seq; bool full = !debugfs_real_fops(m->file)->write; struct lruvec *lruvec = v; @@ -317,7 +317,7 @@ Signed-off-by: Andrew Morton int nid = lruvec_pgdat(lruvec)->node_id; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); -@@ -5549,7 +5549,7 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5826,7 +5826,7 @@ void lru_gen_init_lruvec(struct lruvec * { int i; int gen, type, zone; @@ -328,14 +328,14 @@ Signed-off-by: Andrew Morton lrugen->enabled = lru_gen_enabled(); --- a/mm/workingset.c +++ b/mm/workingset.c -@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct pag +@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct fol unsigned long token; unsigned long min_seq; struct lruvec *lruvec; - struct lru_gen_struct *lrugen; + struct lru_gen_folio *lrugen; int type = folio_is_file_lru(folio); - int delta = thp_nr_folios(folio); + int delta = folio_nr_pages(folio); int refs = folio_lru_refs(folio); @@ -252,7 +252,7 @@ static void lru_gen_refault(struct folio unsigned long token; diff --git a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch index 32b7b39f69a..7940380c5ce 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch @@ -25,9 +25,9 @@ Signed-off-by: Andrew Morton --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -246,9 +246,9 @@ static inline bool lru_gen_add_folio(stru +@@ -256,9 +256,9 @@ static inline bool lru_gen_add_folio(str lru_gen_update_size(lruvec, folio, -1, gen); - /* for rotate_reclaimable_folio() */ + /* for folio_rotate_reclaimable() */ if (reclaiming) - list_add_tail(&folio->lru, &lrugen->lists[gen][type][zone]); + list_add_tail(&folio->lru, &lrugen->folios[gen][type][zone]); @@ -39,16 +39,16 @@ Signed-off-by: Andrew Morton } --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h -@@ -302,7 +302,7 @@ enum lruvec_flags { +@@ -312,7 +312,7 @@ enum lruvec_flags { * They form a sliding window of a variable size [MIN_NR_GENS, MAX_NR_GENS]. An * offset within MAX_NR_GENS, i.e., gen, indexes the LRU list of the * corresponding generation. The gen counter in folio->flags stores gen+1 while - * a page is on one of lrugen->lists[]. Otherwise it stores 0. + * a page is on one of lrugen->folios[]. Otherwise it stores 0. * - * A folio is added to the youngest generation on faulting. The aging needs to - * check the accessed bit at least twice before handing this folio over to the -@@ -314,8 +314,8 @@ enum lruvec_flags { + * A page is added to the youngest generation on faulting. The aging needs to + * check the accessed bit at least twice before handing this page over to the +@@ -324,8 +324,8 @@ enum lruvec_flags { * rest of generations, if they exist, are considered inactive. See * lru_gen_is_active(). * @@ -59,18 +59,18 @@ Signed-off-by: Andrew Morton * considered active is isolated for non-reclaiming purposes, e.g., migration. * See lru_gen_add_folio() and lru_gen_del_folio(). * -@@ -402,7 +402,7 @@ struct lru_gen_folio { +@@ -412,7 +412,7 @@ struct lru_gen_folio { /* the birth time of each generation in jiffies */ unsigned long timestamps[MAX_NR_GENS]; /* the multi-gen LRU lists, lazily sorted on eviction */ - struct list_head lists[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + struct list_head folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the multi-gen LRU sizes, eventually consistent */ - long nr_folios[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; + long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the exponential moving average of refaulted */ --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3987,7 +3987,7 @@ static bool inc_min_seq(struct lruvec *l +@@ -4261,7 +4261,7 @@ static bool inc_min_seq(struct lruvec *l /* prevent cold/hot inversion if force_scan is true */ for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -79,8 +79,8 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { struct folio *folio = lru_to_folio(head); -@@ -3998,7 +3998,7 @@ static bool inc_min_seq(struct lruvec *l - VM_WARN_ON_ONCE_folio(folio_zonenum(folio) != zone, folio); +@@ -4272,7 +4272,7 @@ static bool inc_min_seq(struct lruvec *l + VM_WARN_ON_ONCE_FOLIO(folio_zonenum(folio) != zone, folio); new_gen = folio_inc_gen(lruvec, folio, false); - list_move_tail(&folio->lru, &lrugen->lists[new_gen][type][zone]); @@ -88,7 +88,7 @@ Signed-off-by: Andrew Morton if (!--remaining) return false; -@@ -4026,7 +4026,7 @@ static bool try_to_inc_min_seq(struct lr +@@ -4300,7 +4300,7 @@ static bool try_to_inc_min_seq(struct lr gen = lru_gen_from_seq(min_seq[type]); for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -97,7 +97,7 @@ Signed-off-by: Andrew Morton goto next; } -@@ -4491,7 +4491,7 @@ static bool sort_folio(struct lruvec *lru +@@ -4765,7 +4765,7 @@ static bool sort_folio(struct lruvec *lr /* promoted */ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { @@ -106,7 +106,7 @@ Signed-off-by: Andrew Morton return true; } -@@ -4500,7 +4500,7 @@ static bool sort_folio(struct lruvec *lru +@@ -4774,7 +4774,7 @@ static bool sort_folio(struct lruvec *lr int hist = lru_hist_from_seq(lrugen->min_seq[type]); gen = folio_inc_gen(lruvec, folio, false); @@ -115,16 +115,16 @@ Signed-off-by: Andrew Morton WRITE_ONCE(lrugen->protected[hist][type][tier - 1], lrugen->protected[hist][type][tier - 1] + delta); -@@ -4512,7 +4512,7 @@ static bool sort_folio(struct lruvec *lru - if (folioLocked(folio) || folioWriteback(folio) || - (type == LRU_GEN_FILE && folioDirty(folio))) { +@@ -4786,7 +4786,7 @@ static bool sort_folio(struct lruvec *lr + if (folio_test_locked(folio) || folio_test_writeback(folio) || + (type == LRU_GEN_FILE && folio_test_dirty(folio))) { gen = folio_inc_gen(lruvec, folio, true); - list_move(&folio->lru, &lrugen->lists[gen][type][zone]); + list_move(&folio->lru, &lrugen->folios[gen][type][zone]); return true; } -@@ -4579,7 +4579,7 @@ static int scan_folios(struct lruvec *lru +@@ -4853,7 +4853,7 @@ static int scan_folios(struct lruvec *lr for (zone = sc->reclaim_idx; zone >= 0; zone--) { LIST_HEAD(moved); int skipped = 0; @@ -133,7 +133,7 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { struct folio *folio = lru_to_folio(head); -@@ -4980,7 +4980,7 @@ static bool __maybe_unused state_is_vali +@@ -5253,7 +5253,7 @@ static bool __maybe_unused state_is_vali int gen, type, zone; for_each_gen_type_zone(gen, type, zone) { @@ -142,7 +142,7 @@ Signed-off-by: Andrew Morton return false; } } -@@ -5025,7 +5025,7 @@ static bool drain_evictable(struct lruve +@@ -5298,7 +5298,7 @@ static bool drain_evictable(struct lruve int remaining = MAX_LRU_BATCH; for_each_gen_type_zone(gen, type, zone) { @@ -151,7 +151,7 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { bool success; -@@ -5558,7 +5558,7 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5835,7 +5835,7 @@ void lru_gen_init_lruvec(struct lruvec * lrugen->timestamps[i] = jiffies; for_each_gen_type_zone(gen, type, zone) diff --git a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch index 01babfecb1e..d214898a6d0 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch @@ -37,7 +37,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -443,6 +443,11 @@ static bool cgroup_reclaim(struct scan_c +@@ -448,6 +448,11 @@ static bool cgroup_reclaim(struct scan_c return sc->target_mem_cgroup; } @@ -49,7 +49,7 @@ Signed-off-by: Andrew Morton /** * writeback_throttling_sane - is the usual dirty throttling mechanism available? * @sc: scan_control in question -@@ -493,6 +498,11 @@ static bool cgroup_reclaim(struct scan_c +@@ -498,6 +503,11 @@ static bool cgroup_reclaim(struct scan_c return false; } @@ -61,7 +61,7 @@ Signed-off-by: Andrew Morton static bool writeback_throttling_sane(struct scan_control *sc) { return true; -@@ -4722,8 +4732,7 @@ static int isolate_folios(struct lruvec * +@@ -4996,8 +5006,7 @@ static int isolate_folios(struct lruvec return scanned; } @@ -71,7 +71,7 @@ Signed-off-by: Andrew Morton { int type; int scanned; -@@ -4812,9 +4821,6 @@ retry: +@@ -5086,9 +5095,6 @@ retry: goto retry; } @@ -81,7 +81,7 @@ Signed-off-by: Andrew Morton return scanned; } -@@ -4853,67 +4859,26 @@ done: +@@ -5127,67 +5133,26 @@ done: return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } @@ -158,7 +158,7 @@ Signed-off-by: Andrew Morton lru_add_drain(); -@@ -4938,7 +4902,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5211,7 +5176,7 @@ static void lru_gen_shrink_lruvec(struct if (!nr_to_scan) goto done; @@ -167,7 +167,7 @@ Signed-off-by: Andrew Morton if (!delta) goto done; -@@ -4946,7 +4910,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5219,7 +5184,7 @@ static void lru_gen_shrink_lruvec(struct if (scanned >= nr_to_scan) break; @@ -176,7 +176,7 @@ Signed-off-by: Andrew Morton break; cond_resched(); -@@ -5393,7 +5357,7 @@ static int run_eviction(struct lruvec *l +@@ -5669,7 +5634,7 @@ static int run_eviction(struct lruvec *l if (sc->nr_reclaimed >= nr_to_reclaim) return 0; diff --git a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch index 2f4fb911f5b..7cbabd34e4f 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch @@ -37,7 +37,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -131,7 +131,6 @@ struct scan_control { +@@ -136,7 +136,6 @@ struct scan_control { #ifdef CONFIG_LRU_GEN /* help kswapd make better choices among multiple memcgs */ @@ -45,7 +45,7 @@ Signed-off-by: Andrew Morton unsigned long last_reclaimed; #endif -@@ -4184,7 +4183,7 @@ done: +@@ -4458,7 +4457,7 @@ done: return true; } @@ -54,7 +54,7 @@ Signed-off-by: Andrew Morton struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) { int gen, type, zone; -@@ -4193,6 +4192,13 @@ static bool should_run_aging(struct lruv +@@ -4467,6 +4466,13 @@ static bool should_run_aging(struct lruv unsigned long total = 0; struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); @@ -68,7 +68,7 @@ Signed-off-by: Andrew Morton for (type = !can_swap; type < ANON_AND_FILE; type++) { unsigned long seq; -@@ -4221,8 +4227,6 @@ static bool should_run_aging(struct lruv +@@ -4495,8 +4501,6 @@ static bool should_run_aging(struct lruv * stalls when the number of generations reaches MIN_NR_GENS. Hence, the * ideal number of generations is MIN_NR_GENS+1. */ @@ -77,7 +77,7 @@ Signed-off-by: Andrew Morton if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) return false; -@@ -4241,40 +4245,54 @@ static bool should_run_aging(struct lruv +@@ -4515,40 +4519,54 @@ static bool should_run_aging(struct lruv return false; } @@ -153,7 +153,7 @@ Signed-off-by: Andrew Morton } /* to protect the working set of the last N jiffies */ -@@ -4283,46 +4301,32 @@ static unsigned long lru_gen_min_ttl __r +@@ -4557,46 +4575,32 @@ static unsigned long lru_gen_min_ttl __r static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) { struct mem_cgroup *memcg; @@ -207,7 +207,7 @@ Signed-off-by: Andrew Morton */ if (mutex_trylock(&oom_lock)) { struct oom_control oc = { -@@ -4830,33 +4834,27 @@ retry: +@@ -5104,33 +5108,27 @@ retry: * reclaim. */ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, @@ -247,7 +247,7 @@ Signed-off-by: Andrew Morton } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -4875,9 +4873,7 @@ static unsigned long get_nr_to_reclaim(s +@@ -5149,9 +5147,7 @@ static unsigned long get_nr_to_reclaim(s static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) { struct blk_plug plug; @@ -257,7 +257,7 @@ Signed-off-by: Andrew Morton unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); lru_add_drain(); -@@ -4898,13 +4894,13 @@ static void lru_gen_shrink_lruvec(struct +@@ -5172,13 +5168,13 @@ static void lru_gen_shrink_lruvec(struct else swappiness = 0; @@ -274,7 +274,7 @@ Signed-off-by: Andrew Morton scanned += delta; if (scanned >= nr_to_scan) -@@ -4916,10 +4912,6 @@ static void lru_gen_shrink_lruvec(struct +@@ -5190,10 +5186,6 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } diff --git a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch index 2e6b8b9c9b2..bedbbd3e1b6 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -21,7 +21,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4183,68 +4183,6 @@ done: +@@ -4457,68 +4457,6 @@ done: return true; } @@ -90,7 +90,7 @@ Signed-off-by: Andrew Morton static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) { int gen, type, zone; -@@ -4828,6 +4766,68 @@ retry: +@@ -5102,6 +5040,68 @@ retry: return scanned; } diff --git a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch index 5aa7473c21b..45789ff2094 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch @@ -69,7 +69,7 @@ Signed-off-by: Andrew Morton --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h -@@ -818,6 +818,11 @@ static inline void obj_cgroup_put(struct +@@ -790,6 +790,11 @@ static inline void obj_cgroup_put(struct percpu_ref_put(&objcg->refcnt); } @@ -81,8 +81,8 @@ Signed-off-by: Andrew Morton static inline void mem_cgroup_put(struct mem_cgroup *memcg) { if (memcg) -@@ -1283,6 +1288,11 @@ struct mem_cgroup *mem_cgroup_from_css(s - return NULL; +@@ -1290,6 +1295,11 @@ static inline void obj_cgroup_put(struct + { } +static inline bool mem_cgroup_tryget(struct mem_cgroup *memcg) @@ -95,7 +95,7 @@ Signed-off-by: Andrew Morton } --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -112,6 +112,18 @@ static inline bool lru_gen_in_fault(void +@@ -122,6 +122,18 @@ static inline bool lru_gen_in_fault(void return current->in_lru_fault; } @@ -114,7 +114,7 @@ Signed-off-by: Andrew Morton static inline int lru_gen_from_seq(unsigned long seq) { return seq % MAX_NR_GENS; -@@ -287,6 +299,11 @@ static inline bool lru_gen_in_fault(void +@@ -297,6 +309,11 @@ static inline bool lru_gen_in_fault(void return false; } @@ -136,7 +136,7 @@ Signed-off-by: Andrew Morton #include #include #include -@@ -357,6 +358,15 @@ struct folio_vma_mapped_walk; +@@ -367,6 +368,15 @@ struct page_vma_mapped_walk; #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) @@ -152,7 +152,7 @@ Signed-off-by: Andrew Morton #ifdef CONFIG_LRU_GEN enum { -@@ -416,6 +426,14 @@ struct lru_gen_folio { +@@ -426,6 +436,14 @@ struct lru_gen_folio { atomic_long_t refaulted[NR_HIST_GENS][ANON_AND_FILE][MAX_NR_TIERS]; /* whether the multi-gen LRU is enabled */ bool enabled; @@ -167,7 +167,7 @@ Signed-off-by: Andrew Morton }; enum { -@@ -469,12 +487,87 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -479,12 +497,87 @@ void lru_gen_init_lruvec(struct lruvec * void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); #ifdef CONFIG_MEMCG @@ -256,7 +256,7 @@ Signed-off-by: Andrew Morton static inline void lru_gen_init_lruvec(struct lruvec *lruvec) { } -@@ -484,6 +577,7 @@ static inline void lru_gen_look_around(s +@@ -494,6 +587,7 @@ static inline void lru_gen_look_around(s } #ifdef CONFIG_MEMCG @@ -264,7 +264,7 @@ Signed-off-by: Andrew Morton static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) { } -@@ -491,7 +585,24 @@ static inline void lru_gen_init_memcg(st +@@ -501,7 +595,24 @@ static inline void lru_gen_init_memcg(st static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) { } @@ -290,7 +290,7 @@ Signed-off-by: Andrew Morton #endif /* CONFIG_LRU_GEN */ -@@ -1105,6 +1216,8 @@ typedef struct pglist_data { +@@ -1219,6 +1330,8 @@ typedef struct pglist_data { #ifdef CONFIG_LRU_GEN /* kswap mm walk data */ struct lru_gen_mm_walk mm_walk; @@ -298,10 +298,10 @@ Signed-off-by: Andrew Morton + struct lru_gen_memcg memcg_lru; #endif - ZONE_PADDING(_pad2_) + CACHELINE_PADDING(_pad2_); --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -549,6 +549,16 @@ static void mem_cgroup_update_tree(struc +@@ -477,6 +477,16 @@ static void mem_cgroup_update_tree(struc struct mem_cgroup_per_node *mz; struct mem_cgroup_tree_per_node *mctz; @@ -318,9 +318,9 @@ Signed-off-by: Andrew Morton mctz = soft_limit_tree.rb_tree_per_node[nid]; if (!mctz) return; -@@ -3433,6 +3443,9 @@ unsigned long mem_cgroup_soft_limit_recl +@@ -3522,6 +3532,9 @@ unsigned long mem_cgroup_soft_limit_recl + struct mem_cgroup_tree_per_node *mctz; unsigned long excess; - unsigned long nr_scanned; + if (lru_gen_enabled()) + return 0; @@ -328,15 +328,15 @@ Signed-off-by: Andrew Morton if (order > 0) return 0; -@@ -5321,6 +5334,7 @@ static int mem_cgroup_css_online(struct +@@ -5382,6 +5395,7 @@ static int mem_cgroup_css_online(struct if (unlikely(mem_cgroup_is_root(memcg))) queue_delayed_work(system_unbound_wq, &stats_flush_dwork, 2UL*HZ); + lru_gen_online_memcg(memcg); return 0; - } - -@@ -5347,6 +5361,7 @@ static void mem_cgroup_css_offline(struc + offline_kmem: + memcg_offline_kmem(memcg); +@@ -5413,6 +5427,7 @@ static void mem_cgroup_css_offline(struc memcg_offline_kmem(memcg); reparent_shrinker_deferred(memcg); wb_memcg_offline(memcg); @@ -344,7 +344,7 @@ Signed-off-by: Andrew Morton drain_all_stock(memcg); -@@ -5358,6 +5373,7 @@ static void mem_cgroup_css_released(stru +@@ -5424,6 +5439,7 @@ static void mem_cgroup_css_released(stru struct mem_cgroup *memcg = mem_cgroup_from_css(css); invalidate_reclaim_iterators(memcg); @@ -354,14 +354,14 @@ Signed-off-by: Andrew Morton static void mem_cgroup_css_free(struct cgroup_subsys_state *css) --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7661,6 +7661,7 @@ static void __init free_area_init_node(i +@@ -7957,6 +7957,7 @@ static void __init free_area_init_node(i pgdat_set_deferred_range(pgdat); free_area_init_core(pgdat); + lru_gen_init_pgdat(pgdat); } - void __init free_area_init_memoryless_node(int nid) + static void __init free_area_init_memoryless_node(int nid) --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -54,6 +54,8 @@ @@ -373,7 +373,7 @@ Signed-off-by: Andrew Morton #include #include -@@ -129,11 +131,6 @@ struct scan_control { +@@ -134,11 +136,6 @@ struct scan_control { /* Always discard instead of demoting to lower tier memory */ unsigned int no_demotion:1; @@ -385,7 +385,7 @@ Signed-off-by: Andrew Morton /* Allocation order */ s8 order; -@@ -2880,6 +2877,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_ca +@@ -3160,6 +3157,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_ca for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) @@ -395,7 +395,7 @@ Signed-off-by: Andrew Morton static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) { struct pglist_data *pgdat = NODE_DATA(nid); -@@ -4169,8 +4169,7 @@ done: +@@ -4443,8 +4443,7 @@ done: if (sc->priority <= DEF_PRIORITY - 2) wait_event_killable(lruvec->mm_state.wait, max_seq < READ_ONCE(lrugen->max_seq)); @@ -405,7 +405,7 @@ Signed-off-by: Andrew Morton } VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); -@@ -4243,8 +4242,6 @@ static void lru_gen_age_node(struct pgli +@@ -4517,8 +4516,6 @@ static void lru_gen_age_node(struct pgli VM_WARN_ON_ONCE(!current_is_kswapd()); @@ -414,7 +414,7 @@ Signed-off-by: Andrew Morton /* check the order to exclude compaction-induced reclaim */ if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) return; -@@ -4833,8 +4830,7 @@ static bool should_run_aging(struct lruv +@@ -5107,8 +5104,7 @@ static bool should_run_aging(struct lruv * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg * reclaim. */ @@ -424,7 +424,7 @@ Signed-off-by: Andrew Morton { unsigned long nr_to_scan; struct mem_cgroup *memcg = lruvec_memcg(lruvec); -@@ -4851,10 +4847,8 @@ static unsigned long get_nr_to_scan(stru +@@ -5125,10 +5121,8 @@ static unsigned long get_nr_to_scan(stru if (sc->priority == DEF_PRIORITY) return nr_to_scan; @@ -436,7 +436,7 @@ Signed-off-by: Andrew Morton } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -4863,29 +4857,18 @@ static unsigned long get_nr_to_reclaim(s +@@ -5137,29 +5131,18 @@ static unsigned long get_nr_to_reclaim(s if (!global_reclaim(sc)) return -1; @@ -468,7 +468,7 @@ Signed-off-by: Andrew Morton if (sc->may_swap) swappiness = get_swappiness(lruvec, sc); -@@ -4895,7 +4878,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5169,7 +5152,7 @@ static void lru_gen_shrink_lruvec(struct swappiness = 0; nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); @@ -477,7 +477,7 @@ Signed-off-by: Andrew Morton break; delta = evict_folios(lruvec, sc, swappiness); -@@ -4912,10 +4895,250 @@ static void lru_gen_shrink_lruvec(struct +@@ -5186,10 +5169,250 @@ static void lru_gen_shrink_lruvec(struct cond_resched(); } @@ -728,7 +728,7 @@ Signed-off-by: Andrew Morton /****************************************************************************** * state change -@@ -5370,11 +5593,11 @@ static int run_cmd(char cmd, int memcg_i +@@ -5647,11 +5870,11 @@ static int run_cmd(char cmd, int memcg_i if (!mem_cgroup_disabled()) { rcu_read_lock(); @@ -743,7 +743,7 @@ Signed-off-by: Andrew Morton rcu_read_unlock(); if (!memcg) -@@ -5521,6 +5744,19 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5799,6 +6022,19 @@ void lru_gen_init_lruvec(struct lruvec * } #ifdef CONFIG_MEMCG @@ -763,7 +763,7 @@ Signed-off-by: Andrew Morton void lru_gen_init_memcg(struct mem_cgroup *memcg) { INIT_LIST_HEAD(&memcg->mm_list.fifo); -@@ -5544,7 +5780,69 @@ void lru_gen_exit_memcg(struct mem_cgrou +@@ -5822,7 +6058,69 @@ void lru_gen_exit_memcg(struct mem_cgrou } } } @@ -834,7 +834,7 @@ Signed-off-by: Andrew Morton static int __init init_lru_gen(void) { -@@ -5571,6 +5869,10 @@ static void lru_gen_shrink_lruvec(struct +@@ -5849,6 +6147,10 @@ static void lru_gen_shrink_lruvec(struct { } @@ -845,7 +845,7 @@ Signed-off-by: Andrew Morton #endif /* CONFIG_LRU_GEN */ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -5584,7 +5886,7 @@ static void shrink_lruvec(struct lruvec +@@ -5862,7 +6164,7 @@ static void shrink_lruvec(struct lruvec bool proportional_reclaim; struct blk_plug plug; @@ -854,7 +854,7 @@ Signed-off-by: Andrew Morton lru_gen_shrink_lruvec(lruvec, sc); return; } -@@ -5826,6 +6128,11 @@ static void shrink_node(pg_data_t *pgdat +@@ -6105,6 +6407,11 @@ static void shrink_node(pg_data_t *pgdat struct lruvec *target_lruvec; bool reclaimable = false; diff --git a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch index 029141b2d3e..89f7ed30afa 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -35,7 +35,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -2905,6 +2905,9 @@ static int get_swappiness(struct lruvec +@@ -3185,6 +3185,9 @@ static int get_swappiness(struct lruvec struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); @@ -43,9 +43,9 @@ Signed-off-by: Andrew Morton + return 0; + if (!can_demote(pgdat->node_id, sc) && - mem_cgroup_get_nr_swap_folios(memcg) < MIN_LRU_BATCH) + mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) return 0; -@@ -3952,7 +3955,7 @@ static void walk_mm(struct lruvec *lruve +@@ -4226,7 +4229,7 @@ static void walk_mm(struct lruvec *lruve } while (err == -EAGAIN); } @@ -54,7 +54,7 @@ Signed-off-by: Andrew Morton { struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; -@@ -3960,7 +3963,7 @@ static struct lru_gen_mm_walk *set_mm_wa +@@ -4234,7 +4237,7 @@ static struct lru_gen_mm_walk *set_mm_wa VM_WARN_ON_ONCE(walk); walk = &pgdat->mm_walk; @@ -63,7 +63,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(current_is_kswapd()); walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); -@@ -4146,7 +4149,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4420,7 +4423,7 @@ static bool try_to_inc_max_seq(struct lr goto done; } @@ -72,7 +72,7 @@ Signed-off-by: Andrew Morton if (!walk) { success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; -@@ -4215,8 +4218,6 @@ static bool lruvec_is_reclaimable(struct +@@ -4489,8 +4492,6 @@ static bool lruvec_is_reclaimable(struct struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MIN_SEQ(lruvec); @@ -81,7 +81,7 @@ Signed-off-by: Andrew Morton /* see the comment on lru_gen_folio */ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -@@ -4472,12 +4473,8 @@ static bool isolate_folio(struct lruvec * +@@ -4746,12 +4747,8 @@ static bool isolate_folio(struct lruvec { bool success; @@ -95,7 +95,7 @@ Signed-off-by: Andrew Morton (folio_test_dirty(folio) || (folio_test_anon(folio) && !folio_test_swapcache(folio)))) return false; -@@ -4574,9 +4571,8 @@ static int scan_folios(struct lruvec *lru +@@ -4848,9 +4845,8 @@ static int scan_folios(struct lruvec *lr __count_vm_events(PGSCAN_ANON + type, isolated); /* @@ -107,7 +107,7 @@ Signed-off-by: Andrew Morton */ return isolated || !remaining ? scanned : 0; } -@@ -4836,8 +4832,7 @@ static long get_nr_to_scan(struct lruvec +@@ -5110,8 +5106,7 @@ static long get_nr_to_scan(struct lruvec struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); @@ -117,7 +117,7 @@ Signed-off-by: Andrew Morton return 0; if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) -@@ -4865,17 +4860,14 @@ static bool try_to_shrink_lruvec(struct +@@ -5139,17 +5134,14 @@ static bool try_to_shrink_lruvec(struct long nr_to_scan; unsigned long scanned = 0; unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); @@ -140,7 +140,7 @@ Signed-off-by: Andrew Morton nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); if (nr_to_scan <= 0) -@@ -5005,12 +4997,13 @@ static void lru_gen_shrink_lruvec(struct +@@ -5279,12 +5271,13 @@ static void lru_gen_shrink_lruvec(struct struct blk_plug plug; VM_WARN_ON_ONCE(global_reclaim(sc)); @@ -155,7 +155,7 @@ Signed-off-by: Andrew Morton if (try_to_shrink_lruvec(lruvec, sc)) lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); -@@ -5066,11 +5059,19 @@ static void lru_gen_shrink_node(struct p +@@ -5340,11 +5333,19 @@ static void lru_gen_shrink_node(struct p VM_WARN_ON_ONCE(!global_reclaim(sc)); @@ -176,7 +176,7 @@ Signed-off-by: Andrew Morton set_initial_priority(pgdat, sc); -@@ -5088,7 +5089,7 @@ static void lru_gen_shrink_node(struct p +@@ -5362,7 +5363,7 @@ static void lru_gen_shrink_node(struct p clear_mm_walk(); blk_finish_plug(&plug); @@ -185,7 +185,7 @@ Signed-off-by: Andrew Morton /* kswapd should never fail */ pgdat->kswapd_failures = 0; } -@@ -5656,7 +5657,7 @@ static ssize_t lru_gen_seq_write(struct +@@ -5934,7 +5935,7 @@ static ssize_t lru_gen_seq_write(struct set_task_reclaim_state(current, &sc.reclaim_state); flags = memalloc_noreclaim_save(); blk_start_plug(&plug); diff --git a/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch b/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch index 38d0e5496cc..367f93363bb 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch @@ -23,7 +23,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4144,7 +4144,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4418,7 +4418,7 @@ static bool try_to_inc_max_seq(struct lr * handful of PTEs. Spreading the work out over a period of time usually * is less efficient, but it avoids bursty page faults. */ diff --git a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch index 62904e16553..b9eb5f694e7 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -25,7 +25,7 @@ Signed-off-by: Andrew Morton --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4934,18 +4934,20 @@ static int shrink_one(struct lruvec *lru +@@ -5208,18 +5208,20 @@ static int shrink_one(struct lruvec *lru static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) { @@ -48,7 +48,7 @@ Signed-off-by: Andrew Morton gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); rcu_read_lock(); -@@ -4969,14 +4971,22 @@ restart: +@@ -5243,14 +5245,22 @@ restart: op = shrink_one(lruvec, sc); @@ -74,7 +74,7 @@ Signed-off-by: Andrew Morton /* restart if raced with lru_gen_rotate_memcg() */ if (gen != get_nulls_value(pos)) goto restart; -@@ -4985,11 +4995,6 @@ restart: +@@ -5259,11 +5269,6 @@ restart: bin = get_memcg_bin(bin + 1); if (bin != first_bin) goto restart; diff --git a/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch b/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch index 7e9645ea98d..eb6be5ed00e 100644 --- a/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch +++ b/target/linux/generic/backport-6.1/406-v6.2-0001-mtd-core-simplify-a-bit-code-find-partition-matching.patch @@ -21,7 +21,7 @@ Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-1-zajec5@gmail.com --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -569,18 +569,16 @@ static void mtd_check_of_node(struct mtd +@@ -551,18 +551,16 @@ static void mtd_check_of_node(struct mtd struct device_node *partitions, *parent_dn, *mtd_dn = NULL; const char *pname, *prefix = "partition-"; int plen, mtd_name_len, offset, prefix_len; @@ -42,7 +42,7 @@ Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-1-zajec5@gmail.com if (!parent_dn) return; -@@ -593,15 +591,15 @@ static void mtd_check_of_node(struct mtd +@@ -575,15 +573,15 @@ static void mtd_check_of_node(struct mtd /* Search if a partition is defined with the same name */ for_each_child_of_node(partitions, mtd_dn) { diff --git a/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch b/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch index 48a7c13cd01..f8d3a370d44 100644 --- a/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch +++ b/target/linux/generic/backport-6.1/406-v6.2-0002-mtd-core-try-to-find-OF-node-for-every-MTD-partition.patch @@ -35,7 +35,7 @@ Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-2-zajec5@gmail.com --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -569,20 +569,22 @@ static void mtd_check_of_node(struct mtd +@@ -551,20 +551,22 @@ static void mtd_check_of_node(struct mtd struct device_node *partitions, *parent_dn, *mtd_dn = NULL; const char *pname, *prefix = "partition-"; int plen, mtd_name_len, offset, prefix_len; @@ -61,7 +61,7 @@ Link: https://lore.kernel.org/linux-mtd/20221004083710.27704-2-zajec5@gmail.com if (!partitions) goto exit_parent; -@@ -606,19 +608,11 @@ static void mtd_check_of_node(struct mtd +@@ -588,19 +590,11 @@ static void mtd_check_of_node(struct mtd plen = strlen(pname) - offset; if (plen == mtd_name_len && !strncmp(mtd->name, pname + offset, plen)) { diff --git a/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch b/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch index 505e347e40e..5a5e11c8f7a 100644 --- a/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch +++ b/target/linux/generic/backport-6.1/408-v6.2-mtd-core-set-ROOT_DEV-for-partitions-marked-as-rootf.patch @@ -27,7 +27,7 @@ Link: https://lore.kernel.org/linux-mtd/20221022211318.32009-2-zajec5@gmail.com #include #include -@@ -748,6 +749,17 @@ int add_mtd_device(struct mtd_info *mtd) +@@ -737,6 +738,17 @@ int add_mtd_device(struct mtd_info *mtd) not->add(mtd); mutex_unlock(&mtd_table_mutex); diff --git a/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch b/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch index 9f543365a57..e570564a0bc 100644 --- a/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch +++ b/target/linux/generic/backport-6.1/421-v6.2-mtd-parsers-add-TP-Link-SafeLoader-partitions-table-.patch @@ -42,7 +42,7 @@ Link: https://lore.kernel.org/linux-mtd/20221015092950.27467-2-zajec5@gmail.com --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -113,6 +113,21 @@ config MTD_AFS_PARTS +@@ -123,6 +123,21 @@ config MTD_AFS_PARTS for your particular device. It won't happen automatically. The 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. @@ -66,7 +66,7 @@ Link: https://lore.kernel.org/linux-mtd/20221015092950.27467-2-zajec5@gmail.com depends on MTD && (BCM47XX || ARCH_BCM_5301X || ARCH_MEDIATEK || RALINK || COMPILE_TEST) --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -9,6 +9,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += +@@ -10,6 +10,7 @@ ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart-$(CONFIG_MTD_OF_PARTS_LINKSYS_NS)+= ofpart_linksys_ns.o obj-$(CONFIG_MTD_PARSER_IMAGETAG) += parser_imagetag.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o diff --git a/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch index 017a58ba636..9ddda420ac3 100644 --- a/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch +++ b/target/linux/generic/backport-6.1/424-v6.4-0004-mtd-core-prepare-mtd_otp_nvmem_add-to-handle-EPROBE_.patch @@ -17,7 +17,7 @@ Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -960,8 +960,8 @@ static int mtd_otp_nvmem_add(struct mtd_ +@@ -953,8 +953,8 @@ static int mtd_otp_nvmem_add(struct mtd_ nvmem = mtd_otp_nvmem_register(mtd, "user-otp", size, mtd_nvmem_user_otp_reg_read); if (IS_ERR(nvmem)) { @@ -28,7 +28,7 @@ Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc } mtd->otp_user_nvmem = nvmem; } -@@ -978,7 +978,6 @@ static int mtd_otp_nvmem_add(struct mtd_ +@@ -971,7 +971,6 @@ static int mtd_otp_nvmem_add(struct mtd_ nvmem = mtd_otp_nvmem_register(mtd, "factory-otp", size, mtd_nvmem_fact_otp_reg_read); if (IS_ERR(nvmem)) { @@ -36,7 +36,7 @@ Link: https://lore.kernel.org/linux-mtd/20230308082021.870459-4-michael@walle.cc err = PTR_ERR(nvmem); goto err; } -@@ -991,7 +990,7 @@ static int mtd_otp_nvmem_add(struct mtd_ +@@ -983,7 +982,7 @@ static int mtd_otp_nvmem_add(struct mtd_ err: nvmem_unregister(mtd->otp_user_nvmem); diff --git a/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch b/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch index 71e11405958..84ea86044cd 100644 --- a/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch +++ b/target/linux/generic/backport-6.1/610-v6.3-net-page_pool-use-in_softirq-instead.patch @@ -14,7 +14,7 @@ Signed-off-by: Qingfang DENG --- a/include/net/page_pool.h +++ b/include/net/page_pool.h -@@ -357,7 +357,7 @@ static inline void page_pool_nid_changed +@@ -386,7 +386,7 @@ static inline void page_pool_nid_changed static inline void page_pool_ring_lock(struct page_pool *pool) __acquires(&pool->ring.producer_lock) { @@ -23,7 +23,7 @@ Signed-off-by: Qingfang DENG spin_lock(&pool->ring.producer_lock); else spin_lock_bh(&pool->ring.producer_lock); -@@ -366,7 +366,7 @@ static inline void page_pool_ring_lock(s +@@ -395,7 +395,7 @@ static inline void page_pool_ring_lock(s static inline void page_pool_ring_unlock(struct page_pool *pool) __releases(&pool->ring.producer_lock) { @@ -34,7 +34,7 @@ Signed-off-by: Qingfang DENG spin_unlock_bh(&pool->ring.producer_lock); --- a/net/core/page_pool.c +++ b/net/core/page_pool.c -@@ -512,8 +512,8 @@ static void page_pool_return_page(struct +@@ -511,8 +511,8 @@ static void page_pool_return_page(struct static bool page_pool_recycle_in_ring(struct page_pool *pool, struct page *page) { int ret; @@ -45,7 +45,7 @@ Signed-off-by: Qingfang DENG ret = ptr_ring_produce(&pool->ring, page); else ret = ptr_ring_produce_bh(&pool->ring, page); -@@ -576,7 +576,7 @@ __page_pool_put_page(struct page_pool *p +@@ -570,7 +570,7 @@ __page_pool_put_page(struct page_pool *p page_pool_dma_sync_for_device(pool, page, dma_sync_size); diff --git a/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch b/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch index c5d5d2c3a9c..28b7b4383e6 100644 --- a/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch +++ b/target/linux/generic/backport-6.1/611-v6.3-net-add-helper-eth_addr_add.patch @@ -18,7 +18,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h -@@ -478,6 +478,20 @@ static inline void eth_addr_inc(u8 *addr +@@ -508,6 +508,20 @@ static inline void eth_addr_inc(u8 *addr } /** diff --git a/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch index 6a82d191f90..980cb0f9147 100644 --- a/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch +++ b/target/linux/generic/backport-6.1/707-v6.3-net-pcs-add-driver-for-MediaTek-SGMII-PCS.patch @@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11789,6 +11789,14 @@ L: netdev@vger.kernel.org +@@ -12926,6 +12926,14 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/mediatek/ @@ -49,9 +49,9 @@ Signed-off-by: Jakub Kicinski L: linux-i2c@vger.kernel.org --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig -@@ -18,4 +18,11 @@ config PCS_LYNX - This module provides helpers to phylink for managing the Lynx PCS - which is part of the Layerscape and QorIQ Ethernet SERDES. +@@ -32,4 +32,11 @@ config PCS_ALTERA_TSE + This module provides helper functions for the Altera Triple Speed + Ethernet SGMII PCS, that can be found on the Intel Socfpga family. +config PCS_MTK_LYNXI + tristate @@ -63,7 +63,7 @@ Signed-off-by: Jakub Kicinski endmenu --- a/drivers/net/pcs/Makefile +++ b/drivers/net/pcs/Makefile -@@ -5,3 +5,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs. +@@ -7,3 +7,4 @@ obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o diff --git a/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch b/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch index dbd7e30fbb8..fd5f45df2aa 100644 --- a/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch +++ b/target/linux/generic/backport-6.1/729-02-v6.1-net-ethernet-mtk_wed-introduce-wed-wo-support.patch @@ -44,7 +44,7 @@ Signed-off-by: David S. Miller if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { struct device_node *wlan_node; -@@ -885,9 +888,11 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -878,9 +881,11 @@ mtk_wed_attach(struct mtk_wed_device *de } mtk_wed_hw_init_early(dev); diff --git a/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch b/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch index ffd6bc3589d..a002a5f8516 100644 --- a/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch +++ b/target/linux/generic/backport-6.1/729-03-v6.1-net-ethernet-mtk_wed-rename-tx_wdma-array-in-rx_wdma.patch @@ -23,7 +23,7 @@ Signed-off-by: David S. Miller } static void -@@ -695,10 +695,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device +@@ -688,10 +688,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device } static int @@ -36,7 +36,7 @@ Signed-off-by: David S. Miller if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size)) return -ENOMEM; -@@ -812,9 +812,9 @@ mtk_wed_start(struct mtk_wed_device *dev +@@ -805,9 +805,9 @@ mtk_wed_start(struct mtk_wed_device *dev { int i; @@ -49,7 +49,7 @@ Signed-off-by: David S. Miller mtk_wed_hw_init(dev); mtk_wed_configure_irq(dev, irq_mask); -@@ -923,7 +923,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev +@@ -916,7 +916,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev sizeof(*ring->desc))) return -ENOMEM; diff --git a/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch b/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch index 4c34d0cb33b..eca29739b4a 100644 --- a/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch +++ b/target/linux/generic/backport-6.1/729-04-v6.1-net-ethernet-mtk_wed-add-configure-wed-wo-support.patch @@ -409,7 +409,7 @@ Signed-off-by: David S. Miller if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { struct device_node *wlan_node; -@@ -441,10 +667,12 @@ mtk_wed_set_wpdma(struct mtk_wed_device +@@ -434,10 +660,12 @@ mtk_wed_set_wpdma(struct mtk_wed_device } else { mtk_wed_bus_init(dev); @@ -426,7 +426,7 @@ Signed-off-by: David S. Miller } } -@@ -494,6 +722,132 @@ mtk_wed_hw_init_early(struct mtk_wed_dev +@@ -487,6 +715,132 @@ mtk_wed_hw_init_early(struct mtk_wed_dev } } @@ -559,7 +559,7 @@ Signed-off-by: David S. Miller static void mtk_wed_hw_init(struct mtk_wed_device *dev) { -@@ -505,11 +859,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d +@@ -498,11 +852,11 @@ mtk_wed_hw_init(struct mtk_wed_device *d wed_w32(dev, MTK_WED_TX_BM_CTRL, MTK_WED_TX_BM_CTRL_PAUSE | FIELD_PREP(MTK_WED_TX_BM_CTRL_VLD_GRP_NUM, @@ -573,7 +573,7 @@ Signed-off-by: David S. Miller wed_w32(dev, MTK_WED_TX_BM_BUF_LEN, MTK_WED_PKT_SIZE); -@@ -536,9 +890,9 @@ mtk_wed_hw_init(struct mtk_wed_device *d +@@ -529,9 +883,9 @@ mtk_wed_hw_init(struct mtk_wed_device *d wed_w32(dev, MTK_WED_TX_TKID_CTRL, MTK_WED_TX_TKID_CTRL_PAUSE | FIELD_PREP(MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM, @@ -585,7 +585,7 @@ Signed-off-by: David S. Miller wed_w32(dev, MTK_WED_TX_TKID_DYN_THR, FIELD_PREP(MTK_WED_TX_TKID_DYN_THR_LO, 0) | MTK_WED_TX_TKID_DYN_THR_HI); -@@ -546,18 +900,28 @@ mtk_wed_hw_init(struct mtk_wed_device *d +@@ -539,18 +893,28 @@ mtk_wed_hw_init(struct mtk_wed_device *d mtk_wed_reset(dev, MTK_WED_RESET_TX_BM); @@ -617,7 +617,7 @@ Signed-off-by: David S. Miller { void *head = (void *)ring->desc; int i; -@@ -567,7 +931,10 @@ mtk_wed_ring_reset(struct mtk_wed_ring * +@@ -560,7 +924,10 @@ mtk_wed_ring_reset(struct mtk_wed_ring * desc = (struct mtk_wdma_desc *)(head + i * ring->desc_size); desc->buf0 = 0; @@ -629,7 +629,7 @@ Signed-off-by: David S. Miller desc->buf1 = 0; desc->info = 0; } -@@ -623,7 +990,8 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -616,7 +983,8 @@ mtk_wed_reset_dma(struct mtk_wed_device if (!dev->tx_ring[i].desc) continue; @@ -639,7 +639,7 @@ Signed-off-by: David S. Miller } if (mtk_wed_poll_busy(dev)) -@@ -641,6 +1009,9 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -634,6 +1002,9 @@ mtk_wed_reset_dma(struct mtk_wed_device wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX); wdma_w32(dev, MTK_WDMA_RESET_IDX, 0); @@ -649,7 +649,7 @@ Signed-off-by: David S. Miller if (busy) { mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV); -@@ -675,12 +1046,11 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -668,12 +1039,11 @@ mtk_wed_reset_dma(struct mtk_wed_device MTK_WED_WPDMA_RESET_IDX_RX); wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); } @@ -663,7 +663,7 @@ Signed-off-by: David S. Miller { ring->desc = dma_alloc_coherent(dev->hw->dev, size * desc_size, &ring->desc_phys, GFP_KERNEL); -@@ -689,7 +1059,7 @@ mtk_wed_ring_alloc(struct mtk_wed_device +@@ -682,7 +1052,7 @@ mtk_wed_ring_alloc(struct mtk_wed_device ring->desc_size = desc_size; ring->size = size; @@ -672,7 +672,7 @@ Signed-off-by: David S. Miller return 0; } -@@ -698,9 +1068,14 @@ static int +@@ -691,9 +1061,14 @@ static int mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size) { u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; @@ -689,7 +689,7 @@ Signed-off-by: David S. Miller return -ENOMEM; wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, -@@ -717,6 +1092,60 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we +@@ -710,6 +1085,60 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we return 0; } @@ -750,7 +750,7 @@ Signed-off-by: David S. Miller static void mtk_wed_configure_irq(struct mtk_wed_device *dev, u32 irq_mask) { -@@ -739,6 +1168,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev +@@ -732,6 +1161,8 @@ mtk_wed_configure_irq(struct mtk_wed_dev wed_clr(dev, MTK_WED_WDMA_INT_CTRL, wdma_mask); } else { @@ -759,7 +759,7 @@ Signed-off-by: David S. Miller /* initail tx interrupt trigger */ wed_w32(dev, MTK_WED_WPDMA_INT_CTRL_TX, MTK_WED_WPDMA_INT_CTRL_TX0_DONE_EN | -@@ -757,6 +1188,16 @@ mtk_wed_configure_irq(struct mtk_wed_dev +@@ -750,6 +1181,16 @@ mtk_wed_configure_irq(struct mtk_wed_dev FIELD_PREP(MTK_WED_WPDMA_INT_CTRL_TX_FREE_DONE_TRIG, dev->wlan.txfree_tbit)); @@ -776,7 +776,7 @@ Signed-off-by: David S. Miller wed_w32(dev, MTK_WED_WDMA_INT_CLR, wdma_mask); wed_set(dev, MTK_WED_WDMA_INT_CTRL, FIELD_PREP(MTK_WED_WDMA_INT_CTRL_POLL_SRC_SEL, -@@ -794,9 +1235,15 @@ mtk_wed_dma_enable(struct mtk_wed_device +@@ -787,9 +1228,15 @@ mtk_wed_dma_enable(struct mtk_wed_device wdma_set(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_INFO3_PRERES); } else { @@ -792,7 +792,7 @@ Signed-off-by: David S. Miller wed_set(dev, MTK_WED_WPDMA_GLO_CFG, MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_PKT_PROC | MTK_WED_WPDMA_GLO_CFG_RX_DRV_R0_CRX_SYNC); -@@ -804,6 +1251,15 @@ mtk_wed_dma_enable(struct mtk_wed_device +@@ -797,6 +1244,15 @@ mtk_wed_dma_enable(struct mtk_wed_device wed_clr(dev, MTK_WED_WPDMA_GLO_CFG, MTK_WED_WPDMA_GLO_CFG_TX_TKID_KEEP | MTK_WED_WPDMA_GLO_CFG_TX_DMAD_DW3_PREV); @@ -808,7 +808,7 @@ Signed-off-by: David S. Miller } } -@@ -829,7 +1285,19 @@ mtk_wed_start(struct mtk_wed_device *dev +@@ -822,7 +1278,19 @@ mtk_wed_start(struct mtk_wed_device *dev val |= BIT(0) | (BIT(1) * !!dev->hw->index); regmap_write(dev->hw->mirror, dev->hw->index * 4, val); } else { @@ -829,7 +829,7 @@ Signed-off-by: David S. Miller } mtk_wed_dma_enable(dev); -@@ -863,7 +1331,7 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -856,7 +1324,7 @@ mtk_wed_attach(struct mtk_wed_device *de if (!hw) { module_put(THIS_MODULE); ret = -ENODEV; @@ -838,7 +838,7 @@ Signed-off-by: David S. Miller } device = dev->wlan.bus_type == MTK_WED_BUS_PCIE -@@ -876,15 +1344,24 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -869,15 +1337,24 @@ mtk_wed_attach(struct mtk_wed_device *de dev->dev = hw->dev; dev->irq = hw->irq; dev->wdma_idx = hw->index; @@ -866,7 +866,7 @@ Signed-off-by: David S. Miller } mtk_wed_hw_init_early(dev); -@@ -893,8 +1370,10 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -886,8 +1363,10 @@ mtk_wed_attach(struct mtk_wed_device *de BIT(hw->index), 0); else ret = mtk_wed_wo_init(hw); @@ -878,7 +878,7 @@ Signed-off-by: David S. Miller mutex_unlock(&hw_lock); return ret; -@@ -917,10 +1396,11 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev +@@ -910,10 +1389,11 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev * WDMA RX. */ @@ -892,7 +892,7 @@ Signed-off-by: David S. Miller return -ENOMEM; if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE)) -@@ -967,6 +1447,37 @@ mtk_wed_txfree_ring_setup(struct mtk_wed +@@ -960,6 +1440,37 @@ mtk_wed_txfree_ring_setup(struct mtk_wed return 0; } @@ -930,7 +930,7 @@ Signed-off-by: David S. Miller static u32 mtk_wed_irq_get(struct mtk_wed_device *dev, u32 mask) { -@@ -1063,7 +1574,9 @@ void mtk_wed_add_hw(struct device_node * +@@ -1056,7 +1567,9 @@ void mtk_wed_add_hw(struct device_node * static const struct mtk_wed_ops wed_ops = { .attach = mtk_wed_attach, .tx_ring_setup = mtk_wed_tx_ring_setup, @@ -940,7 +940,7 @@ Signed-off-by: David S. Miller .start = mtk_wed_start, .stop = mtk_wed_stop, .reset_dma = mtk_wed_reset_dma, -@@ -1072,6 +1585,7 @@ void mtk_wed_add_hw(struct device_node * +@@ -1065,6 +1578,7 @@ void mtk_wed_add_hw(struct device_node * .irq_get = mtk_wed_irq_get, .irq_set_mask = mtk_wed_irq_set_mask, .detach = mtk_wed_detach, diff --git a/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch b/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch index 342ffb99d2f..83e015cc6bf 100644 --- a/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch +++ b/target/linux/generic/backport-6.1/729-07-v6.1-net-ethernet-mtk_eth_soc-remove-cpu_relax-in-mtk_pen.patch @@ -12,7 +12,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3437,11 +3437,8 @@ static void mtk_pending_work(struct work +@@ -3495,11 +3495,8 @@ static void mtk_pending_work(struct work rtnl_lock(); dev_dbg(eth->dev, "[%s][%d] reset\n", __func__, __LINE__); @@ -25,7 +25,7 @@ Signed-off-by: David S. Miller /* stop all devices to make sure that dma is properly shut down */ for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) -@@ -3475,7 +3472,7 @@ static void mtk_pending_work(struct work +@@ -3533,7 +3530,7 @@ static void mtk_pending_work(struct work dev_dbg(eth->dev, "[%s][%d] reset done\n", __func__, __LINE__); diff --git a/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch b/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch index d91d8299111..117ccc09025 100644 --- a/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch +++ b/target/linux/generic/backport-6.1/729-09-v6.2-net-ethernet-mtk_wed-add-wcid-overwritten-support-fo.patch @@ -27,7 +27,7 @@ Signed-off-by: David S. Miller } static void -@@ -1297,9 +1297,10 @@ mtk_wed_start(struct mtk_wed_device *dev +@@ -1290,9 +1290,10 @@ mtk_wed_start(struct mtk_wed_device *dev if (mtk_wed_rro_cfg(dev)) return; @@ -39,7 +39,7 @@ Signed-off-by: David S. Miller mtk_wed_dma_enable(dev); dev->running = true; } -@@ -1365,11 +1366,13 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -1358,11 +1359,13 @@ mtk_wed_attach(struct mtk_wed_device *de } mtk_wed_hw_init_early(dev); diff --git a/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch b/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch index d97bb715e0f..ec58c3fc572 100644 --- a/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch +++ b/target/linux/generic/backport-6.1/729-10-v6.2-net-ethernet-mtk_wed-return-status-value-in-mtk_wdma.patch @@ -70,7 +70,7 @@ Signed-off-by: Paolo Abeni } if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) { -@@ -1006,11 +1009,7 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -999,11 +1002,7 @@ mtk_wed_reset_dma(struct mtk_wed_device wed_w32(dev, MTK_WED_RESET_IDX, 0); } diff --git a/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch b/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch index dfc0f8c3f38..f4e842d515a 100644 --- a/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch +++ b/target/linux/generic/backport-6.1/729-12-v6.2-net-ethernet-mtk_wed-update-mtk_wed_stop.patch @@ -67,7 +67,7 @@ Signed-off-by: Paolo Abeni mtk_wdma_rx_reset(dev); mtk_wed_reset(dev, MTK_WED_RESET_WED); -@@ -677,7 +691,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev +@@ -670,7 +684,7 @@ mtk_wed_hw_init_early(struct mtk_wed_dev { u32 mask, set; diff --git a/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch b/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch index 2205fea513d..a0fc9da99e7 100644 --- a/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch +++ b/target/linux/generic/backport-6.1/729-13-v6.2-net-ethernet-mtk_wed-add-mtk_wed_rx_reset-routine.patch @@ -13,7 +13,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -951,42 +951,130 @@ mtk_wed_ring_reset(struct mtk_wed_ring * +@@ -944,42 +944,130 @@ mtk_wed_ring_reset(struct mtk_wed_ring * } static u32 @@ -170,7 +170,7 @@ Signed-off-by: Paolo Abeni } static void -@@ -1004,19 +1092,23 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -997,19 +1085,23 @@ mtk_wed_reset_dma(struct mtk_wed_device true); } @@ -201,7 +201,7 @@ Signed-off-by: Paolo Abeni if (busy) { mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT); -@@ -1033,6 +1125,9 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -1026,6 +1118,9 @@ mtk_wed_reset_dma(struct mtk_wed_device MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE); } @@ -211,7 +211,7 @@ Signed-off-by: Paolo Abeni for (i = 0; i < 100; i++) { val = wed_r32(dev, MTK_WED_TX_BM_INTF); if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40) -@@ -1040,8 +1135,19 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -1033,8 +1128,19 @@ mtk_wed_reset_dma(struct mtk_wed_device } mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT); @@ -231,7 +231,7 @@ Signed-off-by: Paolo Abeni if (busy) { mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT); mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV); -@@ -1052,6 +1158,17 @@ mtk_wed_reset_dma(struct mtk_wed_device +@@ -1045,6 +1151,17 @@ mtk_wed_reset_dma(struct mtk_wed_device MTK_WED_WPDMA_RESET_IDX_RX); wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0); } @@ -249,7 +249,7 @@ Signed-off-by: Paolo Abeni } static int -@@ -1274,6 +1391,9 @@ mtk_wed_start(struct mtk_wed_device *dev +@@ -1267,6 +1384,9 @@ mtk_wed_start(struct mtk_wed_device *dev { int i; @@ -259,7 +259,7 @@ Signed-off-by: Paolo Abeni for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) if (!dev->rx_wdma[i].desc) mtk_wed_wdma_rx_ring_setup(dev, i, 16); -@@ -1362,10 +1482,6 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -1355,10 +1475,6 @@ mtk_wed_attach(struct mtk_wed_device *de goto out; if (mtk_wed_get_rx_capa(dev)) { diff --git a/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch b/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch index 602483bcb8d..4404971cc74 100644 --- a/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch +++ b/target/linux/generic/backport-6.1/729-14-v6.2-net-ethernet-mtk_wed-add-reset-to-tx_ring_setup-call.patch @@ -14,7 +14,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -1188,7 +1188,8 @@ mtk_wed_ring_alloc(struct mtk_wed_device +@@ -1181,7 +1181,8 @@ mtk_wed_ring_alloc(struct mtk_wed_device } static int @@ -24,7 +24,7 @@ Signed-off-by: Paolo Abeni { u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; struct mtk_wed_ring *wdma; -@@ -1197,8 +1198,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we +@@ -1190,8 +1191,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we return -EINVAL; wdma = &dev->rx_wdma[idx]; @@ -35,7 +35,7 @@ Signed-off-by: Paolo Abeni return -ENOMEM; wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE, -@@ -1396,7 +1397,7 @@ mtk_wed_start(struct mtk_wed_device *dev +@@ -1389,7 +1390,7 @@ mtk_wed_start(struct mtk_wed_device *dev for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) if (!dev->rx_wdma[i].desc) @@ -44,7 +44,7 @@ Signed-off-by: Paolo Abeni mtk_wed_hw_init(dev); mtk_wed_configure_irq(dev, irq_mask); -@@ -1505,7 +1506,8 @@ unlock: +@@ -1498,7 +1499,8 @@ unlock: } static int @@ -54,7 +54,7 @@ Signed-off-by: Paolo Abeni { struct mtk_wed_ring *ring = &dev->tx_ring[idx]; -@@ -1524,11 +1526,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev +@@ -1517,11 +1519,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring))) return -EINVAL; diff --git a/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch b/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch index 45b85c06cb5..ce64f84ffbd 100644 --- a/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch +++ b/target/linux/generic/backport-6.1/729-18-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_reset-util.patch @@ -16,7 +16,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3200,6 +3200,27 @@ static void mtk_set_mcr_max_rx(struct mt +@@ -3254,6 +3254,27 @@ static void mtk_set_mcr_max_rx(struct mt mtk_w32(mac->hw, mcr_new, MTK_MAC_MCR(mac->id)); } @@ -44,7 +44,7 @@ Signed-off-by: Paolo Abeni static int mtk_hw_init(struct mtk_eth *eth) { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3239,22 +3260,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3293,22 +3314,9 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } diff --git a/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch b/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch index c34e30c773e..09ee03706b7 100644 --- a/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch +++ b/target/linux/generic/backport-6.1/729-19-v6.3-net-ethernet-mtk_eth_soc-introduce-mtk_hw_warm_reset.patch @@ -17,7 +17,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3221,7 +3221,54 @@ static void mtk_hw_reset(struct mtk_eth +@@ -3275,7 +3275,54 @@ static void mtk_hw_reset(struct mtk_eth 0x3ffffff); } @@ -73,7 +73,7 @@ Signed-off-by: Paolo Abeni { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | ETHSYS_DMA_AG_MAP_PPE; -@@ -3260,7 +3307,12 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3314,7 +3361,12 @@ static int mtk_hw_init(struct mtk_eth *e return 0; } @@ -87,7 +87,7 @@ Signed-off-by: Paolo Abeni if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { /* Set FE to PDMAv2 if necessary */ -@@ -3465,7 +3517,7 @@ static void mtk_pending_work(struct work +@@ -3522,7 +3574,7 @@ static void mtk_pending_work(struct work if (eth->dev->pins) pinctrl_select_state(eth->dev->pins->p, eth->dev->pins->default_state); @@ -96,7 +96,7 @@ Signed-off-by: Paolo Abeni /* restart DMA and enable IRQs */ for (i = 0; i < MTK_MAC_COUNT; i++) { -@@ -4057,7 +4109,7 @@ static int mtk_probe(struct platform_dev +@@ -4114,7 +4166,7 @@ static int mtk_probe(struct platform_dev eth->msg_enable = netif_msg_init(mtk_msg_level, MTK_DEFAULT_MSG_ENABLE); INIT_WORK(ð->pending_work, mtk_pending_work); diff --git a/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch b/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch index 29a5b627390..963235cd92b 100644 --- a/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch +++ b/target/linux/generic/backport-6.1/729-20-v6.3-net-ethernet-mtk_eth_soc-align-reset-procedure-to-ve.patch @@ -16,7 +16,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2786,14 +2786,29 @@ static void mtk_dma_free(struct mtk_eth +@@ -2842,14 +2842,29 @@ static void mtk_dma_free(struct mtk_eth kfree(eth->scratch_head); } @@ -48,7 +48,7 @@ Signed-off-by: Paolo Abeni schedule_work(ð->pending_work); } -@@ -3275,15 +3290,17 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3329,15 +3344,17 @@ static int mtk_hw_init(struct mtk_eth *e const struct mtk_reg_map *reg_map = eth->soc->reg_map; int i, val, ret; @@ -72,7 +72,7 @@ Signed-off-by: Paolo Abeni if (eth->ethsys) regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask, -@@ -3409,8 +3426,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3466,8 +3483,10 @@ static int mtk_hw_init(struct mtk_eth *e return 0; err_disable_pm: @@ -85,7 +85,7 @@ Signed-off-by: Paolo Abeni return ret; } -@@ -3489,30 +3508,53 @@ static int mtk_do_ioctl(struct net_devic +@@ -3546,30 +3565,53 @@ static int mtk_do_ioctl(struct net_devic return -EOPNOTSUPP; } @@ -148,7 +148,7 @@ Signed-off-by: Paolo Abeni if (eth->dev->pins) pinctrl_select_state(eth->dev->pins->p, -@@ -3523,15 +3565,19 @@ static void mtk_pending_work(struct work +@@ -3580,15 +3622,19 @@ static void mtk_pending_work(struct work for (i = 0; i < MTK_MAC_COUNT; i++) { if (!test_bit(i, &restart)) continue; @@ -201,7 +201,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -716,6 +716,33 @@ int mtk_foe_entry_idle_time(struct mtk_p +@@ -710,6 +710,33 @@ int mtk_foe_entry_idle_time(struct mtk_p return __mtk_foe_entry_idle_time(ppe, entry->data.ib1); } @@ -238,7 +238,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_ppe.h +++ b/drivers/net/ethernet/mediatek/mtk_ppe.h @@ -306,6 +306,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ - int version, int index); + void mtk_ppe_deinit(struct mtk_eth *eth); void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); +int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); diff --git a/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch b/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch index cebb750bf64..5fa2500a41e 100644 --- a/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch +++ b/target/linux/generic/backport-6.1/729-21-v6.3-net-ethernet-mtk_eth_soc-add-dma-checks-to-mtk_hw_re.patch @@ -49,7 +49,7 @@ Signed-off-by: Paolo Abeni }; /* strings used by ethtool */ -@@ -3283,6 +3289,102 @@ static void mtk_hw_warm_reset(struct mtk +@@ -3337,6 +3343,102 @@ static void mtk_hw_warm_reset(struct mtk val, rst_mask); } @@ -152,7 +152,7 @@ Signed-off-by: Paolo Abeni static int mtk_hw_init(struct mtk_eth *eth, bool reset) { u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA | -@@ -3615,6 +3717,7 @@ static int mtk_cleanup(struct mtk_eth *e +@@ -3672,6 +3774,7 @@ static int mtk_cleanup(struct mtk_eth *e mtk_unreg_dev(eth); mtk_free_dev(eth); cancel_work_sync(ð->pending_work); @@ -160,7 +160,7 @@ Signed-off-by: Paolo Abeni return 0; } -@@ -4042,6 +4145,7 @@ static int mtk_probe(struct platform_dev +@@ -4099,6 +4202,7 @@ static int mtk_probe(struct platform_dev eth->rx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; INIT_WORK(ð->rx_dim.work, mtk_dim_rx); @@ -168,8 +168,8 @@ Signed-off-by: Paolo Abeni eth->tx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE; INIT_WORK(ð->tx_dim.work, mtk_dim_tx); -@@ -4246,6 +4350,8 @@ static int mtk_probe(struct platform_dev - NAPI_POLL_WEIGHT); +@@ -4301,6 +4405,8 @@ static int mtk_probe(struct platform_dev + netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx); platform_set_drvdata(pdev, eth); + schedule_delayed_work(ð->reset.monitor_work, @@ -179,7 +179,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -256,6 +256,8 @@ +@@ -257,6 +257,8 @@ #define MTK_RX_DONE_INT_V2 BIT(14) @@ -188,7 +188,7 @@ Signed-off-by: Paolo Abeni /* QDMA Interrupt grouping registers */ #define MTK_RLS_DONE_INT BIT(0) -@@ -538,6 +540,17 @@ +@@ -542,6 +544,17 @@ #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c) #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110) @@ -206,7 +206,7 @@ Signed-off-by: Paolo Abeni struct mtk_rx_dma { unsigned int rxd1; unsigned int rxd2; -@@ -934,6 +947,7 @@ struct mtk_reg_map { +@@ -938,6 +951,7 @@ struct mtk_reg_map { u32 delay_irq; /* delay interrupt */ u32 irq_status; /* interrupt status */ u32 irq_mask; /* interrupt mask */ @@ -214,8 +214,8 @@ Signed-off-by: Paolo Abeni u32 int_grp; } pdma; struct { -@@ -960,6 +974,8 @@ struct mtk_reg_map { - u32 gdma_to_ppe0; +@@ -964,6 +978,8 @@ struct mtk_reg_map { + u32 gdma_to_ppe; u32 ppe_base; u32 wdma_base[2]; + u32 pse_iq_sta; @@ -223,7 +223,7 @@ Signed-off-by: Paolo Abeni }; /* struct mtk_eth_data - This is the structure holding all differences -@@ -1002,6 +1018,8 @@ struct mtk_soc_data { +@@ -1006,6 +1022,8 @@ struct mtk_soc_data { } txrx; }; @@ -232,7 +232,7 @@ Signed-off-by: Paolo Abeni /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 -@@ -1124,6 +1142,14 @@ struct mtk_eth { +@@ -1128,6 +1146,14 @@ struct mtk_eth { struct rhashtable flow_table; struct bpf_prog __rcu *prog; diff --git a/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch b/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch index 2eca2686708..2f816af7e22 100644 --- a/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch +++ b/target/linux/generic/backport-6.1/729-22-v6.3-net-ethernet-mtk_wed-add-reset-reset_complete-callba.patch @@ -14,7 +14,7 @@ Signed-off-by: Paolo Abeni --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3646,6 +3646,11 @@ static void mtk_pending_work(struct work +@@ -3703,6 +3703,11 @@ static void mtk_pending_work(struct work set_bit(MTK_RESETTING, ð->state); mtk_prepare_for_reset(eth); @@ -26,7 +26,7 @@ Signed-off-by: Paolo Abeni /* stop all devices to make sure that dma is properly shut down */ for (i = 0; i < MTK_MAC_COUNT; i++) { -@@ -3683,6 +3688,8 @@ static void mtk_pending_work(struct work +@@ -3740,6 +3745,8 @@ static void mtk_pending_work(struct work clear_bit(MTK_RESETTING, ð->state); diff --git a/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch b/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch index cf81acf4919..c63628da99d 100644 --- a/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch +++ b/target/linux/generic/backport-6.1/729-23-v6.3-net-ethernet-mtk_wed-add-reset-to-rx_ring_setup-call.patch @@ -17,7 +17,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -1259,7 +1259,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we +@@ -1252,7 +1252,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_we } static int @@ -27,7 +27,7 @@ Signed-off-by: Jakub Kicinski { u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version; struct mtk_wed_ring *wdma; -@@ -1268,8 +1269,8 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we +@@ -1261,8 +1262,8 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we return -EINVAL; wdma = &dev->tx_wdma[idx]; @@ -38,7 +38,7 @@ Signed-off-by: Jakub Kicinski return -ENOMEM; wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE, -@@ -1279,6 +1280,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we +@@ -1272,6 +1273,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_we wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_CPU_IDX, 0); wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0); @@ -48,7 +48,7 @@ Signed-off-by: Jakub Kicinski if (!idx) { wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE, wdma->desc_phys); -@@ -1618,18 +1622,20 @@ mtk_wed_txfree_ring_setup(struct mtk_wed +@@ -1611,18 +1615,20 @@ mtk_wed_txfree_ring_setup(struct mtk_wed } static int diff --git a/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch index 13245373841..34c41b8d4db 100644 --- a/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch +++ b/target/linux/generic/backport-6.1/730-02-v6.3-net-ethernet-mtk_eth_soc-increase-tx-ring-side-for-Q.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -901,7 +901,7 @@ static int mtk_init_fq_dma(struct mtk_et +@@ -945,7 +945,7 @@ static int mtk_init_fq_dma(struct mtk_et { const struct mtk_soc_data *soc = eth->soc; dma_addr_t phy_ring_tail; @@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; int i; -@@ -2155,19 +2155,25 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2209,19 +2209,25 @@ static int mtk_tx_alloc(struct mtk_eth * struct mtk_tx_ring *ring = ð->tx_ring; int i, sz = soc->txrx.txd_size; struct mtk_tx_dma_v2 *txd; @@ -51,7 +51,7 @@ Signed-off-by: Felix Fietkau u32 next_ptr = ring->phys + next * sz; txd = ring->dma + i * sz; -@@ -2187,22 +2193,22 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2241,22 +2247,22 @@ static int mtk_tx_alloc(struct mtk_eth * * descriptors in ring->dma_pdma. */ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { @@ -79,7 +79,7 @@ Signed-off-by: Felix Fietkau ring->thresh = MAX_SKB_FRAGS; /* make sure that all changes to the dma ring are flushed before we -@@ -2214,14 +2220,14 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2268,14 +2274,14 @@ static int mtk_tx_alloc(struct mtk_eth * mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr); mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr); mtk_w32(eth, @@ -96,7 +96,7 @@ Signed-off-by: Felix Fietkau mtk_w32(eth, 0, MT7628_TX_CTX_IDX0); mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx); } -@@ -2239,7 +2245,7 @@ static void mtk_tx_clean(struct mtk_eth +@@ -2293,7 +2299,7 @@ static void mtk_tx_clean(struct mtk_eth int i; if (ring->buf) { @@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau mtk_tx_unmap(eth, &ring->buf[i], NULL, false); kfree(ring->buf); ring->buf = NULL; -@@ -2247,14 +2253,14 @@ static void mtk_tx_clean(struct mtk_eth +@@ -2301,14 +2307,14 @@ static void mtk_tx_clean(struct mtk_eth if (ring->dma) { dma_free_coherent(eth->dma_dev, @@ -122,7 +122,7 @@ Signed-off-by: Felix Fietkau ring->dma_pdma, ring->phys_pdma); ring->dma_pdma = NULL; } -@@ -2774,7 +2780,7 @@ static void mtk_dma_free(struct mtk_eth +@@ -2830,7 +2836,7 @@ static void mtk_dma_free(struct mtk_eth netdev_reset_queue(eth->netdev[i]); if (eth->scratch_ring) { dma_free_coherent(eth->dma_dev, diff --git a/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch b/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch index 32dc5c37832..f5124ee6d8f 100644 --- a/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch +++ b/target/linux/generic/backport-6.1/730-03-v6.3-net-ethernet-mtk_eth_soc-avoid-port_mg-assignment-on.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4428,7 +4428,7 @@ static const struct mtk_soc_data mt7621_ +@@ -4484,7 +4484,7 @@ static const struct mtk_soc_data mt7621_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7621_CLKS_BITMAP, .required_pctl = false, @@ -21,7 +21,7 @@ Signed-off-by: Felix Fietkau .hash_offset = 2, .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { -@@ -4467,7 +4467,7 @@ static const struct mtk_soc_data mt7623_ +@@ -4523,7 +4523,7 @@ static const struct mtk_soc_data mt7623_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7623_CLKS_BITMAP, .required_pctl = true, diff --git a/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch b/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch index cfbd510c8f2..655faa2452e 100644 --- a/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch +++ b/target/linux/generic/backport-6.1/730-04-v6.3-net-ethernet-mtk_eth_soc-implement-multi-queue-suppo.patch @@ -53,8 +53,8 @@ Signed-off-by: Felix Fietkau + .tx_sch_rate = 0x4798, }, .gdm1_cnt = 0x1c00, - .gdma_to_ppe0 = 0x3333, -@@ -577,6 +581,75 @@ static void mtk_mac_link_down(struct phy + .gdma_to_ppe = 0x3333, +@@ -620,6 +624,75 @@ static void mtk_mac_link_down(struct phy mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); } @@ -130,7 +130,7 @@ Signed-off-by: Felix Fietkau static void mtk_mac_link_up(struct phylink_config *config, struct phy_device *phy, unsigned int mode, phy_interface_t interface, -@@ -602,6 +675,8 @@ static void mtk_mac_link_up(struct phyli +@@ -645,6 +718,8 @@ static void mtk_mac_link_up(struct phyli break; } @@ -139,7 +139,7 @@ Signed-off-by: Felix Fietkau /* Configure duplex */ if (duplex == DUPLEX_FULL) mcr |= MAC_MCR_FORCE_DPX; -@@ -1060,7 +1135,8 @@ static void mtk_tx_set_dma_desc_v1(struc +@@ -1106,7 +1181,8 @@ static void mtk_tx_set_dma_desc_v1(struc WRITE_ONCE(desc->txd1, info->addr); @@ -149,7 +149,7 @@ Signed-off-by: Felix Fietkau if (info->last) data |= TX_DMA_LS0; WRITE_ONCE(desc->txd3, data); -@@ -1094,9 +1170,6 @@ static void mtk_tx_set_dma_desc_v2(struc +@@ -1140,9 +1216,6 @@ static void mtk_tx_set_dma_desc_v2(struc data |= TX_DMA_LS0; WRITE_ONCE(desc->txd3, data); @@ -159,7 +159,7 @@ Signed-off-by: Felix Fietkau data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); WRITE_ONCE(desc->txd4, data); -@@ -1140,11 +1213,12 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1186,11 +1259,12 @@ static int mtk_tx_map(struct sk_buff *sk .gso = gso, .csum = skb->ip_summed == CHECKSUM_PARTIAL, .vlan = skb_vlan_tag_present(skb), @@ -173,7 +173,7 @@ Signed-off-by: Felix Fietkau struct mtk_mac *mac = netdev_priv(dev); struct mtk_eth *eth = mac->hw; const struct mtk_soc_data *soc = eth->soc; -@@ -1152,8 +1226,10 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1198,8 +1272,10 @@ static int mtk_tx_map(struct sk_buff *sk struct mtk_tx_dma *itxd_pdma, *txd_pdma; struct mtk_tx_buf *itx_buf, *tx_buf; int i, n_desc = 1; @@ -184,7 +184,7 @@ Signed-off-by: Felix Fietkau itxd = ring->next_free; itxd_pdma = qdma_to_pdma(ring, itxd); if (itxd == ring->last_free) -@@ -1202,7 +1278,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1248,7 +1324,7 @@ static int mtk_tx_map(struct sk_buff *sk memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); txd_info.size = min_t(unsigned int, frag_size, soc->txrx.dma_max_len); @@ -193,7 +193,7 @@ Signed-off-by: Felix Fietkau txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 && !(frag_size - txd_info.size); txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag, -@@ -1241,7 +1317,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1287,7 +1363,7 @@ static int mtk_tx_map(struct sk_buff *sk txd_pdma->txd2 |= TX_DMA_LS1; } @@ -202,7 +202,7 @@ Signed-off-by: Felix Fietkau skb_tx_timestamp(skb); ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2); -@@ -1253,8 +1329,7 @@ static int mtk_tx_map(struct sk_buff *sk +@@ -1299,8 +1375,7 @@ static int mtk_tx_map(struct sk_buff *sk wmb(); if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) { @@ -212,7 +212,7 @@ Signed-off-by: Felix Fietkau mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr); } else { int next_idx; -@@ -1323,7 +1398,7 @@ static void mtk_wake_queue(struct mtk_et +@@ -1369,7 +1444,7 @@ static void mtk_wake_queue(struct mtk_et for (i = 0; i < MTK_MAC_COUNT; i++) { if (!eth->netdev[i]) continue; @@ -221,7 +221,7 @@ Signed-off-by: Felix Fietkau } } -@@ -1347,7 +1422,7 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1393,7 +1468,7 @@ static netdev_tx_t mtk_start_xmit(struct tx_num = mtk_cal_txd_req(eth, skb); if (unlikely(atomic_read(&ring->free_count) <= tx_num)) { @@ -230,7 +230,7 @@ Signed-off-by: Felix Fietkau netif_err(eth, tx_queued, dev, "Tx Ring full when queue awake!\n"); spin_unlock(ð->page_lock); -@@ -1373,7 +1448,7 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1419,7 +1494,7 @@ static netdev_tx_t mtk_start_xmit(struct goto drop; if (unlikely(atomic_read(&ring->free_count) <= ring->thresh)) @@ -239,7 +239,7 @@ Signed-off-by: Felix Fietkau spin_unlock(ð->page_lock); -@@ -1540,10 +1615,12 @@ static int mtk_xdp_submit_frame(struct m +@@ -1586,10 +1661,12 @@ static int mtk_xdp_submit_frame(struct m struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf); const struct mtk_soc_data *soc = eth->soc; struct mtk_tx_ring *ring = ð->tx_ring; @@ -251,8 +251,8 @@ Signed-off-by: Felix Fietkau + .qid = mac->id, }; int err, index = 0, n_desc = 1, nr_frags; - struct mtk_tx_dma *htxd, *txd, *txd_pdma; -@@ -1594,6 +1671,7 @@ static int mtk_xdp_submit_frame(struct m + struct mtk_tx_buf *htx_buf, *tx_buf; +@@ -1639,6 +1716,7 @@ static int mtk_xdp_submit_frame(struct m memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info)); txd_info.size = skb_frag_size(&sinfo->frags[index]); txd_info.last = index + 1 == nr_frags; @@ -260,7 +260,7 @@ Signed-off-by: Felix Fietkau data = skb_frag_address(&sinfo->frags[index]); index++; -@@ -1945,8 +2023,46 @@ rx_done: +@@ -1993,8 +2071,46 @@ rx_done: return done; } @@ -308,7 +308,7 @@ Signed-off-by: Felix Fietkau { const struct mtk_reg_map *reg_map = eth->soc->reg_map; struct mtk_tx_ring *ring = ð->tx_ring; -@@ -1976,12 +2092,9 @@ static int mtk_poll_tx_qdma(struct mtk_e +@@ -2026,12 +2142,9 @@ static int mtk_poll_tx_qdma(struct mtk_e break; if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { @@ -322,8 +322,8 @@ Signed-off-by: Felix Fietkau - } budget--; } - mtk_tx_unmap(eth, tx_buf, true); -@@ -1999,7 +2112,7 @@ static int mtk_poll_tx_qdma(struct mtk_e + mtk_tx_unmap(eth, tx_buf, &bq, true); +@@ -2050,7 +2163,7 @@ static int mtk_poll_tx_qdma(struct mtk_e } static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget, @@ -332,7 +332,7 @@ Signed-off-by: Felix Fietkau { struct mtk_tx_ring *ring = ð->tx_ring; struct mtk_tx_buf *tx_buf; -@@ -2015,12 +2128,8 @@ static int mtk_poll_tx_pdma(struct mtk_e +@@ -2068,12 +2181,8 @@ static int mtk_poll_tx_pdma(struct mtk_e break; if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) { @@ -346,8 +346,8 @@ Signed-off-by: Felix Fietkau + mtk_poll_tx_done(eth, state, 0, tx_buf->data); budget--; } - mtk_tx_unmap(eth, tx_buf, true); -@@ -2041,26 +2150,15 @@ static int mtk_poll_tx(struct mtk_eth *e + mtk_tx_unmap(eth, tx_buf, &bq, true); +@@ -2095,26 +2204,15 @@ static int mtk_poll_tx(struct mtk_eth *e { struct mtk_tx_ring *ring = ð->tx_ring; struct dim_sample dim_sample = {}; @@ -379,7 +379,7 @@ Signed-off-by: Felix Fietkau dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes, &dim_sample); -@@ -2070,7 +2168,7 @@ static int mtk_poll_tx(struct mtk_eth *e +@@ -2124,7 +2222,7 @@ static int mtk_poll_tx(struct mtk_eth *e (atomic_read(&ring->free_count) > ring->thresh)) mtk_wake_queue(eth); @@ -388,7 +388,7 @@ Signed-off-by: Felix Fietkau } static void mtk_handle_status_irq(struct mtk_eth *eth) -@@ -2156,6 +2254,7 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2210,6 +2308,7 @@ static int mtk_tx_alloc(struct mtk_eth * int i, sz = soc->txrx.txd_size; struct mtk_tx_dma_v2 *txd; int ring_size; @@ -396,7 +396,7 @@ Signed-off-by: Felix Fietkau if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) ring_size = MTK_QDMA_RING_SIZE; -@@ -2223,8 +2322,25 @@ static int mtk_tx_alloc(struct mtk_eth * +@@ -2277,8 +2376,25 @@ static int mtk_tx_alloc(struct mtk_eth * ring->phys + ((ring_size - 1) * sz), soc->reg_map->qdma.crx_ptr); mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr); @@ -424,7 +424,7 @@ Signed-off-by: Felix Fietkau } else { mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0); mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0); -@@ -2904,7 +3020,7 @@ static int mtk_start_dma(struct mtk_eth +@@ -2960,7 +3076,7 @@ static int mtk_start_dma(struct mtk_eth if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) val |= MTK_MUTLI_CNT | MTK_RESV_BUF | MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | @@ -433,7 +433,7 @@ Signed-off-by: Felix Fietkau else val |= MTK_RX_BT_32DWORDS; mtk_w32(eth, val, reg_map->qdma.glo_cfg); -@@ -2950,6 +3066,45 @@ static void mtk_gdm_config(struct mtk_et +@@ -3006,6 +3122,45 @@ static void mtk_gdm_config(struct mtk_et mtk_w32(eth, 0, MTK_RST_GL); } @@ -479,7 +479,7 @@ Signed-off-by: Felix Fietkau static int mtk_open(struct net_device *dev) { struct mtk_mac *mac = netdev_priv(dev); -@@ -2994,7 +3149,8 @@ static int mtk_open(struct net_device *d +@@ -3048,7 +3203,8 @@ static int mtk_open(struct net_device *d refcount_inc(ð->dma_refcnt); phylink_start(mac->phylink); @@ -489,7 +489,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3717,8 +3873,12 @@ static int mtk_unreg_dev(struct mtk_eth +@@ -3774,8 +3930,12 @@ static int mtk_unreg_dev(struct mtk_eth int i; for (i = 0; i < MTK_MAC_COUNT; i++) { @@ -502,7 +502,7 @@ Signed-off-by: Felix Fietkau unregister_netdev(eth->netdev[i]); } -@@ -3935,6 +4095,23 @@ static int mtk_set_rxnfc(struct net_devi +@@ -3992,6 +4152,23 @@ static int mtk_set_rxnfc(struct net_devi return ret; } @@ -526,7 +526,7 @@ Signed-off-by: Felix Fietkau static const struct ethtool_ops mtk_ethtool_ops = { .get_link_ksettings = mtk_get_link_ksettings, .set_link_ksettings = mtk_set_link_ksettings, -@@ -3970,6 +4147,7 @@ static const struct net_device_ops mtk_n +@@ -4027,6 +4204,7 @@ static const struct net_device_ops mtk_n .ndo_setup_tc = mtk_eth_setup_tc, .ndo_bpf = mtk_xdp, .ndo_xdp_xmit = mtk_xdp_xmit, @@ -534,7 +534,7 @@ Signed-off-by: Felix Fietkau }; static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) -@@ -3979,6 +4157,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4036,6 +4214,7 @@ static int mtk_add_mac(struct mtk_eth *e struct phylink *phylink; struct mtk_mac *mac; int id, err; @@ -542,7 +542,7 @@ Signed-off-by: Felix Fietkau if (!_id) { dev_err(eth->dev, "missing mac id\n"); -@@ -3996,7 +4175,10 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4053,7 +4232,10 @@ static int mtk_add_mac(struct mtk_eth *e return -EINVAL; } @@ -554,7 +554,7 @@ Signed-off-by: Felix Fietkau if (!eth->netdev[id]) { dev_err(eth->dev, "alloc_etherdev failed\n"); return -ENOMEM; -@@ -4093,6 +4275,11 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4150,6 +4332,11 @@ static int mtk_add_mac(struct mtk_eth *e else eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN; @@ -576,7 +576,7 @@ Signed-off-by: Felix Fietkau #define MTK_QDMA_PAGE_SIZE 2048 #define MTK_MAX_RX_LENGTH 1536 #define MTK_MAX_RX_LENGTH_2K 2048 -@@ -215,8 +216,26 @@ +@@ -216,8 +217,26 @@ #define MTK_RING_MAX_AGG_CNT_H ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3) /* QDMA TX Queue Configuration Registers */ @@ -603,7 +603,7 @@ Signed-off-by: Felix Fietkau /* QDMA Global Configuration Register */ #define MTK_RX_2B_OFFSET BIT(31) #define MTK_RX_BT_32DWORDS (3 << 11) -@@ -235,6 +254,7 @@ +@@ -236,6 +255,7 @@ #define MTK_WCOMP_EN BIT(24) #define MTK_RESV_BUF (0x40 << 16) #define MTK_MUTLI_CNT (0x4 << 12) @@ -611,7 +611,7 @@ Signed-off-by: Felix Fietkau /* QDMA Flow Control Register */ #define FC_THRES_DROP_MODE BIT(20) -@@ -265,8 +285,6 @@ +@@ -266,8 +286,6 @@ #define MTK_STAT_OFFSET 0x40 /* QDMA TX NUM */ @@ -620,7 +620,7 @@ Signed-off-by: Felix Fietkau #define QID_BITS_V2(x) (((x) & 0x3f) << 16) #define MTK_QDMA_GMAC2_QID 8 -@@ -296,6 +314,7 @@ +@@ -297,6 +315,7 @@ #define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset) #define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len) #define TX_DMA_SWC BIT(14) @@ -628,7 +628,7 @@ Signed-off-by: Felix Fietkau /* PDMA on MT7628 */ #define TX_DMA_DONE BIT(31) -@@ -953,6 +972,7 @@ struct mtk_reg_map { +@@ -957,6 +976,7 @@ struct mtk_reg_map { } pdma; struct { u32 qtx_cfg; /* tx queue configuration */ @@ -636,15 +636,15 @@ Signed-off-by: Felix Fietkau u32 rx_ptr; /* rx base pointer */ u32 rx_cnt_cfg; /* rx max count configuration */ u32 qcrx_ptr; /* rx cpu pointer */ -@@ -970,6 +990,7 @@ struct mtk_reg_map { +@@ -974,6 +994,7 @@ struct mtk_reg_map { u32 fq_tail; /* fq tail pointer */ u32 fq_count; /* fq free page count */ u32 fq_blen; /* fq free page buffer length */ + u32 tx_sch_rate; /* tx scheduler rate control registers */ } qdma; u32 gdm1_cnt; - u32 gdma_to_ppe0; -@@ -1173,6 +1194,7 @@ struct mtk_mac { + u32 gdma_to_ppe; +@@ -1177,6 +1198,7 @@ struct mtk_mac { __be32 hwlro_ip[MTK_MAX_LRO_IP_CNT]; int hwlro_ip_cnt; unsigned int syscfg0; diff --git a/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch b/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch index 8935eb673ae..d29177eee72 100644 --- a/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch +++ b/target/linux/generic/backport-6.1/730-06-v6.3-net-ethernet-mediatek-ppe-assign-per-port-queues-for.patch @@ -10,8 +10,8 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -405,6 +405,24 @@ static inline bool mtk_foe_entry_usable( - FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND; +@@ -399,6 +399,24 @@ int mtk_foe_entry_set_wdma(struct mtk_et + return 0; } +int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry, diff --git a/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch b/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch index 44af9128b75..31a8ca3ea86 100644 --- a/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch +++ b/target/linux/generic/backport-6.1/730-07-v6.3-net-ethernet-mtk_eth_soc-compile-out-netsys-v2-code-.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -917,7 +917,13 @@ enum mkt_eth_capabilities { +@@ -921,7 +921,13 @@ enum mkt_eth_capabilities { #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) diff --git a/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch index 5458279fff0..6b7f3d6018c 100644 --- a/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch +++ b/target/linux/generic/backport-6.1/730-08-v6.3-net-dsa-add-support-for-DSA-rx-offloading-via-metada.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c -@@ -940,12 +940,14 @@ bool __skb_flow_dissect(const struct net +@@ -971,12 +971,14 @@ bool __skb_flow_dissect(const struct net #if IS_ENABLED(CONFIG_NET_DSA) if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) && proto == htons(ETH_P_XDSA))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau else --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c -@@ -20,6 +20,7 @@ +@@ -11,6 +11,7 @@ #include #include #include @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau #include "dsa_priv.h" -@@ -225,6 +226,7 @@ static bool dsa_skb_defer_rx_timestamp(s +@@ -216,6 +217,7 @@ static bool dsa_skb_defer_rx_timestamp(s static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *unused) { @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau struct dsa_port *cpu_dp = dev->dsa_ptr; struct sk_buff *nskb = NULL; struct dsa_slave_priv *p; -@@ -238,7 +240,22 @@ static int dsa_switch_rcv(struct sk_buff +@@ -229,7 +231,22 @@ static int dsa_switch_rcv(struct sk_buff if (!skb) return 0; diff --git a/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch b/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch index beba07238fd..8c368868e48 100644 --- a/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch +++ b/target/linux/generic/backport-6.1/730-09-v6.3-net-ethernet-mtk_eth_soc-fix-VLAN-rx-hardware-accele.patch @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau #include "mtk_eth_soc.h" #include "mtk_wed.h" -@@ -1974,16 +1975,22 @@ static int mtk_poll_rx(struct napi_struc +@@ -2022,16 +2023,22 @@ static int mtk_poll_rx(struct napi_struc htons(RX_DMA_VPID(trxd.rxd4)), RX_DMA_VID(trxd.rxd4)); } else if (trxd.rxd2 & RX_DMA_VTAG) { @@ -52,7 +52,7 @@ Signed-off-by: Felix Fietkau } skb_record_rx_queue(skb, 0); -@@ -2800,15 +2807,30 @@ static netdev_features_t mtk_fix_feature +@@ -2856,15 +2863,30 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -88,7 +88,7 @@ Signed-off-by: Felix Fietkau } /* wait for DMA to finish whatever it is doing before we start using it again */ -@@ -3105,11 +3127,45 @@ found: +@@ -3161,11 +3183,45 @@ found: return NOTIFY_DONE; } @@ -135,7 +135,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { -@@ -3632,6 +3688,10 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3686,6 +3742,10 @@ static int mtk_hw_init(struct mtk_eth *e */ val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); @@ -146,7 +146,7 @@ Signed-off-by: Felix Fietkau /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); -@@ -3865,6 +3925,12 @@ static int mtk_free_dev(struct mtk_eth * +@@ -3922,6 +3982,12 @@ static int mtk_free_dev(struct mtk_eth * free_netdev(eth->netdev[i]); } @@ -181,7 +181,7 @@ Signed-off-by: Felix Fietkau /* CDMP Ingress Control Register */ #define MTK_CDMP_IG_CTRL 0x400 #define MTK_CDMP_STAG_EN BIT(0) -@@ -1166,6 +1172,8 @@ struct mtk_eth { +@@ -1170,6 +1176,8 @@ struct mtk_eth { int ip_align; diff --git a/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch b/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch index 08bf608bc12..efbceb9a13d 100644 --- a/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch +++ b/target/linux/generic/backport-6.1/730-12-v6.3-net-ethernet-mtk_eth_soc-disable-hardware-DSA-untagg.patch @@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3143,7 +3143,8 @@ static int mtk_open(struct net_device *d +@@ -3199,7 +3199,8 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -30,7 +30,7 @@ Signed-off-by: Jakub Kicinski for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { struct metadata_dst *md_dst = eth->dsa_meta[i]; -@@ -3160,7 +3161,8 @@ static int mtk_open(struct net_device *d +@@ -3216,7 +3217,8 @@ static int mtk_open(struct net_device *d } } else { /* Hardware special tag parsing needs to be disabled if at least diff --git a/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch b/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch index efab99ada00..c0bfd9bd042 100644 --- a/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch +++ b/target/linux/generic/backport-6.1/730-13-v6.3-net-ethernet-mtk_eth_soc-enable-special-tag-when-any.patch @@ -23,7 +23,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -3078,7 +3078,7 @@ static void mtk_gdm_config(struct mtk_et +@@ -3134,7 +3134,7 @@ static void mtk_gdm_config(struct mtk_et val |= config; @@ -32,7 +32,7 @@ Signed-off-by: David S. Miller val |= MTK_GDMA_SPECIAL_TAG; mtk_w32(eth, val, MTK_GDMA_FWD_CFG(i)); -@@ -3143,8 +3143,7 @@ static int mtk_open(struct net_device *d +@@ -3199,8 +3199,7 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -42,7 +42,7 @@ Signed-off-by: David S. Miller for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { struct metadata_dst *md_dst = eth->dsa_meta[i]; -@@ -3161,8 +3160,7 @@ static int mtk_open(struct net_device *d +@@ -3217,8 +3216,7 @@ static int mtk_open(struct net_device *d } } else { /* Hardware special tag parsing needs to be disabled if at least diff --git a/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch b/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch index c392429b887..a9879ebfa9d 100644 --- a/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch +++ b/target/linux/generic/backport-6.1/730-14-v6.3-net-ethernet-mtk_eth_soc-fix-DSA-TX-tag-hwaccel-for-.patch @@ -77,7 +77,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1830,7 +1830,9 @@ static int mtk_poll_rx(struct napi_struc +@@ -1878,7 +1878,9 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -87,7 +87,7 @@ Signed-off-by: David S. Miller dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1970,27 +1972,29 @@ static int mtk_poll_rx(struct napi_struc +@@ -2018,27 +2020,29 @@ static int mtk_poll_rx(struct napi_struc if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) { if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { diff --git a/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch b/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch index 74a77ddaca2..a3bb1c5db77 100644 --- a/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch +++ b/target/linux/generic/backport-6.1/730-15-v6.3-net-ethernet-mtk_wed-No-need-to-clear-memory-after-a.patch @@ -16,7 +16,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_wed.c +++ b/drivers/net/ethernet/mediatek/mtk_wed.c -@@ -786,7 +786,6 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_de +@@ -779,7 +779,6 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_de ring->desc_size = sizeof(*ring->desc); ring->size = size; diff --git a/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch b/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch index d1c5fb6656d..0afe7106e54 100644 --- a/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch +++ b/target/linux/generic/backport-6.1/730-17-v6.3-net-ethernet-mtk_wed-fix-possible-deadlock-if-mtk_we.patch @@ -43,7 +43,7 @@ Signed-off-by: Jakub Kicinski mutex_unlock(&hw_lock); } -@@ -1545,8 +1550,10 @@ mtk_wed_attach(struct mtk_wed_device *de +@@ -1538,8 +1543,10 @@ mtk_wed_attach(struct mtk_wed_device *de ret = mtk_wed_wo_init(hw); } out: diff --git a/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch b/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch index e633f6f1fb8..ca5b6b3a3e0 100644 --- a/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch +++ b/target/linux/generic/backport-6.1/730-18-v6.3-net-ethernet-mtk_eth_soc-fix-tx-throughput-regressio.patch @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -676,8 +676,6 @@ static void mtk_mac_link_up(struct phyli +@@ -719,8 +719,6 @@ static void mtk_mac_link_up(struct phyli break; } diff --git a/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch b/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch index 68f3659367a..850b806410c 100644 --- a/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch +++ b/target/linux/generic/backport-6.1/733-v6.2-02-net-mtk_eth_soc-add-definitions-for-PCS.patch @@ -20,7 +20,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -501,8 +501,10 @@ +@@ -504,8 +504,10 @@ #define ETHSYS_DMA_AG_MAP_PPE BIT(2) /* SGMII subsystem config registers */ @@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski #define SGMII_AN_RESTART BIT(9) #define SGMII_ISOLATE BIT(10) #define SGMII_AN_ENABLE BIT(12) -@@ -512,13 +514,18 @@ +@@ -515,13 +517,18 @@ #define SGMII_PCS_FAULT BIT(23) #define SGMII_AN_EXPANSION_CLR BIT(30) diff --git a/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch b/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch index 8d2991f4500..7db59ad871b 100644 --- a/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch +++ b/target/linux/generic/backport-6.1/733-v6.2-12-net-mediatek-sgmii-ensure-the-SGMII-PHY-is-powered-d.patch @@ -34,7 +34,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1070,11 +1070,13 @@ struct mtk_soc_data { +@@ -1073,11 +1073,13 @@ struct mtk_soc_data { * @regmap: The register map pointing at the range used to setup * SGMII modes * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap diff --git a/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch b/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch index 79e5ad147ce..a06298c0a9c 100644 --- a/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch +++ b/target/linux/generic/backport-6.1/733-v6.2-13-net-mediatek-sgmii-fix-duplex-configuration.patch @@ -24,7 +24,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -531,7 +531,7 @@ +@@ -534,7 +534,7 @@ #define SGMII_SPEED_10 FIELD_PREP(SGMII_SPEED_MASK, 0) #define SGMII_SPEED_100 FIELD_PREP(SGMII_SPEED_MASK, 1) #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) diff --git a/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch b/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch index a63b110914b..6acc62d4abc 100644 --- a/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch +++ b/target/linux/generic/backport-6.1/733-v6.3-15-net-ethernet-mtk_eth_soc-reset-PCS-state.patch @@ -22,7 +22,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -539,6 +539,10 @@ +@@ -542,6 +542,10 @@ #define SGMII_SEND_AN_ERROR_EN BIT(11) #define SGMII_IF_MODE_MASK GENMASK(5, 1) diff --git a/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch b/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch index c1cf323800c..1e3f2fb2947 100644 --- a/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch +++ b/target/linux/generic/backport-6.1/733-v6.3-18-net-ethernet-mtk_eth_soc-add-support-for-MT7981.patch @@ -51,7 +51,7 @@ Signed-off-by: Jakub Kicinski mtk_eth_path_name(path), __func__, updated); --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4755,6 +4755,26 @@ static const struct mtk_soc_data mt7629_ +@@ -4808,6 +4808,26 @@ static const struct mtk_soc_data mt7629_ }, }; @@ -78,7 +78,7 @@ Signed-off-by: Jakub Kicinski static const struct mtk_soc_data mt7986_data = { .reg_map = &mt7986_reg_map, .ana_rgc3 = 0x128, -@@ -4797,6 +4817,7 @@ const struct of_device_id of_mtk_match[] +@@ -4849,6 +4869,7 @@ const struct of_device_id of_mtk_match[] { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, @@ -88,7 +88,7 @@ Signed-off-by: Jakub Kicinski {}, --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -553,11 +553,22 @@ +@@ -556,11 +556,22 @@ #define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8 #define SGMII_PHYA_PWD BIT(4) @@ -111,7 +111,7 @@ Signed-off-by: Jakub Kicinski /* MT7628/88 specific stuff */ #define MT7628_PDMA_OFFSET 0x0800 #define MT7628_SDM_OFFSET 0x0c00 -@@ -738,6 +749,17 @@ enum mtk_clks_map { +@@ -741,6 +752,17 @@ enum mtk_clks_map { BIT(MTK_CLK_SGMII2_CDR_FB) | \ BIT(MTK_CLK_SGMII_CK) | \ BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) @@ -129,7 +129,7 @@ Signed-off-by: Jakub Kicinski #define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ BIT(MTK_CLK_SGMII_TX_250M) | \ -@@ -851,6 +873,7 @@ enum mkt_eth_capabilities { +@@ -854,6 +876,7 @@ enum mkt_eth_capabilities { MTK_NETSYS_V2_BIT, MTK_SOC_MT7628_BIT, MTK_RSTCTRL_PPE1_BIT, @@ -137,7 +137,7 @@ Signed-off-by: Jakub Kicinski /* MUX BITS*/ MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, -@@ -885,6 +908,7 @@ enum mkt_eth_capabilities { +@@ -888,6 +911,7 @@ enum mkt_eth_capabilities { #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) @@ -145,7 +145,7 @@ Signed-off-by: Jakub Kicinski #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) -@@ -963,6 +987,11 @@ enum mkt_eth_capabilities { +@@ -966,6 +990,11 @@ enum mkt_eth_capabilities { MTK_MUX_U3_GMAC2_TO_QPHY | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) @@ -157,7 +157,7 @@ Signed-off-by: Jakub Kicinski #define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) -@@ -1076,12 +1105,14 @@ struct mtk_soc_data { +@@ -1079,12 +1108,14 @@ struct mtk_soc_data { * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap * @interface: Currently configured interface mode * @pcs: Phylink PCS structure diff --git a/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch b/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch index 9def19d67eb..ea20bd87f73 100644 --- a/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch +++ b/target/linux/generic/backport-6.1/733-v6.3-19-net-ethernet-mtk_eth_soc-set-MDIO-bus-clock-frequenc.patch @@ -21,7 +21,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -702,8 +702,10 @@ static const struct phylink_mac_ops mtk_ +@@ -745,8 +745,10 @@ static const struct phylink_mac_ops mtk_ static int mtk_mdio_init(struct mtk_eth *eth) { @@ -32,7 +32,7 @@ Signed-off-by: Jakub Kicinski mii_np = of_get_child_by_name(eth->dev->of_node, "mdio-bus"); if (!mii_np) { -@@ -729,6 +731,25 @@ static int mtk_mdio_init(struct mtk_eth +@@ -773,6 +775,25 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->parent = eth->dev; snprintf(eth->mii_bus->id, MII_BUS_ID_SIZE, "%pOFn", mii_np); diff --git a/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch b/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch index 203c5dc48bb..7a04753ceb3 100644 --- a/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch +++ b/target/linux/generic/backport-6.1/733-v6.3-20-net-ethernet-mtk_eth_soc-switch-to-external-PCS-driv.patch @@ -21,7 +21,7 @@ Signed-off-by: Jakub Kicinski --- a/drivers/net/ethernet/mediatek/Kconfig +++ b/drivers/net/ethernet/mediatek/Kconfig -@@ -18,6 +18,8 @@ config NET_MEDIATEK_SOC +@@ -19,6 +19,8 @@ config NET_MEDIATEK_SOC select DIMLIB select PAGE_POOL select PAGE_POOL_STATS @@ -51,7 +51,7 @@ Signed-off-by: Jakub Kicinski #include #include #include -@@ -357,7 +358,7 @@ static struct phylink_pcs *mtk_mac_selec +@@ -400,7 +401,7 @@ static struct phylink_pcs *mtk_mac_selec sid = (MTK_HAS_CAPS(eth->soc->caps, MTK_SHARED_SGMII)) ? 0 : mac->id; @@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski } return NULL; -@@ -3977,8 +3978,17 @@ static int mtk_unreg_dev(struct mtk_eth +@@ -4031,8 +4032,17 @@ static int mtk_unreg_dev(struct mtk_eth return 0; } @@ -78,7 +78,7 @@ Signed-off-by: Jakub Kicinski mtk_unreg_dev(eth); mtk_free_dev(eth); cancel_work_sync(ð->pending_work); -@@ -4408,6 +4418,36 @@ void mtk_eth_set_dma_device(struct mtk_e +@@ -4462,6 +4472,36 @@ void mtk_eth_set_dma_device(struct mtk_e rtnl_unlock(); } @@ -115,7 +115,7 @@ Signed-off-by: Jakub Kicinski static int mtk_probe(struct platform_device *pdev) { struct resource *res = NULL; -@@ -4471,13 +4511,7 @@ static int mtk_probe(struct platform_dev +@@ -4525,13 +4565,7 @@ static int mtk_probe(struct platform_dev } if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) { @@ -130,7 +130,7 @@ Signed-off-by: Jakub Kicinski if (err) return err; -@@ -4488,14 +4522,17 @@ static int mtk_probe(struct platform_dev +@@ -4542,14 +4576,17 @@ static int mtk_probe(struct platform_dev "mediatek,pctl"); if (IS_ERR(eth->pctl)) { dev_err(&pdev->dev, "no pctl regmap found\n"); @@ -151,7 +151,7 @@ Signed-off-by: Jakub Kicinski } if (eth->soc->offload_version) { -@@ -4655,6 +4692,8 @@ err_deinit_hw: +@@ -4708,6 +4745,8 @@ err_deinit_hw: mtk_hw_deinit(eth); err_wed_exit: mtk_wed_exit(); @@ -162,7 +162,7 @@ Signed-off-by: Jakub Kicinski } --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -507,65 +507,6 @@ +@@ -510,65 +510,6 @@ #define ETHSYS_DMA_AG_MAP_QDMA BIT(1) #define ETHSYS_DMA_AG_MAP_PPE BIT(2) @@ -228,7 +228,7 @@ Signed-off-by: Jakub Kicinski /* Infrasys subsystem config registers */ #define INFRA_MISC2 0x70c #define CO_QPHY_SEL BIT(0) -@@ -1105,31 +1046,6 @@ struct mtk_soc_data { +@@ -1108,31 +1049,6 @@ struct mtk_soc_data { /* currently no SoC has more than 2 macs */ #define MTK_MAX_DEVS 2 @@ -260,7 +260,7 @@ Signed-off-by: Jakub Kicinski /* struct mtk_eth - This is the main datasructure for holding the state * of the driver * @dev: The device pointer -@@ -1149,6 +1065,7 @@ struct mtk_sgmii { +@@ -1152,6 +1068,7 @@ struct mtk_sgmii { * MII modes * @infra: The register map pointing at the range used to setup * SGMII and GePHY path @@ -268,7 +268,7 @@ Signed-off-by: Jakub Kicinski * @pctl: The register map pointing at the range used to setup * GMAC port drive/slew values * @dma_refcnt: track how many netdevs are using the DMA engine -@@ -1189,8 +1106,8 @@ struct mtk_eth { +@@ -1192,8 +1109,8 @@ struct mtk_eth { u32 msg_enable; unsigned long sysclk; struct regmap *ethsys; @@ -279,7 +279,7 @@ Signed-off-by: Jakub Kicinski struct regmap *pctl; bool hwlro; refcount_t dma_refcnt; -@@ -1352,10 +1269,6 @@ void mtk_stats_update_mac(struct mtk_mac +@@ -1355,10 +1272,6 @@ void mtk_stats_update_mac(struct mtk_mac void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg); u32 mtk_r32(struct mtk_eth *eth, unsigned reg); diff --git a/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch b/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch index ee12399140b..be97c8ac3c2 100644 --- a/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch +++ b/target/linux/generic/backport-6.1/788-v6.3-net-dsa-mt7530-use-external-PCS-driver.patch @@ -81,7 +81,7 @@ Tested-by: Frank Wunderlich #include #include #include -@@ -2573,128 +2574,11 @@ static int mt7531_rgmii_setup(struct mt7 +@@ -2597,128 +2598,11 @@ static int mt7531_rgmii_setup(struct mt7 return 0; } @@ -210,7 +210,7 @@ Tested-by: Frank Wunderlich static int mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) -@@ -2717,11 +2601,11 @@ mt7531_mac_config(struct dsa_switch *ds, +@@ -2741,11 +2625,11 @@ mt7531_mac_config(struct dsa_switch *ds, phydev = dp->slave->phydev; return mt7531_rgmii_setup(priv, port, interface, phydev); case PHY_INTERFACE_MODE_SGMII: @@ -224,7 +224,7 @@ Tested-by: Frank Wunderlich default: return -EINVAL; } -@@ -2746,11 +2630,11 @@ mt753x_phylink_mac_select_pcs(struct dsa +@@ -2770,11 +2654,11 @@ mt753x_phylink_mac_select_pcs(struct dsa switch (interface) { case PHY_INTERFACE_MODE_TRGMII: @@ -238,7 +238,7 @@ Tested-by: Frank Wunderlich default: return NULL; } -@@ -2991,86 +2875,6 @@ static void mt7530_pcs_get_state(struct +@@ -3015,86 +2899,6 @@ static void mt7530_pcs_get_state(struct state->pause |= MLO_PAUSE_TX; } @@ -325,7 +325,7 @@ Tested-by: Frank Wunderlich static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode, phy_interface_t interface, const unsigned long *advertising, -@@ -3090,18 +2894,57 @@ static const struct phylink_pcs_ops mt75 +@@ -3114,18 +2918,57 @@ static const struct phylink_pcs_ops mt75 .pcs_an_restart = mt7530_pcs_an_restart, }; @@ -389,7 +389,7 @@ Tested-by: Frank Wunderlich int i, ret; /* Initialise the PCS devices */ -@@ -3109,8 +2952,6 @@ mt753x_setup(struct dsa_switch *ds) +@@ -3133,8 +2976,6 @@ mt753x_setup(struct dsa_switch *ds) priv->pcs[i].pcs.ops = priv->info->pcs_ops; priv->pcs[i].priv = priv; priv->pcs[i].port = i; @@ -398,7 +398,7 @@ Tested-by: Frank Wunderlich } ret = priv->info->sw_setup(ds); -@@ -3125,6 +2966,16 @@ mt753x_setup(struct dsa_switch *ds) +@@ -3149,6 +2990,16 @@ mt753x_setup(struct dsa_switch *ds) if (ret && priv->irq) mt7530_free_irq_common(priv); @@ -415,7 +415,7 @@ Tested-by: Frank Wunderlich return ret; } -@@ -3216,7 +3067,7 @@ static const struct mt753x_info mt753x_t +@@ -3240,7 +3091,7 @@ static const struct mt753x_info mt753x_t }, [ID_MT7531] = { .id = ID_MT7531, @@ -424,7 +424,7 @@ Tested-by: Frank Wunderlich .sw_setup = mt7531_setup, .phy_read = mt7531_ind_phy_read, .phy_write = mt7531_ind_phy_write, -@@ -3324,7 +3175,7 @@ static void +@@ -3348,7 +3199,7 @@ static void mt7530_remove(struct mdio_device *mdiodev) { struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); @@ -433,7 +433,7 @@ Tested-by: Frank Wunderlich if (!priv) return; -@@ -3343,6 +3194,10 @@ mt7530_remove(struct mdio_device *mdiode +@@ -3367,6 +3218,10 @@ mt7530_remove(struct mdio_device *mdiode mt7530_free_irq(priv); dsa_unregister_switch(priv->ds); @@ -442,8 +442,8 @@ Tested-by: Frank Wunderlich + mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); + mutex_destroy(&priv->reg_mutex); + } - dev_set_drvdata(&mdiodev->dev, NULL); --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm { diff --git a/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch b/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch index 57137c34fc6..df2f65d4334 100644 --- a/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch +++ b/target/linux/generic/backport-6.1/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch @@ -21,7 +21,7 @@ Signed-off-by: David S. Miller --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -12697,6 +12697,7 @@ F: include/uapi/linux/meye.h +@@ -13959,6 +13959,7 @@ F: include/uapi/linux/meye.h MOTORCOMM PHY DRIVER M: Peter Geis @@ -31,7 +31,7 @@ Signed-off-by: David S. Miller F: drivers/net/phy/motorcomm.c --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -245,7 +245,7 @@ config MOTORCOMM_PHY +@@ -260,7 +260,7 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. diff --git a/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch b/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch index da60c63905d..a2f22ee99b6 100644 --- a/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch +++ b/target/linux/generic/backport-6.1/791-v6.2-03-net-phy-add-Motorcomm-YT8531S-phy-id.patch @@ -22,7 +22,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -245,7 +245,7 @@ config MOTORCOMM_PHY +@@ -260,7 +260,7 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. diff --git a/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch b/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch index 9dce5a8add9..35495978efa 100644 --- a/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch +++ b/target/linux/generic/backport-6.1/791-v6.3-09-net-phy-Add-driver-for-Motorcomm-yt8531-gigabit-ethernet.patch @@ -19,7 +19,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig -@@ -245,7 +245,7 @@ config MOTORCOMM_PHY +@@ -260,7 +260,7 @@ config MOTORCOMM_PHY tristate "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. diff --git a/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch b/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch index 23518d21f70..94cd23c18ac 100644 --- a/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch +++ b/target/linux/generic/backport-6.1/811-v6.4-0002-nvmem-core-introduce-NVMEM-layouts.patch @@ -41,7 +41,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst -@@ -189,3 +189,18 @@ ex:: +@@ -185,3 +185,18 @@ ex:: ===================== See Documentation/devicetree/bindings/nvmem/nvmem.txt diff --git a/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch b/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch index a0874f73d15..200eb1928f8 100644 --- a/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch +++ b/target/linux/generic/backport-6.1/811-v6.4-0014-nvmem-bcm-ocotp-Use-devm_platform_ioremap_resource.patch @@ -19,7 +19,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/nvmem/bcm-ocotp.c +++ b/drivers/nvmem/bcm-ocotp.c -@@ -254,7 +254,6 @@ MODULE_DEVICE_TABLE(acpi, bcm_otpc_acpi_ +@@ -244,7 +244,6 @@ MODULE_DEVICE_TABLE(acpi, bcm_otpc_acpi_ static int bcm_otpc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -27,7 +27,7 @@ Signed-off-by: Greg Kroah-Hartman struct otpc_priv *priv; struct nvmem_device *nvmem; int err; -@@ -269,8 +268,7 @@ static int bcm_otpc_probe(struct platfor +@@ -259,8 +258,7 @@ static int bcm_otpc_probe(struct platfor return -ENODEV; /* Get OTP base address register. */ diff --git a/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch b/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch index 2b2a60e096b..f568c3f6ce5 100644 --- a/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch +++ b/target/linux/generic/backport-6.1/827-v6.3-0001-of-base-add-of_parse_phandle_with_optional_args.patch @@ -24,7 +24,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/include/linux/of.h +++ b/include/linux/of.h -@@ -1169,6 +1169,31 @@ static inline int of_parse_phandle_with_ +@@ -1009,6 +1009,31 @@ static inline int of_parse_phandle_with_ } /** diff --git a/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch b/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch index 39d9fae7239..c4f44b87a4d 100644 --- a/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch +++ b/target/linux/generic/backport-6.1/827-v6.3-0002-of-property-make-.-cells-optional-for-simple-props.patch @@ -21,7 +21,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/of/property.c +++ b/drivers/of/property.c -@@ -1173,8 +1173,8 @@ static struct device_node *parse_prop_ce +@@ -1202,8 +1202,8 @@ static struct device_node *parse_prop_ce if (strcmp(prop_name, list_name)) return NULL; diff --git a/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch b/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch index 774e793ca5a..c2b86de9b97 100644 --- a/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch +++ b/target/linux/generic/backport-6.1/827-v6.3-0003-of-property-add-nvmem-cell-cells-property.patch @@ -19,7 +19,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/of/property.c +++ b/drivers/of/property.c -@@ -1276,7 +1276,7 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-c +@@ -1307,7 +1307,7 @@ DEFINE_SIMPLE_PROP(dmas, "dmas", "#dma-c DEFINE_SIMPLE_PROP(power_domains, "power-domains", "#power-domain-cells") DEFINE_SIMPLE_PROP(hwlocks, "hwlocks", "#hwlock-cells") DEFINE_SIMPLE_PROP(extcon, "extcon", NULL) diff --git a/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch b/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch index 37eefc4570f..8dc370618e6 100644 --- a/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch +++ b/target/linux/generic/backport-6.1/827-v6.3-0004-of-device-Ignore-modalias-of-reused-nodes.patch @@ -17,7 +17,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/of/device.c +++ b/drivers/of/device.c -@@ -249,7 +249,7 @@ static ssize_t of_device_get_modalias(st +@@ -256,7 +256,7 @@ static ssize_t of_device_get_modalias(st ssize_t csize; ssize_t tsize; @@ -26,7 +26,7 @@ Signed-off-by: Greg Kroah-Hartman return -ENODEV; /* Name & Type */ -@@ -372,7 +372,7 @@ int of_device_uevent_modalias(struct dev +@@ -379,7 +379,7 @@ int of_device_uevent_modalias(struct dev { int sl; diff --git a/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch b/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch index dd5820e94a5..dcdc2313ba6 100644 --- a/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch +++ b/target/linux/generic/backport-6.1/827-v6.3-0005-of-device-Do-not-ignore-error-code-in-of_device_ueve.patch @@ -18,7 +18,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/of/device.c +++ b/drivers/of/device.c -@@ -381,6 +381,8 @@ int of_device_uevent_modalias(struct dev +@@ -388,6 +388,8 @@ int of_device_uevent_modalias(struct dev sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], sizeof(env->buf) - env->buflen); diff --git a/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch b/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch index 4713cc71b12..280ed9085c7 100644 --- a/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch +++ b/target/linux/generic/backport-6.1/828-v6.4-0002-of-Update-of_device_get_modalias.patch @@ -23,7 +23,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/of/device.c +++ b/drivers/of/device.c -@@ -241,7 +241,7 @@ const void *of_device_get_match_data(con +@@ -248,7 +248,7 @@ const void *of_device_get_match_data(con } EXPORT_SYMBOL(of_device_get_match_data); @@ -32,7 +32,7 @@ Signed-off-by: Greg Kroah-Hartman { const char *compat; char *c; -@@ -249,19 +249,16 @@ static ssize_t of_device_get_modalias(st +@@ -256,19 +256,16 @@ static ssize_t of_device_get_modalias(st ssize_t csize; ssize_t tsize; @@ -55,7 +55,7 @@ Signed-off-by: Greg Kroah-Hartman csize = strlen(compat) + 1; tsize += csize; if (csize > len) -@@ -286,7 +283,10 @@ int of_device_request_module(struct devi +@@ -293,7 +290,10 @@ int of_device_request_module(struct devi ssize_t size; int ret; @@ -67,7 +67,7 @@ Signed-off-by: Greg Kroah-Hartman if (size < 0) return size; -@@ -297,7 +297,7 @@ int of_device_request_module(struct devi +@@ -304,7 +304,7 @@ int of_device_request_module(struct devi if (!str) return -ENOMEM; @@ -76,7 +76,7 @@ Signed-off-by: Greg Kroah-Hartman str[size - 1] = '\0'; ret = request_module(str); kfree(str); -@@ -314,7 +314,12 @@ EXPORT_SYMBOL_GPL(of_device_request_modu +@@ -321,7 +321,12 @@ EXPORT_SYMBOL_GPL(of_device_request_modu */ ssize_t of_device_modalias(struct device *dev, char *str, ssize_t len) { @@ -90,7 +90,7 @@ Signed-off-by: Greg Kroah-Hartman if (sl < 0) return sl; if (sl > len - 2) -@@ -379,8 +384,8 @@ int of_device_uevent_modalias(struct dev +@@ -386,8 +391,8 @@ int of_device_uevent_modalias(struct dev if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; diff --git a/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch index f15498c7119..f82dc1428aa 100644 --- a/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch +++ b/target/linux/generic/backport-6.1/828-v6.4-0003-of-Rename-of_modalias_node.patch @@ -44,7 +44,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c -@@ -785,9 +785,10 @@ static bool acpi_of_modalias(struct acpi +@@ -806,9 +806,10 @@ static bool acpi_of_modalias(struct acpi * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias buffer * @@ -104,7 +104,7 @@ Signed-off-by: Greg Kroah-Hartman } --- a/drivers/of/base.c +++ b/drivers/of/base.c -@@ -1159,19 +1159,23 @@ struct device_node *of_find_matching_nod +@@ -1208,19 +1208,23 @@ struct device_node *of_find_matching_nod EXPORT_SYMBOL(of_find_matching_node_and_match); /** @@ -133,7 +133,7 @@ Signed-off-by: Greg Kroah-Hartman { const char *compatible, *p; int cplen; -@@ -1180,10 +1184,10 @@ int of_modalias_node(struct device_node +@@ -1229,10 +1233,10 @@ int of_modalias_node(struct device_node if (!compatible || strlen(compatible) > cplen) return -ENODEV; p = strchr(compatible, ','); @@ -148,7 +148,7 @@ Signed-off-by: Greg Kroah-Hartman * of_find_node_by_phandle - Find a node given a phandle --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c -@@ -2128,8 +2128,8 @@ of_register_spi_device(struct spi_contro +@@ -2315,8 +2315,8 @@ of_register_spi_device(struct spi_contro } /* Select device driver */ @@ -161,7 +161,7 @@ Signed-off-by: Greg Kroah-Hartman goto err_out; --- a/include/linux/of.h +++ b/include/linux/of.h -@@ -361,7 +361,8 @@ extern int of_n_addr_cells(struct device +@@ -362,7 +362,8 @@ extern int of_n_addr_cells(struct device extern int of_n_size_cells(struct device_node *np); extern const struct of_device_id *of_match_node( const struct of_device_id *matches, const struct device_node *node); diff --git a/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch b/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch index a70c6f2eec8..39a84161a27 100644 --- a/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch +++ b/target/linux/generic/backport-6.1/828-v6.4-0004-of-Move-of_modalias-to-module.c.patch @@ -43,7 +43,7 @@ Signed-off-by: Greg Kroah-Hartman #include #include #include -@@ -241,42 +240,6 @@ const void *of_device_get_match_data(con +@@ -248,42 +247,6 @@ const void *of_device_get_match_data(con } EXPORT_SYMBOL(of_device_get_match_data); @@ -135,7 +135,7 @@ Signed-off-by: Greg Kroah-Hartman +} --- a/include/linux/of.h +++ b/include/linux/of.h -@@ -373,6 +373,9 @@ extern int of_parse_phandle_with_args_ma +@@ -374,6 +374,9 @@ extern int of_parse_phandle_with_args_ma extern int of_count_phandle_with_args(const struct device_node *np, const char *list_name, const char *cells_name); @@ -145,7 +145,7 @@ Signed-off-by: Greg Kroah-Hartman /* phandle iterator functions */ extern int of_phandle_iterator_init(struct of_phandle_iterator *it, const struct device_node *np, -@@ -885,6 +888,12 @@ static inline int of_count_phandle_with_ +@@ -731,6 +734,12 @@ static inline int of_count_phandle_with_ return -ENOSYS; } diff --git a/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch b/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch index 06bc24ca6e3..046c1df5615 100644 --- a/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch +++ b/target/linux/generic/backport-6.1/828-v6.4-0005-of-Move-the-request-module-helper-logic-to-module.c.patch @@ -31,7 +31,7 @@ Signed-off-by: Greg Kroah-Hartman #include #include #include -@@ -242,30 +241,10 @@ EXPORT_SYMBOL(of_device_get_match_data); +@@ -249,30 +248,10 @@ EXPORT_SYMBOL(of_device_get_match_data); int of_device_request_module(struct device *dev) { @@ -109,7 +109,7 @@ Signed-off-by: Greg Kroah-Hartman +EXPORT_SYMBOL_GPL(of_request_module); --- a/include/linux/of.h +++ b/include/linux/of.h -@@ -375,6 +375,7 @@ extern int of_count_phandle_with_args(co +@@ -376,6 +376,7 @@ extern int of_count_phandle_with_args(co /* module functions */ extern ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len); @@ -117,7 +117,7 @@ Signed-off-by: Greg Kroah-Hartman /* phandle iterator functions */ extern int of_phandle_iterator_init(struct of_phandle_iterator *it, -@@ -893,6 +894,11 @@ static inline ssize_t of_modalias(const +@@ -739,6 +740,11 @@ static inline ssize_t of_modalias(const { return -ENODEV; } From aa56d00aa624ffdc3ed839300d1284f890d31bf7 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 18:07:13 +0200 Subject: [PATCH 68/88] generic: 6.1: refresh hack patches Refresh hack patches with make target/linux/refresh. Signed-off-by: Christian Marangi --- .../generic/hack-6.1/204-module_strip.patch | 38 ++++++++--------- ...-abort-configuration-on-unset-symbol.patch | 4 +- .../hack-6.1/210-darwin_scripts_include.patch | 4 +- .../hack-6.1/212-tools_portability.patch | 29 +------------ .../hack-6.1/220-arm-gc_sections.patch | 8 ++-- .../generic/hack-6.1/221-module_exports.patch | 16 +++---- .../hack-6.1/230-openwrt_lzma_options.patch | 4 +- .../hack-6.1/250-netfilter_depends.patch | 4 +- .../linux/generic/hack-6.1/251-kconfig.patch | 24 +++++------ .../generic/hack-6.1/253-ksmbd-config.patch | 4 +- .../generic/hack-6.1/259-regmap_dynamic.patch | 2 +- .../260-crypto_test_dependencies.patch | 2 +- .../hack-6.1/261-lib-arc4-unhide.patch | 2 +- .../generic/hack-6.1/280-rfkill-stubs.patch | 2 +- .../321-powerpc_crtsavres_prereq.patch | 2 +- ...rans-call-add-disks-after-mtd-device.patch | 6 +-- .../410-block-fit-partition-parser.patch | 20 ++++----- ...upport-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch | 2 +- .../hack-6.1/430-mtk-bmt-support.patch | 2 +- .../generic/hack-6.1/600-bridge_offload.patch | 42 +++++++++---------- ...lter-connmark-introduce-set-dscpmark.patch | 4 +- ...-netfilter-add-xt_FLOWOFFLOAD-target.patch | 12 +++--- .../hack-6.1/651-wireless_mesh_header.patch | 2 +- .../hack-6.1/660-fq_codel_defaults.patch | 2 +- ...t-size-the-hashtable-more-adequately.patch | 2 +- ...-dsa-mv88e6xxx-disable-ATU-violation.patch | 2 +- .../hack-6.1/720-net-phy-add-aqr-phys.patch | 16 +++---- .../721-net-add-packet-mangeling.patch | 18 ++++---- ...hy-aquantia-enable-AQR112-and-AQR412.patch | 15 +++---- ...aquantia-fix-system-side-protocol-mi.patch | 2 +- ...y-aquantia-Add-AQR113-driver-support.patch | 9 ++-- ...ntia-add-PHY_IDs-for-AQR112-variants.patch | 7 ++-- ...-r8152-add-LED-configuration-from-OF.patch | 8 ++-- .../765-mxl-gpy-control-LED-reg-from-DT.patch | 16 +++---- .../hack-6.1/773-bgmac-add-srab-switch.patch | 4 +- .../780-usb-net-MeigLink_modem_support.patch | 6 +-- .../790-SFP-GE-T-ignore-TX_FAULT.patch | 14 +++---- .../800-GPIO-add-named-gpio-exports.patch | 12 +++--- .../hack-6.1/901-debloat_sock_diag.patch | 18 ++++---- .../generic/hack-6.1/902-debloat_proc.patch | 30 ++++++------- .../hack-6.1/904-debloat_dma_buf.patch | 13 +++--- .../911-kobject_add_broadcast_uevent.patch | 2 +- .../hack-6.1/920-device_tree_cmdline.patch | 4 +- ...vert-driver-core-Set-fw_devlink-on-b.patch | 2 +- 44 files changed, 205 insertions(+), 232 deletions(-) diff --git a/target/linux/generic/hack-6.1/204-module_strip.patch b/target/linux/generic/hack-6.1/204-module_strip.patch index ee39d15095d..f0949d32fdd 100644 --- a/target/linux/generic/hack-6.1/204-module_strip.patch +++ b/target/linux/generic/hack-6.1/204-module_strip.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/module.h +++ b/include/linux/module.h -@@ -164,6 +164,7 @@ extern void cleanup_module(void); +@@ -163,6 +163,7 @@ extern void cleanup_module(void); /* Generic info of form tag = "info" */ #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau /* For userspace: you can also call me... */ #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) -@@ -233,12 +234,12 @@ extern void cleanup_module(void); +@@ -232,12 +233,12 @@ extern void cleanup_module(void); * Author(s), use "Name " or just "Name", for multiple * authors use multiple MODULE_AUTHOR() statements/lines. */ @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau /* Creates an alias so file2alias.c can find device table. */ #define MODULE_DEVICE_TABLE(type, name) \ extern typeof(name) __mod_##type##__##name##_device_table \ -@@ -265,7 +266,9 @@ extern typeof(name) __mod_##type##__##na +@@ -264,7 +265,9 @@ extern typeof(name) __mod_##type##__##na */ #if defined(MODULE) || !defined(CONFIG_SYSFS) @@ -49,14 +49,14 @@ Signed-off-by: Felix Fietkau #else #define MODULE_VERSION(_version) \ MODULE_INFO(version, _version); \ -@@ -288,7 +291,7 @@ extern typeof(name) __mod_##type##__##na +@@ -287,7 +290,7 @@ extern typeof(name) __mod_##type##__##na /* Optional firmware file (or files) needed by the module * format is simply firmware file name. Multiple firmware * files require multiple MODULE_FIRMWARE() specifiers */ -#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) +#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware) - #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns) + #define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, __stringify(ns)) --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -88,9 +88,9 @@ Signed-off-by: Felix Fietkau --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig -@@ -2352,6 +2352,13 @@ config UNUSED_KSYMS_WHITELIST - one per line. The path can be absolute, or relative to the kernel - source tree. +@@ -290,4 +290,11 @@ config MODULES_TREE_LOOKUP + def_bool y + depends on PERF_EVENTS || TRACING || CFI_CLANG +config MODULE_STRIPPED + bool "Reduce module size" @@ -100,11 +100,9 @@ Signed-off-by: Felix Fietkau + device tables, etc. + endif # MODULES - - config MODULES_TREE_LOOKUP --- a/kernel/module/main.c +++ b/kernel/module/main.c -@@ -1218,6 +1218,7 @@ static struct module_attribute *modinfo_ +@@ -988,6 +988,7 @@ size_t modinfo_attrs_count = ARRAY_SIZE( static const char vermagic[] = VERMAGIC_STRING; @@ -112,7 +110,7 @@ Signed-off-by: Felix Fietkau int try_to_force_load(struct module *mod, const char *reason) { #ifdef CONFIG_MODULE_FORCE_LOAD -@@ -1229,6 +1230,7 @@ static int try_to_force_load(struct modu +@@ -999,6 +1000,7 @@ int try_to_force_load(struct module *mod return -ENOEXEC; #endif } @@ -120,7 +118,7 @@ Signed-off-by: Felix Fietkau static char *get_modinfo(const struct load_info *info, const char *tag); static char *get_next_modinfo(const struct load_info *info, const char *tag, -@@ -3266,9 +3268,11 @@ static int setup_load_info(struct load_i +@@ -1950,9 +1952,11 @@ static int setup_load_info(struct load_i static int check_modinfo(struct module *mod, struct load_info *info, int flags) { @@ -133,7 +131,7 @@ Signed-off-by: Felix Fietkau if (flags & MODULE_INIT_IGNORE_VERMAGIC) modmagic = NULL; -@@ -3289,6 +3293,7 @@ static int check_modinfo(struct module * +@@ -1973,6 +1977,7 @@ static int check_modinfo(struct module * mod->name); add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK); } @@ -143,7 +141,7 @@ Signed-off-by: Felix Fietkau --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c -@@ -2034,7 +2034,9 @@ static void read_symbols(const char *mod +@@ -1817,7 +1817,9 @@ static void read_symbols(const char *mod symname = remove_dot(info.strtab + sym->st_name); handle_symbol(mod, &info, sym, symname); @@ -153,7 +151,7 @@ Signed-off-by: Felix Fietkau } for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { -@@ -2213,8 +2215,10 @@ static void add_header(struct buffer *b, +@@ -1980,8 +1982,10 @@ static void add_header(struct buffer *b, buf_printf(b, "BUILD_SALT;\n"); buf_printf(b, "BUILD_LTO_INFO;\n"); buf_printf(b, "\n"); @@ -164,7 +162,7 @@ Signed-off-by: Felix Fietkau buf_printf(b, "\n"); buf_printf(b, "__visible struct module __this_module\n"); buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n"); -@@ -2231,8 +2235,10 @@ static void add_header(struct buffer *b, +@@ -1995,8 +1999,10 @@ static void add_header(struct buffer *b, buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); @@ -175,7 +173,7 @@ Signed-off-by: Felix Fietkau buf_printf(b, "\n" -@@ -2245,8 +2251,10 @@ static void add_retpoline(struct buffer +@@ -2004,8 +2010,10 @@ static void add_header(struct buffer *b, "MODULE_INFO(retpoline, \"Y\");\n" "#endif\n"); @@ -186,7 +184,7 @@ Signed-off-by: Felix Fietkau if (strstarts(mod->name, "tools/testing")) buf_printf(b, "\nMODULE_INFO(test, \"Y\");\n"); -@@ -2326,11 +2334,13 @@ static void add_depends(struct buffer *b +@@ -2101,11 +2109,13 @@ static void add_depends(struct buffer *b static void add_srcversion(struct buffer *b, struct module *mod) { @@ -200,7 +198,7 @@ Signed-off-by: Felix Fietkau } static void write_buf(struct buffer *b, const char *fname) -@@ -2579,7 +2589,9 @@ int main(int argc, char **argv) +@@ -2191,7 +2201,9 @@ static void write_mod_c_file(struct modu add_exported_symbols(&buf, mod); add_versions(&buf, mod); add_depends(&buf, mod); diff --git a/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch b/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch index a87c7a51169..df18507041f 100644 --- a/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch +++ b/target/linux/generic/hack-6.1/205-kconfig-abort-configuration-on-unset-symbol.patch @@ -19,7 +19,7 @@ Signed-off-by: David Bauer --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c -@@ -341,6 +341,9 @@ static int conf_askvalue(struct symbol * +@@ -338,6 +338,9 @@ static int conf_askvalue(struct symbol * } /* fall through */ default: @@ -29,7 +29,7 @@ Signed-off-by: David Bauer fflush(stdout); xfgets(line, sizeof(line), stdin); break; -@@ -523,6 +526,9 @@ static int conf_choice(struct menu *menu +@@ -520,6 +523,9 @@ static int conf_choice(struct menu *menu } /* fall through */ case oldaskconfig: diff --git a/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch b/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch index be6adc0d11a..c9612536dec 100644 --- a/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch +++ b/target/linux/generic/hack-6.1/210-darwin_scripts_include.patch @@ -3039,7 +3039,7 @@ Signed-off-by: Florian Fainelli main(int argc, char **argv) --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h -@@ -8,7 +8,11 @@ +@@ -9,7 +9,11 @@ #include #include #include @@ -3049,5 +3049,5 @@ Signed-off-by: Florian Fainelli +#include "elf.h" +#endif + #include "list.h" #include "elfconfig.h" - diff --git a/target/linux/generic/hack-6.1/212-tools_portability.patch b/target/linux/generic/hack-6.1/212-tools_portability.patch index 0b908f7c7d1..4b1c6c49839 100644 --- a/target/linux/generic/hack-6.1/212-tools_portability.patch +++ b/target/linux/generic/hack-6.1/212-tools_portability.patch @@ -83,7 +83,7 @@ Signed-off-by: Felix Fietkau struct kmem_cache; --- a/tools/perf/pmu-events/jevents.py +++ b/tools/perf/pmu-events/jevents.py -@@ -684,6 +684,7 @@ +@@ -684,6 +684,7 @@ def main() -> None: #include "util/header.h" #include "util/pmu.h" #include @@ -91,30 +91,3 @@ Signed-off-by: Felix Fietkau #include struct compact_pmu_event { -# --- a/tools/perf/pmu-events/jevents.c -# +++ b/tools/perf/pmu-events/jevents.c -# @@ -1,4 +1,6 @@ -# +#ifdef __linux__ -# #define _XOPEN_SOURCE 500 /* needed for nftw() */ -# +#endif -# #define _GNU_SOURCE /* needed for asprintf() */ - -# /* Parse event JSON files */ -# @@ -35,6 +37,7 @@ -# #include -# #include -# #include -# +#include -# #include -# #include -# #include -# --- a/tools/perf/pmu-events/json.c -# +++ b/tools/perf/pmu-events/json.c -# @@ -38,7 +38,6 @@ -# #include -# #include "jsmn.h" -# #include "json.h" -# -#include - - -# static char *mapfile(const char *fn, size_t *size) diff --git a/target/linux/generic/hack-6.1/220-arm-gc_sections.patch b/target/linux/generic/hack-6.1/220-arm-gc_sections.patch index 0aa3eb840cd..483118138e2 100644 --- a/target/linux/generic/hack-6.1/220-arm-gc_sections.patch +++ b/target/linux/generic/hack-6.1/220-arm-gc_sections.patch @@ -12,7 +12,7 @@ Signed-off-by: Gabor Juhos --- --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -117,6 +117,7 @@ config ARM +@@ -122,6 +122,7 @@ config ARM select HAVE_UID16 select HAVE_VIRT_CPU_ACCOUNTING_GEN select IRQ_FORCED_THREADING @@ -22,14 +22,14 @@ Signed-off-by: Gabor Juhos select OF_EARLY_FLATTREE if OF --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile -@@ -92,6 +92,7 @@ endif +@@ -91,6 +91,7 @@ endif ifeq ($(CONFIG_USE_OF),y) OBJS += $(libfdt_objs) fdt_check_mem_start.o endif +KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL)) - # -fstack-protector-strong triggers protection checks in this code, - # but it is being used too early to link to meaningful stack_chk logic. + OBJS += lib1funcs.o ashldi3.o bswapsdi2.o + --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -75,7 +75,7 @@ SECTIONS diff --git a/target/linux/generic/hack-6.1/221-module_exports.patch b/target/linux/generic/hack-6.1/221-module_exports.patch index adc2cefbd2e..d1ff81613a8 100644 --- a/target/linux/generic/hack-6.1/221-module_exports.patch +++ b/target/linux/generic/hack-6.1/221-module_exports.patch @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau /* Align . to a 8 byte boundary equals to maximum function alignment. */ #define ALIGN_FUNCTION() . = ALIGN(8) -@@ -485,14 +495,14 @@ +@@ -512,14 +522,14 @@ /* Kernel symbol table: Normal symbols */ \ __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ __start___ksymtab = .; \ @@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau __stop___ksymtab_gpl = .; \ } \ \ -@@ -512,7 +522,7 @@ +@@ -539,7 +549,7 @@ \ /* Kernel symbol table: strings */ \ __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ @@ -56,7 +56,7 @@ Signed-off-by: Felix Fietkau } \ \ /* __*init sections */ \ -@@ -1018,6 +1028,8 @@ +@@ -1048,6 +1058,8 @@ #define COMMON_DISCARDS \ SANITIZER_DISCARDS \ PATCHABLE_DISCARDS \ @@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau *(.modinfo) \ --- a/include/linux/export.h +++ b/include/linux/export.h -@@ -84,6 +84,12 @@ struct kernel_symbol { +@@ -72,6 +72,12 @@ struct kernel_symbol { #else @@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau /* * For every exported symbol, do the following: * -@@ -101,7 +107,7 @@ struct kernel_symbol { +@@ -87,7 +93,7 @@ struct kernel_symbol { extern typeof(sym) sym; \ extern const char __kstrtab_##sym[]; \ extern const char __kstrtabns_##sym[]; \ @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau "__kstrtabns_" #sym ": \n" \ --- a/include/asm-generic/export.h +++ b/include/asm-generic/export.h -@@ -26,6 +26,12 @@ +@@ -31,6 +31,12 @@ #endif .endm @@ -104,7 +104,7 @@ Signed-off-by: Felix Fietkau /* * note on .section use: we specify progbits since usage of the "M" (SHF_MERGE) * section flag requires it. Use '%progbits' instead of '@progbits' since the -@@ -39,7 +45,7 @@ +@@ -44,7 +50,7 @@ __ksymtab_\name: __put \val, __kstrtab_\name .previous @@ -115,7 +115,7 @@ Signed-off-by: Felix Fietkau .previous --- a/scripts/Makefile.build +++ b/scripts/Makefile.build -@@ -397,7 +397,7 @@ targets += $(real-dtb-y) $(lib-y) $(alwa +@@ -388,7 +388,7 @@ targets += $(real-dtb-y) $(lib-y) $(alwa # Linker scripts preprocessor (.lds.S -> .lds) # --------------------------------------------------------------------------- quiet_cmd_cpp_lds_S = LDS $@ diff --git a/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch index a28878427a4..55530c5c7e4 100644 --- a/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch +++ b/target/linux/generic/hack-6.1/230-openwrt_lzma_options.patch @@ -23,7 +23,7 @@ Signed-off-by: Imre Kaloz { {0x02, 0x21}, "lz4", unlz4 }, --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib -@@ -402,10 +402,10 @@ quiet_cmd_bzip2 = BZIP2 $@ +@@ -443,10 +443,10 @@ quiet_cmd_bzip2_with_size = BZIP2 $@ # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ @@ -35,4 +35,4 @@ Signed-off-by: Imre Kaloz + cmd_lzma_with_size = { cat $(real-prereqs) | $(LZMA) e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@ quiet_cmd_lzo = LZO $@ - cmd_lzo = { cat $(real-prereqs) | $(KLZOP) -9; $(size_append); } > $@ + cmd_lzo = cat $(real-prereqs) | $(KLZOP) -9 > $@ diff --git a/target/linux/generic/hack-6.1/250-netfilter_depends.patch b/target/linux/generic/hack-6.1/250-netfilter_depends.patch index 495c73ffa88..fbb5a61157f 100644 --- a/target/linux/generic/hack-6.1/250-netfilter_depends.patch +++ b/target/linux/generic/hack-6.1/250-netfilter_depends.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig -@@ -243,7 +243,6 @@ config NF_CONNTRACK_FTP +@@ -253,7 +253,6 @@ config NF_CONNTRACK_FTP config NF_CONNTRACK_H323 tristate "H.323 protocol support" @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau depends on NETFILTER_ADVANCED help H.323 is a VoIP signalling protocol from ITU-T. As one of the most -@@ -1106,7 +1105,6 @@ config NETFILTER_XT_TARGET_SECMARK +@@ -1118,7 +1117,6 @@ config NETFILTER_XT_TARGET_SECMARK config NETFILTER_XT_TARGET_TCPMSS tristate '"TCPMSS" target support' diff --git a/target/linux/generic/hack-6.1/251-kconfig.patch b/target/linux/generic/hack-6.1/251-kconfig.patch index 0e24c3e8041..e1ecbca6fe3 100644 --- a/target/linux/generic/hack-6.1/251-kconfig.patch +++ b/target/linux/generic/hack-6.1/251-kconfig.patch @@ -16,8 +16,8 @@ Signed-off-by: John Crispin --- a/crypto/Kconfig +++ b/crypto/Kconfig -@@ -34,7 +34,7 @@ config CRYPTO_FIPS - this is. +@@ -55,7 +55,7 @@ config CRYPTO_FIPS_VERSION + By default the KERNELRELEASE value is used. config CRYPTO_ALGAPI - tristate @@ -25,7 +25,7 @@ Signed-off-by: John Crispin select CRYPTO_ALGAPI2 help This option provides the API for cryptographic algorithms. -@@ -43,7 +43,7 @@ config CRYPTO_ALGAPI2 +@@ -64,7 +64,7 @@ config CRYPTO_ALGAPI2 tristate config CRYPTO_AEAD @@ -34,7 +34,7 @@ Signed-off-by: John Crispin select CRYPTO_AEAD2 select CRYPTO_ALGAPI -@@ -54,7 +54,7 @@ config CRYPTO_AEAD2 +@@ -75,7 +75,7 @@ config CRYPTO_AEAD2 select CRYPTO_RNG2 config CRYPTO_SKCIPHER @@ -43,7 +43,7 @@ Signed-off-by: John Crispin select CRYPTO_SKCIPHER2 select CRYPTO_ALGAPI -@@ -64,7 +64,7 @@ config CRYPTO_SKCIPHER2 +@@ -85,7 +85,7 @@ config CRYPTO_SKCIPHER2 select CRYPTO_RNG2 config CRYPTO_HASH @@ -52,7 +52,7 @@ Signed-off-by: John Crispin select CRYPTO_HASH2 select CRYPTO_ALGAPI -@@ -73,7 +73,7 @@ config CRYPTO_HASH2 +@@ -94,7 +94,7 @@ config CRYPTO_HASH2 select CRYPTO_ALGAPI2 config CRYPTO_RNG @@ -92,7 +92,7 @@ Signed-off-by: John Crispin bool --- a/lib/Kconfig +++ b/lib/Kconfig -@@ -443,16 +443,16 @@ config BCH_CONST_T +@@ -457,16 +457,16 @@ config BCH_CONST_T # Textsearch support is select'ed if needed # config TEXTSEARCH @@ -115,8 +115,8 @@ Signed-off-by: John Crispin bool --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig -@@ -11,7 +11,7 @@ config NETFILTER_INGRESS - infrastructure. +@@ -22,7 +22,7 @@ config NETFILTER_SKIP_EGRESS + def_bool NETFILTER_EGRESS && (NET_CLS_ACT || IFB) config NETFILTER_NETLINK - tristate @@ -147,7 +147,7 @@ Signed-off-by: John Crispin config CFG80211 tristate "cfg80211 - wireless configuration API" -@@ -204,7 +204,7 @@ config CFG80211_WEXT_EXPORT +@@ -208,7 +208,7 @@ config CFG80211_WEXT_EXPORT endif # CFG80211 config LIB80211 @@ -156,7 +156,7 @@ Signed-off-by: John Crispin default n help This options enables a library of common routines used -@@ -213,17 +213,17 @@ config LIB80211 +@@ -217,17 +217,17 @@ config LIB80211 Drivers should select this themselves if needed. config LIB80211_CRYPT_WEP @@ -199,7 +199,7 @@ Signed-off-by: John Crispin bool --- a/net/Kconfig +++ b/net/Kconfig -@@ -432,7 +432,7 @@ config NET_DEVLINK +@@ -430,7 +430,7 @@ config NET_DEVLINK default n config PAGE_POOL diff --git a/target/linux/generic/hack-6.1/253-ksmbd-config.patch b/target/linux/generic/hack-6.1/253-ksmbd-config.patch index b8cb94f62bc..b0c379657e3 100644 --- a/target/linux/generic/hack-6.1/253-ksmbd-config.patch +++ b/target/linux/generic/hack-6.1/253-ksmbd-config.patch @@ -10,7 +10,7 @@ Subject: [PATCH] Kconfig: add tristate for OID and ASNI string --- a/init/Kconfig +++ b/init/Kconfig -@@ -2388,7 +2388,7 @@ config PADATA +@@ -2003,7 +2003,7 @@ config PADATA bool config ASN1 @@ -21,7 +21,7 @@ Subject: [PATCH] Kconfig: add tristate for OID and ASNI string that can be interpreted by the ASN.1 stream decoder and used to --- a/lib/Kconfig +++ b/lib/Kconfig -@@ -614,7 +614,7 @@ config LIBFDT +@@ -637,7 +637,7 @@ config LIBFDT bool config OID_REGISTRY diff --git a/target/linux/generic/hack-6.1/259-regmap_dynamic.patch b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch index 8cf6c035e50..407bc72ac8d 100644 --- a/target/linux/generic/hack-6.1/259-regmap_dynamic.patch +++ b/target/linux/generic/hack-6.1/259-regmap_dynamic.patch @@ -125,7 +125,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -3348,3 +3349,5 @@ static int __init regmap_initcall(void) +@@ -3511,3 +3512,5 @@ static int __init regmap_initcall(void) return 0; } postcore_initcall(regmap_initcall); diff --git a/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch b/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch index 64daa827439..7ea517496e2 100644 --- a/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch +++ b/target/linux/generic/hack-6.1/260-crypto_test_dependencies.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/crypto/Kconfig +++ b/crypto/Kconfig -@@ -121,13 +121,13 @@ config CRYPTO_MANAGER +@@ -142,13 +142,13 @@ config CRYPTO_MANAGER cbc(aes). config CRYPTO_MANAGER2 diff --git a/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch b/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch index ee923c73f75..01829b2d51e 100644 --- a/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch +++ b/target/linux/generic/hack-6.1/261-lib-arc4-unhide.patch @@ -13,7 +13,7 @@ from backports. --- a/lib/crypto/Kconfig +++ b/lib/crypto/Kconfig -@@ -6,7 +6,7 @@ config CRYPTO_LIB_AES +@@ -9,7 +9,7 @@ config CRYPTO_LIB_AES tristate config CRYPTO_LIB_ARC4 diff --git a/target/linux/generic/hack-6.1/280-rfkill-stubs.patch b/target/linux/generic/hack-6.1/280-rfkill-stubs.patch index 7a650d132eb..ff6638f7a05 100644 --- a/target/linux/generic/hack-6.1/280-rfkill-stubs.patch +++ b/target/linux/generic/hack-6.1/280-rfkill-stubs.patch @@ -26,7 +26,7 @@ Signed-off-by: John Crispin * @name: name of the struct -- the string is not copied internally --- a/net/Makefile +++ b/net/Makefile -@@ -52,7 +52,7 @@ obj-$(CONFIG_TIPC) += tipc/ +@@ -51,7 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/ obj-$(CONFIG_NETLABEL) += netlabel/ obj-$(CONFIG_IUCV) += iucv/ obj-$(CONFIG_SMC) += smc/ diff --git a/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch index 215528a90c5..17eba0b354e 100644 --- a/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch +++ b/target/linux/generic/hack-6.1/321-powerpc_crtsavres_prereq.patch @@ -16,7 +16,7 @@ Signed-off-by: Alexandros C. Couloumbis --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile -@@ -61,19 +61,6 @@ machine-$(CONFIG_PPC64) += 64 +@@ -42,19 +42,6 @@ machine-$(CONFIG_PPC64) += 64 machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le UTS_MACHINE := $(subst $(space),,$(machine-y)) diff --git a/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch index 7999f5ac6d8..c0fa2ddabf4 100644 --- a/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch +++ b/target/linux/generic/hack-6.1/402-mtd-blktrans-call-add-disks-after-mtd-device.patch @@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c -@@ -384,19 +384,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt +@@ -386,19 +386,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt if (new->readonly) set_disk_ro(gd, 1); @@ -45,7 +45,7 @@ Signed-off-by: Daniel Golle out_free_tag_set: blk_mq_free_tag_set(new->tag_set); out_kfree_tag_set: -@@ -402,6 +395,35 @@ out_list_del: +@@ -408,6 +397,35 @@ out_list_del: return ret; } @@ -91,7 +91,7 @@ Signed-off-by: Daniel Golle #include "mtdcore.h" -@@ -1082,6 +1083,8 @@ int mtd_device_parse_register(struct mtd +@@ -1074,6 +1075,8 @@ int mtd_device_parse_register(struct mtd register_reboot_notifier(&mtd->reboot_notifier); } diff --git a/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch index 854621bb58f..0384dad85e5 100644 --- a/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch +++ b/target/linux/generic/hack-6.1/410-block-fit-partition-parser.patch @@ -19,7 +19,7 @@ Subject: [PATCH] kernel: add block fit partition parser --- a/block/blk.h +++ b/block/blk.h -@@ -354,6 +354,8 @@ void blk_free_ext_minor(unsigned int min +@@ -414,6 +414,8 @@ void blk_free_ext_minor(unsigned int min #define ADDPART_FLAG_NONE 0 #define ADDPART_FLAG_RAID 1 #define ADDPART_FLAG_WHOLEDISK 2 @@ -30,7 +30,7 @@ Subject: [PATCH] kernel: add block fit partition parser int bdev_del_partition(struct gendisk *disk, int partno); --- a/block/partitions/Kconfig +++ b/block/partitions/Kconfig -@@ -101,6 +101,13 @@ config ATARI_PARTITION +@@ -103,6 +103,13 @@ config ATARI_PARTITION Say Y here if you would like to use hard disks under Linux which were partitioned under the Atari OS. @@ -56,7 +56,7 @@ Subject: [PATCH] kernel: add block fit partition parser obj-$(CONFIG_LDM_PARTITION) += ldm.o --- a/block/partitions/check.h +++ b/block/partitions/check.h -@@ -58,6 +58,7 @@ int amiga_partition(struct parsed_partit +@@ -57,6 +57,7 @@ int amiga_partition(struct parsed_partit int atari_partition(struct parsed_partitions *state); int cmdline_partition(struct parsed_partitions *state); int efi_partition(struct parsed_partitions *state); @@ -64,7 +64,7 @@ Subject: [PATCH] kernel: add block fit partition parser int ibm_partition(struct parsed_partitions *); int karma_partition(struct parsed_partitions *state); int ldm_partition(struct parsed_partitions *state); -@@ -68,3 +69,5 @@ int sgi_partition(struct parsed_partitio +@@ -67,3 +68,5 @@ int sgi_partition(struct parsed_partitio int sun_partition(struct parsed_partitions *state); int sysv68_partition(struct parsed_partitions *state); int ultrix_partition(struct parsed_partitions *state); @@ -72,9 +72,9 @@ Subject: [PATCH] kernel: add block fit partition parser +int parse_fit_partitions(struct parsed_partitions *state, u64 start_sector, u64 nr_sectors, int *slot, int add_remain); --- a/block/partitions/core.c +++ b/block/partitions/core.c -@@ -12,6 +12,10 @@ +@@ -10,6 +10,10 @@ + #include #include - #include #include +#ifdef CONFIG_FIT_PARTITION +#include @@ -83,7 +83,7 @@ Subject: [PATCH] kernel: add block fit partition parser #include "check.h" static int (*check_part[])(struct parsed_partitions *) = { -@@ -48,6 +52,9 @@ static int (*check_part[])(struct parsed +@@ -46,6 +50,9 @@ static int (*check_part[])(struct parsed #ifdef CONFIG_EFI_PARTITION efi_partition, /* this must come before msdos */ #endif @@ -93,7 +93,7 @@ Subject: [PATCH] kernel: add block fit partition parser #ifdef CONFIG_SGI_PARTITION sgi_partition, #endif -@@ -408,6 +415,11 @@ static struct block_device *add_partitio +@@ -398,6 +405,11 @@ static struct block_device *add_partitio goto out_del; } @@ -105,7 +105,7 @@ Subject: [PATCH] kernel: add block fit partition parser /* everything is up and running, commence */ err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL); if (err) -@@ -598,6 +610,11 @@ static bool blk_add_partition(struct gen +@@ -585,6 +597,11 @@ static bool blk_add_partition(struct gen (state->parts[p].flags & ADDPART_FLAG_RAID)) md_autodetect_dev(part->bd_dev); @@ -143,7 +143,7 @@ Subject: [PATCH] kernel: add block fit partition parser kfree(gpt); --- a/block/partitions/efi.h +++ b/block/partitions/efi.h -@@ -52,6 +52,9 @@ +@@ -51,6 +51,9 @@ #define PARTITION_LINUX_LVM_GUID \ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) diff --git a/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch b/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch index 947b2c262f3..8e8e5cea8d6 100644 --- a/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch +++ b/target/linux/generic/hack-6.1/420-mtd-support-OpenWrt-s-MTD_ROOTFS_ROOT_DEV.patch @@ -12,7 +12,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c -@@ -761,7 +761,8 @@ int add_mtd_device(struct mtd_info *mtd) +@@ -750,7 +750,8 @@ int add_mtd_device(struct mtd_info *mtd) mutex_unlock(&mtd_table_mutex); diff --git a/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch index 1476f4fd562..1e69ee64460 100644 --- a/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch +++ b/target/linux/generic/hack-6.1/430-mtk-bmt-support.patch @@ -23,7 +23,7 @@ Subject: [PATCH] mtd/nand: add MediaTek NAND bad block managment table depends on HAS_IOMEM --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile -@@ -2,6 +2,7 @@ +@@ -3,6 +3,7 @@ nandcore-objs := core.o bbt.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o diff --git a/target/linux/generic/hack-6.1/600-bridge_offload.patch b/target/linux/generic/hack-6.1/600-bridge_offload.patch index 6462044bbe3..aa78c96e7f1 100644 --- a/target/linux/generic/hack-6.1/600-bridge_offload.patch +++ b/target/linux/generic/hack-6.1/600-bridge_offload.patch @@ -25,7 +25,7 @@ Subject: [PATCH] net/bridge: add bridge offload --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h -@@ -59,6 +59,7 @@ struct br_ip_list { +@@ -60,6 +60,7 @@ struct br_ip_list { #define BR_TX_FWD_OFFLOAD BIT(20) #define BR_PORT_LOCKED BIT(21) #define BR_BPDU_FILTER BIT(22) @@ -54,7 +54,7 @@ Subject: [PATCH] net/bridge: add bridge offload /* * Handle changes in state of network devices enslaved to a bridge. -@@ -381,6 +382,10 @@ static int __init br_init(void) +@@ -389,6 +390,10 @@ static int __init br_init(void) if (err) goto err_out; @@ -65,7 +65,7 @@ Subject: [PATCH] net/bridge: add bridge offload err = register_pernet_subsys(&br_net_ops); if (err) goto err_out1; -@@ -430,6 +435,8 @@ err_out3: +@@ -438,6 +443,8 @@ err_out3: err_out2: unregister_pernet_subsys(&br_net_ops); err_out1: @@ -74,7 +74,7 @@ Subject: [PATCH] net/bridge: add bridge offload br_fdb_fini(); err_out: stp_proto_unregister(&br_stp_proto); -@@ -452,6 +459,7 @@ static void __exit br_deinit(void) +@@ -460,6 +467,7 @@ static void __exit br_deinit(void) #if IS_ENABLED(CONFIG_ATM_LANE) br_fdb_test_addr_hook = NULL; #endif @@ -84,7 +84,7 @@ Subject: [PATCH] net/bridge: add bridge offload --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c -@@ -524,6 +524,8 @@ void br_dev_setup(struct net_device *dev +@@ -525,6 +525,8 @@ void br_dev_setup(struct net_device *dev br->bridge_hello_time = br->hello_time = 2 * HZ; br->bridge_forward_delay = br->forward_delay = 15 * HZ; br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME; @@ -103,7 +103,7 @@ Subject: [PATCH] net/bridge: add bridge offload static const struct rhashtable_params br_fdb_rht_params = { .head_offset = offsetof(struct net_bridge_fdb_entry, rhnode), -@@ -185,6 +185,8 @@ static void fdb_notify(struct net_bridge +@@ -185,6 +186,8 @@ static void fdb_notify(struct net_bridge struct sk_buff *skb; int err = -ENOBUFS; @@ -112,13 +112,13 @@ Subject: [PATCH] net/bridge: add bridge offload if (swdev_notify) br_switchdev_fdb_notify(br, fdb, type); -@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_ +@@ -393,6 +396,8 @@ static struct net_bridge_fdb_entry *fdb_ fdb->key.vlan_id = vid; fdb->flags = flags; fdb->updated = fdb->used = jiffies; + INIT_HLIST_HEAD(&fdb->offload_in); + INIT_HLIST_HEAD(&fdb->offload_out); - err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode, + err = rhashtable_lookup_insert_fast(&br->fdb_hash_tbl, &fdb->rhnode, br_fdb_rht_params); if (err) { --- a/net/bridge/br_forward.c @@ -150,7 +150,7 @@ Subject: [PATCH] net/bridge: add bridge offload /* * Determine initial path cost based on speed. -@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s +@@ -437,7 +438,7 @@ static struct net_bridge_port *new_nbp(s p->path_cost = port_cost(dev); p->priority = 0x8000 >> BR_PORT_BITS; p->port_no = index; @@ -159,7 +159,7 @@ Subject: [PATCH] net/bridge: add bridge offload br_init_port(p); br_set_state(p, BR_STATE_DISABLED); br_stp_port_timer_init(p); -@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri +@@ -761,6 +762,9 @@ void br_port_flags_change(struct net_bri if (mask & BR_NEIGH_SUPPRESS) br_recalculate_neigh_suppress_enabled(br); @@ -179,7 +179,7 @@ Subject: [PATCH] net/bridge: add bridge offload static int br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) -@@ -171,6 +172,7 @@ int br_handle_frame_finish(struct net *n +@@ -189,6 +190,7 @@ int br_handle_frame_finish(struct net *n dst->used = now; br_forward(dst->dst, skb, local_rcv, false); } else { @@ -187,7 +187,7 @@ Subject: [PATCH] net/bridge: add bridge offload if (!mcast_hit) br_flood(br, skb, pkt_type, local_rcv, false); else -@@ -304,6 +306,9 @@ static rx_handler_result_t br_handle_fra +@@ -322,6 +324,9 @@ static rx_handler_result_t br_handle_fra memset(skb->cb, 0, sizeof(struct br_input_skb_cb)); p = br_port_get_rcu(skb->dev); @@ -640,7 +640,7 @@ Subject: [PATCH] net/bridge: add bridge offload +} --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h -@@ -268,7 +268,13 @@ struct net_bridge_fdb_entry { +@@ -271,7 +271,13 @@ struct net_bridge_fdb_entry { unsigned long updated ____cacheline_aligned_in_smp; unsigned long used; @@ -654,8 +654,8 @@ Subject: [PATCH] net/bridge: add bridge offload + }; }; - #define MDB_PG_FLAGS_PERMANENT BIT(0) -@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry { + struct net_bridge_fdb_flush_desc { +@@ -353,6 +359,12 @@ struct net_bridge_mdb_entry { struct rcu_head rcu; }; @@ -668,7 +668,7 @@ Subject: [PATCH] net/bridge: add bridge offload struct net_bridge_port { struct net_bridge *br; struct net_device *dev; -@@ -403,6 +415,7 @@ struct net_bridge_port { +@@ -414,6 +426,7 @@ struct net_bridge_port { u16 backup_redirected_cnt; struct bridge_stp_xstats stp_xstats; @@ -676,7 +676,7 @@ Subject: [PATCH] net/bridge: add bridge offload }; #define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj) -@@ -519,6 +532,9 @@ struct net_bridge { +@@ -531,6 +544,9 @@ struct net_bridge { struct kobject *ifobj; u32 auto_cnt; @@ -686,7 +686,7 @@ Subject: [PATCH] net/bridge: add bridge offload #ifdef CONFIG_NET_SWITCHDEV /* Counter used to make sure that hardware domains get unique * identifiers in case a bridge spans multiple switchdev instances. -@@ -553,6 +569,10 @@ struct br_input_skb_cb { +@@ -565,6 +581,10 @@ struct br_input_skb_cb { #ifdef CONFIG_NETFILTER_FAMILY_BRIDGE u8 br_netfilter_broute:1; #endif @@ -733,7 +733,7 @@ Subject: [PATCH] net/bridge: add bridge offload /* since time values in bpdu are in jiffies and then scaled (1/256) * before sending, make sure that is at least one STP tick. -@@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port +@@ -58,6 +59,8 @@ void br_set_state(struct net_bridge_port (unsigned int) p->port_no, p->dev->name, br_port_state_names[p->state]); @@ -752,7 +752,7 @@ Subject: [PATCH] net/bridge: add bridge offload /* IMPORTANT: new bridge options must be added with netlink support only * please do not add new sysfs entries -@@ -930,6 +931,38 @@ static ssize_t vlan_stats_per_port_store +@@ -933,6 +934,38 @@ static ssize_t vlan_stats_per_port_store static DEVICE_ATTR_RW(vlan_stats_per_port); #endif @@ -791,7 +791,7 @@ Subject: [PATCH] net/bridge: add bridge offload static struct attribute *bridge_attrs[] = { &dev_attr_forward_delay.attr, &dev_attr_hello_time.attr, -@@ -984,6 +1017,8 @@ static struct attribute *bridge_attrs[] +@@ -987,6 +1020,8 @@ static struct attribute *bridge_attrs[] &dev_attr_vlan_stats_enabled.attr, &dev_attr_vlan_stats_per_port.attr, #endif diff --git a/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch b/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch index c368c4ae3bf..444f8edfea7 100644 --- a/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch +++ b/target/linux/generic/hack-6.1/645-netfilter-connmark-introduce-set-dscpmark.patch @@ -83,7 +83,7 @@ Signed-off-by: Kevin Darbyshire-Bryant --- a/include/uapi/linux/netfilter/xt_connmark.h +++ b/include/uapi/linux/netfilter/xt_connmark.h -@@ -20,6 +20,11 @@ enum { +@@ -15,6 +15,11 @@ enum { }; enum { @@ -95,7 +95,7 @@ Signed-off-by: Kevin Darbyshire-Bryant D_SHIFT_LEFT = 0, D_SHIFT_RIGHT, }; -@@ -34,6 +39,11 @@ struct xt_connmark_tginfo2 { +@@ -29,6 +34,11 @@ struct xt_connmark_tginfo2 { __u8 shift_dir, shift_bits, mode; }; diff --git a/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch index 476c5948ab0..386291bfe81 100644 --- a/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch +++ b/target/linux/generic/hack-6.1/650-netfilter-add-xt_FLOWOFFLOAD-target.patch @@ -8,7 +8,7 @@ Signed-off-by: Felix Fietkau --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig -@@ -1011,6 +1010,15 @@ config NETFILTER_XT_TARGET_NOTRACK +@@ -1023,6 +1023,15 @@ config NETFILTER_XT_TARGET_NOTRACK depends on NETFILTER_ADVANCED select NETFILTER_XT_TARGET_CT @@ -26,7 +26,7 @@ Signed-off-by: Felix Fietkau depends on NETFILTER_ADVANCED --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile -@@ -143,6 +143,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF +@@ -154,6 +154,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o @@ -745,7 +745,7 @@ Signed-off-by: Felix Fietkau #include #include #include -@@ -380,8 +379,7 @@ flow_offload_lookup(struct nf_flowtable +@@ -381,8 +380,7 @@ flow_offload_lookup(struct nf_flowtable } EXPORT_SYMBOL_GPL(flow_offload_lookup); @@ -755,13 +755,13 @@ Signed-off-by: Felix Fietkau void (*iter)(struct nf_flowtable *flowtable, struct flow_offload *flow, void *data), void *data) -@@ -435,6 +433,7 @@ static void nf_flow_offload_gc_step(stru +@@ -436,6 +434,7 @@ static void nf_flow_offload_gc_step(stru nf_flow_offload_stats(flow_table, flow); } } +EXPORT_SYMBOL_GPL(nf_flow_table_iterate); - static void nf_flow_offload_work_gc(struct work_struct *work) + void nf_flow_table_gc_run(struct nf_flowtable *flow_table) { --- /dev/null +++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h @@ -785,7 +785,7 @@ Signed-off-by: Felix Fietkau +#endif /* _XT_FLOWOFFLOAD_H */ --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h -@@ -275,6 +275,11 @@ void nf_flow_table_free(struct nf_flowta +@@ -280,6 +280,11 @@ void nf_flow_table_free(struct nf_flowta void flow_offload_teardown(struct flow_offload *flow); diff --git a/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch b/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch index 12a031ec84d..fd7d5346ad9 100644 --- a/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch +++ b/target/linux/generic/hack-6.1/651-wireless_mesh_header.patch @@ -11,7 +11,7 @@ Signed-off-by: Imre Kaloz --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -145,8 +145,8 @@ static inline bool dev_xmit_complete(int +@@ -149,8 +149,8 @@ static inline bool dev_xmit_complete(int #if defined(CONFIG_HYPERV_NET) # define LL_MAX_HEADER 128 diff --git a/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch b/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch index a57a045f4a8..b923a2d206d 100644 --- a/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch +++ b/target/linux/generic/hack-6.1/660-fq_codel_defaults.patch @@ -13,7 +13,7 @@ Signed-off-by: Felix Fietkau --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c -@@ -467,7 +467,11 @@ static int fq_codel_init(struct Qdisc *s +@@ -471,7 +471,11 @@ static int fq_codel_init(struct Qdisc *s sch->limit = 10*1024; q->flows_cnt = 1024; diff --git a/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch b/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch index 683aa8a8df3..b9dda6cadab 100644 --- a/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch +++ b/target/linux/generic/hack-6.1/661-kernel-ct-size-the-hashtable-more-adequately.patch @@ -14,7 +14,7 @@ Signed-off-by: Rui Salvaterra --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c -@@ -2735,7 +2735,7 @@ int nf_conntrack_init_start(void) +@@ -2702,7 +2702,7 @@ int nf_conntrack_init_start(void) if (!nf_conntrack_htable_size) { nf_conntrack_htable_size diff --git a/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch index 8f2e6e0e0e8..25a3f83b242 100644 --- a/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch +++ b/target/linux/generic/hack-6.1/711-net-dsa-mv88e6xxx-disable-ATU-violation.patch @@ -9,7 +9,7 @@ Subject: [PATCH] net/dsa/mv88e6xxx: disable ATU violation --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -2981,6 +2981,9 @@ static int mv88e6xxx_setup_port(struct m +@@ -3465,6 +3465,9 @@ static int mv88e6xxx_setup_port(struct m else reg = 1 << port; diff --git a/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch index de6fdb3ceaa..fd2687d8ba9 100644 --- a/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch +++ b/target/linux/generic/hack-6.1/720-net-phy-add-aqr-phys.patch @@ -9,7 +9,7 @@ Signed-off-by: Birger Koblitz --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -20,6 +20,7 @@ +@@ -23,6 +23,7 @@ #define PHY_ID_AQCS109 0x03a1b5c2 #define PHY_ID_AQR405 0x03a1b4b0 #define PHY_ID_AQR113C 0x31c31c12 @@ -17,7 +17,7 @@ Signed-off-by: Birger Koblitz #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -372,6 +374,49 @@ static int aqr107_read_rate(struct phy_d +@@ -415,6 +416,49 @@ static int aqr107_read_rate(struct phy_d return 0; } @@ -67,7 +67,7 @@ Signed-off-by: Birger Koblitz static int aqr107_read_status(struct phy_device *phydev) { int val, ret; -@@ -502,7 +547,7 @@ static void aqr107_chip_info(struct phy_ +@@ -554,7 +598,7 @@ static void aqr107_chip_info(struct phy_ build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val); prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val); @@ -76,7 +76,7 @@ Signed-off-by: Birger Koblitz fw_major, fw_minor, build_id, prov_id); } -@@ -706,7 +706,7 @@ static struct phy_driver aqr_driver[] = +@@ -809,7 +853,7 @@ static struct phy_driver aqr_driver[] = .config_aneg = aqr_config_aneg, .config_intr = aqr_config_intr, .handle_interrupt = aqr_handle_interrupt, @@ -85,9 +85,9 @@ Signed-off-by: Birger Koblitz .get_tunable = aqr107_get_tunable, .set_tunable = aqr107_set_tunable, .suspend = aqr107_suspend, -@@ -708,6 +762,24 @@ static struct phy_driver aqr_driver[] = - .handle_interrupt = aqr_handle_interrupt, - .read_status = aqr_read_status, +@@ -819,6 +863,24 @@ static struct phy_driver aqr_driver[] = + .get_stats = aqr107_get_stats, + .link_change_notify = aqr107_link_change_notify, }, +{ + PHY_ID_MATCH_MODEL(PHY_ID_AQR813), @@ -110,7 +110,7 @@ Signed-off-by: Birger Koblitz }; module_phy_driver(aqr_driver); -@@ -709,6 +790,7 @@ static struct mdio_device_id __maybe_unu +@@ -832,6 +894,7 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, diff --git a/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch index adb437548ef..14a9818c3a0 100644 --- a/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch +++ b/target/linux/generic/hack-6.1/721-net-add-packet-mangeling.patch @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -1655,6 +1655,7 @@ enum netdev_priv_flags { +@@ -1704,6 +1704,7 @@ enum netdev_priv_flags { IFF_LIVE_RENAME_OK = 1<<30, IFF_TX_SKB_NO_LINEAR = BIT_ULL(31), IFF_CHANGE_PROTO_DOWN = BIT_ULL(32), @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau }; #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN -@@ -1687,6 +1691,7 @@ enum netdev_priv_flags { +@@ -1738,6 +1739,7 @@ enum netdev_priv_flags { #define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER #define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK #define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR @@ -35,7 +35,7 @@ Signed-off-by: Felix Fietkau /* Specifies the type of the struct net_device::ml_priv pointer */ enum netdev_ml_priv_type { -@@ -2048,6 +2054,11 @@ struct net_device { +@@ -2106,6 +2108,11 @@ struct net_device { const struct tlsdev_ops *tlsdev_ops; #endif @@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau const struct header_ops *header_ops; unsigned char operstate; -@@ -2122,6 +2133,10 @@ struct net_device { +@@ -2181,6 +2188,10 @@ struct net_device { struct mctp_dev __rcu *mctp_ptr; #endif @@ -60,7 +60,7 @@ Signed-off-by: Felix Fietkau */ --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2816,6 +2816,10 @@ static inline int pskb_trim(struct sk_bu +@@ -3022,6 +3022,10 @@ static inline int pskb_trim(struct sk_bu return (len < skb->len) ? __pskb_trim(skb, len) : 0; } @@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau /** * pskb_trim_unique - remove end from a paged unique (not cloned) buffer * @skb: buffer to alter -@@ -2966,16 +2970,6 @@ static inline struct sk_buff *dev_alloc_ +@@ -3171,16 +3175,6 @@ static inline struct sk_buff *dev_alloc_ } @@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau help --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -3590,6 +3590,11 @@ static int xmit_one(struct sk_buff *skb, +@@ -3588,6 +3588,11 @@ static int xmit_one(struct sk_buff *skb, if (dev_nit_active(dev)) dev_queue_xmit_nit(skb, dev); @@ -127,7 +127,7 @@ Signed-off-by: Felix Fietkau #include #include -@@ -602,6 +603,22 @@ skb_fail: +@@ -707,6 +708,22 @@ skb_fail: } EXPORT_SYMBOL(__napi_alloc_skb); @@ -152,7 +152,7 @@ Signed-off-by: Felix Fietkau { --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c -@@ -170,6 +170,12 @@ __be16 eth_type_trans(struct sk_buff *sk +@@ -171,6 +171,12 @@ __be16 eth_type_trans(struct sk_buff *sk const struct ethhdr *eth; skb->dev = dev; diff --git a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch index d4024f1a435..77b190464cf 100644 --- a/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch +++ b/target/linux/generic/hack-6.1/722-net-phy-aquantia-enable-AQR112-and-AQR412.patch @@ -15,7 +15,7 @@ Signed-off-by: Alex Marginean --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -20,6 +20,8 @@ +@@ -24,6 +24,8 @@ #define PHY_ID_AQR405 0x03a1b4b0 #define PHY_ID_AQR113C 0x31c31c12 #define PHY_ID_AQR813 0x31c31cb2 @@ -24,9 +24,9 @@ Signed-off-by: Alex Marginean #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -126,6 +128,29 @@ - #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1) - #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0) +@@ -151,6 +153,29 @@ + #define AQR107_OP_IN_PROG_SLEEP 1000 + #define AQR107_OP_IN_PROG_TIMEOUT 100000 +/* registers in MDIO_MMD_VEND1 region */ +#define AQUANTIA_VND1_GLOBAL_SC 0x000 @@ -54,7 +54,7 @@ Signed-off-by: Alex Marginean struct aqr107_hw_stat { const char *name; int reg; -@@ -257,6 +282,51 @@ static int aqr_config_aneg(struct phy_de +@@ -282,6 +307,51 @@ static int aqr_config_aneg(struct phy_de return genphy_c45_check_and_restart_aneg(phydev, changed); } @@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean static int aqr_config_intr(struct phy_device *phydev) { bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED; -@@ -780,6 +850,30 @@ static struct phy_driver aqr_driver[] = +@@ -881,6 +951,30 @@ static struct phy_driver aqr_driver[] = .get_stats = aqr107_get_stats, .link_change_notify = aqr107_link_change_notify, }, @@ -137,7 +137,7 @@ Signed-off-by: Alex Marginean }; module_phy_driver(aqr_driver); -@@ -790,5 +884,7 @@ static struct mdio_device_id __maybe_unu +@@ -895,6 +989,8 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR405) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, @@ -145,3 +145,4 @@ Signed-off-by: Alex Marginean + { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, { } }; + diff --git a/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch index d99b4951b82..8e204cb146a 100644 --- a/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch +++ b/target/linux/generic/hack-6.1/723-net-phy-aquantia-fix-system-side-protocol-mi.patch @@ -14,7 +14,7 @@ Signed-off-by: Alex Marginean --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -315,10 +315,16 @@ static int aqr_config_aneg_set_prot(stru +@@ -340,10 +340,16 @@ static int aqr_config_aneg_set_prot(stru phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE, aquantia_syscfg[if_type].start_rate); diff --git a/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch index dd32690048d..0a1e9706239 100644 --- a/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch +++ b/target/linux/generic/hack-6.1/724-net-phy-aquantia-Add-AQR113-driver-support.patch @@ -10,7 +10,7 @@ Add a new entry for AQR113 PHY_ID --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -21,6 +21,7 @@ +@@ -26,6 +26,7 @@ #define PHY_ID_AQR813 0x31c31cb2 #define PHY_ID_AQR112 0x03a1b662 #define PHY_ID_AQR412 0x03a1b712 @@ -18,8 +18,8 @@ Add a new entry for AQR113 PHY_ID #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -869,6 +870,14 @@ static struct phy_driver aqr_driver[] = - .get_strings = aqr107_get_strings, +@@ -981,6 +982,14 @@ static struct phy_driver aqr_driver[] = + .get_strings = aqr107_get_strings, .get_stats = aqr107_get_stats, }, +{ @@ -33,10 +33,11 @@ Add a new entry for AQR113 PHY_ID }; module_phy_driver(aqr_driver); -@@ -790,5 +884,6 @@ static struct mdio_device_id __maybe_unu +@@ -997,6 +1006,7 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR813) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, + { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, { } }; + diff --git a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch index 57edfc118e4..654fea56611 100644 --- a/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch +++ b/target/linux/generic/hack-6.1/725-net-phy-aquantia-add-PHY_IDs-for-AQR112-variants.patch @@ -12,7 +12,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/aquantia_main.c +++ b/drivers/net/phy/aquantia_main.c -@@ -21,6 +21,8 @@ +@@ -27,6 +27,8 @@ #define PHY_ID_AQR112 0x03a1b662 #define PHY_ID_AQR412 0x03a1b712 #define PHY_ID_AQR113 0x31c31c40 @@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle #define MDIO_PHYXS_VEND_IF_STATUS 0xe812 #define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3) -@@ -870,6 +872,30 @@ static struct phy_driver aqr_driver[] = +@@ -990,6 +992,30 @@ static struct phy_driver aqr_driver[] = .handle_interrupt = aqr_handle_interrupt, .read_status = aqr107_read_status, }, @@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle }; module_phy_driver(aqr_driver); -@@ -900,5 +926,7 @@ static struct mdio_device_id __maybe_unu +@@ -1007,6 +1033,8 @@ static struct mdio_device_id __maybe_unu { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) }, { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) }, @@ -60,3 +60,4 @@ Signed-off-by: Daniel Golle + { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) }, { } }; + diff --git a/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch b/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch index f61c078521e..ba03a00eb27 100644 --- a/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch +++ b/target/linux/generic/hack-6.1/760-net-usb-r8152-add-LED-configuration-from-OF.patch @@ -22,7 +22,7 @@ Signed-off-by: David Bauer #include #include #include -@@ -6886,6 +6887,22 @@ static void rtl_tally_reset(struct r8152 +@@ -6893,6 +6894,22 @@ static void rtl_tally_reset(struct r8152 ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); } @@ -45,7 +45,7 @@ Signed-off-by: David Bauer static void r8152b_init(struct r8152 *tp) { u32 ocp_data; -@@ -6927,6 +6944,8 @@ static void r8152b_init(struct r8152 *tp +@@ -6934,6 +6951,8 @@ static void r8152b_init(struct r8152 *tp ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~(RX_AGG_DISABLE | RX_ZERO_EN); ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); @@ -54,7 +54,7 @@ Signed-off-by: David Bauer } static void r8153_init(struct r8152 *tp) -@@ -7067,6 +7086,8 @@ static void r8153_init(struct r8152 *tp) +@@ -7074,6 +7093,8 @@ static void r8153_init(struct r8152 *tp) tp->coalesce = COALESCE_SLOW; break; } @@ -63,7 +63,7 @@ Signed-off-by: David Bauer } static void r8153b_init(struct r8152 *tp) -@@ -7149,6 +7170,8 @@ static void r8153b_init(struct r8152 *tp +@@ -7156,6 +7177,8 @@ static void r8153b_init(struct r8152 *tp rtl_tally_reset(tp); tp->coalesce = 15000; /* 15 us */ diff --git a/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch index 22fa7289fd3..d7165cb30ac 100644 --- a/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch +++ b/target/linux/generic/hack-6.1/765-mxl-gpy-control-LED-reg-from-DT.patch @@ -23,7 +23,7 @@ Signed-off-by: David Bauer --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c -@@ -8,6 +8,7 @@ +@@ -10,6 +10,7 @@ #include #include #include @@ -31,7 +31,7 @@ Signed-off-by: David Bauer #include #include #include -@@ -30,6 +31,7 @@ +@@ -33,6 +34,7 @@ #define PHY_MIISTAT 0x18 /* MII state */ #define PHY_IMASK 0x19 /* interrupt mask */ #define PHY_ISTAT 0x1A /* interrupt status */ @@ -39,7 +39,7 @@ Signed-off-by: David Bauer #define PHY_FWV 0x1E /* firmware version */ #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0) -@@ -53,10 +55,15 @@ +@@ -56,10 +58,15 @@ PHY_IMASK_ADSC | \ PHY_IMASK_ANC) @@ -55,9 +55,9 @@ Signed-off-by: David Bauer /* SGMII */ #define VSPEC1_SGMII_CTRL 0x08 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */ -@@ -80,6 +87,31 @@ static const struct { - {9, 0x73}, - }; +@@ -241,6 +248,31 @@ out: + return ret; + } +static int gpy_led_write(struct phy_device *phydev) +{ @@ -87,7 +87,7 @@ Signed-off-by: David Bauer static int gpy_config_init(struct phy_device *phydev) { int ret; -@@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_de +@@ -252,7 +284,10 @@ static int gpy_config_init(struct phy_de /* Clear all pending interrupts */ ret = phy_read(phydev, PHY_ISTAT); @@ -98,4 +98,4 @@ Signed-off-by: David Bauer + return gpy_led_write(phydev); } - static int gpy_probe(struct phy_device *phydev) + static bool gpy_has_broken_mdint(struct phy_device *phydev) diff --git a/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch b/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch index 7127aa136c6..633cacd1e7c 100644 --- a/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch +++ b/target/linux/generic/hack-6.1/773-bgmac-add-srab-switch.patch @@ -78,7 +78,7 @@ Signed-off-by: Hauke Mehrtens netif_napi_del(&bgmac->napi); --- a/drivers/net/ethernet/broadcom/bgmac.h +++ b/drivers/net/ethernet/broadcom/bgmac.h -@@ -390,6 +390,7 @@ +@@ -388,6 +388,7 @@ #define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18) #define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19) #define BGMAC_FEAT_IDM_MASK BIT(20) @@ -86,7 +86,7 @@ Signed-off-by: Hauke Mehrtens struct bgmac_slot_info { union { -@@ -497,6 +498,9 @@ struct bgmac { +@@ -495,6 +496,9 @@ struct bgmac { void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask, u32 set); int (*phy_connect)(struct bgmac *bgmac); diff --git a/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch index e3959658a3c..23f8be5d264 100644 --- a/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch +++ b/target/linux/generic/hack-6.1/780-usb-net-MeigLink_modem_support.patch @@ -10,7 +10,7 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c -@@ -1085,6 +1085,7 @@ static const struct usb_device_id produc +@@ -1088,6 +1088,7 @@ static const struct usb_device_id produc {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0801)}, /* Quectel RM520N */ @@ -29,8 +29,8 @@ Subject: [PATCH] net/usb/qmi_wwan: add MeigLink modem support #define QUECTEL_VENDOR_ID 0x2c7c /* These Quectel products use Quectel's vendor ID */ -@@ -1133,6 +1135,11 @@ static const struct usb_device_id option - { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0, 0) }, +@@ -1169,6 +1171,11 @@ static const struct usb_device_id option + .driver_info = ZLP }, { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96), .driver_info = RSVD(4) }, + /* Meiglink products using Qualcomm vendor ID */ diff --git a/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch index 7131b61b35f..6e14d04c5fd 100644 --- a/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch +++ b/target/linux/generic/hack-6.1/790-SFP-GE-T-ignore-TX_FAULT.patch @@ -26,17 +26,17 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c -@@ -393,6 +393,9 @@ static const struct sfp_quirk sfp_quirks - // their EEPROM +@@ -404,6 +404,9 @@ static const struct sfp_quirk sfp_quirks SFP_QUIRK("HUAWEI", "MA5671A", sfp_quirk_2500basex, sfp_fixup_ignore_tx_fault), -+ + + // OEM SFP-GE-T is 1000Base-T module + SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), - ++ // Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report // 2500MBd NRZ in their EEPROM -@@ -2303,7 +2308,8 @@ static void sfp_sm_main(struct sfp *sfp, + SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex), +@@ -2334,7 +2337,8 @@ static void sfp_sm_main(struct sfp *sfp, * or t_start_up, so assume there is a fault. */ sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT, @@ -45,8 +45,8 @@ Signed-off-by: Daniel Golle + (sfp->sm_fault_retries == N_FAULT_INIT)); } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { init_done: - sfp->sm_phy_retries = R_PHY_RETRY; -@@ -2535,10 +2541,12 @@ static void sfp_check_state(struct sfp * + /* Create mdiobus and start trying for PHY */ +@@ -2563,10 +2567,12 @@ static void sfp_check_state(struct sfp * mutex_lock(&sfp->st_mutex); state = sfp_get_state(sfp); changed = state ^ sfp->state; diff --git a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch index 4c2a37e3475..658d9c38069 100644 --- a/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch +++ b/target/linux/generic/hack-6.1/800-GPIO-add-named-gpio-exports.patch @@ -15,7 +15,7 @@ Signed-off-by: John Crispin #include "gpiolib.h" #include "gpiolib-of.h" -@@ -1057,3 +1059,72 @@ void of_gpio_dev_init(struct gpio_chip * +@@ -1030,3 +1032,72 @@ void of_gpio_dev_init(struct gpio_chip * else gc->of_node = gdev->dev.of_node; } @@ -105,7 +105,7 @@ Signed-off-by: John Crispin { --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h -@@ -712,6 +712,7 @@ static inline void devm_acpi_dev_remove_ +@@ -715,6 +715,7 @@ static inline struct gpio_desc *acpi_get #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) @@ -113,7 +113,7 @@ Signed-off-by: John Crispin int gpiod_export(struct gpio_desc *desc, bool direction_may_change); int gpiod_export_link(struct device *dev, const char *name, struct gpio_desc *desc); -@@ -719,6 +720,13 @@ void gpiod_unexport(struct gpio_desc *de +@@ -722,6 +723,13 @@ void gpiod_unexport(struct gpio_desc *de #else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */ @@ -129,7 +129,7 @@ Signed-off-by: John Crispin { --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c -@@ -561,7 +561,7 @@ static struct class gpio_class = { +@@ -544,7 +544,7 @@ static struct class gpio_class = { * * Returns zero on success, else an error. */ @@ -138,7 +138,7 @@ Signed-off-by: John Crispin { struct gpio_chip *chip; struct gpio_device *gdev; -@@ -623,6 +623,8 @@ int gpiod_export(struct gpio_desc *desc, +@@ -606,6 +606,8 @@ int gpiod_export(struct gpio_desc *desc, offset = gpio_chip_hwgpio(desc); if (chip->names && chip->names[offset]) ioname = chip->names[offset]; @@ -147,7 +147,7 @@ Signed-off-by: John Crispin dev = device_create_with_groups(&gpio_class, &gdev->dev, MKDEV(0, 0), data, gpio_groups, -@@ -644,6 +646,12 @@ err_unlock: +@@ -627,6 +629,12 @@ err_unlock: gpiod_dbg(desc, "%s: status %d\n", __func__, status); return status; } diff --git a/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch index 247eb798b33..582a48cb182 100644 --- a/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch +++ b/target/linux/generic/hack-6.1/901-debloat_sock_diag.patch @@ -28,7 +28,7 @@ Signed-off-by: Felix Fietkau help --- a/net/core/Makefile +++ b/net/core/Makefile -@@ -10,11 +10,12 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. +@@ -11,11 +11,12 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core. obj-y += dev.o dev_addr_lists.o dst.o netevent.o \ neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ @@ -52,15 +52,15 @@ Signed-off-by: Felix Fietkau #include -@@ -143,6 +144,7 @@ +@@ -145,6 +146,7 @@ static DEFINE_MUTEX(proto_list_mutex); static LIST_HEAD(proto_list); +DEFINE_COOKIE(sock_cookie); - static void sock_inuse_add(struct net *net, int val); - -@@ -545,6 +547,18 @@ discard_and_relse: + static void sock_def_write_space_wfree(struct sock *sk); + static void sock_def_write_space(struct sock *sk); +@@ -582,6 +584,18 @@ discard_and_relse: } EXPORT_SYMBOL(__sk_receive_skb); @@ -79,7 +79,7 @@ Signed-off-by: Felix Fietkau INDIRECT_CALLABLE_DECLARE(struct dst_entry *ip6_dst_check(struct dst_entry *, u32)); INDIRECT_CALLABLE_DECLARE(struct dst_entry *ipv4_dst_check(struct dst_entry *, -@@ -1983,9 +1997,11 @@ static void __sk_free(struct sock *sk) +@@ -2174,9 +2188,11 @@ static void __sk_free(struct sock *sk) if (likely(sk->sk_net_refcnt)) sock_inuse_add(sock_net(sk), -1); @@ -93,7 +93,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c -@@ -11,7 +11,6 @@ +@@ -12,7 +12,6 @@ #include #include #include @@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau #include #include -@@ -20,20 +19,6 @@ static int (*inet_rcv_compat)(struct sk_ +@@ -21,20 +20,6 @@ static int (*inet_rcv_compat)(struct sk_ static DEFINE_MUTEX(sock_diag_table_mutex); static struct workqueue_struct *broadcast_wq; @@ -124,7 +124,7 @@ Signed-off-by: Felix Fietkau u64 res; --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig -@@ -424,6 +424,7 @@ config INET_TUNNEL +@@ -423,6 +423,7 @@ config INET_TUNNEL config INET_DIAG tristate "INET: socket monitoring interface" diff --git a/target/linux/generic/hack-6.1/902-debloat_proc.patch b/target/linux/generic/hack-6.1/902-debloat_proc.patch index d729b29015a..bac3d4af827 100644 --- a/target/linux/generic/hack-6.1/902-debloat_proc.patch +++ b/target/linux/generic/hack-6.1/902-debloat_proc.patch @@ -29,7 +29,7 @@ Signed-off-by: Felix Fietkau --- a/fs/locks.c +++ b/fs/locks.c -@@ -2953,6 +2953,8 @@ static const struct seq_operations locks +@@ -2909,6 +2909,8 @@ static const struct seq_operations locks static int __init proc_locks_init(void) { @@ -40,7 +40,7 @@ Signed-off-by: Felix Fietkau return 0; --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig -@@ -100,6 +100,11 @@ config PROC_CHILDREN +@@ -101,6 +101,11 @@ config PROC_CHILDREN Say Y if you are running any user-space software which takes benefit from this interface. For example, rkt is such a piece of software. @@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau } --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c -@@ -133,7 +133,10 @@ static const struct seq_operations tty_d +@@ -131,7 +131,10 @@ static const struct seq_operations tty_d void proc_tty_register_driver(struct tty_driver *driver) { struct proc_dir_entry *ent; @@ -78,7 +78,7 @@ Signed-off-by: Felix Fietkau if (!driver->driver_name || driver->proc_entry || !driver->ops->proc_show) return; -@@ -150,6 +153,9 @@ void proc_tty_unregister_driver(struct t +@@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct t { struct proc_dir_entry *ent; @@ -88,7 +88,7 @@ Signed-off-by: Felix Fietkau ent = driver->proc_entry; if (!ent) return; -@@ -164,6 +170,9 @@ void proc_tty_unregister_driver(struct t +@@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct t */ void __init proc_tty_init(void) { @@ -135,7 +135,7 @@ Signed-off-by: Felix Fietkau do { \ --- a/ipc/msg.c +++ b/ipc/msg.c -@@ -1350,6 +1350,9 @@ void __init msg_init(void) +@@ -1370,6 +1370,9 @@ void __init msg_init(void) { msg_init_ns(&init_ipc_ns); @@ -235,7 +235,7 @@ Signed-off-by: Felix Fietkau if (!pe) --- a/mm/vmalloc.c +++ b/mm/vmalloc.c -@@ -3964,6 +3964,8 @@ static const struct seq_operations vmall +@@ -4183,6 +4183,8 @@ static const struct seq_operations vmall static int __init proc_vmalloc_init(void) { @@ -246,7 +246,7 @@ Signed-off-by: Felix Fietkau &vmalloc_op, --- a/mm/vmstat.c +++ b/mm/vmstat.c -@@ -2083,10 +2083,12 @@ void __init init_mm_internals(void) +@@ -2109,10 +2109,12 @@ void __init init_mm_internals(void) start_shepherd_timer(); #endif #ifdef CONFIG_PROC_FS @@ -286,7 +286,7 @@ Signed-off-by: Felix Fietkau goto err; --- a/net/core/net-procfs.c +++ b/net/core/net-procfs.c -@@ -317,10 +317,12 @@ static int __net_init dev_proc_net_init( +@@ -319,10 +319,12 @@ static int __net_init dev_proc_net_init( if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops, sizeof(struct seq_net_private))) goto out; @@ -301,7 +301,7 @@ Signed-off-by: Felix Fietkau sizeof(struct seq_net_private))) goto out_softnet; -@@ -330,9 +332,11 @@ static int __net_init dev_proc_net_init( +@@ -332,9 +334,11 @@ static int __net_init dev_proc_net_init( out: return rc; out_ptype: @@ -315,7 +315,7 @@ Signed-off-by: Felix Fietkau out_dev: remove_proc_entry("dev", net->proc_net); goto out; -@@ -342,8 +346,10 @@ static void __net_exit dev_proc_net_exit +@@ -344,8 +348,10 @@ static void __net_exit dev_proc_net_exit { wext_proc_exit(net); @@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/sock.c +++ b/net/core/sock.c -@@ -3855,6 +3855,8 @@ static __net_initdata struct pernet_oper +@@ -4088,6 +4088,8 @@ static __net_initdata struct pernet_oper static int __init proto_init(void) { @@ -341,7 +341,7 @@ Signed-off-by: Felix Fietkau --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c -@@ -3024,11 +3024,13 @@ static const struct seq_operations fib_r +@@ -3031,11 +3031,13 @@ static const struct seq_operations fib_r int __net_init fib_proc_init(struct net *net) { @@ -357,7 +357,7 @@ Signed-off-by: Felix Fietkau fib_triestat_seq_show, NULL)) goto out2; -@@ -3039,17 +3041,21 @@ int __net_init fib_proc_init(struct net +@@ -3046,17 +3048,21 @@ int __net_init fib_proc_init(struct net return 0; out3: @@ -396,7 +396,7 @@ Signed-off-by: Felix Fietkau } --- a/net/ipv4/route.c +++ b/net/ipv4/route.c -@@ -387,6 +387,9 @@ static struct pernet_operations ip_rt_pr +@@ -380,6 +380,9 @@ static struct pernet_operations ip_rt_pr static int __init ip_rt_proc_init(void) { diff --git a/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch index 8eb705341d5..48c001bfab5 100644 --- a/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch +++ b/target/linux/generic/hack-6.1/904-debloat_dma_buf.patch @@ -13,7 +13,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig -@@ -187,7 +187,7 @@ config SOC_BUS +@@ -198,7 +198,7 @@ config SOC_BUS source "drivers/base/regmap/Kconfig" config DMA_SHARED_BUFFER @@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau +dma-buf-objs-$(CONFIG_DMABUF_HEAPS_CMA) += cma_heap.o --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile -@@ -1,18 +1,22 @@ +@@ -1,12 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \ +obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o @@ -54,8 +54,7 @@ Signed-off-by: Felix Fietkau dmabuf_selftests-y := \ selftest.o \ - st-dma-fence.o \ - st-dma-fence-chain.o \ +@@ -15,4 +17,6 @@ dmabuf_selftests-y := \ st-dma-fence-unwrap.o \ st-dma-resv.o @@ -65,7 +64,7 @@ Signed-off-by: Felix Fietkau +dma-shared-buffer-objs := $(dma-buf-objs-y) --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c -@@ -1513,4 +1513,5 @@ static void __exit dma_buf_deinit(void) +@@ -1583,4 +1583,5 @@ static void __exit dma_buf_deinit(void) kern_unmount(dma_buf_mnt); dma_buf_uninit_sysfs_statistics(); } @@ -74,7 +73,7 @@ Signed-off-by: Felix Fietkau +MODULE_LICENSE("GPL"); --- a/kernel/sched/core.c +++ b/kernel/sched/core.c -@@ -4175,6 +4175,7 @@ int wake_up_state(struct task_struct *p, +@@ -4363,6 +4363,7 @@ int wake_up_state(struct task_struct *p, { return try_to_wake_up(p, state, 0); } @@ -84,7 +83,7 @@ Signed-off-by: Felix Fietkau * Perform scheduler related setup for a newly forked process p. --- a/fs/d_path.c +++ b/fs/d_path.c -@@ -316,6 +316,7 @@ char *dynamic_dname(struct dentry *dentr +@@ -313,6 +313,7 @@ char *dynamic_dname(char *buffer, int bu buffer += buflen - sz; return memcpy(buffer, temp, sz); } diff --git a/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch b/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch index a487d551938..9854585d259 100644 --- a/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch +++ b/target/linux/generic/hack-6.1/911-kobject_add_broadcast_uevent.patch @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau #ifdef CONFIG_UEVENT_HELPER /* path to the userspace helper executed on an event */ extern char uevent_helper[]; -@@ -244,4 +246,7 @@ int kobject_synth_uevent(struct kobject +@@ -224,4 +226,7 @@ int kobject_synth_uevent(struct kobject __printf(2, 3) int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); diff --git a/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch index 2722266722e..cc384bb553b 100644 --- a/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch +++ b/target/linux/generic/hack-6.1/920-device_tree_cmdline.patch @@ -9,7 +9,7 @@ Subject: [PATCH] of/ftd: add device tree cmdline --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c -@@ -1158,6 +1158,9 @@ int __init early_init_dt_scan_chosen(uns +@@ -1183,6 +1183,9 @@ int __init early_init_dt_scan_chosen(cha p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) strscpy(cmdline, p, min(l, COMMAND_LINE_SIZE)); @@ -17,5 +17,5 @@ Subject: [PATCH] of/ftd: add device tree cmdline + if (p != NULL && l > 0) + strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); + handle_cmdline: /* - * CONFIG_CMDLINE is meant to be a default in case nothing else diff --git a/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch b/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch index 4f4d6c75091..98081c4b64b 100644 --- a/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch +++ b/target/linux/generic/hack-6.1/930-Revert-Revert-Revert-driver-core-Set-fw_devlink-on-b.patch @@ -19,7 +19,7 @@ Signed-off-by: Rafał Miłecki --- a/drivers/base/core.c +++ b/drivers/base/core.c -@@ -1562,7 +1562,7 @@ static void device_links_purge(struct de +@@ -1700,7 +1700,7 @@ static void device_links_purge(struct de #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \ DL_FLAG_PM_RUNTIME) From 4ed347aaad5de7b50d047f29aa99138b9b265daa Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 18:07:49 +0200 Subject: [PATCH 69/88] generic: 6.1: refresh pending patches Refresh pending patches with make target/linux/refresh. Signed-off-by: Christian Marangi --- ...include-asm-rwonce.h-for-kernel-code.patch | 8 ++--- ...s-negative-stack-offsets-on-stack-tr.patch | 2 +- .../103-kbuild-export-SUBARCH.patch | 2 +- ...ilicon-Labs-EM3581-device-compatible.patch | 4 +-- ...ilicon-Labs-SI3210-device-compatible.patch | 4 +-- ...e_mem_map-with-ARCH_PFN_OFFSET-calcu.patch | 2 +- ...ically-allocate-note.data-in-parse_e.patch | 6 ++-- ...ge_allow_receiption_on_disabled_port.patch | 8 ++--- ...-rs5c372-support_alarms_up_to_1_week.patch | 8 ++--- ...he_alarm_to_be_used_as_wakeup_source.patch | 10 +++--- .../203-kallsyms_uncompressed.patch | 20 +++++------ .../205-backtrace_module_info.patch | 4 +-- ...e-filenames-from-deps_initramfs-list.patch | 2 +- .../270-platform-mikrotik-build-bits.patch | 4 +-- .../300-mips_expose_boot_raw.patch | 4 +-- ...rriers-between-dcache-icache-flushes.patch | 8 ++--- .../302-mips_no_branch_likely.patch | 2 +- .../pending-6.1/305-mips_module_reloc.patch | 8 ++--- .../pending-6.1/308-mips32r2_tune.patch | 2 +- .../310-arm_module_unresolved_weak_sym.patch | 2 +- ...ernel-XZ-compression-option-on-PPC_8.patch | 2 +- ...ip-bcm-6345-l1-request-memory-region.patch | 4 +-- .../400-mtd-mtdsplit-support.patch | 4 +-- ...support-for-minor-aligned-partitions.patch | 10 +++--- .../pending-6.1/420-mtd-redboot_space.patch | 2 +- ...30-mtd-add-myloader-partition-parser.patch | 6 ++-- ...mtd-add-routerbootpart-parser-config.patch | 4 +-- ...mtd-cfi_cmdset_0002-no-erase_suspend.patch | 2 +- ...et_0002-add-buffer-write-cmd-timeout.patch | 2 +- ...25p80-mx-disable-software-protection.patch | 4 +-- .../476-mtd-spi-nor-add-eon-en25q128.patch | 2 +- .../477-mtd-spi-nor-add-eon-en25qx128a.patch | 2 +- .../479-mtd-spi-nor-add-xtx-xt25f128b.patch | 9 +++-- ...r-add-support-for-Gigadevice-GD25D05.patch | 2 +- .../482-mtd-spi-nor-add-gd25q512.patch | 2 +- .../484-mtd-spi-nor-add-esmt-f25l16pa.patch | 6 ++-- .../485-mtd-spi-nor-add-xmc-xm25qh128c.patch | 8 ++--- ...nand-add-support-for-ESMT-F50x1G41LB.patch | 4 +-- ...nd-Add-support-for-Etron-EM73D044VCx.patch | 6 ++-- .../488-mtd-spi-nor-add-xmc-xm25qh64c.patch | 2 +- ...mtd-device-named-ubi-or-data-on-boot.patch | 4 +-- ...to-create-ubiblock-device-for-rootfs.patch | 4 +-- ...ting-ubi0-rootfs-in-init-do_mounts.c.patch | 4 +-- ...ROOT_DEV-to-ubiblock-rootfs-if-unset.patch | 4 +-- ...i-nor-locking-support-for-MX25L6405D.patch | 6 ++-- ...i-nor-disable-16-bit-sr-for-macronix.patch | 2 +- .../530-jffs2_make_lzma_available.patch | 6 ++-- .../600-netfilter_conntrack_flush.patch | 4 +-- ...etfilter_match_bypass_default_checks.patch | 8 ++--- ...netfilter_match_bypass_default_table.patch | 6 ++-- .../pending-6.1/630-packet_socket_type.patch | 16 ++++----- .../pending-6.1/655-increase_skb_pad.patch | 2 +- ...Add-support-for-MAP-E-FMRs-mesh-mode.patch | 28 +++++++-------- ...ng-with-source-address-failed-policy.patch | 36 +++++++++---------- ...nes-for-_POLICY_FAILED-until-all-cod.patch | 2 +- ...T-skip-GRO-for-foreign-MAC-addresses.patch | 18 +++++----- ...et-add-mac-address-increment-support.patch | 3 +- ...ow_offload-handle-netdevice-events-f.patch | 20 ++++------- ...net-mtk_eth_soc-enable-threaded-NAPI.patch | 6 ++-- ...detach-callback-to-struct-phy_driver.patch | 4 +-- ...d-knob-for-filtering-rx-tx-BPDU-pack.patch | 20 +++++------ ...rtl8221-allow-to-configure-SERDES-mo.patch | 6 ++-- ...support-switching-between-SGMII-and-.patch | 4 +-- ...e-all-MACs-are-powered-down-before-r.patch | 2 +- ...-use-genphy_soft_reset-for-2.5G-PHYs.patch | 12 +++---- ...sable-SGMII-in-band-AN-for-2-5G-PHYs.patch | 4 +-- ...make-sure-paged-read-is-protected-by.patch | 2 +- ...use-inline-functions-for-10GbE-adver.patch | 4 +-- ...check-validity-of-10GbE-link-partner.patch | 2 +- ...-phy-realtek-introduce-rtl822x_probe.patch | 14 ++++---- ...tek-detect-early-version-of-RTL8221B.patch | 4 +-- ...iatek-ppe-add-support-for-flow-accou.patch | 34 +++++++++--------- ...0211_ptr-even-with-no-CFG82111-suppo.patch | 13 ++----- ..._eth_soc-drop-generic-vlan-rx-offloa.patch | 14 ++++---- ..._eth_soc-work-around-issue-with-send.patch | 6 ++-- ..._eth_soc-fix-remaining-throughput-re.patch | 4 +-- ..._eth_soc-ppe-fix-L2-offloading-with-.patch | 2 +- ..._eth_soc-add-code-for-offloading-flo.patch | 6 ++-- ...iatek-mtk_ppe-prefer-newly-added-l2-.patch | 2 +- ..._eth_soc-improve-keeping-track-of-of.patch | 18 +++++----- ...iatek-fix-ppe-flow-accounting-for-L2.patch | 20 +++++------ ...iatek-fix-ppe-flow-accounting-for-v1.patch | 4 +-- ...ional-threading-for-backlog-processi.patch | 36 +++++++++---------- ...equest-assisted-learning-on-CPU-port.patch | 2 +- ...a-b53-add-support-for-BCM63xx-RGMIIs.patch | 4 +-- ...-net-dsa-b53-mmap-add-more-63xx-SoCs.patch | 2 +- ...dsa-b53-mmap-allow-passing-a-chip-ID.patch | 8 ++--- ...sa-b53-mdio-add-support-for-BCM53134.patch | 14 ++++---- ...-missing-linux-if_ether.h-for-ETH_AL.patch | 2 +- ...-bus-mhi-core-add-SBL-state-callback.patch | 2 +- ...gister-OF-node-for-internal-MDIO-bus.patch | 4 +-- ...pio-cascade-add-generic-GPIO-cascade.patch | 4 +-- ...e-old-opp-to-config_clks-on-_set_opp.patch | 25 +++++-------- .../810-pci_disable_common_quirks.patch | 8 ++--- .../811-pci_disable_usb_common_quirks.patch | 2 +- .../pending-6.1/834-ledtrig-libata.patch | 22 ++++++------ ...e-main-irq_chip-structure-a-static-d.patch | 8 ++--- .../pending-6.1/920-mangle_bootargs.patch | 6 ++-- 98 files changed, 348 insertions(+), 374 deletions(-) diff --git a/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch b/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch index 22f52c1d462..7b342e69623 100644 --- a/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch +++ b/target/linux/generic/pending-6.1/100-compiler.h-only-include-asm-rwonce.h-for-kernel-code.patch @@ -11,16 +11,16 @@ Signed-off-by: Felix Fietkau --- a/include/linux/compiler.h +++ b/include/linux/compiler.h -@@ -220,6 +220,8 @@ void ftrace_likely_update(struct ftrace_ - #define function_nocfi(x) (x) - #endif +@@ -203,6 +203,8 @@ void ftrace_likely_update(struct ftrace_ + __v; \ + }) +#include + #endif /* __KERNEL__ */ /* -@@ -252,6 +254,4 @@ static inline void *offset_to_ptr(const +@@ -243,6 +245,4 @@ static inline void *offset_to_ptr(const */ #define prevent_tail_call_optimization() mb() diff --git a/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch b/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch index 95a9656d268..7ce3d491cd3 100644 --- a/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch +++ b/target/linux/generic/pending-6.1/102-MIPS-only-process-negative-stack-offsets-on-stack-tr.patch @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c -@@ -393,6 +393,8 @@ static inline int is_sp_move_ins(union m +@@ -394,6 +394,8 @@ static inline int is_sp_move_ins(union m if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) { diff --git a/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch index 513e394092a..e6480ac03e3 100644 --- a/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch +++ b/target/linux/generic/pending-6.1/103-kbuild-export-SUBARCH.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/Makefile +++ b/Makefile -@@ -523,7 +523,7 @@ KBUILD_LDFLAGS_MODULE := +@@ -606,7 +606,7 @@ endif # Allows the usage of unstable features in stable compilers. export RUSTC_BOOTSTRAP := 1 diff --git a/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch index c2940b601bb..ebeeae2f8fd 100644 --- a/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch +++ b/target/linux/generic/pending-6.1/110-v6.3-0001-spidev-Add-Silicon-Labs-EM3581-device-compatible.patch @@ -14,7 +14,7 @@ Signed-off-by: Vincent Tremblay --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c -@@ -691,6 +691,7 @@ static const struct spi_device_id spidev +@@ -700,6 +700,7 @@ static const struct spi_device_id spidev { .name = "m53cpld" }, { .name = "spi-petra" }, { .name = "spi-authenta" }, @@ -22,7 +22,7 @@ Signed-off-by: Vincent Tremblay {}, }; MODULE_DEVICE_TABLE(spi, spidev_spi_ids); -@@ -705,6 +706,7 @@ static const struct of_device_id spidev_ +@@ -726,6 +727,7 @@ static const struct of_device_id spidev_ { .compatible = "menlo,m53cpld", .data = &spidev_of_check }, { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, { .compatible = "micron,spi-authenta", .data = &spidev_of_check }, diff --git a/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch index d88e5106c17..db5b5800f4b 100644 --- a/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch +++ b/target/linux/generic/pending-6.1/110-v6.3-0002-spidev-Add-Silicon-Labs-SI3210-device-compatible.patch @@ -14,7 +14,7 @@ Signed-off-by: Vincent Tremblay --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c -@@ -692,6 +692,7 @@ static const struct spi_device_id spidev +@@ -701,6 +701,7 @@ static const struct spi_device_id spidev { .name = "spi-petra" }, { .name = "spi-authenta" }, { .name = "em3581" }, @@ -22,7 +22,7 @@ Signed-off-by: Vincent Tremblay {}, }; MODULE_DEVICE_TABLE(spi, spidev_spi_ids); -@@ -707,6 +708,7 @@ static const struct of_device_id spidev_ +@@ -728,6 +729,7 @@ static const struct of_device_id spidev_ { .compatible = "cisco,spi-petra", .data = &spidev_of_check }, { .compatible = "micron,spi-authenta", .data = &spidev_of_check }, { .compatible = "silabs,em3581", .data = &spidev_of_check }, diff --git a/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch index 4e347a46710..c381bcf8e19 100644 --- a/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch +++ b/target/linux/generic/pending-6.1/120-Fix-alloc_node_mem_map-with-ARCH_PFN_OFFSET-calcu.patch @@ -71,7 +71,7 @@ Signed-off-by: Tobias Wolf --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7556,7 +7556,7 @@ static void __init alloc_node_mem_map(st +@@ -7911,7 +7911,7 @@ static void __init alloc_node_mem_map(st if (pgdat == NODE_DATA(0)) { mem_map = NODE_DATA(0)->node_mem_map; if (page_to_pfn(mem_map) != pgdat->node_start_pfn) diff --git a/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch b/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch index f04007e982d..8ec51a99779 100644 --- a/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch +++ b/target/linux/generic/pending-6.1/130-binfmt_elf-dynamically-allocate-note.data-in-parse_e.patch @@ -26,7 +26,7 @@ Cc: stable@vger.kernel.org # v5.8+ --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c -@@ -768,7 +768,7 @@ static int parse_elf_properties(struct f +@@ -769,7 +769,7 @@ static int parse_elf_properties(struct f { union { struct elf_note nhdr; @@ -35,7 +35,7 @@ Cc: stable@vger.kernel.org # v5.8+ } note; loff_t pos; ssize_t n; -@@ -788,26 +788,38 @@ static int parse_elf_properties(struct f +@@ -789,26 +789,38 @@ static int parse_elf_properties(struct f if (phdr->p_filesz > sizeof(note)) return -ENOEXEC; @@ -83,7 +83,7 @@ Cc: stable@vger.kernel.org # v5.8+ datasz = off + note.nhdr.n_descsz; have_prev_type = false; -@@ -817,6 +829,8 @@ static int parse_elf_properties(struct f +@@ -818,6 +830,8 @@ static int parse_elf_properties(struct f have_prev_type = true; } while (!ret); diff --git a/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch b/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch index 9968a79699f..93a2d146b5a 100644 --- a/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch +++ b/target/linux/generic/pending-6.1/150-bridge_allow_receiption_on_disabled_port.patch @@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c -@@ -204,6 +204,9 @@ static void __br_handle_local_finish(str +@@ -222,6 +222,9 @@ static void __br_handle_local_finish(str /* note: already called with rcu_read_lock */ static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { @@ -25,9 +25,9 @@ Signed-off-by: Felix Fietkau __br_handle_local_finish(skb); /* return 1 to signal the okfn() was called so it's ok to use the skb */ -@@ -369,6 +372,17 @@ static rx_handler_result_t br_handle_fra +@@ -390,6 +393,17 @@ forward: + goto defer_stp_filtering; - forward: switch (p->state) { + case BR_STATE_DISABLED: + if (ether_addr_equal(p->br->dev->dev_addr, dest)) @@ -42,4 +42,4 @@ Signed-off-by: Felix Fietkau + case BR_STATE_FORWARDING: case BR_STATE_LEARNING: - if (ether_addr_equal(p->br->dev->dev_addr, dest)) + defer_stp_filtering: diff --git a/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch b/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch index 13b79b5c098..2f5c2228c7a 100644 --- a/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch +++ b/target/linux/generic/pending-6.1/190-rtc-rs5c372-support_alarms_up_to_1_week.patch @@ -14,7 +14,7 @@ Signed-off-by: Daniel González Cabanelas --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c -@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device +@@ -399,7 +399,9 @@ static int rs5c_read_alarm(struct device { struct i2c_client *client = to_i2c_client(dev); struct rs5c372 *rs5c = i2c_get_clientdata(client); @@ -25,7 +25,7 @@ Signed-off-by: Daniel González Cabanelas status = rs5c_get_regs(rs5c); if (status < 0) -@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device +@@ -409,6 +411,30 @@ static int rs5c_read_alarm(struct device t->time.tm_sec = 0; t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f); t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]); @@ -56,7 +56,7 @@ Signed-off-by: Daniel González Cabanelas /* ... and status */ t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE); -@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device +@@ -423,12 +449,20 @@ static int rs5c_set_alarm(struct device struct rs5c372 *rs5c = i2c_get_clientdata(client); int status, addr, i; unsigned char buf[3]; @@ -81,7 +81,7 @@ Signed-off-by: Daniel González Cabanelas /* REVISIT: round up tm_sec */ -@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device +@@ -449,7 +483,9 @@ static int rs5c_set_alarm(struct device /* set alarm */ buf[0] = bin2bcd(t->time.tm_min); buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour); diff --git a/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch index a934af402ec..a9a5cdf8ba2 100644 --- a/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch +++ b/target/linux/generic/pending-6.1/191-rtc-rs5c372-let_the_alarm_to_be_used_as_wakeup_source.patch @@ -17,7 +17,7 @@ Signed-off-by: Daniel González Cabanelas --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c -@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_clie +@@ -833,6 +833,7 @@ static int rs5c372_probe(struct i2c_clie int err = 0; int smbus_mode = 0; struct rs5c372 *rs5c372; @@ -25,7 +25,7 @@ Signed-off-by: Daniel González Cabanelas dev_dbg(&client->dev, "%s\n", __func__); -@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_clie +@@ -868,6 +869,12 @@ static int rs5c372_probe(struct i2c_clie else rs5c372->type = id->driver_data; @@ -38,7 +38,7 @@ Signed-off-by: Daniel González Cabanelas /* we read registers 0x0f then 0x00-0x0f; skip the first one */ rs5c372->regs = &rs5c372->buf[1]; rs5c372->smbus = smbus_mode; -@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_clie +@@ -901,6 +908,8 @@ static int rs5c372_probe(struct i2c_clie goto exit; } @@ -47,7 +47,7 @@ Signed-off-by: Daniel González Cabanelas /* if the oscillator lost power and no other software (like * the bootloader) set it up, do it here. * -@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_clie +@@ -927,6 +936,10 @@ static int rs5c372_probe(struct i2c_clie ); /* REVISIT use client->irq to register alarm irq ... */ @@ -58,7 +58,7 @@ Signed-off-by: Daniel González Cabanelas rs5c372->rtc = devm_rtc_device_register(&client->dev, rs5c372_driver.driver.name, &rs5c372_rtc_ops, THIS_MODULE); -@@ -761,6 +774,10 @@ static int rs5c372_probe(struct i2c_clie +@@ -940,6 +953,10 @@ static int rs5c372_probe(struct i2c_clie if (err) goto exit; diff --git a/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch index bc9fdda9f1a..7b7aea06016 100644 --- a/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch +++ b/target/linux/generic/pending-6.1/203-kallsyms_uncompressed.patch @@ -13,7 +13,7 @@ Signed-off-by: Felix Fietkau --- a/init/Kconfig +++ b/init/Kconfig -@@ -1447,6 +1447,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW +@@ -1481,6 +1481,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW the unaligned access emulation. see arch/parisc/kernel/unaligned.c for reference @@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c -@@ -80,6 +80,11 @@ static unsigned int kallsyms_expand_symb +@@ -69,6 +69,11 @@ static unsigned int kallsyms_expand_symb * For every byte on the compressed symbol data, copy the table * entry for that byte. */ @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau while (len) { tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; data++; -@@ -112,6 +117,9 @@ tail: +@@ -101,6 +106,9 @@ tail: */ static char kallsyms_get_symbol_type(unsigned int off) { @@ -57,7 +57,7 @@ Signed-off-by: Felix Fietkau * and return the first char from this token. --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c -@@ -58,6 +58,7 @@ static struct addr_range percpu_range = +@@ -75,6 +75,7 @@ static struct addr_range percpu_range = static struct sym_entry **table; static unsigned int table_size, table_cnt; static int all_symbols; @@ -65,7 +65,7 @@ Signed-off-by: Felix Fietkau static int absolute_percpu; static int base_relative; -@@ -486,6 +487,9 @@ static void write_src(void) +@@ -535,6 +536,9 @@ static void write_src(void) free(markers); @@ -75,7 +75,7 @@ Signed-off-by: Felix Fietkau output_label("kallsyms_token_table"); off = 0; for (i = 0; i < 256; i++) { -@@ -537,6 +541,9 @@ static unsigned char *find_token(unsigne +@@ -586,6 +590,9 @@ static unsigned char *find_token(unsigne { int i; @@ -85,7 +85,7 @@ Signed-off-by: Felix Fietkau for (i = 0; i < len - 1; i++) { if (str[i] == token[0] && str[i+1] == token[1]) return &str[i]; -@@ -609,6 +616,9 @@ static void optimize_result(void) +@@ -658,6 +665,9 @@ static void optimize_result(void) { int i, best; @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau /* using the '\0' symbol last allows compress_symbols to use standard * fast string functions */ for (i = 255; i >= 0; i--) { -@@ -773,6 +783,7 @@ int main(int argc, char **argv) +@@ -818,6 +828,7 @@ int main(int argc, char **argv) {"all-symbols", no_argument, &all_symbols, 1}, {"absolute-percpu", no_argument, &absolute_percpu, 1}, {"base-relative", no_argument, &base_relative, 1}, @@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh -@@ -266,6 +266,10 @@ kallsyms() +@@ -156,6 +156,10 @@ kallsyms() kallsymopt="${kallsymopt} --base-relative" fi @@ -114,5 +114,5 @@ Signed-off-by: Felix Fietkau + fi + info KSYMS ${2} - ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2} + scripts/kallsyms ${kallsymopt} ${1} > ${2} } diff --git a/target/linux/generic/pending-6.1/205-backtrace_module_info.patch b/target/linux/generic/pending-6.1/205-backtrace_module_info.patch index 6379ce071d7..27a13479819 100644 --- a/target/linux/generic/pending-6.1/205-backtrace_module_info.patch +++ b/target/linux/generic/pending-6.1/205-backtrace_module_info.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/lib/vsprintf.c +++ b/lib/vsprintf.c -@@ -1003,8 +1003,10 @@ char *symbol_string(char *buf, char *end +@@ -985,8 +985,10 @@ char *symbol_string(char *buf, char *end struct printf_spec spec, const char *fmt) { unsigned long value; @@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau #endif if (fmt[1] == 'R') -@@ -1025,8 +1027,14 @@ char *symbol_string(char *buf, char *end +@@ -1007,8 +1009,14 @@ char *symbol_string(char *buf, char *end return string_nocheck(buf, end, sym, spec); #else diff --git a/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch b/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch index 29cfade7163..9e78284ecf7 100644 --- a/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch +++ b/target/linux/generic/pending-6.1/240-remove-unsane-filenames-from-deps_initramfs-list.patch @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau --- a/usr/Makefile +++ b/usr/Makefile -@@ -61,6 +61,8 @@ hostprogs := gen_init_cpio +@@ -56,6 +56,8 @@ hostprogs := gen_init_cpio # The dependency list is generated by gen_initramfs.sh -l -include $(obj)/.initramfs_data.cpio.d diff --git a/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch index f847db983a2..997e6142a70 100644 --- a/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch +++ b/target/linux/generic/pending-6.1/270-platform-mikrotik-build-bits.patch @@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig -@@ -15,3 +15,5 @@ source "drivers/platform/mellanox/Kconfi +@@ -16,3 +16,5 @@ source "drivers/platform/olpc/Kconfig" source "drivers/platform/surface/Kconfig" source "drivers/platform/x86/Kconfig" @@ -24,7 +24,7 @@ Signed-off-by: Thibaut VARÈNE +source "drivers/platform/mikrotik/Kconfig" --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile -@@ -10,3 +10,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/ +@@ -11,3 +11,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ diff --git a/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch b/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch index 05d024925df..a4413e919b4 100644 --- a/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch +++ b/target/linux/generic/pending-6.1/300-mips_expose_boot_raw.patch @@ -9,7 +9,7 @@ Acked-by: Rob Landley --- --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig -@@ -1100,9 +1100,6 @@ config FW_ARC +@@ -1032,9 +1032,6 @@ config FW_ARC config ARCH_MAY_HAVE_PC_FDC bool @@ -19,7 +19,7 @@ Acked-by: Rob Landley config CEVT_BCM1480 bool -@@ -3182,6 +3179,18 @@ choice +@@ -3089,6 +3086,18 @@ choice bool "Extend builtin kernel arguments with bootloader arguments" endchoice diff --git a/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch b/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch index 726c884027f..bd56adad3a0 100644 --- a/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch +++ b/target/linux/generic/pending-6.1/301-MIPS-Add-barriers-between-dcache-icache-flushes.patch @@ -26,7 +26,7 @@ Cc: James Hogan --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c -@@ -515,6 +515,7 @@ static inline void local_r4k___flush_cac +@@ -514,6 +514,7 @@ static inline void local_r4k___flush_cac default: r4k_blast_dcache(); @@ -34,7 +34,7 @@ Cc: James Hogan r4k_blast_icache(); break; } -@@ -595,8 +596,10 @@ static inline void local_r4k_flush_cache +@@ -594,8 +595,10 @@ static inline void local_r4k_flush_cache if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) r4k_blast_dcache(); /* If executable, blast stale lines from icache */ @@ -46,7 +46,7 @@ Cc: James Hogan } static void r4k_flush_cache_range(struct vm_area_struct *vma, -@@ -697,8 +700,13 @@ static inline void local_r4k_flush_cache +@@ -696,8 +699,13 @@ static inline void local_r4k_flush_cache if (cpu_has_dc_aliases || (exec && !cpu_has_ic_fills_f_dc)) { vaddr ? r4k_blast_dcache_page(addr) : r4k_blast_dcache_user_page(addr); @@ -61,7 +61,7 @@ Cc: James Hogan } if (exec) { if (vaddr && cpu_has_vtag_icache && mm == current->active_mm) { -@@ -765,6 +773,7 @@ static inline void __local_r4k_flush_ica +@@ -764,6 +772,7 @@ static inline void __local_r4k_flush_ica else blast_dcache_range(start, end); } diff --git a/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch b/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch index 271923fca8c..542fba651f2 100644 --- a/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch +++ b/target/linux/generic/pending-6.1/302-mips_no_branch_likely.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/arch/mips/Makefile +++ b/arch/mips/Makefile -@@ -95,7 +95,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin +@@ -94,7 +94,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin # machines may also. Since BFD is incredibly buggy with respect to # crossformat linking we rely on the elf2ecoff tool for format conversion. # diff --git a/target/linux/generic/pending-6.1/305-mips_module_reloc.patch b/target/linux/generic/pending-6.1/305-mips_module_reloc.patch index bbea1f61c14..5de9019677e 100644 --- a/target/linux/generic/pending-6.1/305-mips_module_reloc.patch +++ b/target/linux/generic/pending-6.1/305-mips_module_reloc.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/arch/mips/Makefile +++ b/arch/mips/Makefile -@@ -98,8 +98,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin +@@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely cflags-y += -msoft-float LDFLAGS_vmlinux += -G 0 -static -n -nostdlib @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c -@@ -31,23 +31,261 @@ struct mips_hi16 { +@@ -32,23 +32,261 @@ struct mips_hi16 { static LIST_HEAD(dbe_list); static DEFINE_SPINLOCK(dbe_lock); @@ -309,7 +309,7 @@ Signed-off-by: Felix Fietkau if (v % 4) { pr_err("module %s: dangerous R_MIPS_26 relocation\n", me->name); -@@ -55,13 +293,17 @@ static int apply_r_mips_26(struct module +@@ -56,13 +294,17 @@ static int apply_r_mips_26(struct module } if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) { @@ -331,7 +331,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -441,9 +683,36 @@ int module_finalize(const Elf_Ehdr *hdr, +@@ -442,9 +684,36 @@ int module_finalize(const Elf_Ehdr *hdr, list_add(&me->arch.dbe_list, &dbe_list); spin_unlock_irq(&dbe_lock); } diff --git a/target/linux/generic/pending-6.1/308-mips32r2_tune.patch b/target/linux/generic/pending-6.1/308-mips32r2_tune.patch index ef92a5dfb69..db410a6bc06 100644 --- a/target/linux/generic/pending-6.1/308-mips32r2_tune.patch +++ b/target/linux/generic/pending-6.1/308-mips32r2_tune.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/arch/mips/Makefile +++ b/arch/mips/Makefile -@@ -175,7 +175,7 @@ cflags-$(CONFIG_CPU_VR41XX) += -march=r4 +@@ -172,7 +172,7 @@ cflags-$(CONFIG_CPU_R4300) += -march=r43 cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap diff --git a/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch b/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch index 191dc6ac3cd..54cc9ba6476 100644 --- a/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch +++ b/target/linux/generic/pending-6.1/310-arm_module_unresolved_weak_sym.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c -@@ -105,6 +105,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons +@@ -146,6 +146,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons return -ENOEXEC; } diff --git a/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch b/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch index 082b122cb4d..e9b47d185d2 100644 --- a/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch +++ b/target/linux/generic/pending-6.1/342-powerpc-Enable-kernel-XZ-compression-option-on-PPC_8.patch @@ -14,7 +14,7 @@ Signed-off-by: Pawel Dembicki --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig -@@ -221,7 +221,7 @@ config PPC +@@ -229,7 +229,7 @@ config PPC select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE select HAVE_KERNEL_LZO if DEFAULT_UIMAGE diff --git a/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch b/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch index 9fad4f62c61..91654cc294c 100644 --- a/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch +++ b/target/linux/generic/pending-6.1/351-irqchip-bcm-6345-l1-request-memory-region.patch @@ -91,7 +91,7 @@ Acked-by: Florian Fainelli --- a/drivers/irqchip/irq-bcm6345-l1.c +++ b/drivers/irqchip/irq-bcm6345-l1.c -@@ -261,6 +261,9 @@ static int __init bcm6345_l1_init_one(st +@@ -257,6 +257,9 @@ static int __init bcm6345_l1_init_one(st if (!cpu->map_base) return -ENOMEM; @@ -101,7 +101,7 @@ Acked-by: Florian Fainelli for (i = 0; i < n_words; i++) { cpu->enable_cache[i] = 0; __raw_writel(0, cpu->map_base + reg_enable(intc, i)); -@@ -339,8 +342,7 @@ static int __init bcm6345_l1_of_init(str +@@ -335,8 +338,7 @@ static int __init bcm6345_l1_of_init(str for_each_cpu(idx, &intc->cpumask) { struct bcm6345_l1_cpu *cpu = intc->cpus[idx]; diff --git a/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch index 2360d6dcd0f..c619d12ce53 100644 --- a/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch +++ b/target/linux/generic/pending-6.1/400-mtd-mtdsplit-support.patch @@ -264,7 +264,7 @@ Subject: [PATCH] mtd: mtdsplit support * one chunk. Do that by default. --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h -@@ -620,6 +620,24 @@ static inline void mtd_align_erase_req(s +@@ -615,6 +615,24 @@ static inline void mtd_align_erase_req(s req->len += mtd->erasesize - mod; } @@ -289,7 +289,7 @@ Subject: [PATCH] mtd: mtdsplit support static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) { if (mtd->writesize_shift) -@@ -685,6 +703,13 @@ extern void __put_mtd_device(struct mtd_ +@@ -688,6 +706,13 @@ extern struct mtd_info *of_get_mtd_devic extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); diff --git a/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch b/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch index d12bc9c3d59..f04da4000cc 100644 --- a/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch +++ b/target/linux/generic/pending-6.1/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch @@ -193,7 +193,7 @@ Reported-by: Dan Carpenter default y --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c -@@ -1271,6 +1271,8 @@ static u8 spi_nor_convert_3to4_erase(u8 +@@ -1049,6 +1049,8 @@ static u8 spi_nor_convert_3to4_erase(u8 static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) { @@ -202,7 +202,7 @@ Reported-by: Dan Carpenter return !!nor->params->erase_map.uniform_erase_type; } -@@ -2400,6 +2402,7 @@ static int spi_nor_select_erase(struct s +@@ -2157,6 +2159,7 @@ static int spi_nor_select_erase(struct s { struct spi_nor_erase_map *map = &nor->params->erase_map; const struct spi_nor_erase_type *erase = NULL; @@ -210,7 +210,7 @@ Reported-by: Dan Carpenter struct mtd_info *mtd = &nor->mtd; u32 wanted_size = nor->info->sector_size; int i; -@@ -2432,8 +2435,9 @@ static int spi_nor_select_erase(struct s +@@ -2189,8 +2192,9 @@ static int spi_nor_select_erase(struct s */ for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { if (map->erase_type[i].size) { @@ -222,7 +222,7 @@ Reported-by: Dan Carpenter } } -@@ -2441,6 +2445,9 @@ static int spi_nor_select_erase(struct s +@@ -2198,6 +2202,9 @@ static int spi_nor_select_erase(struct s return -EINVAL; mtd->erasesize = erase->size; @@ -234,7 +234,7 @@ Reported-by: Dan Carpenter --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h -@@ -250,6 +250,8 @@ struct mtd_info { +@@ -245,6 +245,8 @@ struct mtd_info { * information below if they desire */ uint32_t erasesize; diff --git a/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch index fee19365933..5518ea71dd5 100644 --- a/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch +++ b/target/linux/generic/pending-6.1/420-mtd-redboot_space.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/parsers/redboot.c +++ b/drivers/mtd/parsers/redboot.c -@@ -277,14 +277,21 @@ nogood: +@@ -278,14 +278,21 @@ nogood: #endif names += strlen(names) + 1; diff --git a/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch b/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch index 8a6e6305301..c8cf3f5d3be 100644 --- a/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch +++ b/target/linux/generic/pending-6.1/430-mtd-add-myloader-partition-parser.patch @@ -10,7 +10,7 @@ Signed-off-by: Adrian Schmutzler --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -57,6 +57,22 @@ config MTD_CMDLINE_PARTS +@@ -67,6 +67,22 @@ config MTD_CMDLINE_PARTS If unsure, say 'N'. @@ -35,9 +35,9 @@ Signed-off-by: Adrian Schmutzler default y --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part. - obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o +@@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm4 obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o + obj-$(CONFIG_MTD_BRCM_U_BOOT) += brcm_u-boot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o +obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o diff --git a/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch b/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch index ee949f73c09..a42dcc868f7 100644 --- a/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch +++ b/target/linux/generic/pending-6.1/435-mtd-add-routerbootpart-parser-config.patch @@ -16,7 +16,7 @@ Signed-off-by: Thibaut VARÈNE --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig -@@ -226,3 +226,12 @@ config MTD_SERCOMM_PARTS +@@ -236,3 +236,12 @@ config MTD_SERCOMM_PARTS partition map. This partition table contains real partition offsets, which may differ from device to device depending on the number and location of bad blocks on NAND. @@ -31,7 +31,7 @@ Signed-off-by: Thibaut VARÈNE + formatted DTS. --- a/drivers/mtd/parsers/Makefile +++ b/drivers/mtd/parsers/Makefile -@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa +@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_SERCOMM_PARTS) += scpa obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_QCOMSMEM_PARTS) += qcomsmempart.o diff --git a/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch b/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch index 0be74a59777..1b653fb735c 100644 --- a/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch +++ b/target/linux/generic/pending-6.1/460-mtd-cfi_cmdset_0002-no-erase_suspend.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c -@@ -907,7 +907,7 @@ static int get_chip(struct map_info *map +@@ -908,7 +908,7 @@ static int get_chip(struct map_info *map return 0; case FL_ERASING: diff --git a/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch b/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch index ca56de82711..f2788c52140 100644 --- a/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch +++ b/target/linux/generic/pending-6.1/461-mtd-cfi_cmdset_0002-add-buffer-write-cmd-timeout.patch @@ -7,7 +7,7 @@ Signed-off-by: George Kashperko 1 file changed, 1 insertion(+) --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c -@@ -2051,6 +2051,7 @@ static int __xipram do_write_buffer(stru +@@ -2052,6 +2052,7 @@ static int __xipram do_write_buffer(stru /* Write Buffer Load */ map_write(map, CMD(0x25), cmd_adr); diff --git a/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch b/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch index f58d5452abe..1e280773381 100644 --- a/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch +++ b/target/linux/generic/pending-6.1/465-m25p80-mx-disable-software-protection.patch @@ -8,11 +8,11 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c -@@ -93,6 +93,7 @@ static void macronix_default_init(struct +@@ -106,6 +106,7 @@ static void macronix_nor_default_init(st { nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; + nor->flags |= SNOR_F_HAS_LOCK; } - static const struct spi_nor_fixups macronix_fixups = { + static const struct spi_nor_fixups macronix_nor_fixups = { diff --git a/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch index 4caf97fcf2b..303e488433a 100644 --- a/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch +++ b/target/linux/generic/pending-6.1/476-mtd-spi-nor-add-eon-en25q128.patch @@ -8,7 +8,7 @@ Signed-off-by: Piotr Dymacz --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c -@@ -15,6 +15,8 @@ static const struct flash_info eon_parts +@@ -17,6 +17,8 @@ static const struct flash_info eon_nor_p { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128) }, { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128) NO_SFDP_FLAGS(SECT_4K) }, diff --git a/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch index e94c836f62a..6740d1d7beb 100644 --- a/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch +++ b/target/linux/generic/pending-6.1/477-mtd-spi-nor-add-eon-en25qx128a.patch @@ -11,7 +11,7 @@ Signed-off-by: Christian Marangi --- a/drivers/mtd/spi-nor/eon.c +++ b/drivers/mtd/spi-nor/eon.c -@@ -26,6 +26,7 @@ static const struct flash_info eon_parts +@@ -19,6 +19,7 @@ static const struct flash_info eon_nor_p NO_SFDP_FLAGS(SECT_4K) }, { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256) NO_SFDP_FLAGS(SECT_4K) }, diff --git a/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch index 8eb09596ad1..0ec6aa7fb65 100644 --- a/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch +++ b/target/linux/generic/pending-6.1/479-mtd-spi-nor-add-xtx-xt25f128b.patch @@ -31,7 +31,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile -@@ -17,7 +17,8 @@ spi-nor-objs += sst.o +@@ -17,6 +17,7 @@ spi-nor-objs += sst.o spi-nor-objs += winbond.o spi-nor-objs += xilinx.o spi-nor-objs += xmc.o @@ -39,7 +39,6 @@ Signed-off-by: Felix Fietkau spi-nor-$(CONFIG_DEBUG_FS) += debugfs.o obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o - obj-$(CONFIG_MTD_SPI_NOR) += controllers/ --- /dev/null +++ b/drivers/mtd/spi-nor/xtx.c @@ -0,0 +1,17 @@ @@ -62,17 +61,17 @@ Signed-off-by: Felix Fietkau +}; --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c -@@ -1859,6 +1859,7 @@ static const struct spi_nor_manufacturer +@@ -1635,6 +1635,7 @@ static const struct spi_nor_manufacturer &spi_nor_winbond, &spi_nor_xilinx, &spi_nor_xmc, + &spi_nor_xtx, }; - static const struct flash_info * + static const struct flash_info *spi_nor_match_id(struct spi_nor *nor, --- a/drivers/mtd/spi-nor/core.h +++ b/drivers/mtd/spi-nor/core.h -@@ -489,6 +489,7 @@ extern const struct spi_nor_manufacturer +@@ -633,6 +633,7 @@ extern const struct spi_nor_manufacturer extern const struct spi_nor_manufacturer spi_nor_winbond; extern const struct spi_nor_manufacturer spi_nor_xilinx; extern const struct spi_nor_manufacturer spi_nor_xmc; diff --git a/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch index 764dfd68cb3..581e06190b5 100644 --- a/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch +++ b/target/linux/generic/pending-6.1/481-mtd-spi-nor-add-support-for-Gigadevice-GD25D05.patch @@ -10,7 +10,7 @@ Signed-off-by: Koen Vandeputte --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c -@@ -24,6 +24,10 @@ static struct spi_nor_fixups gd25q256_fi +@@ -34,6 +34,10 @@ static const struct spi_nor_fixups gd25q }; static const struct flash_info gigadevice_nor_parts[] = { diff --git a/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch index 614263f190b..ddd3405ae71 100644 --- a/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch +++ b/target/linux/generic/pending-6.1/482-mtd-spi-nor-add-gd25q512.patch @@ -9,7 +9,7 @@ Subject: [PATCH] spi-nor/gigadevic: add gd25q512 --- a/drivers/mtd/spi-nor/gigadevice.c +++ b/drivers/mtd/spi-nor/gigadevice.c -@@ -53,6 +53,11 @@ static const struct flash_info gigadevic +@@ -71,6 +71,11 @@ static const struct flash_info gigadevic FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) FIXUP_FLAGS(SPI_NOR_4B_OPCODES) .fixups = &gd25q256_fixups }, diff --git a/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch index d7223ae8c46..d5ebe203097 100644 --- a/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch +++ b/target/linux/generic/pending-6.1/484-mtd-spi-nor-add-esmt-f25l16pa.patch @@ -14,11 +14,11 @@ flash. +++ b/drivers/mtd/spi-nor/esmt.c @@ -10,6 +10,9 @@ - static const struct flash_info esmt_parts[] = { + static const struct flash_info esmt_nor_parts[] = { /* ESMT */ + { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32) + FLAGS(SPI_NOR_HAS_LOCK) + NO_SFDP_FLAGS(SECT_4K) }, { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64) - FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) - NO_SFDP_FLAGS(SECT_4K) }, + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) + NO_SFDP_FLAGS(SECT_4K) }, diff --git a/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch index 4020a428bee..e8583cc2571 100644 --- a/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch +++ b/target/linux/generic/pending-6.1/485-mtd-spi-nor-add-xmc-xm25qh128c.patch @@ -13,10 +13,10 @@ Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c -@@ -14,6 +14,9 @@ static const struct flash_info xmc_parts - { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256) - NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | - SPI_NOR_QUAD_READ) }, +@@ -16,6 +16,9 @@ static const struct flash_info xmc_nor_p + { "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, + { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256) + NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | + SPI_NOR_QUAD_READ) }, diff --git a/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch index 8191c3c61dc..b8116db8420 100644 --- a/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch +++ b/target/linux/generic/pending-6.1/486-01-mtd-spinand-add-support-for-ESMT-F50x1G41LB.patch @@ -31,7 +31,7 @@ Signed-off-by: Chuanhong Guo obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -896,6 +896,7 @@ static const struct nand_ops spinand_ops +@@ -938,6 +938,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { &ato_spinand_manufacturer, @@ -133,7 +133,7 @@ Signed-off-by: Chuanhong Guo +}; --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h -@@ -260,6 +260,7 @@ struct spinand_manufacturer { +@@ -261,6 +261,7 @@ struct spinand_manufacturer { /* SPI NAND manufacturers */ extern const struct spinand_manufacturer ato_spinand_manufacturer; diff --git a/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch index 00c20e37ca6..81378fba868 100644 --- a/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch +++ b/target/linux/generic/pending-6.1/487-mtd-spinand-Add-support-for-Etron-EM73D044VCx.patch @@ -47,7 +47,7 @@ Submitted-by: Daniel Danzberger obj-$(CONFIG_MTD_SPI_NAND) += spinand.o --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c -@@ -908,6 +908,7 @@ static const struct nand_ops spinand_ops +@@ -939,6 +939,7 @@ static const struct nand_ops spinand_ops static const struct spinand_manufacturer *spinand_manufacturers[] = { &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, @@ -158,9 +158,9 @@ Submitted-by: Daniel Danzberger +}; --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h -@@ -261,6 +261,7 @@ struct spinand_manufacturer { - +@@ -262,6 +262,7 @@ struct spinand_manufacturer { /* SPI NAND manufacturers */ + extern const struct spinand_manufacturer ato_spinand_manufacturer; extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer; +extern const struct spinand_manufacturer etron_spinand_manufacturer; extern const struct spinand_manufacturer gigadevice_spinand_manufacturer; diff --git a/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch index 8c73b6031b7..e1e4f25e119 100644 --- a/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch +++ b/target/linux/generic/pending-6.1/488-mtd-spi-nor-add-xmc-xm25qh64c.patch @@ -11,7 +11,7 @@ Signed-off-by: Joe Mullally --- a/drivers/mtd/spi-nor/xmc.c +++ b/drivers/mtd/spi-nor/xmc.c -@@ -12,6 +12,9 @@ static const struct flash_info xmc_parts +@@ -13,6 +13,9 @@ static const struct flash_info xmc_nor_p { "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128) NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, diff --git a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch index aa6700b0171..99a03e31c37 100644 --- a/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch +++ b/target/linux/generic/pending-6.1/490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c -@@ -1200,6 +1200,73 @@ static struct mtd_info * __init open_mtd +@@ -1205,6 +1205,73 @@ static struct mtd_info * __init open_mtd return mtd; } @@ -82,7 +82,7 @@ Signed-off-by: Daniel Golle static int __init ubi_init(void) { int err, i, k; -@@ -1283,6 +1350,12 @@ static int __init ubi_init(void) +@@ -1289,6 +1356,12 @@ static int __init ubi_init(void) } } diff --git a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch index ae53770c11c..17e8d8bedb6 100644 --- a/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch +++ b/target/linux/generic/pending-6.1/491-ubi-auto-create-ubiblock-device-for-rootfs.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c -@@ -642,6 +642,47 @@ static void __init ubiblock_create_from_ +@@ -653,6 +653,47 @@ static void __init ubiblock_create_from_ } } @@ -56,7 +56,7 @@ Signed-off-by: Daniel Golle static void ubiblock_remove_all(void) { struct ubiblock *next; -@@ -674,6 +715,10 @@ int __init ubiblock_init(void) +@@ -685,6 +726,10 @@ int __init ubiblock_init(void) */ ubiblock_create_from_param(); diff --git a/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch b/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch index cf41c8cad3f..f95ec46f14e 100644 --- a/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch +++ b/target/linux/generic/pending-6.1/492-try-auto-mounting-ubi0-rootfs-in-init-do_mounts.c.patch @@ -8,7 +8,7 @@ Signed-off-by: Daniel Golle --- a/init/do_mounts.c +++ b/init/do_mounts.c -@@ -447,7 +447,30 @@ retry: +@@ -446,7 +446,30 @@ retry: out: put_page(page); } @@ -40,7 +40,7 @@ Signed-off-by: Daniel Golle #ifdef CONFIG_ROOT_NFS #define NFSROOT_TIMEOUT_MIN 5 -@@ -580,6 +603,10 @@ void __init mount_root(void) +@@ -579,6 +602,10 @@ void __init mount_root(void) return; } #endif diff --git a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch index 266a6331c2a..e3493ef19ef 100644 --- a/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch +++ b/target/linux/generic/pending-6.1/493-ubi-set-ROOT_DEV-to-ubiblock-rootfs-if-unset.patch @@ -16,7 +16,7 @@ Signed-off-by: Daniel Golle #include "ubi-media.h" #include "ubi.h" -@@ -451,6 +452,15 @@ int ubiblock_create(struct ubi_volume_in +@@ -459,6 +460,15 @@ int ubiblock_create(struct ubi_volume_in dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)", dev->ubi_num, dev->vol_id, vi->name); mutex_unlock(&devices_mutex); @@ -31,4 +31,4 @@ Signed-off-by: Daniel Golle + return 0; - out_remove_minor: + out_destroy_wq: diff --git a/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch index 6c480673c69..1a4d5a766f2 100644 --- a/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch +++ b/target/linux/generic/pending-6.1/498-mtd-spi-nor-locking-support-for-MX25L6405D.patch @@ -22,13 +22,11 @@ Signed-off-by: Nick Hainke --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c -@@ -41,7 +41,8 @@ static const struct flash_info macronix_ +@@ -48,6 +48,7 @@ static const struct flash_info macronix_ { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64) NO_SFDP_FLAGS(SECT_4K) }, { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128) -- NO_SFDP_FLAGS(SECT_4K) }, + FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) -+ NO_SFDP_FLAGS(SECT_4K) }, + NO_SFDP_FLAGS(SECT_4K) }, { "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4) NO_SFDP_FLAGS(SECT_4K) }, - { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64) diff --git a/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch b/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch index ec14f6341cc..99e0fc72bf7 100644 --- a/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch +++ b/target/linux/generic/pending-6.1/499-mtd-spi-nor-disable-16-bit-sr-for-macronix.patch @@ -20,7 +20,7 @@ Signed-off-by: Nick Hainke --- a/drivers/mtd/spi-nor/macronix.c +++ b/drivers/mtd/spi-nor/macronix.c -@@ -94,6 +94,7 @@ static void macronix_default_init(struct +@@ -107,6 +107,7 @@ static void macronix_nor_default_init(st { nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode; diff --git a/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch index fd6ca784c0f..b6b75d4ac51 100644 --- a/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch +++ b/target/linux/generic/pending-6.1/530-jffs2_make_lzma_available.patch @@ -1087,7 +1087,7 @@ Signed-off-by: Alexandros C. Couloumbis #define JFFS2_NODE_ACCURATE 0x2000 --- a/lib/Kconfig +++ b/lib/Kconfig -@@ -340,6 +340,12 @@ config ZSTD_DECOMPRESS +@@ -354,6 +354,12 @@ config ZSTD_DECOMPRESS source "lib/xz/Kconfig" @@ -1102,7 +1102,7 @@ Signed-off-by: Alexandros C. Couloumbis # ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) --- a/lib/Makefile +++ b/lib/Makefile -@@ -135,6 +135,16 @@ CFLAGS_kobject.o += -DDEBUG +@@ -134,6 +134,16 @@ CFLAGS_kobject.o += -DDEBUG CFLAGS_kobject_uevent.o += -DDEBUG endif @@ -1119,7 +1119,7 @@ Signed-off-by: Alexandros C. Couloumbis obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) -@@ -192,6 +202,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ +@@ -194,6 +204,8 @@ obj-$(CONFIG_ZSTD_COMPRESS) += zstd/ obj-$(CONFIG_ZSTD_DECOMPRESS) += zstd/ obj-$(CONFIG_XZ_DEC) += xz/ obj-$(CONFIG_RAID6_PQ) += raid6/ diff --git a/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch index d8531ed740a..d7548c14199 100644 --- a/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch +++ b/target/linux/generic/pending-6.1/600-netfilter_conntrack_flush.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau #include #ifdef CONFIG_SYSCTL #include -@@ -462,6 +463,58 @@ static int ct_cpu_seq_show(struct seq_fi +@@ -465,6 +466,58 @@ static int ct_cpu_seq_show(struct seq_fi return 0; } @@ -76,7 +76,7 @@ Signed-off-by: Felix Fietkau static const struct seq_operations ct_cpu_seq_ops = { .start = ct_cpu_seq_start, .next = ct_cpu_seq_next, -@@ -475,8 +526,9 @@ static int nf_conntrack_standalone_init_ +@@ -478,8 +531,9 @@ static int nf_conntrack_standalone_init_ kuid_t root_uid; kgid_t root_gid; diff --git a/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch b/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch index c1e050e935e..7e34ef37133 100644 --- a/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch +++ b/target/linux/generic/pending-6.1/610-netfilter_match_bypass_default_checks.patch @@ -59,7 +59,7 @@ Signed-off-by: Felix Fietkau static bool ip_checkentry(const struct ipt_ip *ip) { -@@ -524,6 +550,8 @@ find_check_entry(struct ipt_entry *e, st +@@ -525,6 +551,8 @@ find_check_entry(struct ipt_entry *e, st struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; @@ -68,7 +68,7 @@ Signed-off-by: Felix Fietkau if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) return -ENOMEM; -@@ -818,6 +846,7 @@ copy_entries_to_user(unsigned int total_ +@@ -819,6 +847,7 @@ copy_entries_to_user(unsigned int total_ const struct xt_table_info *private = table->private; int ret = 0; const void *loc_cpu_entry; @@ -76,7 +76,7 @@ Signed-off-by: Felix Fietkau counters = alloc_counters(table); if (IS_ERR(counters)) -@@ -845,6 +874,14 @@ copy_entries_to_user(unsigned int total_ +@@ -846,6 +875,14 @@ copy_entries_to_user(unsigned int total_ goto free_counters; } @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau for (i = sizeof(struct ipt_entry); i < e->target_offset; i += m->u.match_size) { -@@ -1222,12 +1259,15 @@ compat_copy_entry_to_user(struct ipt_ent +@@ -1223,12 +1260,15 @@ compat_copy_entry_to_user(struct ipt_ent compat_uint_t origsize; const struct xt_entry_match *ematch; int ret = 0; diff --git a/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch b/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch index baf738a8d20..dd557fd3eaa 100644 --- a/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch +++ b/target/linux/generic/pending-6.1/611-netfilter_match_bypass_default_table.patch @@ -41,8 +41,8 @@ Signed-off-by: Felix Fietkau + /* Returns one of the generic firewall policies, like NF_ACCEPT. */ unsigned int - ipt_do_table(struct sk_buff *skb, -@@ -266,27 +293,28 @@ ipt_do_table(struct sk_buff *skb, + ipt_do_table(void *priv, +@@ -267,27 +294,28 @@ ipt_do_table(void *priv, unsigned int addend; /* Initialization */ @@ -86,7 +86,7 @@ Signed-off-by: Felix Fietkau jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; /* Switch to alternate jumpstack if we're being invoked via TEE. -@@ -299,7 +327,16 @@ ipt_do_table(struct sk_buff *skb, +@@ -300,7 +328,16 @@ ipt_do_table(void *priv, if (static_key_false(&xt_tee_enabled)) jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); diff --git a/target/linux/generic/pending-6.1/630-packet_socket_type.patch b/target/linux/generic/pending-6.1/630-packet_socket_type.patch index 2d2c7b6cc55..0d586a5584c 100644 --- a/target/linux/generic/pending-6.1/630-packet_socket_type.patch +++ b/target/linux/generic/pending-6.1/630-packet_socket_type.patch @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau #define PACKET_FANOUT_LB 1 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c -@@ -1826,6 +1826,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1862,6 +1862,7 @@ static int packet_rcv_spkt(struct sk_buf { struct sock *sk; struct sockaddr_pkt *spkt; @@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau /* * When we registered the protocol we saved the socket in the data -@@ -1833,6 +1834,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1869,6 +1870,7 @@ static int packet_rcv_spkt(struct sk_buf */ sk = pt->af_packet_priv; @@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau /* * Yank back the headers [hope the device set this -@@ -1845,7 +1847,7 @@ static int packet_rcv_spkt(struct sk_buf +@@ -1881,7 +1883,7 @@ static int packet_rcv_spkt(struct sk_buf * so that this procedure is noop. */ @@ -55,7 +55,7 @@ Signed-off-by: Felix Fietkau goto out; if (!net_eq(dev_net(dev), sock_net(sk))) -@@ -2093,12 +2095,12 @@ static int packet_rcv(struct sk_buff *sk +@@ -2129,12 +2131,12 @@ static int packet_rcv(struct sk_buff *sk unsigned int snaplen, res; bool is_drop_n_account = false; @@ -71,7 +71,7 @@ Signed-off-by: Felix Fietkau if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; -@@ -2224,12 +2226,12 @@ static int tpacket_rcv(struct sk_buff *s +@@ -2261,12 +2263,12 @@ static int tpacket_rcv(struct sk_buff *s BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32); BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48); @@ -87,7 +87,7 @@ Signed-off-by: Felix Fietkau if (!net_eq(dev_net(dev), sock_net(sk))) goto drop; -@@ -3342,6 +3344,7 @@ static int packet_create(struct net *net +@@ -3374,6 +3376,7 @@ static int packet_create(struct net *net mutex_init(&po->pg_vec_lock); po->rollover = NULL; po->prot_hook.func = packet_rcv; @@ -95,7 +95,7 @@ Signed-off-by: Felix Fietkau if (sock->type == SOCK_PACKET) po->prot_hook.func = packet_rcv_spkt; -@@ -3979,6 +3982,16 @@ packet_setsockopt(struct socket *sock, i +@@ -4009,6 +4012,16 @@ packet_setsockopt(struct socket *sock, i WRITE_ONCE(po->xmit, val ? packet_direct_xmit : dev_queue_xmit); return 0; } @@ -112,7 +112,7 @@ Signed-off-by: Felix Fietkau default: return -ENOPROTOOPT; } -@@ -4035,6 +4048,13 @@ static int packet_getsockopt(struct sock +@@ -4065,6 +4078,13 @@ static int packet_getsockopt(struct sock case PACKET_VNET_HDR: val = po->has_vnet_hdr; break; diff --git a/target/linux/generic/pending-6.1/655-increase_skb_pad.patch b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch index f89ee0b8d20..d9fb62b2c1a 100644 --- a/target/linux/generic/pending-6.1/655-increase_skb_pad.patch +++ b/target/linux/generic/pending-6.1/655-increase_skb_pad.patch @@ -9,7 +9,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -2782,7 +2782,7 @@ static inline int pskb_network_may_pull( +@@ -2988,7 +2988,7 @@ static inline int pskb_network_may_pull( * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) */ #ifndef NET_SKB_PAD diff --git a/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch b/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch index 2f6fbd59e43..2bc25eb4fa6 100644 --- a/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch +++ b/target/linux/generic/pending-6.1/666-Add-support-for-MAP-E-FMRs-mesh-mode.patch @@ -154,7 +154,7 @@ Signed-off-by: Steven Barth } return &ip6n->tnls[prio][h]; } -@@ -378,6 +397,12 @@ ip6_tnl_dev_uninit(struct net_device *de +@@ -376,6 +395,12 @@ ip6_tnl_dev_uninit(struct net_device *de struct net *net = t->net; struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); @@ -167,7 +167,7 @@ Signed-off-by: Steven Barth if (dev == ip6n->fb_tnl_dev) RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); else -@@ -790,6 +815,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, +@@ -788,6 +813,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t, } EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl); @@ -275,7 +275,7 @@ Signed-off-by: Steven Barth static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, -@@ -843,6 +969,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl +@@ -840,6 +966,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl skb_reset_network_header(skb); memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); @@ -303,7 +303,7 @@ Signed-off-by: Steven Barth __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); -@@ -994,6 +1141,7 @@ static void init_tel_txopt(struct ipv6_t +@@ -987,6 +1134,7 @@ static void init_tel_txopt(struct ipv6_t opt->ops.opt_nflen = 8; } @@ -311,7 +311,7 @@ Signed-off-by: Steven Barth /** * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own * @t: the outgoing tunnel device -@@ -1274,6 +1422,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str +@@ -1278,6 +1426,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str u8 protocol) { struct ip6_tnl *t = netdev_priv(dev); @@ -319,7 +319,7 @@ Signed-off-by: Steven Barth struct ipv6hdr *ipv6h; const struct iphdr *iph; int encap_limit = -1; -@@ -1373,6 +1522,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str +@@ -1377,6 +1526,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield); @@ -338,7 +338,7 @@ Signed-off-by: Steven Barth if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) return -1; -@@ -1526,6 +1687,14 @@ ip6_tnl_change(struct ip6_tnl *t, const +@@ -1530,6 +1691,14 @@ ip6_tnl_change(struct ip6_tnl *t, const t->parms.link = p->link; t->parms.proto = p->proto; t->parms.fwmark = p->fwmark; @@ -352,7 +352,7 @@ Signed-off-by: Steven Barth + dst_cache_reset(&t->dst_cache); ip6_tnl_link_config(t); - return 0; + } @@ -1564,6 +1733,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_ p->flowinfo = u->flowinfo; p->link = u->link; @@ -423,8 +423,8 @@ Signed-off-by: Steven Barth + } } - static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[], -@@ -2102,6 +2321,12 @@ static void ip6_tnl_dellink(struct net_d + static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev, +@@ -2070,6 +2289,12 @@ static void ip6_tnl_dellink(struct net_d static size_t ip6_tnl_get_size(const struct net_device *dev) { @@ -437,7 +437,7 @@ Signed-off-by: Steven Barth return /* IFLA_IPTUN_LINK */ nla_total_size(4) + -@@ -2131,6 +2356,24 @@ static size_t ip6_tnl_get_size(const str +@@ -2099,6 +2324,24 @@ static size_t ip6_tnl_get_size(const str nla_total_size(0) + /* IFLA_IPTUN_FWMARK */ nla_total_size(4) + @@ -462,7 +462,7 @@ Signed-off-by: Steven Barth 0; } -@@ -2138,6 +2381,9 @@ static int ip6_tnl_fill_info(struct sk_b +@@ -2106,6 +2349,9 @@ static int ip6_tnl_fill_info(struct sk_b { struct ip6_tnl *tunnel = netdev_priv(dev); struct __ip6_tnl_parm *parm = &tunnel->parms; @@ -472,7 +472,7 @@ Signed-off-by: Steven Barth if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || -@@ -2147,9 +2393,27 @@ static int ip6_tnl_fill_info(struct sk_b +@@ -2115,9 +2361,27 @@ static int ip6_tnl_fill_info(struct sk_b nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || @@ -501,7 +501,7 @@ Signed-off-by: Steven Barth if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || -@@ -2189,6 +2453,7 @@ static const struct nla_policy ip6_tnl_p +@@ -2157,6 +2421,7 @@ static const struct nla_policy ip6_tnl_p [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, diff --git a/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch b/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch index 86bd9664e55..e5103570f1f 100644 --- a/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch +++ b/target/linux/generic/pending-6.1/670-ipv6-allow-rejecting-with-source-address-failed-policy.patch @@ -43,7 +43,7 @@ Signed-off-by: Jonas Gorski --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h -@@ -256,6 +256,7 @@ enum { +@@ -265,6 +265,7 @@ enum { RTN_THROW, /* Not in this table */ RTN_NAT, /* Translate this address */ RTN_XRESOLVE, /* Use external resolver */ @@ -53,7 +53,7 @@ Signed-off-by: Jonas Gorski --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c -@@ -143,6 +143,10 @@ const struct fib_prop fib_props[RTN_MAX +@@ -145,6 +145,10 @@ const struct fib_prop fib_props[RTN_MAX .error = -EINVAL, .scope = RT_SCOPE_NOWHERE, }, @@ -66,7 +66,7 @@ Signed-off-by: Jonas Gorski static void rt_fibinfo_free(struct rtable __rcu **rtp) --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c -@@ -2772,6 +2772,7 @@ static const char *const rtn_type_names[ +@@ -2778,6 +2778,7 @@ static const char *const rtn_type_names[ [RTN_THROW] = "THROW", [RTN_NAT] = "NAT", [RTN_XRESOLVE] = "XRESOLVE", @@ -76,7 +76,7 @@ Signed-off-by: Jonas Gorski static inline const char *rtn_type(char *buf, size_t len, unsigned int t) --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c -@@ -175,6 +175,7 @@ static int ipmr_rule_action(struct fib_r +@@ -180,6 +180,7 @@ static int ipmr_rule_action(struct fib_r case FR_ACT_UNREACHABLE: return -ENETUNREACH; case FR_ACT_PROHIBIT: @@ -86,7 +86,7 @@ Signed-off-by: Jonas Gorski default: --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c -@@ -220,6 +220,10 @@ static int __fib6_rule_action(struct fib +@@ -221,6 +221,10 @@ static int __fib6_rule_action(struct fib err = -EACCES; rt = net->ipv6.ip6_prohibit_entry; goto discard_pkt; @@ -99,7 +99,7 @@ Signed-off-by: Jonas Gorski tb_id = fib_rule_get_table(rule, arg); --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c -@@ -163,6 +163,8 @@ static int ip6mr_rule_action(struct fib_ +@@ -170,6 +170,8 @@ static int ip6mr_rule_action(struct fib_ return -ENETUNREACH; case FR_ACT_PROHIBIT: return -EACCES; @@ -119,7 +119,7 @@ Signed-off-by: Jonas Gorski static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu, -@@ -312,6 +314,18 @@ static const struct rt6_info ip6_prohibi +@@ -317,6 +319,18 @@ static const struct rt6_info ip6_prohibi .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), }; @@ -138,7 +138,7 @@ Signed-off-by: Jonas Gorski static const struct rt6_info ip6_blk_hole_entry_template = { .dst = { .__refcnt = ATOMIC_INIT(1), -@@ -1033,6 +1047,7 @@ static const int fib6_prop[RTN_MAX + 1] +@@ -1036,6 +1050,7 @@ static const int fib6_prop[RTN_MAX + 1] [RTN_BLACKHOLE] = -EINVAL, [RTN_UNREACHABLE] = -EHOSTUNREACH, [RTN_PROHIBIT] = -EACCES, @@ -146,7 +146,7 @@ Signed-off-by: Jonas Gorski [RTN_THROW] = -EAGAIN, [RTN_NAT] = -EINVAL, [RTN_XRESOLVE] = -EINVAL, -@@ -1068,6 +1083,10 @@ static void ip6_rt_init_dst_reject(struc +@@ -1071,6 +1086,10 @@ static void ip6_rt_init_dst_reject(struc rt->dst.output = ip6_pkt_prohibit_out; rt->dst.input = ip6_pkt_prohibit; break; @@ -157,7 +157,7 @@ Signed-off-by: Jonas Gorski case RTN_THROW: case RTN_UNREACHABLE: default: -@@ -4560,6 +4579,17 @@ static int ip6_pkt_prohibit_out(struct n +@@ -4539,6 +4558,17 @@ static int ip6_pkt_prohibit_out(struct n return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); } @@ -175,7 +175,7 @@ Signed-off-by: Jonas Gorski /* * Allocate a dst for local (unicast / anycast) address. */ -@@ -5047,7 +5077,8 @@ static int rtm_to_fib6_config(struct sk_ +@@ -5032,7 +5062,8 @@ static int rtm_to_fib6_config(struct sk_ if (rtm->rtm_type == RTN_UNREACHABLE || rtm->rtm_type == RTN_BLACKHOLE || rtm->rtm_type == RTN_PROHIBIT || @@ -185,7 +185,7 @@ Signed-off-by: Jonas Gorski cfg->fc_flags |= RTF_REJECT; if (rtm->rtm_type == RTN_LOCAL) -@@ -6301,6 +6332,8 @@ static int ip6_route_dev_notify(struct n +@@ -6286,6 +6317,8 @@ static int ip6_route_dev_notify(struct n #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry->dst.dev = dev; net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); @@ -194,7 +194,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.dev = dev; net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); #endif -@@ -6312,6 +6345,7 @@ static int ip6_route_dev_notify(struct n +@@ -6297,6 +6330,7 @@ static int ip6_route_dev_notify(struct n in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev); @@ -202,7 +202,7 @@ Signed-off-by: Jonas Gorski in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev); #endif } -@@ -6503,6 +6537,8 @@ static int __net_init ip6_route_net_init +@@ -6488,6 +6522,8 @@ static int __net_init ip6_route_net_init #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.fib6_has_custom_rules = false; @@ -211,7 +211,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, sizeof(*net->ipv6.ip6_prohibit_entry), GFP_KERNEL); -@@ -6513,11 +6549,21 @@ static int __net_init ip6_route_net_init +@@ -6498,11 +6534,21 @@ static int __net_init ip6_route_net_init ip6_template_metrics, true); INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached); @@ -234,7 +234,7 @@ Signed-off-by: Jonas Gorski net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, ip6_template_metrics, true); -@@ -6544,6 +6590,8 @@ out: +@@ -6529,6 +6575,8 @@ out: return ret; #ifdef CONFIG_IPV6_MULTIPLE_TABLES @@ -243,7 +243,7 @@ Signed-off-by: Jonas Gorski out_ip6_prohibit_entry: kfree(net->ipv6.ip6_prohibit_entry); out_ip6_null_entry: -@@ -6563,6 +6611,7 @@ static void __net_exit ip6_route_net_exi +@@ -6548,6 +6596,7 @@ static void __net_exit ip6_route_net_exi kfree(net->ipv6.ip6_null_entry); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.ip6_prohibit_entry); @@ -251,7 +251,7 @@ Signed-off-by: Jonas Gorski kfree(net->ipv6.ip6_blk_hole_entry); #endif dst_entries_destroy(&net->ipv6.ip6_dst_ops); -@@ -6646,6 +6695,9 @@ void __init ip6_route_init_special_entri +@@ -6631,6 +6680,9 @@ void __init ip6_route_init_special_entri init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); diff --git a/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch b/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch index bea43b2bada..94416a5d70e 100644 --- a/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch +++ b/target/linux/generic/pending-6.1/671-net-provide-defines-for-_POLICY_FAILED-until-all-cod.patch @@ -39,7 +39,7 @@ Signed-off-by: Jonas Gorski */ --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h -@@ -260,6 +260,8 @@ enum { +@@ -269,6 +269,8 @@ enum { __RTN_MAX }; diff --git a/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch index e61f59f7561..0494762a1a5 100644 --- a/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch +++ b/target/linux/generic/pending-6.1/680-NET-skip-GRO-for-foreign-MAC-addresses.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2075,6 +2075,8 @@ struct net_device { +@@ -2132,6 +2132,8 @@ struct net_device { struct netdev_hw_addr_list mc; struct netdev_hw_addr_list dev_addrs; @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau #endif --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h -@@ -890,6 +890,7 @@ struct sk_buff { +@@ -964,6 +964,7 @@ struct sk_buff { #ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; #endif @@ -32,7 +32,7 @@ Signed-off-by: Felix Fietkau __u8 inner_protocol_type:1; --- a/net/core/gro.c +++ b/net/core/gro.c -@@ -6062,6 +6062,9 @@ static enum gro_result dev_gro_receive(s +@@ -491,6 +491,9 @@ static enum gro_result dev_gro_receive(s int same_flow; int grow; @@ -44,7 +44,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -8076,6 +8079,48 @@ static void __netdev_adjacent_dev_unlink +@@ -7604,6 +7604,48 @@ static void __netdev_adjacent_dev_unlink &upper_dev->adj_list.lower); } @@ -93,7 +93,7 @@ Signed-off-by: Felix Fietkau static int __netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev, bool master, void *upper_priv, void *upper_info, -@@ -8127,6 +8172,7 @@ static int __netdev_upper_dev_link(struc +@@ -7655,6 +7697,7 @@ static int __netdev_upper_dev_link(struc if (ret) return ret; @@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, &changeupper_info.info); ret = notifier_to_errno(ret); -@@ -8223,6 +8269,7 @@ static void __netdev_upper_dev_unlink(st +@@ -7751,6 +7794,7 @@ static void __netdev_upper_dev_unlink(st __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); @@ -109,7 +109,7 @@ Signed-off-by: Felix Fietkau call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, &changeupper_info.info); -@@ -9042,6 +9089,7 @@ int dev_set_mac_address(struct net_devic +@@ -8803,6 +8847,7 @@ int dev_set_mac_address(struct net_devic if (err) return err; dev->addr_assign_type = NET_ADDR_SET; @@ -119,7 +119,7 @@ Signed-off-by: Felix Fietkau return 0; --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c -@@ -142,6 +142,18 @@ u32 eth_get_headlen(const struct net_dev +@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev } EXPORT_SYMBOL(eth_get_headlen); @@ -138,7 +138,7 @@ Signed-off-by: Felix Fietkau /** * eth_type_trans - determine the packet's protocol ID. * @skb: received socket data -@@ -173,6 +185,10 @@ __be16 eth_type_trans(struct sk_buff *sk +@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk } else { skb->pkt_type = PACKET_OTHERHOST; } diff --git a/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch b/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch index fe6faddc7d7..f6ae9f31f1f 100644 --- a/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch +++ b/target/linux/generic/pending-6.1/682-of_net-add-mac-address-increment-support.patch @@ -20,7 +20,7 @@ Signed-off-by: Ansuel Smith --- a/net/core/of_net.c +++ b/net/core/of_net.c -@@ -119,27 +119,62 @@ static int of_get_mac_addr_nvmem(struct +@@ -119,28 +119,63 @@ static int of_get_mac_addr_nvmem(struct * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists * but is all zeros. * @@ -87,3 +87,4 @@ Signed-off-by: Ansuel Smith + return ret; } EXPORT_SYMBOL(of_get_mac_address); + diff --git a/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch index 3de0201f955..182a0cbc6a7 100644 --- a/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch +++ b/target/linux/generic/pending-6.1/700-netfilter-nft_flow_offload-handle-netdevice-events-f.patch @@ -10,7 +10,7 @@ Signed-off-by: Pablo Neira Ayuso --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c -@@ -608,28 +608,52 @@ void nf_flow_table_free(struct nf_flowta +@@ -659,6 +659,23 @@ static struct pernet_operations nf_flow_ .exit_batch = nf_flow_table_pernet_exit, }; @@ -34,19 +34,14 @@ Signed-off-by: Pablo Neira Ayuso static int __init nf_flow_table_module_init(void) { int ret; - - ret = register_pernet_subsys(&nf_flow_table_net_ops); - if (ret < 0) - return ret; - - ret = nf_flow_table_offload_init(); +@@ -671,8 +688,14 @@ static int __init nf_flow_table_module_i if (ret) goto out_offload; -+ + + ret = register_netdevice_notifier(&flow_offload_netdev_notifier); + if (ret) + goto out_offload_init; - ++ return 0; +out_offload_init: @@ -54,18 +49,17 @@ Signed-off-by: Pablo Neira Ayuso out_offload: unregister_pernet_subsys(&nf_flow_table_net_ops); return ret; - } +@@ -680,6 +703,7 @@ out_offload: static void __exit nf_flow_table_module_exit(void) { + unregister_netdevice_notifier(&flow_offload_netdev_notifier); nf_flow_table_offload_exit(); - unregister_pernet_subsys(&nf_flow_table_net_ops); + unregister_pernet_subsys(&nf_flow_table_net_ops); } - --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c -@@ -444,47 +444,14 @@ static struct nft_expr_type nft_flow_off +@@ -468,47 +468,14 @@ static struct nft_expr_type nft_flow_off .owner = THIS_MODULE, }; diff --git a/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch index 649b3010538..7d603f5de3a 100644 --- a/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch +++ b/target/linux/generic/pending-6.1/702-net-ethernet-mtk_eth_soc-enable-threaded-NAPI.patch @@ -10,7 +10,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -2443,8 +2443,8 @@ static irqreturn_t mtk_handle_irq_rx(int +@@ -3048,8 +3048,8 @@ static irqreturn_t mtk_handle_irq_rx(int eth->rx_events++; if (likely(napi_schedule_prep(ð->rx_napi))) { @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -2456,8 +2456,8 @@ static irqreturn_t mtk_handle_irq_tx(int +@@ -3061,8 +3061,8 @@ static irqreturn_t mtk_handle_irq_tx(int eth->tx_events++; if (likely(napi_schedule_prep(ð->tx_napi))) { @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau } return IRQ_HANDLED; -@@ -3623,6 +3623,8 @@ static int mtk_probe(struct platform_dev +@@ -4727,6 +4727,8 @@ static int mtk_probe(struct platform_dev * for NAPI to work */ init_dummy_netdev(ð->dummy_dev); diff --git a/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch index 21c322b4f11..48b1afe3f28 100644 --- a/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch +++ b/target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch @@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c -@@ -1738,6 +1738,9 @@ void phy_detach(struct phy_device *phyde +@@ -1750,6 +1750,9 @@ void phy_detach(struct phy_device *phyde struct module *ndev_owner = NULL; struct mii_bus *bus; @@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos sysfs_remove_link(&dev->dev.kobj, "phydev"); --- a/include/linux/phy.h +++ b/include/linux/phy.h -@@ -789,6 +789,12 @@ struct phy_driver { +@@ -858,6 +858,12 @@ struct phy_driver { /** @handle_interrupt: Override default interrupt handling */ irqreturn_t (*handle_interrupt)(struct phy_device *phydev); diff --git a/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch index 3aa88066b50..0ecb8703336 100644 --- a/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch +++ b/target/linux/generic/pending-6.1/710-bridge-add-knob-for-filtering-rx-tx-BPDU-pack.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h -@@ -58,6 +58,7 @@ struct br_ip_list { +@@ -59,6 +59,7 @@ struct br_ip_list { #define BR_MRP_LOST_IN_CONT BIT(19) #define BR_TX_FWD_OFFLOAD BIT(20) #define BR_PORT_LOCKED BIT(21) @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev) --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c -@@ -326,6 +326,8 @@ static rx_handler_result_t br_handle_fra +@@ -344,6 +344,8 @@ static rx_handler_result_t br_handle_fra fwd_mask |= p->group_fwd_mask; switch (dest[5]) { case 0x00: /* Bridge Group Address */ @@ -106,7 +106,7 @@ Signed-off-by: Felix Fietkau --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h -@@ -536,6 +536,7 @@ enum { +@@ -561,6 +561,7 @@ enum { IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT, IFLA_BRPORT_MCAST_EHT_HOSTS_CNT, IFLA_BRPORT_LOCKED, @@ -116,7 +116,7 @@ Signed-off-by: Felix Fietkau #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c -@@ -184,6 +184,7 @@ static inline size_t br_port_info_size(v +@@ -188,6 +188,7 @@ static inline size_t br_port_info_size(v + nla_total_size(1) /* IFLA_BRPORT_NEIGH_SUPPRESS */ + nla_total_size(1) /* IFLA_BRPORT_ISOLATED */ + nla_total_size(1) /* IFLA_BRPORT_LOCKED */ @@ -124,7 +124,7 @@ Signed-off-by: Felix Fietkau + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */ + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */ + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */ -@@ -269,7 +270,8 @@ static int br_port_fill_attrs(struct sk_ +@@ -274,7 +275,8 @@ static int br_port_fill_attrs(struct sk_ nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, !!(p->flags & BR_MRP_LOST_IN_CONT)) || nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) || @@ -134,15 +134,15 @@ Signed-off-by: Felix Fietkau return -EMSGSIZE; timerval = br_timer_value(&p->message_age_timer); -@@ -829,6 +831,7 @@ static const struct nla_policy br_port_p - [IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 }, +@@ -878,6 +880,7 @@ static const struct nla_policy br_port_p + [IFLA_BRPORT_LOCKED] = { .type = NLA_U8 }, [IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 }, [IFLA_BRPORT_MCAST_EHT_HOSTS_LIMIT] = { .type = NLA_U32 }, + [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 }, }; /* Change the state of the port and notify spanning tree */ -@@ -893,6 +896,7 @@ static int br_setport(struct net_bridge_ +@@ -943,6 +946,7 @@ static int br_setport(struct net_bridge_ br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS); br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); br_set_port_flag(p, tb, IFLA_BRPORT_LOCKED, BR_PORT_LOCKED); @@ -152,7 +152,7 @@ Signed-off-by: Felix Fietkau --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c -@@ -55,7 +55,7 @@ +@@ -57,7 +57,7 @@ #include "dev.h" #define RTNL_MAX_TYPE 50 @@ -161,7 +161,7 @@ Signed-off-by: Felix Fietkau struct rtnl_link { rtnl_doit_func doit; -@@ -4700,7 +4700,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu +@@ -4811,7 +4811,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu brport_nla_put_flag(skb, flags, mask, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) || brport_nla_put_flag(skb, flags, mask, diff --git a/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch b/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch index c93fe42273e..f29e690350c 100644 --- a/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch +++ b/target/linux/generic/pending-6.1/721-net-phy-realtek-rtl8221-allow-to-configure-SERDES-mo.patch @@ -39,7 +39,7 @@ Signed-off-by: Alexander Couzens #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -841,6 +850,48 @@ static irqreturn_t rtl9000a_handle_inter +@@ -849,6 +858,48 @@ static irqreturn_t rtl9000a_handle_inter return IRQ_HANDLED; } @@ -88,7 +88,7 @@ Signed-off-by: Alexander Couzens static struct phy_driver realtek_drvs[] = { { PHY_ID_MATCH_EXACT(0x00008201), -@@ -981,6 +1032,7 @@ static struct phy_driver realtek_drvs[] +@@ -1001,6 +1052,7 @@ static struct phy_driver realtek_drvs[] PHY_ID_MATCH_EXACT(0x001cc849), .name = "RTL8221B-VB-CG 2.5Gbps PHY", .get_features = rtl822x_get_features, @@ -96,7 +96,7 @@ Signed-off-by: Alexander Couzens .config_aneg = rtl822x_config_aneg, .read_status = rtl822x_read_status, .suspend = genphy_suspend, -@@ -992,6 +1044,7 @@ static struct phy_driver realtek_drvs[] +@@ -1012,6 +1064,7 @@ static struct phy_driver realtek_drvs[] .name = "RTL8221B-VM-CG 2.5Gbps PHY", .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, diff --git a/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch b/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch index 211a8ed297f..b236c0816c2 100644 --- a/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch +++ b/target/linux/generic/pending-6.1/722-net-phy-realtek-support-switching-between-SGMII-and-.patch @@ -16,7 +16,7 @@ Signed-off-by: Chukun Pan --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -676,6 +676,25 @@ static int rtl822x_config_aneg(struct ph +@@ -684,6 +684,25 @@ static int rtl822x_config_aneg(struct ph return __genphy_config_aneg(phydev, ret); } @@ -42,7 +42,7 @@ Signed-off-by: Chukun Pan static int rtl822x_read_status(struct phy_device *phydev) { int ret; -@@ -694,11 +713,14 @@ static int rtl822x_read_status(struct ph +@@ -702,11 +721,14 @@ static int rtl822x_read_status(struct ph phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); } diff --git a/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch b/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch index d93ee0685b2..06642ec8662 100644 --- a/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch +++ b/target/linux/generic/pending-6.1/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch @@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2347,6 +2347,10 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2196,6 +2196,10 @@ mt7530_setup(struct dsa_switch *ds) return -ENODEV; } diff --git a/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch b/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch index 69418183510..cdc18176378 100644 --- a/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch +++ b/target/linux/generic/pending-6.1/724-net-phy-realtek-use-genphy_soft_reset-for-2.5G-PHYs.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -1018,6 +1018,7 @@ static struct phy_driver realtek_drvs[] +@@ -1038,6 +1038,7 @@ static struct phy_driver realtek_drvs[] .write_page = rtl821x_write_page, .read_mmd = rtl822x_read_mmd, .write_mmd = rtl822x_write_mmd, @@ -23,7 +23,7 @@ Signed-off-by: Daniel Golle }, { PHY_ID_MATCH_EXACT(0x001cc840), .name = "RTL8226B_RTL8221B 2.5Gbps PHY", -@@ -1030,6 +1031,7 @@ static struct phy_driver realtek_drvs[] +@@ -1050,6 +1051,7 @@ static struct phy_driver realtek_drvs[] .write_page = rtl821x_write_page, .read_mmd = rtl822x_read_mmd, .write_mmd = rtl822x_write_mmd, @@ -31,7 +31,7 @@ Signed-off-by: Daniel Golle }, { PHY_ID_MATCH_EXACT(0x001cc838), .name = "RTL8226-CG 2.5Gbps PHY", -@@ -1040,6 +1042,7 @@ static struct phy_driver realtek_drvs[] +@@ -1060,6 +1062,7 @@ static struct phy_driver realtek_drvs[] .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, @@ -39,7 +39,7 @@ Signed-off-by: Daniel Golle }, { PHY_ID_MATCH_EXACT(0x001cc848), .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", -@@ -1050,6 +1053,7 @@ static struct phy_driver realtek_drvs[] +@@ -1070,6 +1073,7 @@ static struct phy_driver realtek_drvs[] .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, @@ -47,7 +47,7 @@ Signed-off-by: Daniel Golle }, { PHY_ID_MATCH_EXACT(0x001cc849), .name = "RTL8221B-VB-CG 2.5Gbps PHY", -@@ -1061,6 +1065,7 @@ static struct phy_driver realtek_drvs[] +@@ -1081,6 +1085,7 @@ static struct phy_driver realtek_drvs[] .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, @@ -55,7 +55,7 @@ Signed-off-by: Daniel Golle }, { PHY_ID_MATCH_EXACT(0x001cc84a), .name = "RTL8221B-VM-CG 2.5Gbps PHY", -@@ -1072,6 +1077,7 @@ static struct phy_driver realtek_drvs[] +@@ -1092,6 +1097,7 @@ static struct phy_driver realtek_drvs[] .resume = rtlgen_resume, .read_page = rtl821x_read_page, .write_page = rtl821x_write_page, diff --git a/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch b/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch index 1370c6324bb..d709a790999 100644 --- a/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch +++ b/target/linux/generic/pending-6.1/725-net-phy-realtek-disable-SGMII-in-band-AN-for-2-5G-PHYs.patch @@ -19,7 +19,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -875,6 +875,7 @@ static irqreturn_t rtl9000a_handle_inter +@@ -883,6 +883,7 @@ static irqreturn_t rtl9000a_handle_inter static int rtl8221b_config_init(struct phy_device *phydev) { u16 option_mode; @@ -27,7 +27,7 @@ Signed-off-by: Daniel Golle switch (phydev->interface) { case PHY_INTERFACE_MODE_2500BASEX: -@@ -911,6 +912,13 @@ static int rtl8221b_config_init(struct p +@@ -919,6 +920,13 @@ static int rtl8221b_config_init(struct p break; } diff --git a/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch b/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch index 31f0622327b..986e842e1c3 100644 --- a/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch +++ b/target/linux/generic/pending-6.1/726-net-phy-realtek-make-sure-paged-read-is-protected-by.patch @@ -18,7 +18,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -727,9 +727,11 @@ static bool rtlgen_supports_2_5gbps(stru +@@ -735,9 +735,11 @@ static bool rtlgen_supports_2_5gbps(stru { int val; diff --git a/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch b/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch index a24b4dd79a1..717ece0d5e6 100644 --- a/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch +++ b/target/linux/generic/pending-6.1/727-net-phy-realtek-use-inline-functions-for-10GbE-adver.patch @@ -25,7 +25,7 @@ Signed-off-by: Daniel Golle #define RTL9000A_GINMR 0x14 #define RTL9000A_GINMR_LINK_STATUS BIT(4) -@@ -661,14 +657,11 @@ static int rtl822x_config_aneg(struct ph +@@ -669,14 +665,11 @@ static int rtl822x_config_aneg(struct ph int ret = 0; if (phydev->autoneg == AUTONEG_ENABLE) { @@ -44,7 +44,7 @@ Signed-off-by: Daniel Golle if (ret < 0) return ret; } -@@ -705,12 +698,7 @@ static int rtl822x_read_status(struct ph +@@ -713,12 +706,7 @@ static int rtl822x_read_status(struct ph if (lpadv < 0) return lpadv; diff --git a/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch b/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch index 084ee4b6450..bae24a2ec99 100644 --- a/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch +++ b/target/linux/generic/pending-6.1/728-net-phy-realtek-check-validity-of-10GbE-link-partner.patch @@ -15,7 +15,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -698,6 +698,10 @@ static int rtl822x_read_status(struct ph +@@ -706,6 +706,10 @@ static int rtl822x_read_status(struct ph if (lpadv < 0) return lpadv; diff --git a/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch b/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch index 87102d38187..b5dbfa383a2 100644 --- a/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch +++ b/target/linux/generic/pending-6.1/729-net-phy-realtek-introduce-rtl822x_probe.patch @@ -24,7 +24,7 @@ Signed-off-by: Daniel Golle #define RTL8366RB_POWER_SAVE 0x15 #define RTL8366RB_POWER_SAVE_ON BIT(12) -@@ -740,6 +744,25 @@ static int rtl8226_match_phy_device(stru +@@ -748,6 +752,25 @@ static int rtl8226_match_phy_device(stru rtlgen_supports_2_5gbps(phydev); } @@ -50,7 +50,7 @@ Signed-off-by: Daniel Golle static int rtlgen_resume(struct phy_device *phydev) { int ret = genphy_resume(phydev); -@@ -1013,6 +1036,7 @@ static struct phy_driver realtek_drvs[] +@@ -1033,6 +1056,7 @@ static struct phy_driver realtek_drvs[] .match_phy_device = rtl8226_match_phy_device, .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -58,7 +58,7 @@ Signed-off-by: Daniel Golle .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, -@@ -1026,6 +1050,7 @@ static struct phy_driver realtek_drvs[] +@@ -1046,6 +1070,7 @@ static struct phy_driver realtek_drvs[] .name = "RTL8226B_RTL8221B 2.5Gbps PHY", .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -66,7 +66,7 @@ Signed-off-by: Daniel Golle .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, -@@ -1039,6 +1064,7 @@ static struct phy_driver realtek_drvs[] +@@ -1059,6 +1084,7 @@ static struct phy_driver realtek_drvs[] .name = "RTL8226-CG 2.5Gbps PHY", .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -74,7 +74,7 @@ Signed-off-by: Daniel Golle .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, -@@ -1050,6 +1076,7 @@ static struct phy_driver realtek_drvs[] +@@ -1070,6 +1096,7 @@ static struct phy_driver realtek_drvs[] .name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY", .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, @@ -82,7 +82,7 @@ Signed-off-by: Daniel Golle .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, -@@ -1062,6 +1089,7 @@ static struct phy_driver realtek_drvs[] +@@ -1082,6 +1109,7 @@ static struct phy_driver realtek_drvs[] .get_features = rtl822x_get_features, .config_init = rtl8221b_config_init, .config_aneg = rtl822x_config_aneg, @@ -90,7 +90,7 @@ Signed-off-by: Daniel Golle .read_status = rtl822x_read_status, .suspend = genphy_suspend, .resume = rtlgen_resume, -@@ -1074,6 +1102,7 @@ static struct phy_driver realtek_drvs[] +@@ -1094,6 +1122,7 @@ static struct phy_driver realtek_drvs[] .get_features = rtl822x_get_features, .config_aneg = rtl822x_config_aneg, .config_init = rtl8221b_config_init, diff --git a/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch b/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch index 6d414bfbade..ac385551516 100644 --- a/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch +++ b/target/linux/generic/pending-6.1/730-net-phy-realtek-detect-early-version-of-RTL8221B.patch @@ -13,7 +13,7 @@ Signed-off-by: Daniel Golle --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c -@@ -744,6 +744,38 @@ static int rtl8226_match_phy_device(stru +@@ -752,6 +752,38 @@ static int rtl8226_match_phy_device(stru rtlgen_supports_2_5gbps(phydev); } @@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle static int rtl822x_probe(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; -@@ -1084,7 +1116,7 @@ static struct phy_driver realtek_drvs[] +@@ -1104,7 +1136,7 @@ static struct phy_driver realtek_drvs[] .write_page = rtl821x_write_page, .soft_reset = genphy_soft_reset, }, { diff --git a/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch index 2071bb0f947..e18b1d0ee8e 100644 --- a/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch +++ b/target/linux/generic/pending-6.1/731-net-ethernet-mediatek-ppe-add-support-for-flow-accou.patch @@ -53,7 +53,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4642,8 +4642,8 @@ static int mtk_probe(struct platform_dev +@@ -4696,8 +4696,8 @@ static int mtk_probe(struct platform_dev for (i = 0; i < num_ppe; i++) { u32 ppe_addr = eth->soc->reg_map->ppe_base + i * 0x400; @@ -63,8 +63,8 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov + if (!eth->ppe[i]) { err = -ENOMEM; - goto err_free_dev; -@@ -4770,6 +4770,7 @@ static const struct mtk_soc_data mt7622_ + goto err_deinit_ppe; +@@ -4823,6 +4823,7 @@ static const struct mtk_soc_data mt7622_ .required_pctl = false, .offload_version = 2, .hash_offset = 2, @@ -72,7 +72,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, .txrx = { .txd_size = sizeof(struct mtk_tx_dma), -@@ -4807,6 +4808,7 @@ static const struct mtk_soc_data mt7629_ +@@ -4860,6 +4861,7 @@ static const struct mtk_soc_data mt7629_ .hw_features = MTK_HW_FEATURES, .required_clks = MT7629_CLKS_BITMAP, .required_pctl = false, @@ -80,7 +80,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .txrx = { .txd_size = sizeof(struct mtk_tx_dma), .rxd_size = sizeof(struct mtk_rx_dma), -@@ -4827,6 +4829,7 @@ static const struct mtk_soc_data mt7981_ +@@ -4880,6 +4882,7 @@ static const struct mtk_soc_data mt7981_ .offload_version = 2, .hash_offset = 4, .foe_entry_size = sizeof(struct mtk_foe_entry), @@ -88,8 +88,8 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .txrx = { .txd_size = sizeof(struct mtk_tx_dma_v2), .rxd_size = sizeof(struct mtk_rx_dma_v2), -@@ -4847,6 +4850,7 @@ static const struct mtk_soc_data mt7986_ - .offload_version = 2, +@@ -4899,6 +4902,7 @@ static const struct mtk_soc_data mt7986_ + .required_pctl = false, .hash_offset = 4, .foe_entry_size = sizeof(struct mtk_foe_entry), + .has_accounting = true, @@ -98,7 +98,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov .rxd_size = sizeof(struct mtk_rx_dma_v2), --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1014,6 +1014,8 @@ struct mtk_reg_map { +@@ -1017,6 +1017,8 @@ struct mtk_reg_map { * the extra setup for those pins used by GMAC. * @hash_offset Flow table hash offset. * @foe_entry_size Foe table entry size. @@ -107,7 +107,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov * @txd_size Tx DMA descriptor size. * @rxd_size Rx DMA descriptor size. * @rx_irq_done_mask Rx irq done register mask. -@@ -1031,6 +1033,7 @@ struct mtk_soc_data { +@@ -1034,6 +1036,7 @@ struct mtk_soc_data { u8 hash_offset; u16 foe_entry_size; netdev_features_t hw_features; @@ -166,7 +166,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) { ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR); -@@ -464,6 +506,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -459,6 +501,13 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); mtk_ppe_cache_clear(ppe); @@ -180,7 +180,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov } entry->hash = 0xffff; -@@ -571,6 +620,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -566,6 +615,9 @@ __mtk_foe_entry_commit(struct mtk_ppe *p wmb(); hwe->ib1 = entry->ib1; @@ -190,7 +190,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov dma_wmb(); mtk_ppe_cache_clear(ppe); -@@ -762,11 +814,39 @@ int mtk_ppe_prepare_reset(struct mtk_ppe +@@ -757,11 +809,39 @@ int mtk_ppe_prepare_reset(struct mtk_ppe return mtk_ppe_wait_busy(ppe); } @@ -232,7 +232,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov struct mtk_ppe *ppe; u32 foe_flow_size; void *foe; -@@ -783,7 +863,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ +@@ -778,7 +858,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ ppe->base = base; ppe->eth = eth; ppe->dev = dev; @@ -242,9 +242,9 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * soc->foe_entry_size, -@@ -799,6 +880,23 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ +@@ -794,6 +875,23 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ if (!ppe->foe_flow) - return NULL; + goto err_free_l2_flows; + if (accounting) { + mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), @@ -266,7 +266,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov mtk_ppe_debugfs_init(ppe, index); return ppe; -@@ -913,6 +1011,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe) +@@ -923,6 +1021,16 @@ void mtk_ppe_start(struct mtk_ppe *ppe) ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777); ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f); } @@ -338,7 +338,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov void mtk_ppe_deinit(struct mtk_eth *eth); void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); -@@ -354,5 +373,7 @@ int mtk_foe_entry_commit(struct mtk_ppe +@@ -359,5 +377,7 @@ int mtk_foe_entry_commit(struct mtk_ppe void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index); diff --git a/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch b/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch index b736ecc75a3..204440c41fb 100644 --- a/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch +++ b/target/linux/generic/pending-6.1/731-net-permit-ieee80211_ptr-even-with-no-CFG82111-suppo.patch @@ -15,11 +15,9 @@ Signed-off-by: Christian Marangi net/wireless/Kconfig | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h -index eddf8ee270e7..1ac7390772de 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -2156,7 +2156,7 @@ struct net_device { +@@ -2167,7 +2167,7 @@ struct net_device { #if IS_ENABLED(CONFIG_AX25) void *ax25_ptr; #endif @@ -28,11 +26,9 @@ index eddf8ee270e7..1ac7390772de 100644 struct wireless_dev *ieee80211_ptr; #endif #if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN) -diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c -index 41c1ad33d009..58a1c5999b44 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c -@@ -308,7 +308,7 @@ static bool batadv_is_cfg80211_netdev(struct net_device *net_device) +@@ -308,7 +308,7 @@ static bool batadv_is_cfg80211_netdev(st if (!net_device) return false; @@ -41,8 +37,6 @@ index 41c1ad33d009..58a1c5999b44 100644 /* cfg80211 drivers have to set ieee80211_ptr */ if (net_device->ieee80211_ptr) return true; -diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig -index f620acd2a0f5..9f1aa9ec9fa3 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -26,6 +26,7 @@ config CFG80211 @@ -63,6 +57,3 @@ index f620acd2a0f5..9f1aa9ec9fa3 100644 if CFG80211 config NL80211_TESTMODE --- -2.37.2 - diff --git a/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch b/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch index 35b296a2553..e55375f3a2a 100644 --- a/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch +++ b/target/linux/generic/pending-6.1/732-00-net-ethernet-mtk_eth_soc-drop-generic-vlan-rx-offloa.patch @@ -17,7 +17,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1850,9 +1850,7 @@ static int mtk_poll_rx(struct napi_struc +@@ -1898,9 +1898,7 @@ static int mtk_poll_rx(struct napi_struc while (done < budget) { unsigned int pktlen, *rxdcsum; @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau dma_addr_t dma_addr; u32 hash, reason; int mac = 0; -@@ -1987,36 +1985,21 @@ static int mtk_poll_rx(struct napi_struc +@@ -2035,36 +2033,21 @@ static int mtk_poll_rx(struct napi_struc skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, netdev); @@ -70,7 +70,7 @@ Signed-off-by: Felix Fietkau skb_record_rx_queue(skb, 0); napi_gro_receive(napi, skb); -@@ -2831,29 +2814,11 @@ static netdev_features_t mtk_fix_feature +@@ -2887,29 +2870,11 @@ static netdev_features_t mtk_fix_feature static int mtk_set_features(struct net_device *dev, netdev_features_t features) { @@ -100,7 +100,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3167,30 +3132,6 @@ static int mtk_open(struct net_device *d +@@ -3223,30 +3188,6 @@ static int mtk_open(struct net_device *d struct mtk_eth *eth = mac->hw; int i, err; @@ -131,7 +131,7 @@ Signed-off-by: Felix Fietkau err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0); if (err) { netdev_err(dev, "%s: could not attach PHY: %d\n", __func__, -@@ -3231,6 +3172,35 @@ static int mtk_open(struct net_device *d +@@ -3285,6 +3226,35 @@ static int mtk_open(struct net_device *d phylink_start(mac->phylink); netif_tx_start_all_queues(dev); @@ -167,7 +167,7 @@ Signed-off-by: Felix Fietkau return 0; } -@@ -3715,10 +3685,9 @@ static int mtk_hw_init(struct mtk_eth *e +@@ -3769,10 +3739,9 @@ static int mtk_hw_init(struct mtk_eth *e if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { val = mtk_r32(eth, MTK_CDMP_IG_CTRL); mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); @@ -180,7 +180,7 @@ Signed-off-by: Felix Fietkau /* set interrupt delays based on current Net DIM sample */ mtk_dim_rx(ð->rx_dim.work); -@@ -4365,7 +4334,7 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4419,7 +4388,7 @@ static int mtk_add_mac(struct mtk_eth *e eth->netdev[id]->hw_features |= NETIF_F_LRO; eth->netdev[id]->vlan_features = eth->soc->hw_features & diff --git a/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch b/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch index fbf0cb5735e..c0a5a93a456 100644 --- a/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch +++ b/target/linux/generic/pending-6.1/732-01-net-ethernet-mtk_eth_soc-work-around-issue-with-send.patch @@ -16,7 +16,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -1423,12 +1423,28 @@ static void mtk_wake_queue(struct mtk_et +@@ -1469,12 +1469,28 @@ static void mtk_wake_queue(struct mtk_et } } @@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau bool gso = false; int tx_num; -@@ -1450,6 +1466,18 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1496,6 +1512,18 @@ static netdev_tx_t mtk_start_xmit(struct return NETDEV_TX_BUSY; } @@ -64,7 +64,7 @@ Signed-off-by: Felix Fietkau /* TSO: fill MSS info in tcp checksum field */ if (skb_is_gso(skb)) { if (skb_cow_head(skb, 0)) { -@@ -1465,8 +1493,14 @@ static netdev_tx_t mtk_start_xmit(struct +@@ -1511,8 +1539,14 @@ static netdev_tx_t mtk_start_xmit(struct } } diff --git a/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch b/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch index 0aa9382b6bd..77973180f63 100644 --- a/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch +++ b/target/linux/generic/pending-6.1/732-03-net-ethernet-mtk_eth_soc-fix-remaining-throughput-re.patch @@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -667,6 +667,7 @@ static void mtk_mac_link_up(struct phyli +@@ -710,6 +710,7 @@ static void mtk_mac_link_up(struct phyli MAC_MCR_FORCE_RX_FC); /* Configure speed */ @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau switch (speed) { case SPEED_2500: case SPEED_1000: -@@ -3145,6 +3146,9 @@ found: +@@ -3201,6 +3202,9 @@ found: if (dp->index >= MTK_QDMA_NUM_QUEUES) return NOTIFY_DONE; diff --git a/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch b/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch index 9ef65ec16f7..dc2163959d1 100644 --- a/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch +++ b/target/linux/generic/pending-6.1/734-net-ethernet-mtk_eth_soc-ppe-fix-L2-offloading-with-.patch @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau #include #include "mtk_eth_soc.h" #include "mtk_ppe.h" -@@ -757,7 +758,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe +@@ -752,7 +753,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK) goto out; diff --git a/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch b/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch index 4f765c5c145..c5654a60619 100644 --- a/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch +++ b/target/linux/generic/pending-6.1/736-01-net-ethernet-mtk_eth_soc-add-code-for-offloading-flo.patch @@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -1277,6 +1277,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk +@@ -1280,6 +1280,9 @@ int mtk_gmac_rgmii_path_setup(struct mtk int mtk_eth_offload_init(struct mtk_eth *eth); int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); @@ -120,7 +120,7 @@ Signed-off-by: Felix Fietkau static void wed_m32(struct mtk_wed_device *dev, u32 reg, u32 mask, u32 val) { -@@ -1752,6 +1759,99 @@ out: +@@ -1745,6 +1752,99 @@ out: mutex_unlock(&hw_lock); } @@ -220,7 +220,7 @@ Signed-off-by: Felix Fietkau void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth, void __iomem *wdma, phys_addr_t wdma_phy, int index) -@@ -1771,6 +1871,7 @@ void mtk_wed_add_hw(struct device_node * +@@ -1764,6 +1864,7 @@ void mtk_wed_add_hw(struct device_node * .irq_set_mask = mtk_wed_irq_set_mask, .detach = mtk_wed_detach, .ppe_check = mtk_wed_ppe_check, diff --git a/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch b/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch index 6e17e4dc529..08036e0b17d 100644 --- a/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch +++ b/target/linux/generic/pending-6.1/736-02-net-ethernet-mediatek-mtk_ppe-prefer-newly-added-l2-.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -639,10 +639,20 @@ void mtk_foe_entry_clear(struct mtk_ppe +@@ -634,10 +634,20 @@ void mtk_foe_entry_clear(struct mtk_ppe static int mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { diff --git a/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch b/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch index 29d6e0b0991..ec04fb35425 100644 --- a/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch +++ b/target/linux/generic/pending-6.1/736-03-net-ethernet-mtk_eth_soc-improve-keeping-track-of-of.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -466,42 +466,43 @@ int mtk_foe_entry_set_queue(struct mtk_e +@@ -460,42 +460,43 @@ int mtk_foe_entry_set_queue(struct mtk_e return 0; } @@ -72,7 +72,7 @@ Signed-off-by: Felix Fietkau struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, entry->hash); hwe->ib1 &= ~MTK_FOE_IB1_STATE; -@@ -520,7 +521,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -515,7 +516,8 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW) return; @@ -82,7 +82,7 @@ Signed-off-by: Felix Fietkau kfree(entry); } -@@ -536,66 +538,55 @@ static int __mtk_foe_entry_idle_time(str +@@ -531,66 +533,55 @@ static int __mtk_foe_entry_idle_time(str return now - timestamp; } @@ -178,7 +178,7 @@ Signed-off-by: Felix Fietkau } static void -@@ -632,7 +623,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -627,7 +618,8 @@ __mtk_foe_entry_commit(struct mtk_ppe *p void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { spin_lock_bh(&ppe_lock); @@ -188,7 +188,7 @@ Signed-off-by: Felix Fietkau spin_unlock_bh(&ppe_lock); } -@@ -679,8 +671,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ +@@ -674,8 +666,8 @@ mtk_foe_entry_commit_subflow(struct mtk_ { const struct mtk_soc_data *soc = ppe->eth->soc; struct mtk_flow_entry *flow_info; @@ -198,7 +198,7 @@ Signed-off-by: Felix Fietkau u32 ib1_mask = mtk_get_ib1_pkt_type_mask(ppe->eth) | MTK_FOE_IB1_UDP; int type; -@@ -688,30 +680,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ +@@ -683,30 +675,30 @@ mtk_foe_entry_commit_subflow(struct mtk_ if (!flow_info) return; @@ -239,7 +239,7 @@ Signed-off-by: Felix Fietkau } void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash) -@@ -721,9 +713,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe +@@ -716,9 +708,11 @@ void __mtk_ppe_check_skb(struct mtk_ppe struct mtk_foe_entry *hwe = mtk_foe_get_entry(ppe, hash); struct mtk_flow_entry *entry; struct mtk_foe_bridge key = {}; @@ -251,7 +251,7 @@ Signed-off-by: Felix Fietkau u8 *tag; spin_lock_bh(&ppe_lock); -@@ -731,20 +725,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe +@@ -726,20 +720,14 @@ void __mtk_ppe_check_skb(struct mtk_ppe if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND) goto out; @@ -278,7 +278,7 @@ Signed-off-by: Felix Fietkau continue; } -@@ -795,9 +783,17 @@ out: +@@ -790,9 +778,17 @@ out: int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry) { diff --git a/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch index 26b33351197..79386d6cf90 100644 --- a/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch +++ b/target/linux/generic/pending-6.1/736-04-net-ethernet-mediatek-fix-ppe-flow-accounting-for-L2.patch @@ -77,7 +77,7 @@ Signed-off-by: Felix Fietkau } static void mtk_ppe_cache_clear(struct mtk_ppe *ppe) -@@ -508,13 +523,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp +@@ -503,13 +518,6 @@ __mtk_foe_entry_clear(struct mtk_ppe *pp hwe->ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_INVALID); dma_wmb(); mtk_ppe_cache_clear(ppe); @@ -91,7 +91,7 @@ Signed-off-by: Felix Fietkau } entry->hash = 0xffff; -@@ -539,11 +547,14 @@ static int __mtk_foe_entry_idle_time(str +@@ -534,11 +542,14 @@ static int __mtk_foe_entry_idle_time(str } static bool @@ -107,7 +107,7 @@ Signed-off-by: Felix Fietkau int len; if (hash == 0xffff) -@@ -554,18 +565,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp +@@ -549,18 +560,35 @@ mtk_flow_entry_update(struct mtk_ppe *pp memcpy(&foe, hwe, len); if (!mtk_flow_entry_match(ppe->eth, entry, &foe, len) || @@ -146,7 +146,7 @@ Signed-off-by: Felix Fietkau struct mtk_flow_entry *cur; struct hlist_node *tmp; int idle; -@@ -574,7 +602,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe +@@ -569,7 +597,9 @@ mtk_flow_entry_update_l2(struct mtk_ppe hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_list) { int cur_idle; @@ -157,7 +157,7 @@ Signed-off-by: Felix Fietkau __mtk_foe_entry_clear(ppe, entry, false); continue; } -@@ -589,10 +619,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe +@@ -584,10 +614,29 @@ mtk_flow_entry_update_l2(struct mtk_ppe } } @@ -187,7 +187,7 @@ Signed-off-by: Felix Fietkau struct mtk_eth *eth = ppe->eth; u16 timestamp = mtk_eth_timestamp(eth); struct mtk_foe_entry *hwe; -@@ -617,6 +666,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -612,6 +661,12 @@ __mtk_foe_entry_commit(struct mtk_ppe *p dma_wmb(); @@ -200,7 +200,7 @@ Signed-off-by: Felix Fietkau mtk_ppe_cache_clear(ppe); } -@@ -781,21 +836,6 @@ out: +@@ -776,21 +831,6 @@ out: spin_unlock_bh(&ppe_lock); } @@ -222,7 +222,7 @@ Signed-off-by: Felix Fietkau int mtk_ppe_prepare_reset(struct mtk_ppe *ppe) { if (!ppe) -@@ -823,32 +863,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe +@@ -818,32 +858,6 @@ int mtk_ppe_prepare_reset(struct mtk_ppe return mtk_ppe_wait_busy(ppe); } @@ -266,7 +266,7 @@ Signed-off-by: Felix Fietkau }; struct mtk_mib_entry { -@@ -325,6 +327,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_ +@@ -326,6 +328,7 @@ void mtk_ppe_deinit(struct mtk_eth *eth) void mtk_ppe_start(struct mtk_ppe *ppe); int mtk_ppe_stop(struct mtk_ppe *ppe); int mtk_ppe_prepare_reset(struct mtk_ppe *ppe); @@ -274,7 +274,7 @@ Signed-off-by: Felix Fietkau void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash); -@@ -373,9 +376,8 @@ int mtk_foe_entry_set_queue(struct mtk_e +@@ -374,9 +377,8 @@ int mtk_foe_entry_set_queue(struct mtk_e unsigned int queue); int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry); diff --git a/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch b/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch index 3dfa193e707..33c98383272 100644 --- a/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch +++ b/target/linux/generic/pending-6.1/736-06-net-ethernet-mediatek-fix-ppe-flow-accounting-for-v1.patch @@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau --- a/drivers/net/ethernet/mediatek/mtk_ppe.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe.c -@@ -646,6 +646,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -640,6 +640,7 @@ __mtk_foe_entry_commit(struct mtk_ppe *p struct mtk_eth *eth = ppe->eth; u16 timestamp = mtk_eth_timestamp(eth); struct mtk_foe_entry *hwe; @@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP_V2; -@@ -662,8 +663,13 @@ __mtk_foe_entry_commit(struct mtk_ppe *p +@@ -656,8 +657,13 @@ __mtk_foe_entry_commit(struct mtk_ppe *p wmb(); hwe->ib1 = entry->ib1; diff --git a/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch index 8dace90b966..50943469efd 100644 --- a/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch +++ b/target/linux/generic/pending-6.1/760-net-core-add-optional-threading-for-backlog-processi.patch @@ -12,7 +12,7 @@ Signed-off-by: Felix Fietkau --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h -@@ -502,6 +502,7 @@ static inline bool napi_complete(struct +@@ -520,6 +520,7 @@ static inline bool napi_complete(struct } int dev_set_threaded(struct net_device *dev, bool threaded); @@ -20,7 +20,7 @@ Signed-off-by: Felix Fietkau /** * napi_disable - prevent NAPI from scheduling -@@ -3365,6 +3366,7 @@ struct softnet_data { +@@ -3126,6 +3127,7 @@ struct softnet_data { unsigned int processed; unsigned int time_squeeze; unsigned int received_rps; @@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau #endif --- a/net/core/dev.c +++ b/net/core/dev.c -@@ -4574,7 +4574,7 @@ static int rps_ipi_queued(struct softnet +@@ -4604,7 +4604,7 @@ static int napi_schedule_rps(struct soft struct softnet_data *mysd = this_cpu_ptr(&softnet_data); #ifdef CONFIG_RPS @@ -39,7 +39,7 @@ Signed-off-by: Felix Fietkau sd->rps_ipi_next = mysd->rps_ipi_list; mysd->rps_ipi_list = sd; -@@ -5755,6 +5755,8 @@ static DEFINE_PER_CPU(struct work_struct +@@ -5785,6 +5785,8 @@ static DEFINE_PER_CPU(struct work_struct /* Network device is going away, flush any packets still pending */ static void flush_backlog(struct work_struct *work) { @@ -48,7 +48,7 @@ Signed-off-by: Felix Fietkau struct sk_buff *skb, *tmp; struct softnet_data *sd; -@@ -5770,8 +5772,17 @@ static void flush_backlog(struct work_st +@@ -5799,8 +5801,17 @@ static void flush_backlog(struct work_st input_queue_head_incr(sd); } } @@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau skb_queue_walk_safe(&sd->process_queue, skb, tmp) { if (skb->dev->reg_state == NETREG_UNREGISTERING) { __skb_unlink(skb, &sd->process_queue); -@@ -5780,7 +5791,16 @@ static void flush_backlog(struct work_st +@@ -5808,7 +5819,16 @@ static void flush_backlog(struct work_st input_queue_head_incr(sd); } } @@ -83,15 +83,15 @@ Signed-off-by: Felix Fietkau } static bool flush_required(int cpu) -@@ -6463,6 +6485,7 @@ static int process_backlog(struct napi_s +@@ -5940,6 +5960,7 @@ static int process_backlog(struct napi_s } - + rps_lock_irq_disable(sd); + sd->process_queue_empty++; if (skb_queue_empty(&sd->input_pkt_queue)) { /* * Inline a custom version of __napi_complete(). -@@ -6472,7 +6495,8 @@ static int process_backlog(struct napi_s +@@ -5949,7 +5970,8 @@ static int process_backlog(struct napi_s * We can use a plain write instead of clear_bit(), * and we dont need an smp_mb() memory barrier. */ @@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau again = false; } else { skb_queue_splice_tail_init(&sd->input_pkt_queue, -@@ -6889,6 +6913,55 @@ int dev_set_threaded(struct net_device * +@@ -6365,6 +6387,55 @@ int dev_set_threaded(struct net_device * } EXPORT_SYMBOL(dev_set_threaded); @@ -155,9 +155,9 @@ Signed-off-by: Felix Fietkau +} + void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), int weight) + int (*poll)(struct napi_struct *, int), int weight) { -@@ -11367,6 +11442,9 @@ static int dev_cpu_dead(unsigned int old +@@ -11137,6 +11208,9 @@ static int dev_cpu_dead(unsigned int old raise_softirq_irqoff(NET_TX_SOFTIRQ); local_irq_enable(); @@ -167,9 +167,9 @@ Signed-off-by: Felix Fietkau #ifdef CONFIG_RPS remsd = oldsd->rps_ipi_list; oldsd->rps_ipi_list = NULL; -@@ -11706,6 +11784,7 @@ static int __init net_dev_init(void) - sd->cpu = i; - #endif +@@ -11440,6 +11514,7 @@ static int __init net_dev_init(void) + INIT_CSD(&sd->defer_csd, trigger_rx_softirq, sd); + spin_lock_init(&sd->defer_lock); + INIT_LIST_HEAD(&sd->backlog.poll_list); init_gro_hash(&sd->backlog); @@ -177,7 +177,7 @@ Signed-off-by: Felix Fietkau sd->backlog.weight = weight_p; --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c -@@ -28,6 +28,7 @@ static int int_3600 = 3600; +@@ -29,6 +29,7 @@ static int int_3600 = 3600; static int min_sndbuf = SOCK_MIN_SNDBUF; static int min_rcvbuf = SOCK_MIN_RCVBUF; static int max_skb_frags = MAX_SKB_FRAGS; @@ -185,7 +185,7 @@ Signed-off-by: Felix Fietkau static int net_msg_warn; /* Unused, but still a sysctl */ -@@ -114,6 +115,23 @@ static int rps_sock_flow_sysctl(struct c +@@ -112,6 +113,23 @@ static int rps_sock_flow_sysctl(struct c } #endif /* CONFIG_RPS */ @@ -209,7 +209,7 @@ Signed-off-by: Felix Fietkau #ifdef CONFIG_NET_FLOW_LIMIT static DEFINE_MUTEX(flow_limit_update_mutex); -@@ -470,6 +488,15 @@ static struct ctl_table net_core_table[] +@@ -473,6 +491,15 @@ static struct ctl_table net_core_table[] .proc_handler = rps_sock_flow_sysctl }, #endif diff --git a/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch b/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch index 18933de3a03..a9c3f60ce08 100644 --- a/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch +++ b/target/linux/generic/pending-6.1/768-net-dsa-mv88e6xxx-Request-assisted-learning-on-CPU-port.patch @@ -17,7 +17,7 @@ Signed-off-by: Tobias Waldekranz --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c -@@ -6333,6 +6333,7 @@ static int mv88e6xxx_register_switch(str +@@ -6971,6 +6971,7 @@ static int mv88e6xxx_register_switch(str ds->ops = &mv88e6xxx_switch_ops; ds->ageing_time_min = chip->info->age_time_coeff; ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX; diff --git a/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch b/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch index ca963d1260c..23859816fa8 100644 --- a/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch +++ b/target/linux/generic/pending-6.1/772-net-dsa-b53-add-support-for-BCM63xx-RGMIIs.patch @@ -152,7 +152,7 @@ Reviewed-by: Andrew Lunn if (is531x5(dev) && phy_interface_is_rgmii(phydev)) { if (port == dev->imp_port) off = B53_RGMII_CTRL_IMP; -@@ -1419,6 +1462,9 @@ void b53_phylink_mac_link_up(struct dsa_ +@@ -1402,6 +1445,9 @@ void b53_phylink_mac_link_up(struct dsa_ { struct b53_device *dev = ds->priv; @@ -164,7 +164,7 @@ Reviewed-by: Andrew Lunn --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h -@@ -206,6 +206,7 @@ static inline int is58xx(struct b53_devi +@@ -211,6 +211,7 @@ static inline int is58xx(struct b53_devi dev->chip_id == BCM7278_DEVICE_ID; } diff --git a/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch b/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch index e2da4e7f055..8ab701ef563 100644 --- a/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch +++ b/target/linux/generic/pending-6.1/773-net-dsa-b53-mmap-add-more-63xx-SoCs.patch @@ -94,7 +94,7 @@ Reviewed-by: Florian Fainelli --- a/drivers/net/dsa/b53/b53_mmap.c +++ b/drivers/net/dsa/b53/b53_mmap.c -@@ -347,8 +347,11 @@ static void b53_mmap_shutdown(struct pla +@@ -345,8 +345,11 @@ static void b53_mmap_shutdown(struct pla static const struct of_device_id b53_mmap_of_table[] = { { .compatible = "brcm,bcm3384-switch" }, diff --git a/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch b/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch index 456643f05d6..de237374af9 100644 --- a/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch +++ b/target/linux/generic/pending-6.1/774-net-dsa-b53-mmap-allow-passing-a-chip-ID.patch @@ -100,7 +100,7 @@ Signed-off-by: Álvaro Fernández Rojas --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c -@@ -2461,6 +2461,19 @@ static const struct b53_chip_data b53_sw +@@ -2466,6 +2466,19 @@ static const struct b53_chip_data b53_sw .jumbo_size_reg = B53_JUMBO_MAX_SIZE_63XX, }, { @@ -131,7 +131,7 @@ Signed-off-by: Álvaro Fernández Rojas pdata->big_endian = of_property_read_bool(np, "big-endian"); of_ports = of_get_child_by_name(np, "ports"); -@@ -346,14 +346,28 @@ static void b53_mmap_shutdown(struct pla +@@ -344,14 +344,28 @@ static void b53_mmap_shutdown(struct pla } static const struct of_device_id b53_mmap_of_table[] = { @@ -170,7 +170,7 @@ Signed-off-by: Álvaro Fernández Rojas --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h -@@ -75,6 +75,7 @@ enum { +@@ -70,6 +70,7 @@ enum { BCM53125_DEVICE_ID = 0x53125, BCM53128_DEVICE_ID = 0x53128, BCM63XX_DEVICE_ID = 0x6300, @@ -178,7 +178,7 @@ Signed-off-by: Álvaro Fernández Rojas BCM53010_DEVICE_ID = 0x53010, BCM53011_DEVICE_ID = 0x53011, BCM53012_DEVICE_ID = 0x53012, -@@ -186,7 +187,13 @@ static inline int is531x5(struct b53_dev +@@ -191,7 +192,13 @@ static inline int is531x5(struct b53_dev static inline int is63xx(struct b53_device *dev) { diff --git a/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch b/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch index 53494eca6ed..f0ae2defcec 100644 --- a/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch +++ b/target/linux/generic/pending-6.1/777-net-dsa-b53-mdio-add-support-for-BCM53134.patch @@ -100,7 +100,7 @@ Signed-off-by: Álvaro Fernández Rojas --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c -@@ -2609,6 +2609,20 @@ static const struct b53_chip_data b53_sw +@@ -2613,6 +2613,20 @@ static const struct b53_chip_data b53_sw .jumbo_pm_reg = B53_JUMBO_PORT_MASK, .jumbo_size_reg = B53_JUMBO_MAX_SIZE, }, @@ -121,7 +121,7 @@ Signed-off-by: Álvaro Fernández Rojas }; static int b53_switch_init(struct b53_device *dev) -@@ -2785,6 +2799,7 @@ int b53_switch_detect(struct b53_device +@@ -2790,6 +2804,7 @@ int b53_switch_detect(struct b53_device case BCM53012_DEVICE_ID: case BCM53018_DEVICE_ID: case BCM53019_DEVICE_ID: @@ -149,7 +149,7 @@ Signed-off-by: Álvaro Fernández Rojas dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); return -ENODEV; } -@@ -377,6 +379,7 @@ static const struct of_device_id b53_of_ +@@ -375,6 +377,7 @@ static const struct of_device_id b53_of_ { .compatible = "brcm,bcm53115" }, { .compatible = "brcm,bcm53125" }, { .compatible = "brcm,bcm53128" }, @@ -159,15 +159,15 @@ Signed-off-by: Álvaro Fernández Rojas { .compatible = "brcm,bcm5395" }, --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h -@@ -85,6 +85,7 @@ enum { +@@ -80,6 +80,7 @@ enum { BCM583XX_DEVICE_ID = 0x58300, BCM7445_DEVICE_ID = 0x7445, BCM7278_DEVICE_ID = 0x7278, + BCM53134_DEVICE_ID = 0x5075, }; - #define B53_N_PORTS 9 -@@ -182,7 +183,8 @@ static inline int is531x5(struct b53_dev + struct b53_pcs { +@@ -187,7 +188,8 @@ static inline int is531x5(struct b53_dev { return dev->chip_id == BCM53115_DEVICE_ID || dev->chip_id == BCM53125_DEVICE_ID || @@ -177,7 +177,7 @@ Signed-off-by: Álvaro Fernández Rojas } static inline int is63xx(struct b53_device *dev) -@@ -210,7 +212,8 @@ static inline int is58xx(struct b53_devi +@@ -215,7 +217,8 @@ static inline int is58xx(struct b53_devi return dev->chip_id == BCM58XX_DEVICE_ID || dev->chip_id == BCM583XX_DEVICE_ID || dev->chip_id == BCM7445_DEVICE_ID || diff --git a/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch b/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch index fcf7892c04e..39ba71606ec 100644 --- a/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch +++ b/target/linux/generic/pending-6.1/780-ARM-kirkwood-add-missing-linux-if_ether.h-for-ETH_AL.patch @@ -51,7 +51,7 @@ Signed-off-by: Daniel Golle --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c -@@ -14,6 +14,7 @@ +@@ -11,6 +11,7 @@ #include #include #include diff --git a/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch b/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch index 2f728fefd73..874df43e7ce 100644 --- a/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch +++ b/target/linux/generic/pending-6.1/790-bus-mhi-core-add-SBL-state-callback.patch @@ -20,7 +20,7 @@ Signed-off-by: Robert Marko --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c -@@ -891,6 +891,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ +@@ -900,6 +900,7 @@ int mhi_process_ctrl_ev_ring(struct mhi_ switch (event) { case MHI_EE_SBL: st = DEV_ST_TRANSITION_SBL; diff --git a/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch b/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch index f9b88db9955..0e0af2a718b 100644 --- a/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch +++ b/target/linux/generic/pending-6.1/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch @@ -16,7 +16,7 @@ Signed-off-by: David Bauer --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2081,10 +2081,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr +@@ -2086,10 +2086,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr { struct dsa_switch *ds = priv->ds; struct device *dev = priv->dev; @@ -30,7 +30,7 @@ Signed-off-by: David Bauer bus = devm_mdiobus_alloc(dev); if (!bus) return -ENOMEM; -@@ -2101,7 +2104,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr +@@ -2106,7 +2109,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr if (priv->irq) mt7530_setup_mdio_irq(priv); diff --git a/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch b/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch index c1e14b92714..a13d405e647 100644 --- a/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch +++ b/target/linux/generic/pending-6.1/801-gpio-gpio-cascade-add-generic-GPIO-cascade.patch @@ -70,7 +70,7 @@ v1 -> v2: --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig -@@ -1683,4 +1683,19 @@ config GPIO_VIRTIO +@@ -1711,4 +1711,19 @@ config GPIO_SIM endmenu @@ -92,7 +92,7 @@ v1 -> v2: endif --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile -@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd +@@ -43,6 +43,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o diff --git a/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch b/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch index 477b10c7f29..2b3e4bbf716 100644 --- a/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch +++ b/target/linux/generic/pending-6.1/802-OPP-Provide-old-opp-to-config_clks-on-_set_opp.patch @@ -17,11 +17,9 @@ Signed-off-by: Christian Marangi include/linux/pm_opp.h | 11 ++++++----- 3 files changed, 15 insertions(+), 12 deletions(-) -diff --git a/drivers/devfreq/tegra30-devfreq.c b/drivers/devfreq/tegra30-devfreq.c -index 503376b894b6..92cdb6bf9a89 100644 --- a/drivers/devfreq/tegra30-devfreq.c +++ b/drivers/devfreq/tegra30-devfreq.c -@@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(struct device *dev, +@@ -823,8 +823,9 @@ static int devm_tegra_devfreq_init_hw(st static int tegra_devfreq_config_clks_nop(struct device *dev, struct opp_table *opp_table, @@ -33,11 +31,9 @@ index 503376b894b6..92cdb6bf9a89 100644 { /* We want to skip clk configuration via dev_pm_opp_set_opp() */ return 0; -diff --git a/drivers/opp/core.c b/drivers/opp/core.c -index e87567dbe99f..2f44ceaf8d3c 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c -@@ -816,7 +816,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, +@@ -816,7 +816,8 @@ static int _set_opp_voltage(struct devic static int _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, @@ -47,7 +43,7 @@ index e87567dbe99f..2f44ceaf8d3c 100644 { unsigned long *target = data; unsigned long freq; -@@ -848,8 +849,8 @@ _opp_config_clk_single(struct device *dev, struct opp_table *opp_table, +@@ -848,8 +849,8 @@ _opp_config_clk_single(struct device *de * the order in which they are present in the array while scaling up. */ int dev_pm_opp_config_clks_simple(struct device *dev, @@ -58,7 +54,7 @@ index e87567dbe99f..2f44ceaf8d3c 100644 { int ret, i; -@@ -1121,7 +1122,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, +@@ -1121,7 +1122,7 @@ static int _set_opp(struct device *dev, } if (opp_table->config_clks) { @@ -67,7 +63,7 @@ index e87567dbe99f..2f44ceaf8d3c 100644 if (ret) return ret; } -@@ -1196,7 +1197,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) +@@ -1196,7 +1197,7 @@ int dev_pm_opp_set_rate(struct device *d * equivalent to a clk_set_rate() */ if (!_get_opp_count(opp_table)) { @@ -76,11 +72,9 @@ index e87567dbe99f..2f44ceaf8d3c 100644 &target_freq, false); goto put_opp_table; } -diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h -index dc1fb5890792..6c24a4f9fc49 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h -@@ -61,7 +61,8 @@ typedef int (*config_regulators_t)(struct device *dev, +@@ -61,7 +61,8 @@ typedef int (*config_regulators_t)(struc struct dev_pm_opp *old_opp, struct dev_pm_opp *new_opp, struct regulator **regulators, unsigned int count); @@ -90,7 +84,7 @@ index dc1fb5890792..6c24a4f9fc49 100644 struct dev_pm_opp *opp, void *data, bool scaling_down); /** -@@ -160,8 +161,8 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); +@@ -160,8 +161,8 @@ int dev_pm_opp_set_config(struct device int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config); void dev_pm_opp_clear_config(int token); int dev_pm_opp_config_clks_simple(struct device *dev, @@ -101,7 +95,7 @@ index dc1fb5890792..6c24a4f9fc49 100644 struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp); int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); -@@ -346,8 +347,8 @@ static inline int devm_pm_opp_set_config(struct device *dev, struct dev_pm_opp_c +@@ -346,8 +347,8 @@ static inline int devm_pm_opp_set_config static inline void dev_pm_opp_clear_config(int token) {} static inline int dev_pm_opp_config_clks_simple(struct device *dev, @@ -112,6 +106,3 @@ index dc1fb5890792..6c24a4f9fc49 100644 { return -EOPNOTSUPP; } --- -2.37.2 - diff --git a/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch b/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch index 7edbd94f762..33d2c625479 100644 --- a/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch +++ b/target/linux/generic/pending-6.1/810-pci_disable_common_quirks.patch @@ -25,7 +25,7 @@ Signed-off-by: Gabor Juhos --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c -@@ -206,6 +206,7 @@ static void quirk_mmio_always_on(struct +@@ -207,6 +207,7 @@ static void quirk_mmio_always_on(struct DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on); @@ -33,7 +33,7 @@ Signed-off-by: Gabor Juhos /* * The Mellanox Tavor device gives false positive parity errors. Disable * parity error reporting. -@@ -3363,6 +3364,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I +@@ -3388,6 +3389,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata); @@ -42,7 +42,7 @@ Signed-off-by: Gabor Juhos /* * Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. * To work around this, query the size it should be configured to by the -@@ -3388,6 +3391,8 @@ static void quirk_intel_ntb(struct pci_d +@@ -3413,6 +3416,8 @@ static void quirk_intel_ntb(struct pci_d DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb); @@ -51,7 +51,7 @@ Signed-off-by: Gabor Juhos /* * Some BIOS implementations leave the Intel GPU interrupts enabled, even * though no one is handling them (e.g., if the i915 driver is never -@@ -3426,6 +3431,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN +@@ -3451,6 +3456,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq); diff --git a/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch index 67406bac84c..98ea4c06d9f 100644 --- a/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch +++ b/target/linux/generic/pending-6.1/811-pci_disable_usb_common_quirks.patch @@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau #endif /* __LINUX_USB_PCI_QUIRKS_H */ --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h -@@ -497,7 +497,14 @@ extern int usb_hcd_pci_probe(struct pci_ +@@ -483,7 +483,14 @@ extern int usb_hcd_pci_probe(struct pci_ extern void usb_hcd_pci_remove(struct pci_dev *dev); extern void usb_hcd_pci_shutdown(struct pci_dev *dev); diff --git a/target/linux/generic/pending-6.1/834-ledtrig-libata.patch b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch index 9654f4429a8..f3c0b1802b3 100644 --- a/target/linux/generic/pending-6.1/834-ledtrig-libata.patch +++ b/target/linux/generic/pending-6.1/834-ledtrig-libata.patch @@ -45,7 +45,7 @@ Signed-off-by: Daniel Golle depends on ACPI --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c -@@ -656,6 +656,19 @@ u64 ata_tf_read_block(const struct ata_t +@@ -663,6 +663,19 @@ u64 ata_tf_read_block(const struct ata_t return block; } @@ -64,18 +64,18 @@ Signed-off-by: Daniel Golle + /** * ata_build_rw_tf - Build ATA taskfile for given read/write request - * @tf: Target ATA taskfile -@@ -4576,6 +4589,9 @@ struct ata_queued_cmd *ata_qc_new_init(s - if (tag < 0) - return NULL; + * @qc: Metadata associated with the taskfile to build +@@ -4622,6 +4635,9 @@ void __ata_qc_complete(struct ata_queued + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; } +#ifdef CONFIG_ATA_LEDS + ata_led_act(ap); +#endif - qc = __ata_qc_from_tag(ap, tag); - qc->tag = qc->hw_tag = tag; -@@ -5354,6 +5370,9 @@ struct ata_port *ata_port_alloc(struct a + /* clear exclusive status */ + if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL && +@@ -5328,6 +5344,9 @@ struct ata_port *ata_port_alloc(struct a ap->stats.unhandled_irq = 1; ap->stats.idle_irq = 1; #endif @@ -85,7 +85,7 @@ Signed-off-by: Daniel Golle ata_sff_port_init(ap); return ap; -@@ -5389,6 +5408,12 @@ static void ata_host_release(struct kref +@@ -5363,6 +5382,12 @@ static void ata_host_release(struct kref kfree(ap->pmp_link); kfree(ap->slave_link); @@ -98,7 +98,7 @@ Signed-off-by: Daniel Golle kfree(ap); host->ports[i] = NULL; } -@@ -5795,7 +5820,23 @@ int ata_host_register(struct ata_host *h +@@ -5765,7 +5790,23 @@ int ata_host_register(struct ata_host *h host->ports[i]->print_id = atomic_inc_return(&ata_print_id); host->ports[i]->local_port_no = i + 1; } @@ -134,7 +134,7 @@ Signed-off-by: Daniel Golle /* * Define if arch has non-standard setup. This is a _PCI_ standard -@@ -894,6 +897,12 @@ struct ata_port { +@@ -857,6 +860,12 @@ struct ata_port { #ifdef CONFIG_ATA_ACPI struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */ #endif diff --git a/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch index de28ebe73aa..fc61ee202a5 100644 --- a/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch +++ b/target/linux/generic/pending-6.1/850-0023-PCI-aardvark-Make-main-irq_chip-structure-a-static-d.patch @@ -33,7 +33,7 @@ Signed-off-by: Marek Behún --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c -@@ -274,7 +274,6 @@ struct advk_pcie { +@@ -277,7 +277,6 @@ struct advk_pcie { u8 wins_count; struct irq_domain *rp_irq_domain; struct irq_domain *irq_domain; @@ -41,7 +41,7 @@ Signed-off-by: Marek Behún raw_spinlock_t irq_lock; struct irq_domain *msi_domain; struct irq_domain *msi_inner_domain; -@@ -1330,14 +1329,19 @@ static void advk_pcie_irq_unmask(struct +@@ -1426,14 +1425,19 @@ static void advk_pcie_irq_unmask(struct raw_spin_unlock_irqrestore(&pcie->irq_lock, flags); } @@ -63,7 +63,7 @@ Signed-off-by: Marek Behún irq_set_chip_data(virq, pcie); return 0; -@@ -1396,7 +1400,6 @@ static int advk_pcie_init_irq_domain(str +@@ -1492,7 +1496,6 @@ static int advk_pcie_init_irq_domain(str struct device *dev = &pcie->pdev->dev; struct device_node *node = dev->of_node; struct device_node *pcie_intc_node; @@ -71,7 +71,7 @@ Signed-off-by: Marek Behún int ret = 0; raw_spin_lock_init(&pcie->irq_lock); -@@ -1407,28 +1410,14 @@ static int advk_pcie_init_irq_domain(str +@@ -1503,28 +1506,14 @@ static int advk_pcie_init_irq_domain(str return -ENODEV; } diff --git a/target/linux/generic/pending-6.1/920-mangle_bootargs.patch b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch index 23784616624..60ceff00d66 100644 --- a/target/linux/generic/pending-6.1/920-mangle_bootargs.patch +++ b/target/linux/generic/pending-6.1/920-mangle_bootargs.patch @@ -13,7 +13,7 @@ Signed-off-by: Imre Kaloz --- a/init/Kconfig +++ b/init/Kconfig -@@ -1814,6 +1814,15 @@ config EMBEDDED +@@ -1826,6 +1826,15 @@ config EMBEDDED an embedded system so certain expert options are available for configuration. @@ -31,7 +31,7 @@ Signed-off-by: Imre Kaloz help --- a/init/main.c +++ b/init/main.c -@@ -615,6 +615,29 @@ static inline void setup_nr_cpu_ids(void +@@ -609,6 +609,29 @@ static inline void setup_nr_cpu_ids(void static inline void smp_prepare_cpus(unsigned int maxcpus) { } #endif @@ -61,7 +61,7 @@ Signed-off-by: Imre Kaloz /* * We need to store the untouched command line for future reference. * We also need to store the touched command line since the parameter -@@ -955,6 +978,7 @@ asmlinkage __visible void __init __no_sa +@@ -957,6 +980,7 @@ asmlinkage __visible void __init __no_sa pr_notice("%s", linux_banner); early_security_init(); setup_arch(&command_line); From 5f987b84ef0b5d6dc2bcc3d15819e1358d1f3eb0 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 23:48:42 +0200 Subject: [PATCH 70/88] kernel: refresh IFF_NO_IP_ALIGN ifdef for kernel >= 6.1 Kernel 6.1 expanded the priv_flags to long bitmap so update and restore it to priv_flags. Signed-off-by: Christian Marangi --- target/linux/ath25/files/drivers/net/phy/mvswitch.c | 8 ++++++++ target/linux/generic/files/drivers/net/phy/ar8216.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/target/linux/ath25/files/drivers/net/phy/mvswitch.c b/target/linux/ath25/files/drivers/net/phy/mvswitch.c index 29f2f9f0e82..285d306ef09 100644 --- a/target/linux/ath25/files/drivers/net/phy/mvswitch.c +++ b/target/linux/ath25/files/drivers/net/phy/mvswitch.c @@ -312,7 +312,11 @@ mvswitch_config_init(struct phy_device *pdev) priv->orig_features = dev->features; #ifdef HEADER_MODE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) + dev->priv_flags |= IFF_NO_IP_ALIGN; +#else dev->extra_priv_flags |= IFF_NO_IP_ALIGN; +#endif dev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX; #else dev->features |= NETIF_F_HW_VLAN_CTAG_RX; @@ -372,7 +376,11 @@ mvswitch_detach(struct phy_device *pdev) dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; dev->features = priv->orig_features; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) + dev->priv_flags &= ~IFF_NO_IP_ALIGN; +#else dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; +#endif } static void diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 5e248f856ef..876754597a9 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -2459,7 +2459,11 @@ ar8xxx_phy_config_init(struct phy_device *phydev) /* VID fixup only needed on ar8216 */ if (chip_is_ar8216(priv)) { dev->phy_ptr = priv; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) + dev->priv_flags |= IFF_NO_IP_ALIGN; +#else LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags |= IFF_NO_IP_ALIGN; +#endif dev->eth_mangle_rx = ar8216_mangle_rx; dev->eth_mangle_tx = ar8216_mangle_tx; } @@ -2694,7 +2698,11 @@ ar8xxx_phy_detach(struct phy_device *phydev) #ifdef CONFIG_ETHERNET_PACKET_MANGLE dev->phy_ptr = NULL; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) + dev->priv_flags &= ~IFF_NO_IP_ALIGN; +#else LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; +#endif dev->eth_mangle_rx = NULL; dev->eth_mangle_tx = NULL; #endif From fb6de77a824d6d7542ad314721448fcb8c6ccc1a Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 20 Oct 2022 02:20:17 +0200 Subject: [PATCH 71/88] kernel: refresh swconfig_leds to handle new trigger locking Refresh swconfig_leds source to handle new trigger locking that is now a spinlock. Signed-off-by: Christian Marangi --- .../files/drivers/net/phy/swconfig_leds.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c index df53e5cd4a2..1d309c046c8 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig_leds.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig_leds.c @@ -85,7 +85,11 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) sw_trig = (void *) trigger; port_mask = 0; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) + spin_lock(&trigger->leddev_list_lock); +#else read_lock(&trigger->leddev_list_lock); +#endif list_for_each(entry, &trigger->led_cdevs) { struct led_classdev *led_cdev; struct swconfig_trig_data *trig_data; @@ -98,7 +102,11 @@ swconfig_trig_update_port_mask(struct led_trigger *trigger) read_unlock(&trig_data->lock); } } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) + spin_unlock(&trigger->leddev_list_lock); +#else read_unlock(&trigger->leddev_list_lock); +#endif sw_trig->port_mask = port_mask; @@ -418,14 +426,22 @@ swconfig_trig_update_leds(struct switch_led_trigger *sw_trig) struct led_trigger *trigger; trigger = &sw_trig->trig; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) + spin_lock(&trigger->leddev_list_lock); +#else read_lock(&trigger->leddev_list_lock); +#endif list_for_each(entry, &trigger->led_cdevs) { struct led_classdev *led_cdev; led_cdev = list_entry(entry, struct led_classdev, trig_list); swconfig_trig_led_event(sw_trig, led_cdev); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0) + spin_unlock(&trigger->leddev_list_lock); +#else read_unlock(&trigger->leddev_list_lock); +#endif } static void From 0605fa693e3ae5266c6d9b0a291ee12a3adac09b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 02:34:20 +0200 Subject: [PATCH 72/88] kernek: use struct_group to wipe ar8216 volatile priv data Instead of reference vlan and do strange subtraction, use the handy struct_group() to create a virtual struct of the same size of the members. This permits to have a more secure memset and fix compilation warning in 6.1 where additional checks are done. Signed-off-by: Christian Marangi --- .../generic/files/drivers/net/phy/ar8216.c | 7 +++-- .../generic/files/drivers/net/phy/ar8216.h | 26 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 876754597a9..850bcefb74e 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -1419,8 +1419,7 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev) int i; mutex_lock(&priv->reg_mutex); - memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) - - offsetof(struct ar8xxx_priv, vlan)); + memset(&priv->ar8xxx_priv_volatile, 0, sizeof(priv->ar8xxx_priv_volatile)); for (i = 0; i < dev->vlans; i++) priv->vlan_id[i] = i; @@ -2461,7 +2460,7 @@ ar8xxx_phy_config_init(struct phy_device *phydev) dev->phy_ptr = priv; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags |= IFF_NO_IP_ALIGN; -#else LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) +#else dev->extra_priv_flags |= IFF_NO_IP_ALIGN; #endif dev->eth_mangle_rx = ar8216_mangle_rx; @@ -2700,7 +2699,7 @@ ar8xxx_phy_detach(struct phy_device *phydev) dev->phy_ptr = NULL; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) dev->priv_flags &= ~IFF_NO_IP_ALIGN; -#else LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) +#else dev->extra_priv_flags &= ~IFF_NO_IP_ALIGN; #endif dev->eth_mangle_rx = NULL; diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h index d62cf60f57e..f046b35f43f 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -506,20 +506,22 @@ struct ar8xxx_priv { unsigned int use_count; /* all fields below are cleared on reset */ - bool vlan; + struct_group(ar8xxx_priv_volatile, + bool vlan; - u16 vlan_id[AR8XXX_MAX_VLANS]; - u8 vlan_table[AR8XXX_MAX_VLANS]; - u8 vlan_tagged; - u16 pvid[AR8X16_MAX_PORTS]; - int arl_age_time; + u16 vlan_id[AR8XXX_MAX_VLANS]; + u8 vlan_table[AR8XXX_MAX_VLANS]; + u8 vlan_tagged; + u16 pvid[AR8X16_MAX_PORTS]; + int arl_age_time; - /* mirroring */ - bool mirror_rx; - bool mirror_tx; - int source_port; - int monitor_port; - u8 port_vlan_prio[AR8X16_MAX_PORTS]; + /* mirroring */ + bool mirror_rx; + bool mirror_tx; + int source_port; + int monitor_port; + u8 port_vlan_prio[AR8X16_MAX_PORTS]; + ); }; u32 From 9273487930b8bb267b63113dbc0d12eb27328f02 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 15:08:40 +0200 Subject: [PATCH 73/88] kernel: use eth_random_addr instead of random_ether_addr random_ether_addr is just a reference to eth_random_addr, that was later dropped in more recent kernel version. Drop random_ether_addr and use eth_random_addr directly to fix compilation error in 6.1 Signed-off-by: Christian Marangi --- target/linux/generic/files/drivers/bcma/fallback-sprom.c | 2 +- target/linux/generic/files/drivers/ssb/fallback-sprom.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/linux/generic/files/drivers/bcma/fallback-sprom.c b/target/linux/generic/files/drivers/bcma/fallback-sprom.c index ce93560a482..db583fca9cc 100644 --- a/target/linux/generic/files/drivers/bcma/fallback-sprom.c +++ b/target/linux/generic/files/drivers/bcma/fallback-sprom.c @@ -494,7 +494,7 @@ static int bcma_fbs_probe(struct platform_device *pdev) if (is_valid_ether_addr(mac)) { dev_info(dev, "mtd mac %pM\n", mac); } else { - random_ether_addr(mac); + eth_random_addr(mac); dev_info(dev, "random mac %pM\n", mac); } diff --git a/target/linux/generic/files/drivers/ssb/fallback-sprom.c b/target/linux/generic/files/drivers/ssb/fallback-sprom.c index 26f0fd2f036..b8a4dcedcf4 100644 --- a/target/linux/generic/files/drivers/ssb/fallback-sprom.c +++ b/target/linux/generic/files/drivers/ssb/fallback-sprom.c @@ -705,7 +705,7 @@ static int ssb_fbs_probe(struct platform_device *pdev) if (is_valid_ether_addr(mac)) { dev_info(dev, "mtd mac %pM\n", mac); } else { - random_ether_addr(mac); + eth_random_addr(mac); dev_info(dev, "random mac %pM\n", mac); } From 7612f8d6eb6f682d7acffae8bcd58f01ed01f35f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 00:03:17 +0200 Subject: [PATCH 74/88] kernel: add CONFIG_INITRAMFS_PRESERVE_MTIME config to Initramfs function New kernel version 6.1 introduced new INITRAMFS option. Add them to the Initramfs functions to correctly compile initramfs images. Signed-off-by: Christian Marangi --- include/kernel-defaults.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/kernel-defaults.mk b/include/kernel-defaults.mk index 6a341c32255..6a0251a9e2c 100644 --- a/include/kernel-defaults.mk +++ b/include/kernel-defaults.mk @@ -75,6 +75,7 @@ endif rm -f $(LINUX_DIR)/.config.prev mv $(LINUX_DIR)/.config $(LINUX_DIR)/.config.old $(call Kernel/SetInitramfs/PreConfigure) + echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config ifneq ($(CONFIG_TARGET_ROOTFS_INITRAMFS_SEPARATE),y) echo 'CONFIG_INITRAMFS_ROOT_UID=$(shell id -u)' >> $(LINUX_DIR)/.config echo 'CONFIG_INITRAMFS_ROOT_GID=$(shell id -g)' >> $(LINUX_DIR)/.config @@ -99,6 +100,7 @@ define Kernel/SetNoInitramfs grep -v INITRAMFS $(LINUX_DIR)/.config.old > $(LINUX_DIR)/.config.set echo 'CONFIG_INITRAMFS_SOURCE=""' >> $(LINUX_DIR)/.config.set echo '# CONFIG_INITRAMFS_FORCE is not set' >> $(LINUX_DIR)/.config.set + echo "# CONFIG_INITRAMFS_PRESERVE_MTIME is not set" >> $(LINUX_DIR)/.config.set endef define Kernel/Configure/Default From 6bdc6bb173ec8eaf67614b5e7e3890a8496cf5d9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:45:09 +0200 Subject: [PATCH 75/88] generic: 6.1: refresh config and add missing symbols Refresh generic config for 6.1 and add missing symbols. Then sorted using: $ ./scripts/kconfig.pl '+' target/linux/generic/config-6.1 /dev/null > target/linux/generic/config-6.1-new $ mv target/linux/generic/config-6.1-new target/linux/generic/config-6.1 Signed-off-by: Christian Marangi --- target/linux/generic/config-6.1 | 232 +++++++++++++++++++++++++++++--- 1 file changed, 211 insertions(+), 21 deletions(-) diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index 83ce378c05c..d620c125b98 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -31,6 +31,7 @@ CONFIG_64BIT_TIME=y # CONFIG_AD2S1200 is not set # CONFIG_AD2S1210 is not set # CONFIG_AD2S90 is not set +# CONFIG_AD3552R is not set # CONFIG_AD5064 is not set # CONFIG_AD5110 is not set # CONFIG_AD525X_DPOT is not set @@ -64,8 +65,10 @@ CONFIG_64BIT_TIME=y # CONFIG_AD7280 is not set # CONFIG_AD7291 is not set # CONFIG_AD7292 is not set +# CONFIG_AD7293 is not set # CONFIG_AD7298 is not set # CONFIG_AD7303 is not set +# CONFIG_AD74413R is not set # CONFIG_AD7476 is not set # CONFIG_AD7606 is not set # CONFIG_AD7606_IFACE_PARALLEL is not set @@ -87,11 +90,14 @@ CONFIG_64BIT_TIME=y # CONFIG_AD9523 is not set # CONFIG_AD9832 is not set # CONFIG_AD9834 is not set +# CONFIG_ADA4250 is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_ADE7854 is not set # CONFIG_ADF4350 is not set # CONFIG_ADF4371 is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADIN1100_PHY is not set +# CONFIG_ADIN1110 is not set # CONFIG_ADIN_PHY is not set # CONFIG_ADIS16080 is not set # CONFIG_ADIS16130 is not set @@ -109,11 +115,20 @@ CONFIG_64BIT_TIME=y # CONFIG_ADJD_S311 is not set # CONFIG_ADM6996_PHY is not set # CONFIG_ADM8211 is not set +# CONFIG_ADMV1013 is not set +# CONFIG_ADMV4420 is not set +# CONFIG_ADRF6780 is not set # CONFIG_ADT7316 is not set # CONFIG_ADUX1020 is not set CONFIG_ADVISE_SYSCALLS=y +# CONFIG_ADXL313_I2C is not set +# CONFIG_ADXL313_SPI is not set # CONFIG_ADXL345_I2C is not set # CONFIG_ADXL345_SPI is not set +# CONFIG_ADXL355_I2C is not set +# CONFIG_ADXL355_SPI is not set +# CONFIG_ADXL367_I2C is not set +# CONFIG_ADXL367_SPI is not set # CONFIG_ADXL372_I2C is not set # CONFIG_ADXL372_SPI is not set # CONFIG_ADXRS290 is not set @@ -132,6 +147,7 @@ CONFIG_AF_UNIX_OOB=y # CONFIG_AGP is not set # CONFIG_AHCI_BRCM is not set # CONFIG_AHCI_CEVA is not set +# CONFIG_AHCI_DWC is not set # CONFIG_AHCI_IMX is not set # CONFIG_AHCI_MVEBU is not set # CONFIG_AHCI_QORIQ is not set @@ -163,8 +179,11 @@ CONFIG_ALLOW_DEV_COREDUMP=y # CONFIG_AMD_XGBE_HAVE_ECC is not set # CONFIG_AMIGA_PARTITION is not set # CONFIG_AMILO_RFKILL is not set +# CONFIG_AMT is not set # CONFIG_ANDROID is not set +# CONFIG_ANDROID_BINDER_IPC is not set CONFIG_ANON_INODES=y +# CONFIG_ANON_VMA_NAME is not set # CONFIG_APDS9300 is not set # CONFIG_APDS9802ALS is not set # CONFIG_APDS9960 is not set @@ -182,6 +201,7 @@ CONFIG_ANON_INODES=y # CONFIG_AR8216_PHY_LEDS is not set # CONFIG_ARCH_ACTIONS is not set # CONFIG_ARCH_AGILEX is not set +# CONFIG_ARCH_AIROHA is not set # CONFIG_ARCH_ALPINE is not set # CONFIG_ARCH_APPLE is not set # CONFIG_ARCH_ARTPEC is not set @@ -219,6 +239,7 @@ CONFIG_ARCH_FLATMEM_ENABLE=y # CONFIG_ARCH_HI3xxx is not set # CONFIG_ARCH_HIGHBANK is not set # CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_HPE is not set # CONFIG_ARCH_INTEGRATOR is not set # CONFIG_ARCH_INTEL_SOCFPGA is not set # CONFIG_ARCH_IOP13XX is not set @@ -287,6 +308,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_STI is not set # CONFIG_ARCH_STM32 is not set # CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SUNPLUS is not set # CONFIG_ARCH_SUNXI is not set # CONFIG_ARCH_SYNQUACER is not set # CONFIG_ARCH_TANGO is not set @@ -389,6 +411,7 @@ CONFIG_ARM_DMA_MEM_BUFFERABLE=y # CONFIG_ARM_ERRATA_751472 is not set # CONFIG_ARM_ERRATA_754322 is not set # CONFIG_ARM_ERRATA_754327 is not set +# CONFIG_ARM_ERRATA_764319 is not set # CONFIG_ARM_ERRATA_764369 is not set # CONFIG_ARM_ERRATA_773022 is not set # CONFIG_ARM_ERRATA_775420 is not set @@ -541,6 +564,7 @@ CONFIG_ATM_CLIP_NO_ICMP=y # CONFIG_BACKLIGHT_RPI is not set # CONFIG_BACKLIGHT_SAHARA is not set # CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_BACKTRACE_VERBOSE is not set # CONFIG_BAREUDP is not set CONFIG_BASE_FULL=y CONFIG_BASE_SMALL=0 @@ -559,7 +583,9 @@ CONFIG_BASE_SMALL=0 # CONFIG_BATTERY_MAX17042 is not set # CONFIG_BATTERY_MAX1721X is not set # CONFIG_BATTERY_RT5033 is not set +# CONFIG_BATTERY_SAMSUNG_SDI is not set # CONFIG_BATTERY_SBS is not set +# CONFIG_BATTERY_UG3105 is not set # CONFIG_BAYCOM_EPP is not set # CONFIG_BAYCOM_PAR is not set # CONFIG_BAYCOM_SER_FDX is not set @@ -681,6 +707,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 # CONFIG_BLK_DEV_THROTTLING is not set # CONFIG_BLK_DEV_TRIFLEX is not set # CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_UBLK is not set # CONFIG_BLK_DEV_UMC8672 is not set # CONFIG_BLK_DEV_UMEM is not set # CONFIG_BLK_DEV_VIA82CXXX is not set @@ -689,6 +716,7 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 # CONFIG_BLK_SED_OPAL is not set # CONFIG_BLK_WBT is not set CONFIG_BLOCK=y +# CONFIG_BLOCK_LEGACY_AUTOLOAD is not set # CONFIG_BMA180 is not set # CONFIG_BMA220 is not set # CONFIG_BMA400 is not set @@ -718,6 +746,7 @@ CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT=3 # CONFIG_BOOT_CONFIG is not set # CONFIG_BOOT_PRINTK_DELAY is not set CONFIG_BOOT_RAW=y +# CONFIG_BOSCH_BNO055_I2C is not set # CONFIG_BOUNCE is not set CONFIG_BPF=y # CONFIG_BPFILTER is not set @@ -827,8 +856,12 @@ CONFIG_CACHE_L2X0_PMU=y # CONFIG_CAIF is not set # CONFIG_CAN is not set # CONFIG_CAN_BCM is not set +# CONFIG_CAN_CAN327 is not set +# CONFIG_CAN_CTUCANFD_PCI is not set +# CONFIG_CAN_CTUCANFD_PLATFORM is not set # CONFIG_CAN_DEBUG_DEVICES is not set # CONFIG_CAN_DEV is not set +# CONFIG_CAN_ESD_USB is not set # CONFIG_CAN_ETAS_ES58X is not set # CONFIG_CAN_GS_USB is not set # CONFIG_CAN_GW is not set @@ -840,6 +873,7 @@ CONFIG_CACHE_L2X0_PMU=y # CONFIG_CAN_MCBA_USB is not set # CONFIG_CAN_MCP251XFD is not set # CONFIG_CAN_M_CAN is not set +# CONFIG_CAN_NETLINK is not set # CONFIG_CAN_PEAK_PCIEFD is not set # CONFIG_CAN_RAW is not set # CONFIG_CAN_RCAR is not set @@ -879,6 +913,7 @@ CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y CONFIG_CFG80211_HEADERS=y # CONFIG_CFG80211_CERTIFICATION_ONUS is not set # CONFIG_CGROUPS is not set +# CONFIG_CGROUP_FAVOR_DYNMODS is not set # CONFIG_CGROUP_MISC is not set # CONFIG_CHARGER_ADP5061 is not set # CONFIG_CHARGER_BD99954 is not set @@ -898,6 +933,7 @@ CONFIG_CFG80211_HEADERS=y # CONFIG_CHARGER_LTC3651 is not set # CONFIG_CHARGER_LTC4162L is not set # CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_MAX77976 is not set # CONFIG_CHARGER_MAX8903 is not set # CONFIG_CHARGER_QCOM_SMBB is not set # CONFIG_CHARGER_RT9455 is not set @@ -938,6 +974,7 @@ CONFIG_CIFS_XATTR=y # CONFIG_CLKSRC_VERSATILE is not set # CONFIG_CLK_GFM_LPASS_SM8250 is not set # CONFIG_CLK_HSDK is not set +# CONFIG_CLK_ICST is not set # CONFIG_CLK_QORIQ is not set # CONFIG_CLK_SP810 is not set # CONFIG_CLOCK_THERMAL is not set @@ -981,12 +1018,14 @@ CONFIG_CMDLINE="" # CONFIG_COMMON_CLK_PWM is not set # CONFIG_COMMON_CLK_PXA is not set # CONFIG_COMMON_CLK_QCOM is not set +# CONFIG_COMMON_CLK_RS9_PCIE is not set # CONFIG_COMMON_CLK_SI514 is not set # CONFIG_COMMON_CLK_SI5341 is not set # CONFIG_COMMON_CLK_SI5351 is not set # CONFIG_COMMON_CLK_SI544 is not set # CONFIG_COMMON_CLK_SI570 is not set # CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_VC7 is not set # CONFIG_COMMON_CLK_XGENE is not set # CONFIG_COMMON_CLK_XLNX_CLKWZRD is not set CONFIG_COMPACTION=y @@ -1029,7 +1068,6 @@ CONFIG_CONSTRUCTORS=y # CONFIG_CPU_IDLE_GOV_TEO is not set # CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set # CONFIG_CPU_ISOLATION is not set -# CONFIG_CPU_LITTLE_ENDIAN is not set # CONFIG_CPU_NO_EFFICIENT_FFS is not set CONFIG_CPU_SW_DOMAIN_PAN=y # CONFIG_CPU_THERMAL is not set @@ -1046,6 +1084,7 @@ CONFIG_CRC32_SARWATE=y # CONFIG_CRC32_SLICEBY8 is not set # CONFIG_CRC4 is not set # CONFIG_CRC64 is not set +# CONFIG_CRC64_ROCKSOFT is not set # CONFIG_CRC7 is not set # CONFIG_CRC8 is not set # CONFIG_CRC_CCITT is not set @@ -1085,6 +1124,7 @@ CONFIG_CRYPTO_ALGAPI2=y # CONFIG_CRYPTO_ANSI_CPRNG is not set # CONFIG_CRYPTO_ANUBIS is not set # CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_ARIA is not set # CONFIG_CRYPTO_AUTHENC is not set # CONFIG_CRYPTO_BLAKE2B is not set # CONFIG_CRYPTO_BLAKE2B_NEON is not set @@ -1177,6 +1217,7 @@ CONFIG_CRYPTO_GHASH=y # CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y +# CONFIG_CRYPTO_HCTR2 is not set # CONFIG_CRYPTO_HMAC is not set # CONFIG_CRYPTO_HW is not set # CONFIG_CRYPTO_JITTERENTROPY is not set @@ -1249,8 +1290,10 @@ CONFIG_CRYPTO_SKCIPHER2=y # CONFIG_CRYPTO_SM2 is not set # CONFIG_CRYPTO_SM3 is not set # CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM3_GENERIC is not set # CONFIG_CRYPTO_SM4 is not set # CONFIG_CRYPTO_SM4_ARM64_CE is not set +# CONFIG_CRYPTO_SM4_GENERIC is not set # CONFIG_CRYPTO_SPECK is not set # CONFIG_CRYPTO_STATS is not set # CONFIG_CRYPTO_STREEBOG is not set @@ -1318,6 +1361,7 @@ CONFIG_DEBUG_FS_ALLOW_ALL=y # CONFIG_DEBUG_INFO_DWARF4 is not set # CONFIG_DEBUG_INFO_DWARF5 is not set CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +# CONFIG_DEBUG_INFO_NONE is not set # CONFIG_DEBUG_INFO_REDUCED is not set # CONFIG_DEBUG_INFO_SPLIT is not set # CONFIG_DEBUG_IRQFLAGS is not set @@ -1333,9 +1377,11 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_LOCKDEP is not set # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set # CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_MAPLE_TREE is not set # CONFIG_DEBUG_MEMORY_INIT is not set # CONFIG_DEBUG_MISC is not set # CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_NET is not set # CONFIG_DEBUG_NOTIFIERS is not set # CONFIG_DEBUG_NX_TEST is not set # CONFIG_DEBUG_OBJECTS is not set @@ -1429,6 +1475,7 @@ CONFIG_DEVPORT=y # CONFIG_DLHL60D is not set # CONFIG_DLM is not set # CONFIG_DM9000 is not set +# CONFIG_DM9051 is not set # CONFIG_DMABUF_DEBUG is not set # CONFIG_DMABUF_HEAPS is not set # CONFIG_DMABUF_MOVE_NOTIFY is not set @@ -1485,6 +1532,7 @@ CONFIG_DOUBLEFAULT=y # CONFIG_DP83867_PHY is not set # CONFIG_DP83869_PHY is not set # CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83TD510_PHY is not set # CONFIG_DPOT_DAC is not set # CONFIG_DPS310 is not set CONFIG_DQL=y @@ -1516,6 +1564,7 @@ CONFIG_DQL=y # CONFIG_DRM_CIRRUS_QEMU is not set # CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set # CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_MODESET_LOCK is not set # CONFIG_DRM_DEBUG_SELFTEST is not set # CONFIG_DRM_DISPLAY_CONNECTOR is not set # CONFIG_DRM_DP_AUX_CHARDEV is not set @@ -1635,7 +1684,6 @@ CONFIG_DQL=y # CONFIG_DRM_RADEON_USERPTR is not set # CONFIG_DRM_RCAR_DW_HDMI is not set # CONFIG_DRM_RCAR_LVDS is not set -# CONFIG_DRM_ROCKCHIP is not set # CONFIG_DRM_SII902X is not set # CONFIG_DRM_SII9234 is not set # CONFIG_DRM_SIL_SII8620 is not set @@ -1919,6 +1967,7 @@ CONFIG_F2FS_FS_XATTR=y # CONFIG_F2FS_IOSTAT is not set # CONFIG_F2FS_IO_TRACE is not set CONFIG_F2FS_STAT_FS=y +# CONFIG_F2FS_UNFAIR_RWSEM is not set # CONFIG_FAILOVER is not set # CONFIG_FAIR_GROUP_SCHED is not set # CONFIG_FANOTIFY is not set @@ -2072,6 +2121,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_FONT_TER16x32 is not set # CONFIG_FORCEDETH is not set CONFIG_FORCE_MAX_ZONEORDER=11 +# CONFIG_FORCE_NR_CPUS is not set CONFIG_FORTIFY_SOURCE=y # CONFIG_FPGA is not set # CONFIG_FRAMEBUFFER_CONSOLE is not set @@ -2113,6 +2163,7 @@ CONFIG_FSNOTIFY=y # CONFIG_FUJITSU_TABLET is not set # CONFIG_FUNCTION_ERROR_INJECTION is not set # CONFIG_FUNCTION_TRACER is not set +# CONFIG_FUN_ETH is not set # CONFIG_FUSE_FS is not set # CONFIG_FUSION is not set # CONFIG_FUSION_FC is not set @@ -2125,6 +2176,7 @@ CONFIG_FW_LOADER=y # CONFIG_FW_LOADER_COMPRESS is not set CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_UPLOAD is not set # CONFIG_FXAS21002C is not set # CONFIG_FXLS8962AF_I2C is not set # CONFIG_FXLS8962AF_SPI is not set @@ -2227,6 +2279,7 @@ CONFIG_GPIOLIB_FASTPATH_LIMIT=512 # CONFIG_GPIO_SCH is not set # CONFIG_GPIO_SCH311X is not set # CONFIG_GPIO_SIFIVE is not set +# CONFIG_GPIO_SIM is not set # CONFIG_GPIO_SX150X is not set # CONFIG_GPIO_SYSCON is not set CONFIG_GPIO_SYSFS=y @@ -2243,6 +2296,7 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_XRA1403 is not set # CONFIG_GPIO_ZEVIO is not set # CONFIG_GPIO_ZX is not set +# CONFIG_GP_PCI1XXXX is not set # CONFIG_GREENASIA_FF is not set # CONFIG_GREYBUS is not set # CONFIG_GS_FPGABOOT is not set @@ -2331,6 +2385,7 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_LCPOWER is not set # CONFIG_HID_LED is not set # CONFIG_HID_LENOVO is not set +# CONFIG_HID_LETSKETCH is not set # CONFIG_HID_LOGITECH is not set # CONFIG_HID_LOGITECH_DJ is not set # CONFIG_HID_LOGITECH_HIDPP is not set @@ -2339,9 +2394,11 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_MALTRON is not set # CONFIG_HID_MAYFLASH is not set # CONFIG_HID_MCP2221 is not set +# CONFIG_HID_MEGAWORLD_FF is not set # CONFIG_HID_MICROSOFT is not set # CONFIG_HID_MONTEREY is not set # CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NINTENDO is not set # CONFIG_HID_NTI is not set # CONFIG_HID_NTRIG is not set # CONFIG_HID_ORTEK is not set @@ -2354,6 +2411,8 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_PLAYSTATION is not set # CONFIG_HID_PRIMAX is not set # CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_PXRC is not set +# CONFIG_HID_RAZER is not set # CONFIG_HID_REDRAGON is not set # CONFIG_HID_RETRODE is not set # CONFIG_HID_RMI is not set @@ -2362,6 +2421,7 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_SAMSUNG is not set # CONFIG_HID_SEMITEK is not set # CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_SIGMAMICRO is not set # CONFIG_HID_SMARTJOYPLUS is not set # CONFIG_HID_SONY is not set # CONFIG_HID_SPEEDLINK is not set @@ -2371,6 +2431,7 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_THINGM is not set # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_TIVO is not set +# CONFIG_HID_TOPRE is not set # CONFIG_HID_TOPSEED is not set # CONFIG_HID_TWINHAN is not set # CONFIG_HID_U2FZERO is not set @@ -2378,9 +2439,11 @@ CONFIG_HARDEN_EL2_VECTORS=y # CONFIG_HID_UDRAW_PS3 is not set # CONFIG_HID_VIEWSONIC is not set # CONFIG_HID_VIVALDI is not set +# CONFIG_HID_VRC2 is not set # CONFIG_HID_WACOM is not set # CONFIG_HID_WALTOP is not set # CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XIAOMI is not set # CONFIG_HID_XINMO is not set # CONFIG_HID_ZEROPLUS is not set # CONFIG_HID_ZYDACRON is not set @@ -2408,11 +2471,6 @@ CONFIG_HIGH_RES_TIMERS=y # CONFIG_HOSTAP_PLX is not set # CONFIG_HOTPLUG_CPU is not set # CONFIG_HOTPLUG_PCI is not set -# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set -# CONFIG_HOTPLUG_PCI_COMPAQ is not set -# CONFIG_HOTPLUG_PCI_CPCI is not set -# CONFIG_HOTPLUG_PCI_IBM is not set -# CONFIG_HOTPLUG_PCI_SHPC is not set # CONFIG_HP03 is not set # CONFIG_HP100 is not set # CONFIG_HP206C is not set @@ -2426,6 +2484,7 @@ CONFIG_HPET_MMAP_DEFAULT=y # CONFIG_HTC_EGPIO is not set # CONFIG_HTC_I2CPLD is not set # CONFIG_HTC_PASIC3 is not set +# CONFIG_HTE is not set # CONFIG_HTS221 is not set # CONFIG_HTU21 is not set # CONFIG_HUGETLBFS is not set @@ -2512,6 +2571,7 @@ CONFIG_HZ_100=y # CONFIG_I2C_HELPER_AUTO is not set # CONFIG_I2C_HID is not set # CONFIG_I2C_HID_OF is not set +# CONFIG_I2C_HID_OF_ELAN is not set # CONFIG_I2C_HID_OF_GOODIX is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_IBM_IIC is not set @@ -2541,6 +2601,7 @@ CONFIG_HZ_100=y # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PCA_ISA is not set # CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PCI1XXXX is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PXA_PCI is not set # CONFIG_I2C_PXA_SLAVE is not set @@ -2634,6 +2695,7 @@ CONFIG_IIO_CONSUMERS_PER_TRIGGER=2 # CONFIG_IKCONFIG_PROC is not set # CONFIG_IKHEADERS is not set # CONFIG_IMA is not set +# CONFIG_IMAGE_CMDLINE_HACK is not set # CONFIG_IMGPDC_WDT is not set # CONFIG_IMG_MDC_DMA is not set # CONFIG_IMX7D_ADC is not set @@ -2674,6 +2736,7 @@ CONFIG_INET_TABLE_PERTURB_ORDER=16 # CONFIG_INGENIC_TCU_CLK is not set # CONFIG_INGENIC_TCU_IRQ is not set # CONFIG_INGENIC_TIMER is not set +# CONFIG_INITRAMFS_PRESERVE_MTIME is not set CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set @@ -2710,6 +2773,7 @@ CONFIG_INOTIFY_USER=y # CONFIG_INPUT_IMS_PCU is not set # CONFIG_INPUT_IQS269A is not set # CONFIG_INPUT_IQS626A is not set +# CONFIG_INPUT_IQS7222 is not set # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_KEYBOARD is not set @@ -2755,8 +2819,6 @@ CONFIG_INPUT_MISC=y # CONFIG_INTEL_HID_EVENT is not set # CONFIG_INTEL_IDLE is not set # CONFIG_INTEL_IDMA64 is not set -# CONFIG_INTEL_IDXD is not set -# CONFIG_INTEL_IDXD_COMPAT is not set # CONFIG_INTEL_INT0002_VGPIO is not set # CONFIG_INTEL_IOATDMA is not set # CONFIG_INTEL_ISH_HID is not set @@ -2784,9 +2846,6 @@ CONFIG_INPUT_MISC=y # CONFIG_INV_MPU6050_I2C is not set # CONFIG_INV_MPU6050_IIO is not set # CONFIG_INV_MPU6050_SPI is not set -# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set -# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set -# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set # CONFIG_IOMMU_SUPPORT is not set # CONFIG_IONIC is not set # CONFIG_IOSCHED_BFQ is not set @@ -2795,6 +2854,7 @@ CONFIG_IO_STRICT_DEVMEM=y # CONFIG_IO_URING is not set CONFIG_IO_WQ=y # CONFIG_IP17XX_PHY is not set +# CONFIG_IP5XXX_POWER is not set # CONFIG_IP6_NF_FILTER is not set # CONFIG_IP6_NF_IPTABLES is not set # CONFIG_IP6_NF_MANGLE is not set @@ -3010,6 +3070,7 @@ CONFIG_KERNFS=y # CONFIG_KEYBOARD_ATKBD is not set # CONFIG_KEYBOARD_BCM is not set # CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_CYPRESS_SF is not set # CONFIG_KEYBOARD_DLINK_DIR685 is not set # CONFIG_KEYBOARD_GPIO is not set # CONFIG_KEYBOARD_GPIO_POLLED is not set @@ -3023,6 +3084,7 @@ CONFIG_KERNFS=y # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_OMAP4 is not set # CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_PINEPHONE is not set # CONFIG_KEYBOARD_PXA27x is not set # CONFIG_KEYBOARD_QT1050 is not set # CONFIG_KEYBOARD_QT1070 is not set @@ -3072,6 +3134,7 @@ CONFIG_KUSER_HELPERS=y # CONFIG_L2TP_IP is not set # CONFIG_L2TP_V3 is not set # CONFIG_LAN743X is not set +# CONFIG_LAN966X_SWITCH is not set # CONFIG_LANMEDIA is not set # CONFIG_LANTIQ is not set # CONFIG_LAPB is not set @@ -3235,11 +3298,13 @@ CONFIG_LSM_MMAP_MIN_ADDR=65536 # CONFIG_LTC2496 is not set # CONFIG_LTC2497 is not set # CONFIG_LTC2632 is not set +# CONFIG_LTC2688 is not set # CONFIG_LTC2983 is not set # CONFIG_LTE_GDM724X is not set CONFIG_LTO_NONE=y # CONFIG_LTPC is not set # CONFIG_LTR501 is not set +# CONFIG_LTRF216A is not set # CONFIG_LUSTRE_FS is not set # CONFIG_LV0104CS is not set # CONFIG_LWTUNNEL is not set @@ -3294,11 +3359,13 @@ CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" # CONFIG_MAX1027 is not set # CONFIG_MAX11100 is not set # CONFIG_MAX1118 is not set +# CONFIG_MAX11205 is not set # CONFIG_MAX1241 is not set # CONFIG_MAX1363 is not set # CONFIG_MAX30100 is not set # CONFIG_MAX30102 is not set # CONFIG_MAX31856 is not set +# CONFIG_MAX31865 is not set # CONFIG_MAX44000 is not set # CONFIG_MAX44009 is not set # CONFIG_MAX517 is not set @@ -3353,6 +3420,7 @@ CONFIG_MAY_USE_DEVLINK=y # CONFIG_MEDIA_CONTROLLER_DVB is not set # CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set # CONFIG_MEDIA_PCI_SUPPORT is not set +# CONFIG_MEDIA_PLATFORM_DRIVERS is not set # CONFIG_MEDIA_PLATFORM_SUPPORT is not set # CONFIG_MEDIA_RADIO_SUPPORT is not set # CONFIG_MEDIA_RC_SUPPORT is not set @@ -3460,6 +3528,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_MAX77650 is not set # CONFIG_MFD_MAX77686 is not set # CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77714 is not set # CONFIG_MFD_MAX77843 is not set # CONFIG_MFD_MAX8907 is not set # CONFIG_MFD_MAX8925 is not set @@ -3471,8 +3540,10 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_MENF21BMC is not set # CONFIG_MFD_MP2629 is not set # CONFIG_MFD_MT6360 is not set +# CONFIG_MFD_MT6370 is not set # CONFIG_MFD_MT6397 is not set # CONFIG_MFD_NTXEC is not set +# CONFIG_MFD_OCELOT is not set # CONFIG_MFD_OMAP_USB_HOST is not set # CONFIG_MFD_PALMAS is not set # CONFIG_MFD_PCF50633 is not set @@ -3492,6 +3563,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_RSMU_SPI is not set # CONFIG_MFD_RT4831 is not set # CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RT5120 is not set # CONFIG_MFD_RTSX_PCI is not set # CONFIG_MFD_RTSX_USB is not set # CONFIG_MFD_SEC_CORE is not set @@ -3503,6 +3575,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MFD_STMFX is not set # CONFIG_MFD_STMPE is not set # CONFIG_MFD_STPMIC1 is not set +# CONFIG_MFD_SY7636A is not set # CONFIG_MFD_SYSCON is not set # CONFIG_MFD_T7L66XB is not set # CONFIG_MFD_TC3589X is not set @@ -3538,6 +3611,7 @@ CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 # CONFIG_MG_DISK is not set # CONFIG_MHI_BUS is not set # CONFIG_MHI_BUS_DEBUG is not set +# CONFIG_MHI_BUS_EP is not set # CONFIG_MHI_BUS_PCI_GENERIC is not set # CONFIG_MHI_NET is not set # CONFIG_MHI_WWAN_CTRL is not set @@ -3595,6 +3669,7 @@ CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y # CONFIG_MLX4_CORE is not set # CONFIG_MLX4_EN is not set # CONFIG_MLX5_CORE is not set +# CONFIG_MLX5_EN_MACSEC is not set # CONFIG_MLX5_SF is not set # CONFIG_MLX90614 is not set # CONFIG_MLX90632 is not set @@ -3613,6 +3688,7 @@ CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY=y # CONFIG_MMC_ARMMMCI is not set # CONFIG_MMC_AU1X is not set # CONFIG_MMC_BLOCK is not set +CONFIG_MMC_BLOCK_BOUNCE=y CONFIG_MMC_BLOCK_MINORS=8 # CONFIG_MMC_CAVIUM_THUNDERX is not set # CONFIG_MMC_CB710 is not set @@ -3673,6 +3749,7 @@ CONFIG_MODULE_COMPRESS_NONE=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_MODULE_STRIPPED=y CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set # CONFIG_MODVERSIONS is not set # CONFIG_MOST is not set # CONFIG_MOTORCOMM_PHY is not set @@ -3700,9 +3777,11 @@ CONFIG_MODULE_UNLOAD=y # CONFIG_MQ_IOSCHED_KYBER is not set # CONFIG_MS5611 is not set # CONFIG_MS5637 is not set +# CONFIG_MSA311 is not set # CONFIG_MSCC_OCELOT_SWITCH is not set # CONFIG_MSDOS_FS is not set CONFIG_MSDOS_PARTITION=y +# CONFIG_MSE102X is not set # CONFIG_MSI_BITMAP_SELFTEST is not set # CONFIG_MSI_LAPTOP is not set # CONFIG_MSM_GCC_8953 is not set @@ -3776,6 +3855,7 @@ CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xff108018 # CONFIG_MTD_NAND_DOCG4 is not set # CONFIG_MTD_NAND_ECC is not set # CONFIG_MTD_NAND_ECC_BCH is not set +# CONFIG_MTD_NAND_ECC_MXIC is not set # CONFIG_MTD_NAND_ECC_SMC is not set # CONFIG_MTD_NAND_ECC_SW_BCH is not set # CONFIG_MTD_NAND_ECC_SW_HAMMING is not set @@ -3919,6 +3999,7 @@ CONFIG_NETDEVICES=y # CONFIG_NETFILTER is not set # CONFIG_NETFILTER_ADVANCED is not set # CONFIG_NETFILTER_DEBUG is not set +# CONFIG_NETFILTER_EGRESS is not set # CONFIG_NETFILTER_INGRESS is not set # CONFIG_NETFILTER_NETLINK is not set # CONFIG_NETFILTER_NETLINK_ACCT is not set @@ -4045,6 +4126,7 @@ CONFIG_NET_CLS_IND=y # CONFIG_NET_CLS_U32 is not set CONFIG_NET_CORE=y # CONFIG_NET_DEVLINK is not set +# CONFIG_NET_DEV_REFCNT_TRACKER is not set # CONFIG_NET_DROP_MONITOR is not set # CONFIG_NET_DSA is not set # CONFIG_NET_DSA_AR9331 is not set @@ -4054,6 +4136,7 @@ CONFIG_NET_CORE=y # CONFIG_NET_DSA_LOOP is not set # CONFIG_NET_DSA_MICROCHIP_KSZ8795 is not set # CONFIG_NET_DSA_MICROCHIP_KSZ9477 is not set +# CONFIG_NET_DSA_MICROCHIP_KSZ_COMMON is not set # CONFIG_NET_DSA_MSCC_FELIX is not set # CONFIG_NET_DSA_MSCC_SEVILLE is not set # CONFIG_NET_DSA_MT7530 is not set @@ -4066,6 +4149,7 @@ CONFIG_NET_CORE=y # CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set # CONFIG_NET_DSA_MV88E6XXX_PTP is not set # CONFIG_NET_DSA_QCA8K is not set +# CONFIG_NET_DSA_REALTEK is not set # CONFIG_NET_DSA_REALTEK_SMI is not set # CONFIG_NET_DSA_SJA1105 is not set # CONFIG_NET_DSA_SMSC_LAN9303_I2C is not set @@ -4086,6 +4170,8 @@ CONFIG_NET_CORE=y # CONFIG_NET_DSA_TAG_OCELOT_8021Q is not set # CONFIG_NET_DSA_TAG_QCA is not set # CONFIG_NET_DSA_TAG_RTL4_A is not set +# CONFIG_NET_DSA_TAG_RTL8_4 is not set +# CONFIG_NET_DSA_TAG_RZN1_A5PSW is not set # CONFIG_NET_DSA_TAG_SJA1105 is not set # CONFIG_NET_DSA_TAG_TRAILER is not set # CONFIG_NET_DSA_TAG_XRS700X is not set @@ -4121,6 +4207,7 @@ CONFIG_NET_IPGRE_BROADCAST=y # CONFIG_NET_MPLS_GSO is not set # CONFIG_NET_NCSI is not set # CONFIG_NET_NSH is not set +# CONFIG_NET_NS_REFCNT_TRACKER is not set # CONFIG_NET_PACKET_ENGINE is not set # CONFIG_NET_PKTGEN is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -4174,6 +4261,7 @@ CONFIG_NET_SOCK_MSG=y CONFIG_NET_VENDOR_3COM=y CONFIG_NET_VENDOR_8390=y CONFIG_NET_VENDOR_ADAPTEC=y +CONFIG_NET_VENDOR_ADI=y CONFIG_NET_VENDOR_AGERE=y CONFIG_NET_VENDOR_ALACRITECH=y CONFIG_NET_VENDOR_ALTEON=y @@ -4181,6 +4269,7 @@ CONFIG_NET_VENDOR_AMAZON=y CONFIG_NET_VENDOR_AMD=y CONFIG_NET_VENDOR_AQUANTIA=y CONFIG_NET_VENDOR_ARC=y +# CONFIG_NET_VENDOR_ASIX is not set CONFIG_NET_VENDOR_ATHEROS=y CONFIG_NET_VENDOR_AURORA=y CONFIG_NET_VENDOR_BROADCOM=y @@ -4191,14 +4280,17 @@ CONFIG_NET_VENDOR_CHELSIO=y CONFIG_NET_VENDOR_CIRRUS=y CONFIG_NET_VENDOR_CISCO=y CONFIG_NET_VENDOR_CORTINA=y +# CONFIG_NET_VENDOR_DAVICOM is not set CONFIG_NET_VENDOR_DEC=y CONFIG_NET_VENDOR_DLINK=y CONFIG_NET_VENDOR_EMULEX=y +# CONFIG_NET_VENDOR_ENGLEDER is not set CONFIG_NET_VENDOR_EXAR=y CONFIG_NET_VENDOR_EZCHIP=y CONFIG_NET_VENDOR_FARADAY=y CONFIG_NET_VENDOR_FREESCALE=y CONFIG_NET_VENDOR_FUJITSU=y +# CONFIG_NET_VENDOR_FUNGIBLE is not set CONFIG_NET_VENDOR_GOOGLE=y CONFIG_NET_VENDOR_HISILICON=y CONFIG_NET_VENDOR_HP=y @@ -4241,7 +4333,9 @@ CONFIG_NET_VENDOR_SYNOPSYS=y CONFIG_NET_VENDOR_TEHUTI=y CONFIG_NET_VENDOR_TI=y CONFIG_NET_VENDOR_TOSHIBA=y +# CONFIG_NET_VENDOR_VERTEXCOM is not set CONFIG_NET_VENDOR_VIA=y +# CONFIG_NET_VENDOR_WANGXUN is not set CONFIG_NET_VENDOR_WIZNET=y CONFIG_NET_VENDOR_XILINX=y CONFIG_NET_VENDOR_XIRCOM=y @@ -4318,6 +4412,7 @@ CONFIG_NF_CONNTRACK_PROCFS=y # CONFIG_NF_DUP_IPV4 is not set # CONFIG_NF_DUP_IPV6 is not set # CONFIG_NF_FLOW_TABLE is not set +# CONFIG_NF_FLOW_TABLE_PROCFS is not set # CONFIG_NF_LOG_ARP is not set # CONFIG_NF_LOG_BRIDGE is not set # CONFIG_NF_LOG_IPV4 is not set @@ -4348,6 +4443,7 @@ CONFIG_NF_TABLES_NETDEV=y # CONFIG_NF_TABLES_SET is not set # CONFIG_NF_TPROXY_IPV4 is not set # CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NGBE is not set # CONFIG_NI65 is not set # CONFIG_NI903X_WDT is not set # CONFIG_NIC7018_WDT is not set @@ -4443,9 +4539,11 @@ CONFIG_NMI_LOG_BUF_SHIFT=13 # CONFIG_NVMEM_RMEM is not set # CONFIG_NVMEM_SYSFS is not set # CONFIG_NVMEM_U_BOOT_ENV is not set +# CONFIG_NVME_AUTH is not set # CONFIG_NVME_FC is not set # CONFIG_NVME_TARGET is not set # CONFIG_NVME_TCP is not set +# CONFIG_NVME_VERBOSE_ERRORS is not set # CONFIG_NVRAM is not set # CONFIG_NV_TCO is not set # CONFIG_NXP_C45_TJA11XX_PHY is not set @@ -4469,6 +4567,7 @@ CONFIG_OF_RESERVED_MEM=y # CONFIG_OMAP_USB2 is not set # CONFIG_OMFS_FS is not set # CONFIG_OPENVSWITCH is not set +# CONFIG_OPEN_DICE is not set # CONFIG_OPROFILE is not set # CONFIG_OPROFILE_EVENT_MULTIPLEX is not set # CONFIG_OPT3001 is not set @@ -4659,6 +4758,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PD6729 is not set # CONFIG_PDA_POWER is not set # CONFIG_PDC_ADMA is not set +# CONFIG_PECI is not set # CONFIG_PERCPU_STATS is not set # CONFIG_PERCPU_TEST is not set # CONFIG_PERF_EVENTS is not set @@ -4670,6 +4770,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PHYS_ADDR_T_64BIT is not set # CONFIG_PHY_CADENCE_DP is not set # CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_DPHY_RX is not set # CONFIG_PHY_CADENCE_SALVO is not set # CONFIG_PHY_CADENCE_SIERRA is not set # CONFIG_PHY_CADENCE_TORRENT is not set @@ -4680,6 +4781,7 @@ CONFIG_PCI_SYSCALL=y # CONFIG_PHY_FSL_IMX8MQ_USB is not set # CONFIG_PHY_INGENIC_USB is not set # CONFIG_PHY_INTEL_KEEMBAY_EMMC is not set +# CONFIG_PHY_LAN966X_SERDES is not set # CONFIG_PHY_MAPPHONE_MDM6600 is not set # CONFIG_PHY_MIXEL_MIPI_DPHY is not set # CONFIG_PHY_MTK_HDMI is not set @@ -4703,6 +4805,7 @@ CONFIG_PINCONF=y # CONFIG_PINCTRL_AMD is not set # CONFIG_PINCTRL_AXP209 is not set # CONFIG_PINCTRL_CEDARFORK is not set +# CONFIG_PINCTRL_CY8C95X0 is not set # CONFIG_PINCTRL_EXYNOS is not set # CONFIG_PINCTRL_EXYNOS5440 is not set # CONFIG_PINCTRL_ICELAKE is not set @@ -4838,6 +4941,7 @@ CONFIG_PROC_SYSCTL=y # CONFIG_PROVE_RCU_REPEATEDLY is not set # CONFIG_PSAMPLE is not set # CONFIG_PSB6970_PHY is not set +# CONFIG_PSE_CONTROLLER is not set # CONFIG_PSI is not set # CONFIG_PSTORE is not set # CONFIG_PSTORE_842_COMPRESS is not set @@ -4896,6 +5000,7 @@ CONFIG_PWRSEQ_SIMPLE=y # CONFIG_QCOM_SPMI_IADC is not set # CONFIG_QCOM_SPMI_TEMP_ALARM is not set # CONFIG_QCOM_SPMI_VADC is not set +# CONFIG_QCOM_SSC_BLOCK_BUS is not set # CONFIG_QED is not set # CONFIG_QFMT_V1 is not set # CONFIG_QLA3XXX is not set @@ -4942,6 +5047,7 @@ CONFIG_PWRSEQ_SIMPLE=y # CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set CONFIG_RANDOM_TRUST_BOOTLOADER=y CONFIG_RANDOM_TRUST_CPU=y +# CONFIG_RANDSTRUCT_NONE is not set # CONFIG_RAPIDIO is not set # CONFIG_RAS is not set # CONFIG_RBTREE_TEST is not set @@ -4950,6 +5056,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=60 # CONFIG_RCU_EQS_DEBUG is not set # CONFIG_RCU_EXPEDITE_BOOT is not set # CONFIG_RCU_EXPERT is not set +CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0 CONFIG_RCU_KTHREAD_PRIO=0 CONFIG_RCU_NEED_SEGCBLIST=y # CONFIG_RCU_PERF_TEST is not set @@ -5008,6 +5115,7 @@ CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 # CONFIG_REGULATOR_LTC3589 is not set # CONFIG_REGULATOR_LTC3676 is not set # CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX20086 is not set # CONFIG_REGULATOR_MAX77620 is not set # CONFIG_REGULATOR_MAX77826 is not set # CONFIG_REGULATOR_MAX8649 is not set @@ -5032,6 +5140,8 @@ CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 # CONFIG_REGULATOR_PWM is not set # CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set # CONFIG_REGULATOR_RT4801 is not set +# CONFIG_REGULATOR_RT5190A is not set +# CONFIG_REGULATOR_RT5759 is not set # CONFIG_REGULATOR_RT6160 is not set # CONFIG_REGULATOR_RT6245 is not set # CONFIG_REGULATOR_RTMV20 is not set @@ -5044,6 +5154,7 @@ CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY=3 # CONFIG_REGULATOR_TI_ABB is not set # CONFIG_REGULATOR_TPS51632 is not set # CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS6286X is not set # CONFIG_REGULATOR_TPS65023 is not set # CONFIG_REGULATOR_TPS6507X is not set # CONFIG_REGULATOR_TPS65132 is not set @@ -5071,11 +5182,13 @@ CONFIG_REISERFS_FS_XATTR=y # CONFIG_RESET_LPC18XX is not set # CONFIG_RESET_MESON is not set # CONFIG_RESET_PISTACHIO is not set +# CONFIG_RESET_SIMPLE is not set # CONFIG_RESET_SOCFPGA is not set # CONFIG_RESET_STM32 is not set # CONFIG_RESET_SUNXI is not set # CONFIG_RESET_TEGRA_BPMP is not set # CONFIG_RESET_TI_SYSCON is not set +# CONFIG_RESET_TI_TPS380X is not set # CONFIG_RESET_ZYNQ is not set # CONFIG_RFD77402 is not set # CONFIG_RFD_FTL is not set @@ -5085,6 +5198,7 @@ CONFIG_RFKILL=y # CONFIG_RFKILL_INPUT is not set # CONFIG_RFKILL_LEDS is not set # CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RICHTEK_RTQ6056 is not set # CONFIG_RING_BUFFER_BENCHMARK is not set # CONFIG_RING_BUFFER_STARTUP_TEST is not set # CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set @@ -5158,6 +5272,7 @@ CONFIG_RTC_DRV_CMOS=y # CONFIG_RTC_DRV_MPC5121 is not set # CONFIG_RTC_DRV_MSM6242 is not set # CONFIG_RTC_DRV_MT2712 is not set +# CONFIG_RTC_DRV_NCT3018Y is not set # CONFIG_RTC_DRV_OMAP is not set # CONFIG_RTC_DRV_PCF2123 is not set # CONFIG_RTC_DRV_PCF2127 is not set @@ -5259,6 +5374,7 @@ CONFIG_SBITMAP=y # CONFIG_SCACHE_DEBUGFS is not set # CONFIG_SCC is not set # CONFIG_SCD30_CORE is not set +# CONFIG_SCD4X is not set # CONFIG_SCF_TORTURE_TEST is not set # CONFIG_SCHEDSTATS is not set # CONFIG_SCHED_AUTOGROUP is not set @@ -5364,6 +5480,7 @@ CONFIG_SCSI_PROC_FS=y # CONFIG_SC_GCC_7280 is not set # CONFIG_SC_GCC_8180X is not set # CONFIG_SC_GPUCC_7280 is not set +# CONFIG_SC_GPUCC_8280XP is not set # CONFIG_SC_VIDEOCC_7280 is not set # CONFIG_SCx200_ACB is not set # CONFIG_SDIO_UART is not set @@ -5395,6 +5512,7 @@ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=0 # CONFIG_SECURITY_TOMOYO is not set # CONFIG_SECURITY_YAMA is not set CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_SENSEAIR_SUNRISE_CO2 is not set # CONFIG_SENSIRION_SGP30 is not set # CONFIG_SENSIRION_SGP40 is not set # CONFIG_SENSORS_ABITUGURU is not set @@ -5443,6 +5561,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_CORSAIR_CPRO is not set # CONFIG_SENSORS_CORSAIR_PSU is not set # CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_DELTA_AHE50DC_FAN is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_DPS920AB is not set # CONFIG_SENSORS_DRIVETEMP is not set @@ -5476,6 +5595,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_IBM_CFFPS is not set # CONFIG_SENSORS_IIO_HWMON is not set # CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA238 is not set # CONFIG_SENSORS_INA2XX is not set # CONFIG_SENSORS_INA3221 is not set # CONFIG_SENSORS_INSPUR_IPSPS is not set @@ -5511,6 +5631,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_LM95234 is not set # CONFIG_SENSORS_LM95241 is not set # CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_LT7182S is not set # CONFIG_SENSORS_LTC2945 is not set # CONFIG_SENSORS_LTC2947_I2C is not set # CONFIG_SENSORS_LTC2947_SPI is not set @@ -5538,9 +5659,11 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_MAX20751 is not set # CONFIG_SENSORS_MAX31722 is not set # CONFIG_SENSORS_MAX31730 is not set +# CONFIG_SENSORS_MAX31760 is not set # CONFIG_SENSORS_MAX31785 is not set # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MAX34440 is not set +# CONFIG_SENSORS_MAX6620 is not set # CONFIG_SENSORS_MAX6621 is not set # CONFIG_SENSORS_MAX6639 is not set # CONFIG_SENSORS_MAX6642 is not set @@ -5550,20 +5673,24 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_MCP3021 is not set # CONFIG_SENSORS_MP2888 is not set # CONFIG_SENSORS_MP2975 is not set +# CONFIG_SENSORS_MP5023 is not set # CONFIG_SENSORS_MR75203 is not set # CONFIG_SENSORS_NCT6683 is not set # CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT6775_I2C is not set # CONFIG_SENSORS_NCT7802 is not set # CONFIG_SENSORS_NCT7904 is not set # CONFIG_SENSORS_NPCM7XX is not set # CONFIG_SENSORS_NSA320 is not set # CONFIG_SENSORS_NTC_THERMISTOR is not set # CONFIG_SENSORS_NZXT_KRAKEN2 is not set +# CONFIG_SENSORS_NZXT_SMART2 is not set # CONFIG_SENSORS_OCC_P8_I2C is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_PIM4328 is not set +# CONFIG_SENSORS_PLI1209BC is not set # CONFIG_SENSORS_PM6764TR is not set # CONFIG_SENSORS_PMBUS is not set # CONFIG_SENSORS_POWR1220 is not set @@ -5597,10 +5724,12 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_TMP108 is not set # CONFIG_SENSORS_TMP401 is not set # CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TMP464 is not set # CONFIG_SENSORS_TMP513 is not set # CONFIG_SENSORS_TPS23861 is not set # CONFIG_SENSORS_TPS40422 is not set # CONFIG_SENSORS_TPS53679 is not set +# CONFIG_SENSORS_TPS546D24 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_SENSORS_TSL2563 is not set # CONFIG_SENSORS_UCD9000 is not set @@ -5621,6 +5750,7 @@ CONFIG_SELECT_MEMORY_MODEL=y # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83L786NG is not set # CONFIG_SENSORS_XDPE122 is not set +# CONFIG_SENSORS_XDPE152 is not set # CONFIG_SENSORS_XGENE is not set # CONFIG_SENSORS_ZL6100 is not set CONFIG_SERIAL_8250=y @@ -5648,6 +5778,7 @@ CONFIG_SERIAL_8250_DMA=y # CONFIG_SERIAL_8250_MOXA is not set CONFIG_SERIAL_8250_NR_UARTS=2 # CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_PERICOM is not set # CONFIG_SERIAL_8250_RSA is not set # CONFIG_SERIAL_8250_RT288X is not set CONFIG_SERIAL_8250_RUNTIME_UARTS=2 @@ -5702,6 +5833,7 @@ CONFIG_SERIAL_EARLYCON=y # CONFIG_SERIO_SUN4I_PS2 is not set # CONFIG_SFC is not set # CONFIG_SFC_FALCON is not set +# CONFIG_SFC_SIENA is not set # CONFIG_SFI is not set # CONFIG_SFP is not set # CONFIG_SF_PDMA is not set @@ -5717,6 +5849,7 @@ CONFIG_SERIAL_EARLYCON=y # CONFIG_SG_POOL is not set # CONFIG_SG_SPLIT is not set CONFIG_SHMEM=y +# CONFIG_SHRINKER_DEBUG is not set # CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set # CONFIG_SH_ETH is not set # CONFIG_SH_TIMER_CMT is not set @@ -5776,6 +5909,7 @@ CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SM_GCC_6115 is not set # CONFIG_SM_GCC_6125 is not set # CONFIG_SM_GCC_6350 is not set +# CONFIG_SM_GCC_6375 is not set # CONFIG_SM_GCC_8350 is not set # CONFIG_SND is not set # CONFIG_SND_AC97_POWER_SAVE is not set @@ -5788,6 +5922,7 @@ CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SND_ALS100 is not set # CONFIG_SND_ALS300 is not set # CONFIG_SND_ALS4000 is not set +# CONFIG_SND_AMD_ACP_CONFIG is not set # CONFIG_SND_ARM is not set # CONFIG_SND_ASIHPI is not set # CONFIG_SND_ATIIXP is not set @@ -5798,6 +5933,7 @@ CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SND_AU8820 is not set # CONFIG_SND_AU8830 is not set # CONFIG_SND_AUDIO_GRAPH_CARD is not set +# CONFIG_SND_AUDIO_GRAPH_CARD2 is not set # CONFIG_SND_AUDIO_GRAPH_SCU_CARD is not set # CONFIG_SND_AW2 is not set # CONFIG_SND_AZT2320 is not set @@ -5814,6 +5950,8 @@ CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_SND_CS46XX is not set # CONFIG_SND_CS5530 is not set # CONFIG_SND_CS5535AUDIO is not set +# CONFIG_SND_CTL_FAST_LOOKUP is not set +# CONFIG_SND_CTL_INPUT_VALIDATION is not set # CONFIG_SND_CTXFI is not set # CONFIG_SND_DARLA20 is not set # CONFIG_SND_DARLA24 is not set @@ -5937,6 +6075,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_ADI is not set # CONFIG_SND_SOC_AK4104 is not set # CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4375 is not set # CONFIG_SND_SOC_AK4458 is not set # CONFIG_SND_SOC_AK4554 is not set # CONFIG_SND_SOC_AK4613 is not set @@ -5950,6 +6089,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_AMD_RENOIR is not set # CONFIG_SND_SOC_AU1XAUDIO is not set # CONFIG_SND_SOC_AU1XPSC is not set +# CONFIG_SND_SOC_AW8738 is not set # CONFIG_SND_SOC_BD28623 is not set # CONFIG_SND_SOC_BT_SCO is not set # CONFIG_SND_SOC_CS35L32 is not set @@ -5957,6 +6097,10 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_CS35L34 is not set # CONFIG_SND_SOC_CS35L35 is not set # CONFIG_SND_SOC_CS35L36 is not set +# CONFIG_SND_SOC_CS35L41_I2C is not set +# CONFIG_SND_SOC_CS35L41_SPI is not set +# CONFIG_SND_SOC_CS35L45_I2C is not set +# CONFIG_SND_SOC_CS35L45_SPI is not set # CONFIG_SND_SOC_CS4234 is not set # CONFIG_SND_SOC_CS4265 is not set # CONFIG_SND_SOC_CS4270 is not set @@ -5968,6 +6112,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_CS42L52 is not set # CONFIG_SND_SOC_CS42L56 is not set # CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS42L83 is not set # CONFIG_SND_SOC_CS42XX8_I2C is not set # CONFIG_SND_SOC_CS43130 is not set # CONFIG_SND_SOC_CS4341 is not set @@ -5980,6 +6125,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_ES7134 is not set # CONFIG_SND_SOC_ES7241 is not set # CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8326 is not set # CONFIG_SND_SOC_ES8328 is not set # CONFIG_SND_SOC_ES8328_I2C is not set # CONFIG_SND_SOC_ES8328_SPI is not set @@ -5996,6 +6142,7 @@ CONFIG_SND_PROC_FS=y # CONFIG_SND_SOC_FSL_SSI is not set # CONFIG_SND_SOC_FSL_XCVR is not set # CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_HDA is not set # CONFIG_SND_SOC_ICS43432 is not set # CONFIG_SND_SOC_IMG is not set # CONFIG_SND_SOC_IMX_AUDMIX is not set @@ -6056,7 +6203,9 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_MAX98373 is not set # CONFIG_SND_SOC_MAX98373_I2C is not set # CONFIG_SND_SOC_MAX98390 is not set +# CONFIG_SND_SOC_MAX98396 is not set # CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX98520 is not set # CONFIG_SND_SOC_MAX9860 is not set # CONFIG_SND_SOC_MAX9867 is not set # CONFIG_SND_SOC_MAX98927 is not set @@ -6080,6 +6229,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_NAU8315 is not set # CONFIG_SND_SOC_NAU8540 is not set # CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8821 is not set # CONFIG_SND_SOC_NAU8822 is not set # CONFIG_SND_SOC_NAU8824 is not set # CONFIG_SND_SOC_PCM1681 is not set @@ -6098,19 +6248,19 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_PCM512x_SPI is not set # CONFIG_SND_SOC_QCOM is not set # CONFIG_SND_SOC_RK3328 is not set -# CONFIG_SND_SOC_RK817 is not set -# CONFIG_SND_SOC_ROCKCHIP is not set # CONFIG_SND_SOC_RT5616 is not set # CONFIG_SND_SOC_RT5631 is not set # CONFIG_SND_SOC_RT5640 is not set # CONFIG_SND_SOC_RT5659 is not set # CONFIG_SND_SOC_RT5677_SPI is not set +# CONFIG_SND_SOC_RT9120 is not set # CONFIG_SND_SOC_SGTL5000 is not set # CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set # CONFIG_SND_SOC_SIMPLE_MUX is not set # CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set # CONFIG_SND_SOC_SOF_TOPLEVEL is not set # CONFIG_SND_SOC_SPDIF is not set +# CONFIG_SND_SOC_SRC4XXX_I2C is not set # CONFIG_SND_SOC_SSM2305 is not set # CONFIG_SND_SOC_SSM2518 is not set # CONFIG_SND_SOC_SSM2602_I2C is not set @@ -6123,13 +6273,16 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_TAS2562 is not set # CONFIG_SND_SOC_TAS2764 is not set # CONFIG_SND_SOC_TAS2770 is not set +# CONFIG_SND_SOC_TAS2780 is not set # CONFIG_SND_SOC_TAS5086 is not set # CONFIG_SND_SOC_TAS571X is not set # CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS5805M is not set # CONFIG_SND_SOC_TAS6424 is not set # CONFIG_SND_SOC_TDA7419 is not set # CONFIG_SND_SOC_TFA9879 is not set # CONFIG_SND_SOC_TFA989X is not set +# CONFIG_SND_SOC_TLV320ADC3XXX is not set # CONFIG_SND_SOC_TLV320ADCX140 is not set # CONFIG_SND_SOC_TLV320AIC23_I2C is not set # CONFIG_SND_SOC_TLV320AIC23_SPI is not set @@ -6151,6 +6304,8 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_WM8711 is not set # CONFIG_SND_SOC_WM8728 is not set # CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8731_I2C is not set +# CONFIG_SND_SOC_WM8731_SPI is not set # CONFIG_SND_SOC_WM8737 is not set # CONFIG_SND_SOC_WM8741 is not set # CONFIG_SND_SOC_WM8750 is not set @@ -6162,6 +6317,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SOC_WM8804_SPI is not set # CONFIG_SND_SOC_WM8903 is not set # CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8940 is not set # CONFIG_SND_SOC_WM8960 is not set # CONFIG_SND_SOC_WM8962 is not set # CONFIG_SND_SOC_WM8974 is not set @@ -6180,6 +6336,7 @@ CONFIG_SND_SOC_INTEL_SST_TOPLEVEL=y # CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI is not set # CONFIG_SND_SUN4I_CODEC is not set # CONFIG_SND_SUPPORT_OLD_API is not set +# CONFIG_SND_TEST_COMPONENT is not set # CONFIG_SND_TIMER is not set # CONFIG_SND_TRIDENT is not set CONFIG_SND_USB=y @@ -6239,6 +6396,7 @@ CONFIG_SND_X86=y # CONFIG_SPI_ALTERA is not set # CONFIG_SPI_AMD is not set # CONFIG_SPI_AU1550 is not set +# CONFIG_SPI_AX88796C is not set # CONFIG_SPI_AXI_SPI_ENGINE is not set # CONFIG_SPI_BCM2835 is not set # CONFIG_SPI_BCM_QSPI is not set @@ -6246,6 +6404,7 @@ CONFIG_SND_X86=y # CONFIG_SPI_BUTTERFLY is not set # CONFIG_SPI_CADENCE is not set # CONFIG_SPI_CADENCE_QUADSPI is not set +# CONFIG_SPI_CADENCE_XSPI is not set # CONFIG_SPI_DEBUG is not set # CONFIG_SPI_DESIGNWARE is not set # CONFIG_SPI_FSL_DSPI is not set @@ -6259,6 +6418,8 @@ CONFIG_SND_X86=y # CONFIG_SPI_LOOPBACK_TEST is not set # CONFIG_SPI_MASTER is not set # CONFIG_SPI_MEM is not set +# CONFIG_SPI_MICROCHIP_CORE is not set +# CONFIG_SPI_MICROCHIP_CORE_QSPI is not set # CONFIG_SPI_MPC52xx is not set # CONFIG_SPI_MPC52xx_PSC is not set # CONFIG_SPI_MTK_QUADSPI is not set @@ -6320,6 +6481,7 @@ CONFIG_SSB_POSSIBLE=y # CONFIG_SSB_SILENT is not set # CONFIG_SSFDC is not set # CONFIG_STACKPROTECTOR is not set +# CONFIG_STACKPROTECTOR_PER_TASK is not set # CONFIG_STACKPROTECTOR_STRONG is not set # CONFIG_STACKTRACE is not set # CONFIG_STACKTRACE_BUILD_ID is not set @@ -6380,6 +6542,8 @@ CONFIG_SWAP=y # CONFIG_SWCONFIG_LEDS is not set # CONFIG_SW_SYNC is not set # CONFIG_SX9310 is not set +# CONFIG_SX9324 is not set +# CONFIG_SX9360 is not set # CONFIG_SX9500 is not set # CONFIG_SXGBE_ETH is not set CONFIG_SYMBOLIC_ERRNAME=y @@ -6419,6 +6583,7 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_TCG_NSC is not set # CONFIG_TCG_ST33_I2C is not set # CONFIG_TCG_TIS is not set +# CONFIG_TCG_TIS_I2C is not set # CONFIG_TCG_TIS_I2C_ATMEL is not set # CONFIG_TCG_TIS_I2C_CR50 is not set # CONFIG_TCG_TIS_I2C_INFINEON is not set @@ -6475,14 +6640,17 @@ CONFIG_TCP_CONG_CUBIC=y # CONFIG_TEST_LIST_SORT is not set # CONFIG_TEST_LKM is not set # CONFIG_TEST_LOCKUP is not set +# CONFIG_TEST_MAPLE_TREE is not set # CONFIG_TEST_MEMCAT_P is not set # CONFIG_TEST_MEMINIT is not set # CONFIG_TEST_MIN_HEAP is not set # CONFIG_TEST_OVERFLOW is not set # CONFIG_TEST_POWER is not set # CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_REF_TRACKER is not set # CONFIG_TEST_RHASHTABLE is not set # CONFIG_TEST_SCANF is not set +# CONFIG_TEST_SIPHASH is not set # CONFIG_TEST_SORT is not set # CONFIG_TEST_STACKINIT is not set # CONFIG_TEST_STATIC_KEYS is not set @@ -6631,6 +6799,7 @@ CONFIG_TMPFS_XATTR=y # CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set # CONFIG_TOUCHSCREEN_ILI210X is not set # CONFIG_TOUCHSCREEN_ILITEK is not set +# CONFIG_TOUCHSCREEN_IMAGIS is not set # CONFIG_TOUCHSCREEN_IMX6UL_TSC is not set # CONFIG_TOUCHSCREEN_INEXIO is not set # CONFIG_TOUCHSCREEN_IPAQ_MICRO is not set @@ -6734,11 +6903,13 @@ CONFIG_TRAD_SIGNALS=y # CONFIG_TRIM_UNUSED_KSYMS is not set # CONFIG_TRUSTED_FOUNDATIONS is not set # CONFIG_TRUSTED_KEYS is not set +# CONFIG_TRUSTED_KEYS_TPM is not set # CONFIG_TSL2583 is not set # CONFIG_TSL2591 is not set # CONFIG_TSL2772 is not set # CONFIG_TSL2x7x is not set # CONFIG_TSL4531 is not set +# CONFIG_TSNEP is not set # CONFIG_TSYS01 is not set # CONFIG_TSYS02D is not set # CONFIG_TTPCI_EEPROM is not set @@ -6750,6 +6921,7 @@ CONFIG_TTY=y # CONFIG_TWL4030_MADC is not set # CONFIG_TWL6030_GPADC is not set # CONFIG_TWL6040_CORE is not set +# CONFIG_TXGBE is not set # CONFIG_TYPEC is not set # CONFIG_TYPEC_TCPM is not set # CONFIG_TYPEC_UCSI is not set @@ -7032,6 +7204,7 @@ CONFIG_USB_GADGET_VBUS_DRAW=2 # CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set # CONFIG_USB_OHCI_HCD_SSB is not set CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_ONBOARD_HUB is not set # CONFIG_USB_OTG is not set # CONFIG_USB_OTG_BLACKLIST_HUB is not set # CONFIG_USB_OTG_DISABLE_EXTERNAL_HUB is not set @@ -7045,6 +7218,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_PRINTER is not set # CONFIG_USB_PWC_INPUT_EVDEV is not set # CONFIG_USB_PXA27X is not set +# CONFIG_USB_QCOM_EUD is not set # CONFIG_USB_R8A66597 is not set # CONFIG_USB_R8A66597_HCD is not set # CONFIG_USB_RAW_GADGET is not set @@ -7178,6 +7352,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USELIB is not set # CONFIG_USERFAULTFD is not set # CONFIG_USERIO is not set +# CONFIG_USER_DECRYPTED_DATA is not set # CONFIG_USE_OF is not set # CONFIG_UTS_NS is not set # CONFIG_UWB is not set @@ -7190,6 +7365,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_VCNL3020 is not set # CONFIG_VCNL4000 is not set # CONFIG_VCNL4035 is not set +# CONFIG_VCPU_STALL_DETECTOR is not set # CONFIG_VDPA is not set CONFIG_VDSO=y # CONFIG_VEML6030 is not set @@ -7228,6 +7404,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_AK7375 is not set # CONFIG_VIDEO_AK881X is not set # CONFIG_VIDEO_AM437X_VPFE is not set +# CONFIG_VIDEO_AR0521 is not set # CONFIG_VIDEO_ASPEED is not set # CONFIG_VIDEO_ATMEL_ISC is not set # CONFIG_VIDEO_ATMEL_ISI is not set @@ -7237,6 +7414,8 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_BT856 is not set # CONFIG_VIDEO_BT866 is not set # CONFIG_VIDEO_CADENCE is not set +# CONFIG_VIDEO_CADENCE_CSI2RX is not set +# CONFIG_VIDEO_CADENCE_CSI2TX is not set # CONFIG_VIDEO_CAFE_CCIC is not set # CONFIG_VIDEO_CCS is not set # CONFIG_VIDEO_CODA is not set @@ -7262,6 +7441,8 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_HEXIUM_GEMINI is not set # CONFIG_VIDEO_HEXIUM_ORION is not set # CONFIG_VIDEO_HI556 is not set +# CONFIG_VIDEO_HI846 is not set +# CONFIG_VIDEO_HI847 is not set # CONFIG_VIDEO_I2C is not set # CONFIG_VIDEO_IMX_PXP is not set # CONFIG_VIDEO_IMX208 is not set @@ -7279,6 +7460,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_IMX8_JPEG is not set # CONFIG_VIDEO_IRS1125 is not set # CONFIG_VIDEO_IR_I2C is not set +# CONFIG_VIDEO_ISL7998X is not set # CONFIG_VIDEO_IVTV is not set # CONFIG_VIDEO_KS0127 is not set # CONFIG_VIDEO_LM3560 is not set @@ -7301,9 +7483,12 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_MUX is not set # CONFIG_VIDEO_MXB is not set # CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_VIDEO_OG01A1B is not set # CONFIG_VIDEO_OMAP2_VOUT is not set # CONFIG_VIDEO_OV02A10 is not set +# CONFIG_VIDEO_OV08D10 is not set # CONFIG_VIDEO_OV13858 is not set +# CONFIG_VIDEO_OV13B10 is not set # CONFIG_VIDEO_OV2311 is not set # CONFIG_VIDEO_OV2640 is not set # CONFIG_VIDEO_OV2659 is not set @@ -7316,6 +7501,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_OV5648 is not set # CONFIG_VIDEO_OV5670 is not set # CONFIG_VIDEO_OV5675 is not set +# CONFIG_VIDEO_OV5693 is not set # CONFIG_VIDEO_OV5695 is not set # CONFIG_VIDEO_OV6650 is not set # CONFIG_VIDEO_OV7251 is not set @@ -7334,7 +7520,6 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_RDACM20 is not set # CONFIG_VIDEO_RDACM21 is not set # CONFIG_VIDEO_RJ54N1 is not set -# CONFIG_VIDEO_ROCKCHIP_ISP1 is not set # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_S5K4ECGX is not set # CONFIG_VIDEO_S5K5BAF is not set @@ -7391,7 +7576,6 @@ CONFIG_VHOST_MENU=y # CONFIG_VIRTIO_CONSOLE is not set # CONFIG_VIRTIO_FS is not set # CONFIG_VIRTIO_INPUT is not set -# CONFIG_VIRTIO_IOMMU is not set CONFIG_VIRTIO_MENU=y # CONFIG_VIRTIO_MMIO is not set # CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES is not set @@ -7406,6 +7590,7 @@ CONFIG_VIRT_TO_BUS=y CONFIG_VLAN_8021Q=y # CONFIG_VLAN_8021Q_GVRP is not set # CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_VMAP_STACK is not set # CONFIG_VME_BUS is not set # CONFIG_VMLINUX_MAP is not set # CONFIG_VMSPLIT_1G is not set @@ -7471,15 +7656,15 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0 # CONFIG_WDAT_WDT is not set # CONFIG_WDTPCI is not set CONFIG_WERROR=y -# CONFIG_WEXT_CORE is not set -# CONFIG_WEXT_PRIV is not set -# CONFIG_WEXT_PROC is not set -# CONFIG_WEXT_SPY is not set +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PRIV=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_SPY=y CONFIG_WILINK_PLATFORM_DATA=y # CONFIG_WIMAX is not set # CONFIG_WIREGUARD is not set CONFIG_WIRELESS=y -# CONFIG_WIRELESS_EXT is not set +CONFIG_WIRELESS_EXT=y # CONFIG_WIRELESS_WDS is not set # CONFIG_WIZNET_W5100 is not set # CONFIG_WIZNET_W5300 is not set @@ -7497,10 +7682,12 @@ CONFIG_WLAN=y # CONFIG_WLAN_VENDOR_MARVELL is not set # CONFIG_WLAN_VENDOR_MEDIATEK is not set # CONFIG_WLAN_VENDOR_MICROCHIP is not set +# CONFIG_WLAN_VENDOR_PURELIFI is not set # CONFIG_WLAN_VENDOR_QUANTENNA is not set # CONFIG_WLAN_VENDOR_RALINK is not set # CONFIG_WLAN_VENDOR_REALTEK is not set # CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_SILABS is not set # CONFIG_WLAN_VENDOR_ST is not set # CONFIG_WLAN_VENDOR_TI is not set # CONFIG_WLAN_VENDOR_ZYDAS is not set @@ -7538,6 +7725,7 @@ CONFIG_XFRM=y # CONFIG_XILINX_DMA is not set # CONFIG_XILINX_EMACLITE is not set # CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_XILINX_INTC is not set # CONFIG_XILINX_LL_TEMAC is not set # CONFIG_XILINX_SDFEC is not set # CONFIG_XILINX_VCU is not set @@ -7555,6 +7743,7 @@ CONFIG_XZ_DEC=y # CONFIG_XZ_DEC_ARMTHUMB is not set # CONFIG_XZ_DEC_BCJ is not set # CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_MICROLZMA is not set # CONFIG_XZ_DEC_POWERPC is not set # CONFIG_XZ_DEC_SPARC is not set # CONFIG_XZ_DEC_TEST is not set @@ -7589,4 +7778,5 @@ CONFIG_ZONE_DMA=y # CONFIG_ZRAM_DEF_COMP_ZSTD is not set # CONFIG_ZRAM_MEMORY_TRACKING is not set # CONFIG_ZSMALLOC is not set +# CONFIG_ZSWAP is not set # CONFIG_ZX_TDM is not set From 178278bcd33efcbbcffb2774c04eadc368b15ccb Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 26 Oct 2022 13:26:14 +0200 Subject: [PATCH 76/88] generic: 6.1: add missing symbols These symbols got exposed once building for ipq807x. Signed-off-by: Robert Marko --- target/linux/generic/config-6.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index d620c125b98..20b57ccbb37 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -2506,6 +2506,7 @@ CONFIG_HW_PERF_EVENTS=y # CONFIG_HW_RANDOM_BCM2835 is not set # CONFIG_HW_RANDOM_CAVIUM is not set # CONFIG_HW_RANDOM_CCTRNG is not set +# CONFIG_HW_RANDOM_CN10K is not set # CONFIG_HW_RANDOM_EXYNOS is not set # CONFIG_HW_RANDOM_GEODE is not set # CONFIG_HW_RANDOM_INTEL is not set From 47e43c86e44c471973d367b230ddc29aa2dc8888 Mon Sep 17 00:00:00 2001 From: Pawel Dembicki Date: Tue, 18 Apr 2023 10:28:33 +0200 Subject: [PATCH 77/88] generic: kernel: add missing symbol Add missing symbol while adding layerscape support Signed-off-by: Pawel Dembicki [ add commit description ] Signed-off-by: Christian Marangi --- target/linux/generic/config-6.1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index 20b57ccbb37..f8c0e9f9390 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -116,7 +116,9 @@ CONFIG_64BIT_TIME=y # CONFIG_ADM6996_PHY is not set # CONFIG_ADM8211 is not set # CONFIG_ADMV1013 is not set +# CONFIG_ADMV1014 is not set # CONFIG_ADMV4420 is not set +# CONFIG_ADMV8818 is not set # CONFIG_ADRF6780 is not set # CONFIG_ADT7316 is not set # CONFIG_ADUX1020 is not set @@ -7341,6 +7343,7 @@ CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y # CONFIG_USB_WHCI_HCD is not set # CONFIG_USB_WUSB is not set # CONFIG_USB_WUSB_CBAF is not set +# CONFIG_USB_XEN_HCD is not set # CONFIG_USB_XHCI_DBGCAP is not set # CONFIG_USB_XHCI_HCD is not set # CONFIG_USB_XHCI_MVEBU is not set From a5118876441b6fe41ae7240f84a93c21c2a7ce36 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 20 Oct 2022 03:13:50 +0200 Subject: [PATCH 78/88] kernel: modules: adapt for kernel 6.1 Adapt kernel modules to support kernel 6.1. Signed-off-by: Christian Marangi --- package/kernel/linux/modules/hwmon.mk | 2 +- package/kernel/linux/modules/i2c.mk | 16 +++++++++++++++- package/kernel/linux/modules/lib.mk | 1 + package/kernel/linux/modules/netfilter.mk | 10 +++++----- package/kernel/linux/modules/netsupport.mk | 4 +++- package/kernel/linux/modules/other.mk | 3 ++- package/kernel/linux/modules/usb.mk | 4 +++- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/package/kernel/linux/modules/hwmon.mk b/package/kernel/linux/modules/hwmon.mk index 29392548d40..23e32655b2c 100644 --- a/package/kernel/linux/modules/hwmon.mk +++ b/package/kernel/linux/modules/hwmon.mk @@ -52,7 +52,7 @@ define KernelPackage/hwmon-adt7410 $(LINUX_DIR)/drivers/hwmon/adt7x10.ko \ $(LINUX_DIR)/drivers/hwmon/adt7410.ko AUTOLOAD:=$(call AutoLoad,60,adt7x10 adt7410) - $(call AddDepends/hwmon,+kmod-i2c-core) + $(call AddDepends/hwmon,+kmod-i2c-core +LINUX_6_1:kmod-regmap-core) endef define KernelPackage/hwmon-adt7410/description diff --git a/package/kernel/linux/modules/i2c.mk b/package/kernel/linux/modules/i2c.mk index 6b3cf98345c..1c65a26edce 100644 --- a/package/kernel/linux/modules/i2c.mk +++ b/package/kernel/linux/modules/i2c.mk @@ -84,6 +84,20 @@ endef $(eval $(call KernelPackage,i2c-algo-pcf)) +I2C_CCGS_UCSI_MODULES:= \ + CONFIG_I2C_CCGX_UCSI:drivers/i2c/busses/i2c-ccgx-ucsi + +define KernelPackage/i2c-ccgs-ucsi + $(call i2c_defaults,$(I2C_CCGS_UCSI_MODULES),58) + TITLE:=Cypress CCGx Type-C controller + DEPENDS:=+kmod-i2c-core +kmod-regmap-core + HIDDEN:=y +endef + + +$(eval $(call KernelPackage,i2c-ccgs-ucsi)) + + I2C_DWCORE_MODULES:= \ CONFIG_I2C_DESIGNWARE_CORE:drivers/i2c/busses/i2c-designware-core @@ -103,7 +117,7 @@ I2C_DWPCI_MODULES:= \ define KernelPackage/i2c-designware-pci $(call i2c_defaults,$(I2C_DWPCI_MODULES),59) TITLE:=Synopsys DesignWare PCI - DEPENDS:=@PCI_SUPPORT +kmod-i2c-designware-core + DEPENDS:=@PCI_SUPPORT +kmod-i2c-designware-core +kmod-i2c-ccgs-ucsi endef define KernelPackage/i2c-designware-pci/description diff --git a/package/kernel/linux/modules/lib.mk b/package/kernel/linux/modules/lib.mk index 299c5a8c354..c7d32d73170 100644 --- a/package/kernel/linux/modules/lib.mk +++ b/package/kernel/linux/modules/lib.mk @@ -134,6 +134,7 @@ define KernelPackage/lib-zstd FILES:= \ $(LINUX_DIR)/crypto/zstd.ko \ $(LINUX_DIR)/lib/xxhash.ko \ + $(LINUX_DIR)/lib/zstd/zstd_common.ko@ge6.1 \ $(LINUX_DIR)/lib/zstd/zstd_compress.ko \ $(LINUX_DIR)/lib/zstd/zstd_decompress.ko AUTOLOAD:=$(call AutoProbe,xxhash zstd zstd_compress zstd_decompress) diff --git a/package/kernel/linux/modules/netfilter.mk b/package/kernel/linux/modules/netfilter.mk index 99a48a37d47..7cfbecd949c 100644 --- a/package/kernel/linux/modules/netfilter.mk +++ b/package/kernel/linux/modules/netfilter.mk @@ -1165,15 +1165,15 @@ define KernelPackage/nft-offload DEPENDS:=@IPV6 +kmod-nf-flow +kmod-nft-nat KCONFIG:= \ CONFIG_NF_FLOW_TABLE_INET \ - CONFIG_NF_FLOW_TABLE_IPV4 \ - CONFIG_NF_FLOW_TABLE_IPV6 \ + CONFIG_NF_FLOW_TABLE_IPV4@lt5.17 \ + CONFIG_NF_FLOW_TABLE_IPV6@lt5.17 \ CONFIG_NFT_FLOW_OFFLOAD FILES:= \ $(LINUX_DIR)/net/netfilter/nf_flow_table_inet.ko \ - $(LINUX_DIR)/net/ipv4/netfilter/nf_flow_table_ipv4.ko \ - $(LINUX_DIR)/net/ipv6/netfilter/nf_flow_table_ipv6.ko \ + $(LINUX_DIR)/net/ipv4/netfilter/nf_flow_table_ipv4.ko@lt5.17 \ + $(LINUX_DIR)/net/ipv6/netfilter/nf_flow_table_ipv6.ko@lt5.17 \ $(LINUX_DIR)/net/netfilter/nft_flow_offload.ko - AUTOLOAD:=$(call AutoProbe,nf_flow_table_inet nf_flow_table_ipv4 nf_flow_table_ipv6 nft_flow_offload) + AUTOLOAD:=$(call AutoProbe,nf_flow_table_inet nf_flow_table_ipv4@lt5.17 nf_flow_table_ipv6@lt5.17 nft_flow_offload) endef $(eval $(call KernelPackage,nft-offload)) diff --git a/package/kernel/linux/modules/netsupport.mk b/package/kernel/linux/modules/netsupport.mk index b7392898092..8ef99069d37 100644 --- a/package/kernel/linux/modules/netsupport.mk +++ b/package/kernel/linux/modules/netsupport.mk @@ -92,7 +92,9 @@ define KernelPackage/vxlan +kmod-udptunnel4 \ +IPV6:kmod-udptunnel6 KCONFIG:=CONFIG_VXLAN - FILES:=$(LINUX_DIR)/drivers/net/vxlan.ko + FILES:= \ + $(LINUX_DIR)/drivers/net/vxlan.ko@lt5.18 \ + $(LINUX_DIR)/drivers/net/vxlan/vxlan.ko@ge5.18 AUTOLOAD:=$(call AutoLoad,13,vxlan) endef diff --git a/package/kernel/linux/modules/other.mk b/package/kernel/linux/modules/other.mk index cd827725bd5..ac26c2a1503 100644 --- a/package/kernel/linux/modules/other.mk +++ b/package/kernel/linux/modules/other.mk @@ -57,7 +57,8 @@ define KernelPackage/bluetooth $(LINUX_DIR)/drivers/bluetooth/hci_uart.ko \ $(LINUX_DIR)/drivers/bluetooth/btusb.ko \ $(LINUX_DIR)/drivers/bluetooth/btintel.ko \ - $(LINUX_DIR)/drivers/bluetooth/btrtl.ko + $(LINUX_DIR)/drivers/bluetooth/btrtl.ko \ + $(LINUX_DIR)/drivers/bluetooth/btmtk.ko@ge5.17 AUTOLOAD:=$(call AutoProbe,bluetooth rfcomm bnep hidp hci_uart btusb) endef diff --git a/package/kernel/linux/modules/usb.mk b/package/kernel/linux/modules/usb.mk index 2561f36aa3d..f9b00fabd8a 100644 --- a/package/kernel/linux/modules/usb.mk +++ b/package/kernel/linux/modules/usb.mk @@ -1155,7 +1155,9 @@ $(eval $(call KernelPackage,usb-net-aqc111)) define KernelPackage/usb-net-asix TITLE:=Kernel module for USB-to-Ethernet Asix convertors - DEPENDS:=+kmod-libphy +kmod-net-selftests +kmod-mdio-devres +kmod-phy-ax88796b + DEPENDS:= \ + +kmod-libphy +kmod-net-selftests +kmod-mdio-devres +kmod-phy-ax88796b \ + +LINUX_6_1:kmod-phylink KCONFIG:=CONFIG_USB_NET_AX8817X FILES:=$(LINUX_DIR)/drivers/$(USBNET_DIR)/asix.ko AUTOLOAD:=$(call AutoProbe,asix) From 4a02c5954f10291cf046f9bbf727fa01ce04a235 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Fri, 21 Oct 2022 13:08:35 +0200 Subject: [PATCH 79/88] kernel: modules: wwan: adapt for kernel 6.1 Update the WWAN kmods for compilation under kernel 6.1: * Depend on kernel not being 5.10 rather than only 5.15 * Enable CONFIG_WWAN_DEBUGFS as its now optional from 5.17 * Add missing symbols for new WWAN drivers to generic config Signed-off-by: Robert Marko --- package/kernel/linux/modules/netdevices.mk | 6 ++++-- target/linux/generic/config-6.1 | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package/kernel/linux/modules/netdevices.mk b/package/kernel/linux/modules/netdevices.mk index dd458ece4cf..934ba3c4f2d 100644 --- a/package/kernel/linux/modules/netdevices.mk +++ b/package/kernel/linux/modules/netdevices.mk @@ -1448,13 +1448,15 @@ $(eval $(call KernelPackage,sfc-falcon)) define KernelPackage/wwan SUBMENU:=$(NETWORK_DEVICES_MENU) TITLE:=WWAN Driver Core - KCONFIG:=CONFIG_WWAN + KCONFIG:= \ + CONFIG_WWAN \ + CONFIG_WWAN_DEBUGFS=y@ge5.17 FILES:=$(LINUX_DIR)/drivers/net/wwan/wwan.ko AUTOLOAD:=$(call AutoProbe,wwan) endef define KernelPackage/wwan/description - his driver provides a common framework for WWAN drivers. + This driver provides a common framework for WWAN drivers. endef $(eval $(call KernelPackage,wwan)) diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index f8c0e9f9390..48485051cb9 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -3968,6 +3968,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y # CONFIG_MTK_DEVAPC is not set # CONFIG_MTK_MMC is not set # CONFIG_MTK_MMSYS is not set +# CONFIG_MTK_T7XX is not set # CONFIG_MTK_THERMAL is not set # CONFIG_MULTIPLEXER is not set CONFIG_MULTIUSER=y @@ -4989,6 +4990,7 @@ CONFIG_PWRSEQ_SIMPLE=y # CONFIG_QCA7000_SPI is not set # CONFIG_QCA7000_UART is not set # CONFIG_QCOM_A7PLL is not set +# CONFIG_QCOM_BAM_DMUX is not set # CONFIG_QCOM_EMAC is not set # CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set # CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set From 6dce5a7b58b023153a87f282311ae7fb6b895472 Mon Sep 17 00:00:00 2001 From: Robert Marko Date: Wed, 26 Oct 2022 13:27:51 +0200 Subject: [PATCH 80/88] kernel: modules: fs: adapt for kernel 6.1 Adapt filesystem kmods for building under kernel 6.1: * Depend on kernel not being 5.10 rather than only 5.15 * kmod-fs-9p depends on kmod-fs-netfs from 5.17 as they started using netfs helpers * Set new KConfig options to N Signed-off-by: Robert Marko --- package/kernel/linux/modules/fs.mk | 6 ++++-- package/kernel/linux/modules/netsupport.mk | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/package/kernel/linux/modules/fs.mk b/package/kernel/linux/modules/fs.mk index 1dddebfed73..5fb9a2b7d64 100644 --- a/package/kernel/linux/modules/fs.mk +++ b/package/kernel/linux/modules/fs.mk @@ -10,7 +10,7 @@ FS_MENU:=Filesystems define KernelPackage/fs-9p SUBMENU:=$(FS_MENU) TITLE:=Plan 9 Resource Sharing Support - DEPENDS:=+kmod-9pnet + DEPENDS:=+kmod-9pnet +LINUX_6_1:kmod-fs-netfs KCONFIG:=\ CONFIG_9P_FS \ CONFIG_9P_FS_POSIX_ACL=n \ @@ -269,7 +269,9 @@ define KernelPackage/fs-fscache CONFIG_FSCACHE_OBJECT_LIST=n \ CONFIG_CACHEFILES \ CONFIG_CACHEFILES_DEBUG=n \ - CONFIG_CACHEFILES_HISTOGRAM=n + CONFIG_CACHEFILES_HISTOGRAM=n \ + CONFIG_CACHEFILES_ERROR_INJECTION=n@ge5.17 \ + CONFIG_CACHEFILES_ONDEMAND=n@ge5.19 FILES:= \ $(LINUX_DIR)/fs/fscache/fscache.ko \ $(LINUX_DIR)/fs/cachefiles/cachefiles.ko diff --git a/package/kernel/linux/modules/netsupport.mk b/package/kernel/linux/modules/netsupport.mk index 8ef99069d37..dcc2799c79a 100644 --- a/package/kernel/linux/modules/netsupport.mk +++ b/package/kernel/linux/modules/netsupport.mk @@ -1316,7 +1316,8 @@ define KernelPackage/9pnet CONFIG_NET_9P \ CONFIG_NET_9P_DEBUG=n \ CONFIG_NET_9P_XEN=n \ - CONFIG_NET_9P_VIRTIO + CONFIG_NET_9P_VIRTIO \ + CONFIG_NET_9P_FD=n@ge5.17 FILES:= \ $(LINUX_DIR)/net/9p/9pnet.ko \ $(LINUX_DIR)/net/9p/9pnet_virtio.ko From dbac8e8819dd81d5d2149b58fb789f9ebb2b4861 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:46:43 +0200 Subject: [PATCH 81/88] ipq806x: 6.1: copy patches, files and config from 5.15 Copy patches, files and config from 5.15 kernel version. Signed-off-by: Christian Marangi --- target/linux/ipq806x/config-6.1 | 507 ++++++++++ .../arm/boot/dts/qcom-ipq8062-wg2600hp3.dts | 510 ++++++++++ .../boot/dts/qcom-ipq8064-ad7200-c2600.dtsi | 402 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-ad7200.dts | 135 +++ .../arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 134 +++ .../arch/arm/boot/dts/qcom-ipq8064-ap161.dts | 172 ++++ .../arm/boot/dts/qcom-ipq8064-asus-onhub.dts | 92 ++ .../arch/arm/boot/dts/qcom-ipq8064-c2600.dts | 119 +++ .../arch/arm/boot/dts/qcom-ipq8064-d7800.dts | 394 ++++++++ .../arch/arm/boot/dts/qcom-ipq8064-db149.dts | 179 ++++ .../arm/boot/dts/qcom-ipq8064-ea7500-v1.dts | 91 ++ .../arch/arm/boot/dts/qcom-ipq8064-ea8500.dts | 128 +++ .../arm/boot/dts/qcom-ipq8064-eax500.dtsi | 232 +++++ .../arch/arm/boot/dts/qcom-ipq8064-g10.dts | 292 ++++++ .../arch/arm/boot/dts/qcom-ipq8064-onhub.dtsi | 491 ++++++++++ .../arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 327 +++++++ .../arm/boot/dts/qcom-ipq8064-r7500v2.dts | 387 ++++++++ .../boot/dts/qcom-ipq8064-tplink-onhub.dts | 209 ++++ .../arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts | 315 ++++++ .../arm/boot/dts/qcom-ipq8064-vr2600v.dts | 424 ++++++++ .../arm/boot/dts/qcom-ipq8064-wg2600hp.dts | 463 +++++++++ .../arch/arm/boot/dts/qcom-ipq8064-wpq864.dts | 473 +++++++++ .../arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts | 539 ++++++++++ .../arch/arm/boot/dts/qcom-ipq8065-ac400i.dts | 318 ++++++ .../arm/boot/dts/qcom-ipq8065-nbg6817.dts | 332 +++++++ .../arm/boot/dts/qcom-ipq8065-nighthawk.dtsi | 466 +++++++++ .../arch/arm/boot/dts/qcom-ipq8065-r7800.dts | 48 + .../boot/dts/qcom-ipq8065-rt4230w-rev6.dts | 418 ++++++++ .../arm/boot/dts/qcom-ipq8065-tr4400-v2.dts | 432 ++++++++ .../arch/arm/boot/dts/qcom-ipq8065-xr500.dts | 50 + .../boot/dts/qcom-ipq8068-cryptid-common.dtsi | 236 +++++ .../arm/boot/dts/qcom-ipq8068-ecw5410.dts | 329 +++++++ .../arch/arm/boot/dts/qcom-ipq8068-mr42.dts | 228 +++++ .../arch/arm/boot/dts/qcom-ipq8068-mr52.dts | 254 +++++ ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 ++ ...Mangle-bootloader-s-kernel-arguments.patch | 280 ++++++ ...806x-fix-wrong-naming-for-gcc_pxo_pl.patch | 109 +++ ...806x-convert-parent_names-to-parent_.patch | 921 ++++++++++++++++++ ...q806x-use-ARRAY_SIZE-for-num_parents.patch | 325 ++++++ ...pq806x-add-additional-freq-nss-cores.patch | 88 ++ ...806x-add-unusued-flag-for-critical-c.patch | 65 ++ ...om-clk-rcg-add-clk_rcg_floor_ops-ops.patch | 69 ++ ...806x-add-additional-freq-for-sdc-tab.patch | 38 + ...ngs-clock-add-ipq8064-ce5-clk-define.patch | 39 + ...-gcc-ipq806x-add-CryptoEngine-clocks.patch | 304 ++++++ ...indings-reset-add-ipq8064-ce5-resets.patch | 29 + ...-gcc-ipq806x-add-CryptoEngine-resets.patch | 30 + ...mac-add-missing-sgmii-configure-for-.patch | 151 +++ ...mac-reset-force-speed-bit-for-ipq806.patch | 110 +++ ...conflicts-with-OpenWrt-auto-mounting.patch | 25 + ...-syscon-and-cxo-pxo-clock-to-gcc-nod.patch | 48 + ...lace-gcc-PXO-with-pxo_board-fixed-cl.patch | 29 + ...8064-add-multiple-missing-pin-defini.patch | 101 ++ ...ipq8064-add-gsbi6-missing-definition.patch | 67 ++ ...8064-add-specific-dtsi-with-smb208-r.patch | 66 ++ ...8064-add-missing-snps-dwmac-compatib.patch | 56 ++ ...m-ipq8064-disable-usb-phy-by-default.patch | 37 + ...8064-fix-and-add-some-missing-gsbi-n.patch | 94 ++ ...pq8064-add-speedbin-efuse-nvmem-node.patch | 28 + ...Add-support-for-mmio-usage-to-sfpb-m.patch | 71 ++ ...-dts-qcom-ipq8064-add-missing-hwlock.patch | 31 + ...-ipq8064-add-missing-smem-compatible.patch | 30 + ...dts-qcom-ipq8064-add-v2-dtsi-variant.patch | 129 +++ ...dts-qcom-ipq8064-add-ipq8062-variant.patch | 67 ++ ...dts-qcom-ipq8064-add-ipq8065-variant.patch | 67 ++ ...add-saw-for-l2-cache-and-kraitcc-for.patch | 95 ++ ...add-opp-table-for-cpu-and-l2-for-ipq.patch | 268 +++++ ...add-multiple-missing-binding-for-cpu.patch | 153 +++ ...-wrong-nad_pins-definition-for-ipq80.patch | 29 + ...-MDIO-dedicated-controller-node-for-.patch | 188 ++++ ...-clock-add-pcm-reset-for-ipq806x-lcc.patch | 29 + ...com-lcc-ipq806x-add-reset-definition.patch | 48 + ...m-lcc-ipq806x-convert-to-parent-data.patch | 217 +++++ ...ns-init-debugfs-only-with-successful.patch | 41 + ...tsens-simplify-debugfs-init-function.patch | 54 + ...t-devfreq_get_freq_range-symbol-with.patch | 113 +++ ...pu-based-scaling-support-to-passive-.patch | 461 +++++++++ ...ve-Reduce-duplicate-code-when-passiv.patch | 110 +++ ...ve-Keep-cpufreq_policy-for-possible-.patch | 232 +++++ ...ve-Return-non-error-when-not-support.patch | 31 + ...ernel-warning-with-cpufreq-passive-r.patch | 31 + ...x-cpufreq-passive-unregister-errorin.patch | 85 ++ ...ernel-panic-with-cpu-based-scaling-t.patch | 34 + ...work-freq_table-to-be-local-to-devfr.patch | 269 +++++ ...Mute-warning-on-governor-PROBE_DEFER.patch | 28 + ...-L2-Krait-Cache-devfreq-scaling-driv.patch | 242 +++++ ...-krait-cache-compatible-for-ipq806x-.patch | 50 + ...eq-add-ipq806x-fabric-scaling-driver.patch | 203 ++++ ...com-add-fab-scaling-node-for-ipq806x.patch | 48 + ...m_nandc-reorder-qcom_nand_host-struc.patch | 268 +++++ ...m_nandc-add-support-for-unprotected-.patch | 406 ++++++++ ...com-clk-hfpll-use-poll_timeout-macro.patch | 41 + ...it-add-apq-ipq8064-errata-workaround.patch | 86 ++ ...vm_-hw_register_mux_parent_data_tabl.patch | 46 + ...-kpss-xcc-convert-to-parent-data-API.patch | 70 ++ ...-rpmcc-missing-clocks-for-apq-ipq806.patch | 61 ++ ...m-clk-rpm-convert-to-parent_data-API.patch | 78 ++ ...kpss-xcc-register-it-as-clk-provider.patch | 61 ++ ...c-use-devm-variant-for-clk-notifier-.patch | 27 + ...c-fix-wrong-parent-order-for-seconda.patch | 46 + ...c-also-enable-secondary-mux-and-div-.patch | 68 ++ ...c-handle-secondary-mux-sourcing-out-.patch | 48 + ...t-cc-convert-to-devm_clk_hw_register.patch | 104 ++ ...-krait-cc-convert-to-parent_data-API.patch | 414 ++++++++ ...t-cc-handle-qsb-clock-defined-in-DTS.patch | 47 + ...ait-cc-register-REAL-qsb-fixed-clock.patch | 36 + ...ait-cc-drop-pr_info-and-use-dev_info.patch | 44 + ...c-rework-mux-reset-logic-and-reset-h.patch | 88 ++ ...m-clk-krait-generilize-div-functions.patch | 156 +++ ...ipq806x-remove-cc_register_board-for.patch | 31 + ...-handle-ret-from-parse-with-codeword.patch | 55 ++ ...q8064-disable-mmc-ddr-1_8v-for-sdcc1.patch | 28 + .../850-soc-add-qualcomm-syscon.patch | 121 +++ .../900-arm-add-cmdline-override.patch | 37 + 114 files changed, 19218 insertions(+) create mode 100644 target/linux/ipq806x/config-6.1 create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap148.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap161.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-asus-onhub.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-c2600.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-d7800.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-db149.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-g10.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-onhub.dtsi create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-tplink-onhub.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-ac400i.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nighthawk.dtsi create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-r7800.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-xr500.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-cryptid-common.dtsi create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr42.dts create mode 100644 target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr52.dts create mode 100644 target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch create mode 100644 target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch create mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch create mode 100644 target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch create mode 100644 target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch create mode 100644 target/linux/ipq806x/patches-6.1/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch create mode 100644 target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch create mode 100644 target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch create mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch create mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch create mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch create mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch create mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch create mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch create mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch create mode 100644 target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch create mode 100644 target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch create mode 100644 target/linux/ipq806x/patches-6.1/107-15-ARM-dts-qcom-add-multiple-missing-binding-for-cpu.patch create mode 100644 target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch create mode 100644 target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch create mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch create mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch create mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch create mode 100644 target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch create mode 100644 target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch create mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch create mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch create mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch create mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch create mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch create mode 100644 target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch create mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch create mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch create mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch create mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch create mode 100644 target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch create mode 100644 target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch create mode 100644 target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch create mode 100644 target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch create mode 100644 target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch create mode 100644 target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch create mode 100644 target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch create mode 100644 target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch create mode 100644 target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch create mode 100644 target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch create mode 100644 target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch create mode 100644 target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch create mode 100644 target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-02-clk-qcom-krait-cc-fix-wrong-parent-order-for-seconda.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-03-clk-qcom-krait-cc-also-enable-secondary-mux-and-div-.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-04-clk-qcom-krait-cc-handle-secondary-mux-sourcing-out-.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-05-clk-qcom-krait-cc-convert-to-devm_clk_hw_register.patch create mode 100644 target/linux/ipq806x/patches-6.1/121-v6.2-06-clk-qcom-krait-cc-convert-to-parent_data-API.patch create mode 100644 target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch create mode 100644 target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch create mode 100644 target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch create mode 100644 target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch create mode 100644 target/linux/ipq806x/patches-6.1/122-05-clk-qcom-clk-krait-generilize-div-functions.patch create mode 100644 target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch create mode 100644 target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch create mode 100644 target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch create mode 100644 target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch create mode 100644 target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch diff --git a/target/linux/ipq806x/config-6.1 b/target/linux/ipq806x/config-6.1 new file mode 100644 index 00000000000..69e17cfa504 --- /dev/null +++ b/target/linux/ipq806x/config-6.1 @@ -0,0 +1,507 @@ +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_APQ_GCC_8084 is not set +# CONFIG_APQ_MMCC_8084 is not set +CONFIG_AR8216_PHY=y +CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +# CONFIG_ARCH_IPQ40XX is not set +CONFIG_ARCH_KEEP_MEMBLOCK=y +# CONFIG_ARCH_MDM9615 is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +CONFIG_ARCH_MSM8960=y +CONFIG_ARCH_MSM8974=y +CONFIG_ARCH_MSM8X60=y +CONFIG_ARCH_MULTIPLATFORM=y +CONFIG_ARCH_MULTI_V6_V7=y +CONFIG_ARCH_MULTI_V7=y +CONFIG_ARCH_NR_GPIO=0 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_ARM=y +CONFIG_ARM_AMBA=y +CONFIG_ARM_APPENDED_DTB=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ATAG_DTB_COMPAT=y +# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set +CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_ARM_CPU_SUSPEND=y +# CONFIG_ARM_CPU_TOPOLOGY is not set +CONFIG_ARM_CRYPTO=y +CONFIG_ARM_GIC=y +CONFIG_ARM_HAS_SG_CHAIN=y +# CONFIG_ARM_IPQ806X_FAB_DEVFREQ is not set +# CONFIG_ARM_KRAIT_CACHE_DEVFREQ is not set +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_MODULE_PLTS=y +CONFIG_ARM_PATCH_IDIV=y +CONFIG_ARM_PATCH_PHYS_VIRT=y +# CONFIG_ARM_QCOM_CPUFREQ_HW is not set +CONFIG_ARM_QCOM_CPUFREQ_NVMEM=y +CONFIG_ARM_QCOM_SPM_CPUIDLE=y +# CONFIG_ARM_SMMU is not set +CONFIG_ARM_THUMB=y +CONFIG_ARM_UNWIND=y +CONFIG_ARM_VIRT_EXT=y +CONFIG_AT803X_PHY=y +CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_MQ_PCI=y +CONFIG_BOUNCE=y +# CONFIG_CACHE_L2X0 is not set +CONFIG_CLKSRC_QCOM=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CMDLINE_OVERRIDE=y +CONFIG_COMMON_CLK=y +CONFIG_COMMON_CLK_QCOM=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_PM=y +CONFIG_CPU_RMAP=y +CONFIG_CPU_SPECTRE=y +CONFIG_CPU_THERMAL=y +CONFIG_CPU_THUMB_CAPABLE=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_V7=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRC8=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_DEV_QCOM_RNG=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_HW=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LZO=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_ZSTD=y +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_DEBUG_GPIO=y +CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" +CONFIG_DEVFREQ_GOV_PASSIVE=y +# CONFIG_DEVFREQ_GOV_PERFORMANCE is not set +# CONFIG_DEVFREQ_GOV_POWERSAVE is not set +# CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND is not set +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_THERMAL is not set +CONFIG_DMADEVICES=y +CONFIG_DMA_ENGINE=y +CONFIG_DMA_OF=y +CONFIG_DMA_OPS=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DTC=y +CONFIG_DT_IDLE_STATES=y +# CONFIG_DWMAC_GENERIC is not set +CONFIG_DWMAC_IPQ806X=y +# CONFIG_DWMAC_QCOM_ETHQOS is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_ETHERNET_PACKET_MANGLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FWNODE_MDIO=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_PHY=y +CONFIG_GENERIC_PINCONF=y +CONFIG_GENERIC_PINCTRL_GROUPS=y +CONFIG_GENERIC_PINMUX_FUNCTIONS=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_VDSO_32=y +CONFIG_GLOB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GRO_CELLS=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAVE_SMP=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_HOTPLUG_CPU=y +CONFIG_HWMON=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_HW_RANDOM=y +CONFIG_HZ_FIXED=0 +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_HELPER_AUTO=y +# CONFIG_I2C_QCOM_CCI is not set +CONFIG_I2C_QUP=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set +CONFIG_IOMMU_SUPPORT=y +# CONFIG_IPQ_APSS_PLL is not set +# CONFIG_IPQ_GCC_4019 is not set +# CONFIG_IPQ_GCC_6018 is not set +CONFIG_IPQ_GCC_806X=y +# CONFIG_IPQ_GCC_8074 is not set +# CONFIG_IPQ_LCC_806X is not set +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FASTEOI_HIERARCHY_HANDLERS=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_KMAP_LOCAL=y +CONFIG_KMAP_LOCAL_NON_LINEAR_PTE_ARRAY=y +CONFIG_KPSS_XCC=y +CONFIG_KRAITCC=y +CONFIG_KRAIT_CLOCKS=y +CONFIG_KRAIT_L2_ACCESSORS=y +CONFIG_LIBFDT=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +CONFIG_MDIO_GPIO=y +CONFIG_MDIO_IPQ8064=y +# CONFIG_MDM_GCC_9615 is not set +# CONFIG_MDM_LCC_9615 is not set +CONFIG_MEMFD_CREATE=y +# CONFIG_MFD_HI6421_SPMI is not set +CONFIG_MFD_QCOM_RPM=y +# CONFIG_MFD_SPMI_PMIC is not set +CONFIG_MFD_SYSCON=y +CONFIG_MIGHT_HAVE_CACHE_L2X0=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_ARMMMCI=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=16 +CONFIG_MMC_CQHCI=y +CONFIG_MMC_QCOM_DML=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_IO_ACCESSORS=y +CONFIG_MMC_SDHCI_MSM=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MODULES_USE_ELF_REL=y +CONFIG_MSM_GCC_8660=y +# CONFIG_MSM_GCC_8916 is not set +# CONFIG_MSM_GCC_8939 is not set +# CONFIG_MSM_GCC_8960 is not set +# CONFIG_MSM_GCC_8974 is not set +# CONFIG_MSM_GCC_8994 is not set +# CONFIG_MSM_GCC_8996 is not set +# CONFIG_MSM_GCC_8998 is not set +# CONFIG_MSM_GPUCC_8998 is not set +# CONFIG_MSM_IOMMU is not set +# CONFIG_MSM_LCC_8960 is not set +# CONFIG_MSM_MMCC_8960 is not set +# CONFIG_MSM_MMCC_8974 is not set +# CONFIG_MSM_MMCC_8996 is not set +# CONFIG_MSM_MMCC_8998 is not set +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_NAND_CORE=y +CONFIG_MTD_NAND_ECC=y +CONFIG_MTD_NAND_ECC_SW_HAMMING=y +CONFIG_MTD_NAND_QCOM=y +CONFIG_MTD_QCOMSMEM_PARTS=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPLIT_FIRMWARE=y +CONFIG_MTD_SPLIT_FIT_FW=y +CONFIG_MTD_SPLIT_UIMAGE_FW=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_BEB_LIMIT=20 +CONFIG_MTD_UBI_BLOCK=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEON=y +CONFIG_NET_DEVLINK=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_QCA8K=y +CONFIG_NET_DSA_TAG_QCA=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SELFTESTS=y +CONFIG_NET_SWITCHDEV=y +CONFIG_NLS=y +CONFIG_NO_HZ=y +CONFIG_NO_HZ_COMMON=y +CONFIG_NO_HZ_IDLE=y +CONFIG_NR_CPUS=2 +CONFIG_NVMEM=y +CONFIG_NVMEM_QCOM_QFPROM=y +# CONFIG_NVMEM_SPMI_SDAM is not set +CONFIG_NVMEM_SYSFS=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OLD_SIGACTION=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xC0000000 +CONFIG_PAGE_POOL=y +CONFIG_PCI=y +CONFIG_PCIEAER=y +CONFIG_PCIEPORTBUS=y +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +CONFIG_PCIE_QCOM=y +CONFIG_PCI_DEBUG=y +CONFIG_PCI_DISABLE_COMMON_QUIRKS=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_MSI=y +CONFIG_PCI_MSI_IRQ_DOMAIN=y +CONFIG_PCS_XPCS=y +CONFIG_PERF_USE_VMALLOC=y +CONFIG_PGTABLE_LEVELS=2 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +# CONFIG_PHY_QCOM_APQ8064_SATA is not set +# CONFIG_PHY_QCOM_IPQ4019_USB is not set +CONFIG_PHY_QCOM_IPQ806X_SATA=y +# CONFIG_PHY_QCOM_IPQ806X_USB is not set +# CONFIG_PHY_QCOM_PCIE2 is not set +# CONFIG_PHY_QCOM_QMP is not set +# CONFIG_PHY_QCOM_QUSB2 is not set +# CONFIG_PHY_QCOM_USB_HS_28NM is not set +# CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2 is not set +# CONFIG_PHY_QCOM_USB_SS is not set +CONFIG_PINCTRL=y +# CONFIG_PINCTRL_APQ8064 is not set +# CONFIG_PINCTRL_APQ8084 is not set +# CONFIG_PINCTRL_IPQ4019 is not set +# CONFIG_PINCTRL_IPQ6018 is not set +CONFIG_PINCTRL_IPQ8064=y +# CONFIG_PINCTRL_IPQ8074 is not set +# CONFIG_PINCTRL_MDM9615 is not set +CONFIG_PINCTRL_MSM=y +# CONFIG_PINCTRL_MSM8226 is not set +# CONFIG_PINCTRL_MSM8660 is not set +# CONFIG_PINCTRL_MSM8916 is not set +# CONFIG_PINCTRL_MSM8960 is not set +# CONFIG_PINCTRL_MSM8976 is not set +# CONFIG_PINCTRL_MSM8994 is not set +# CONFIG_PINCTRL_MSM8996 is not set +# CONFIG_PINCTRL_MSM8998 is not set +# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set +# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set +# CONFIG_PINCTRL_QCS404 is not set +# CONFIG_PINCTRL_SC7180 is not set +# CONFIG_PINCTRL_SDM660 is not set +# CONFIG_PINCTRL_SDM845 is not set +# CONFIG_PINCTRL_SM8150 is not set +# CONFIG_PINCTRL_SM8250 is not set +CONFIG_PM_DEVFREQ=y +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_PM_OPP=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_MSM=y +CONFIG_POWER_SUPPLY=y +CONFIG_PPS=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +# CONFIG_QCOM_A53PLL is not set +CONFIG_QCOM_ADM=y +CONFIG_QCOM_BAM_DMA=y +CONFIG_QCOM_CLK_RPM=y +# CONFIG_QCOM_COMMAND_DB is not set +# CONFIG_QCOM_CPR is not set +# CONFIG_QCOM_EBI2 is not set +# CONFIG_QCOM_GENI_SE is not set +CONFIG_QCOM_GSBI=y +CONFIG_QCOM_HFPLL=y +# CONFIG_QCOM_IOMMU is not set +# CONFIG_QCOM_LLCC is not set +# CONFIG_QCOM_OCMEM is not set +# CONFIG_QCOM_PDC is not set +# CONFIG_QCOM_RMTFS_MEM is not set +CONFIG_QCOM_RPMCC=y +# CONFIG_QCOM_RPMH is not set +CONFIG_QCOM_SCM=y +# CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT is not set +CONFIG_QCOM_SMEM=y +# CONFIG_QCOM_SMSM is not set +CONFIG_QCOM_SOCINFO=y +CONFIG_QCOM_TCSR=y +CONFIG_QCOM_TSENS=y +CONFIG_QCOM_WDT=y +# CONFIG_QCS_GCC_404 is not set +# CONFIG_QCS_Q6SSTOP_404 is not set +# CONFIG_QCS_TURING_404 is not set +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_QCOM_LABIBB is not set +CONFIG_REGULATOR_QCOM_RPM=y +# CONFIG_REGULATOR_QCOM_SPMI is not set +# CONFIG_REGULATOR_QCOM_USB_VBUS is not set +# CONFIG_REGULATOR_VQMMC_IPQ4019 is not set +CONFIG_RESET_CONTROLLER=y +# CONFIG_RESET_QCOM_AOSS is not set +# CONFIG_RESET_QCOM_PDC is not set +CONFIG_RFS_ACCEL=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SC_DISPCC_7180 is not set +# CONFIG_SC_GCC_7180 is not set +# CONFIG_SC_GPUCC_7180 is not set +# CONFIG_SC_LPASS_CORECC_7180 is not set +# CONFIG_SC_MSS_7180 is not set +# CONFIG_SC_VIDEOCC_7180 is not set +# CONFIG_SDM_CAMCC_845 is not set +# CONFIG_SDM_DISPCC_845 is not set +# CONFIG_SDM_GCC_660 is not set +# CONFIG_SDM_GCC_845 is not set +# CONFIG_SDM_GPUCC_845 is not set +# CONFIG_SDM_LPASSCC_845 is not set +# CONFIG_SDM_VIDEOCC_845 is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SGL_ALLOC=y +CONFIG_SMP=y +CONFIG_SMP_ON_UP=y +# CONFIG_SM_GCC_8150 is not set +# CONFIG_SM_GCC_8250 is not set +# CONFIG_SM_GPUCC_8150 is not set +# CONFIG_SM_GPUCC_8250 is not set +# CONFIG_SM_VIDEOCC_8150 is not set +# CONFIG_SM_VIDEOCC_8250 is not set +CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_SOC_BUS=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_QUP=y +CONFIG_SPMI=y +# CONFIG_SPMI_HISI3670 is not set +CONFIG_SPMI_MSM_PMIC_ARB=y +# CONFIG_SPMI_PMIC_CLKDIV is not set +CONFIG_SRCU=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +CONFIG_SWCONFIG=y +CONFIG_SWCONFIG_LEDS=y +CONFIG_SWPHY=y +CONFIG_SWP_EMULATE=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_THERMAL=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_GOV_STEP_WISE=y +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +# CONFIG_UCLAMP_TASK is not set +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" +CONFIG_UNWINDER_ARM=y +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_SUPPORT=y +CONFIG_USE_OF=y +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_XXHASH=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_BCJ=y +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZLIB_DEFLATE=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZSTD_COMPRESS=y +CONFIG_ZSTD_DECOMPRESS=y diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts new file mode 100644 index 00000000000..c55287a4f12 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8062-wg2600hp3.dts @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8062-smb208.dtsi" +#include + +/ { + model = "NEC Platforms Aterm WG2600HP3"; + compatible = "nec,wg2600hp3", "qcom,ipq8062", "qcom,ipq8064"; + + memory { + device_type = "memory"; + reg = <0x42000000 0x1e000000>; + }; + + aliases { + label-mac-device = &gmac2; + + led-boot = &led_power_green; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_red; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&buttons_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + mode0 { + label = "mode0"; + gpios = <&qcom_pinmux 40 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + mode1 { + label = "mode1"; + gpios = <&qcom_pinmux 41 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&leds_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 14 GPIO_ACTIVE_HIGH>; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 35 GPIO_ACTIVE_HIGH>; + }; + + active_green { + label = "green:active"; + gpios = <&qcom_pinmux 42 GPIO_ACTIVE_HIGH>; + }; + + active_red { + label = "red:active"; + gpios = <&qcom_pinmux 38 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy1tpt"; + }; + + wlan2g_red { + label = "red:wlan2g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tpt"; + }; + + wlan5g_red { + label = "red:wlan5g"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_HIGH>; + }; + + tv_green { + label = "green:tv"; + gpios = <&qcom_pinmux 46 GPIO_ACTIVE_HIGH>; + }; + + tv_red { + label = "red:tv"; + gpios = <&qcom_pinmux 36 GPIO_ACTIVE_HIGH>; + }; + + converter_green { + label = "green:converter"; + gpios = <&qcom_pinmux 43 GPIO_ACTIVE_HIGH>; + }; + + converter_red { + label = "red:converter"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* nand_pins are used for leds_pins, empty the node + * from ipq8064.dtsi + */ +&nand_pins { + /delete-property/ disable; + /delete-property/ pullups; + /delete-property/ hold; +}; + +&qcom_pinmux { + pinctrl-0 = <&akro_pins>; + pinctrl-names = "default"; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + buttons_pins: buttons_pins { + mux { + pins = "gpio22", "gpio24", "gpio40", + "gpio41"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + leds_pins: leds_pins { + mux { + pins = "gpio14", "gpio15", "gpio35", + "gpio36", "gpio38", "gpio42", + "gpio43", "gpio46", "gpio55", + "gpio56", "gpio57", "gpio58"; + function = "gpio"; + bias-pull-down; + }; + + akro2 { + pins = "gpio15", "gpio35", "gpio38", + "gpio42", "gpio43", "gpio46", + "gpio55", "gpio56", "gpio57", + "gpio58"; + drive-strength = <2>; + }; + + akro4 { + pins = "gpio14", "gpio36"; + drive-strength = <4>; + }; + }; + + /* + * Stock firmware has the following settings, so let's do the same. + * I don't sure why these are required. + */ + akro_pins: akro_pinmux { + akro { + pins = "gpio17", "gpio26", "gpio47"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + reset { + pins = "gpio45"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-low; + }; + + gmac0_rgmii { + pins = "gpio25"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + }; +}; + +&gsbi5 { + status = "okay"; + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <50000000>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0000000 0x0020000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x0020000 0x0020000>; + read-only; + }; + + partition@40000 { + label = "SBL2"; + reg = <0x0040000 0x0040000>; + read-only; + }; + + partition@80000 { + label = "SBL3"; + reg = <0x0080000 0x0080000>; + read-only; + }; + + partition@100000 { + label = "DDRCONFIG"; + reg = <0x0100000 0x0010000>; + read-only; + }; + + partition@110000 { + label = "SSD"; + reg = <0x0110000 0x0010000>; + read-only; + }; + + partition@120000 { + label = "TZ"; + reg = <0x0120000 0x0080000>; + read-only; + }; + + partition@1a0000 { + label = "RPM"; + reg = <0x01a0000 0x0080000>; + read-only; + }; + + partition@220000 { + label = "APPSBL"; + reg = <0x0220000 0x0080000>; + read-only; + }; + + partition@2a0000 { + label = "APPSBLENV"; + reg = <0x02a0000 0x0010000>; + read-only; + }; + + factory: partition@2b0000 { + label = "PRODUCTDATA"; + reg = <0x02b0000 0x0030000>; + read-only; + }; + + partition@2e0000 { + label = "ART"; + reg = <0x02e0000 0x0040000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + partition@320000 { + label = "TP"; + reg = <0x0320000 0x0040000>; + read-only; + }; + + partition@360000 { + label = "TINY"; + reg = <0x0360000 0x0500000>; + read-only; + }; + + partition@860000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x0860000 0x17a0000>; + }; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + reg = <0x00010000 0 0 0 0>; + + qcom,ath10k-calibration-variant = "NEC-Platforms-WG2600HP3"; + + nvmem-cells = <&macaddr_PRODUCTDATA_12>, <&precal_ART_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&pcie1 { + status = "okay"; + force_gen1 = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + reg = <0x00010000 0 0 0 0>; + + ieee80211-freq-limit = <2400000 2483000>; + qcom,ath10k-calibration-variant = "NEC-Platforms-WG2600HP3"; + + nvmem-cells = <&macaddr_PRODUCTDATA_c>, <&precal_ART_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x04 0x80080080 /* PAD0_MODE */ + 0x0c 0x06000000 /* PAD6_MODE */ + 0x10 0x002613a0 /* PWS_REG */ + 0x50 0xcc36cc36 /* LED_CTRL0 */ + 0x54 0xca36ca36 /* LED_CTRL1 */ + 0x58 0xc936c936 /* LED_CTRL2 */ + 0x5c 0x03ffff00 /* LED_CTRL3 */ + 0x7c 0x0000004e /* PORT0_STATUS */ + 0x94 0x0000004e /* PORT6_STATUS */ + 0xe0 0xc74164de /* SGMII_CTRL */ + 0xe4 0x0006a545 /* MAC_PWR_SEL */ + >; + }; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + mdiobus = <&mdio0>; + nvmem-cells = <&macaddr_factory_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + mdiobus = <&mdio0>; + nvmem-cells = <&macaddr_factory_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&factory { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_factory_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_factory_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + macaddr_PRODUCTDATA_c: macaddr@c { + reg = <0xc 0x6>; + }; + + macaddr_PRODUCTDATA_12: macaddr@12 { + reg = <0x12 0x6>; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi new file mode 100644 index 00000000000..3494b2bde2f --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200-c2600.dtsi @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + ramoops@42100000 { + compatible = "ramoops"; + reg = <0x42100000 0x40000>; + record-size = <0x4000>; + console-size = <0x4000>; + ftrace-size = <0x4000>; + pmsg-size = <0x4000>; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + label-mac-device = &gmac2; + }; +}; + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb0_pwr_en_pin: usb0_pwr_en_pin { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + usb1_pwr_en_pin: usb1_pwr_en_pin { + mux { + pins = "gpio23"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + partition@40000 { + label = "SBL2"; + reg = <0x40000 0x20000>; + read-only; + }; + + partition@60000 { + label = "SBL3"; + reg = <0x60000 0x30000>; + read-only; + }; + + partition@90000 { + label = "DDRCONFIG"; + reg = <0x90000 0x10000>; + read-only; + }; + + partition@a0000 { + label = "SSD"; + reg = <0xa0000 0x10000>; + read-only; + }; + + partition@b0000 { + label = "TZ"; + reg = <0xb0000 0x30000>; + read-only; + }; + + partition@e0000 { + label = "RPM"; + reg = <0xe0000 0x20000>; + read-only; + }; + + partition@100000 { + label = "fs-uboot"; + reg = <0x100000 0x70000>; + read-only; + }; + + partition@170000 { + label = "uboot-env"; + reg = <0x170000 0x40000>; + read-only; + }; + + partition@1b0000 { + label = "radio"; + reg = <0x1b0000 0x40000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + precal_radio_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_radio_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + partition@1f0000 { + label = "os-image"; + reg = <0x1f0000 0x400000>; + }; + + partition@5f0000 { + label = "rootfs"; + reg = <0x5f0000 0x1900000>; + }; + + defaultmac: partition@1ef0000 { + label = "default-mac"; + reg = <0x1ef0000 0x00200>; + read-only; + }; + + partition@1ef0200 { + label = "pin"; + reg = <0x1ef0200 0x00200>; + read-only; + }; + + partition@1ef0400 { + label = "product-info"; + reg = <0x1ef0400 0x0fc00>; + read-only; + }; + + partition@1f00000 { + label = "partition-table"; + reg = <0x1f00000 0x10000>; + read-only; + }; + + partition@1f10000 { + label = "soft-version"; + reg = <0x1f10000 0x10000>; + read-only; + }; + + partition@1f20000 { + label = "support-list"; + reg = <0x1f20000 0x10000>; + read-only; + }; + + partition@1f30000 { + label = "profile"; + reg = <0x1f30000 0x10000>; + read-only; + }; + + partition@1f40000 { + label = "default-config"; + reg = <0x1f40000 0x10000>; + read-only; + }; + + partition@1f50000 { + label = "user-config"; + reg = <0x1f50000 0x40000>; + read-only; + }; + + partition@1f90000 { + label = "qos-db"; + reg = <0x1f90000 0x40000>; + read-only; + }; + + partition@1fd0000 { + label = "usb-config"; + reg = <0x1fd0000 0x10000>; + read-only; + }; + + partition@1fe0000 { + label = "log"; + reg = <0x1fe0000 0x20000>; + read-only; + }; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pin>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pin>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_defaultmac_8>, <&precal_radio_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(-1)>; + }; + }; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_defaultmac_8>, <&precal_radio_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_defaultmac_8>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_defaultmac_8>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&defaultmac { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_defaultmac_8: macaddr@8 { + reg = <0x8 0x6>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts new file mode 100644 index 00000000000..6cb21fc4f3f --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ad7200.dts @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-ad7200-c2600.dtsi" + +/ { + model = "TP-Link Talon AD7200"; + compatible = "tplink,ad7200", "qcom,ipq8064"; + + aliases { + led-boot = &led_status; + led-failsafe = &led_status; + led-running = &led_status; + led-upgrade = &led_status; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + led_enable { + label = "led-enable"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + lan { + label = "blue:lan"; + gpios = <&qcom_pinmux 2 GPIO_ACTIVE_HIGH>; + }; + + usb1 { + label = "blue:usb1"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "blue:wlan5g"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + + usb3 { + label = "blue:usb3"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "blue:wlan2g"; + gpios = <&qcom_pinmux 17 GPIO_ACTIVE_HIGH>; + }; + + wan_orange { + label = "orange:wan"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + wan_blue { + label = "blue:wan"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_LOW>; + }; + + wps { + label = "blue:wps"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; + + wlan60g { + label = "blue:wlan60g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + led_status: status { + label = "blue:status"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio53", "gpio54", "gpio67"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio2", "gpio8", "gpio15", "gpio16", "gpio17", "gpio26", + "gpio33", "gpio55", "gpio56", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&pcie2 { + status = "okay"; + max-link-speed = <1>; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap148.dts new file mode 100644 index 00000000000..d3b7c44877e --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap148.dts @@ -0,0 +1,134 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. IPQ8064/AP-148"; + compatible = "qcom,ipq8064-ap148", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&flash { + partitions { + compatible = "qcom,smem-part"; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap161.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap161.dts new file mode 100644 index 00000000000..02ddbf31180 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ap161.dts @@ -0,0 +1,172 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm IPQ8064/AP161"; + compatible = "qcom,ipq8064-ap161", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + }; +}; + +&qcom_pinmux { + rgmii2_pins: rgmii2-pins { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", + "gpio51", "gpio52", "gpio59", + "gpio60", "gpio61", "gpio62", + "gpio2", "gpio66"; + }; + }; +}; + +&flash { + partitions { + compatible = "qcom,smem-part"; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&pcie2 { + status = "okay"; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x20080 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,phy-rgmii-en; + qca,txclk-delay-en; + qca,rxclk-delay-en; + }; + + phy3: ethernet-phy@3 { + device_type = "ethernet-phy"; + reg = <3>; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-asus-onhub.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-asus-onhub.dts new file mode 100644 index 00000000000..442bcf19a67 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-asus-onhub.dts @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014 The ChromiumOS Authors + */ + +#include "qcom-ipq8064-onhub.dtsi" +#include +#include +#include + +/ { + model = "ASUS OnHub"; + compatible = "asus,onhub", "google,arkham", "qcom,ipq8064"; +}; + +&qcom_pinmux { + ap3223_pins: ap3223_pinmux { + pins = "gpio22"; + function = "gpio"; + bias-none; + }; + + i2c7_pins: i2c7_pinmux { + mux { + pins = "gpio8", "gpio9"; + function = "gsbi7"; + }; + data { + pins = "gpio8"; + bias-disable; + }; + clk { + pins = "gpio9"; + bias-disable; + }; + }; +}; + +&gsbi7 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi7_i2c { + status = "okay"; + clock-frequency = <100000>; + pinctrl-0 = <&i2c7_pins>; + pinctrl-names = "default"; + + ap3223@1c { + compatible = "dynaimage,ap3223"; + reg = <0x1c>; + + pinctrl-0 = <&ap3223_pins>; + pinctrl-names = "default"; + + int-gpio = <&qcom_pinmux 22 GPIO_ACTIVE_LOW>; + }; + + led-controller@32 { + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = /bits/ 8 <1>; + #address-cells = <1>; + #size-cells = <0>; + + led@4 { + reg = <4>; + color = ; + chan-name = "green:status"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0xfa>; + max-cur = /bits/ 8 <0xff>; + }; + + led@5 { + reg = <5>; + color = ; + chan-name = "blue:status"; + led-cur = /bits/ 8 <0xfa>; + max-cur = /bits/ 8 <0xff>; + }; + + led@8 { + reg = <8>; + color = ; + chan-name = "red:status"; + led-cur = /bits/ 8 <0xfa>; + max-cur = /bits/ 8 <0xff>; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-c2600.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-c2600.dts new file mode 100644 index 00000000000..cef1aba3444 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-c2600.dts @@ -0,0 +1,119 @@ +#include "qcom-ipq8064-ad7200-c2600.dtsi" + +/ { + model = "TP-Link Archer C2600"; + compatible = "tplink,c2600", "qcom,ipq8064"; + + aliases { + led-boot = &power; + led-failsafe = &general; + led-running = &power; + led-upgrade = &general; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 49 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ledswitch { + label = "ledswitch"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + lan { + label = "white:lan"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_HIGH>; + }; + + usb4 { + label = "white:usb_4"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb_2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_LOW>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + general: general { + label = "white:general"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio16", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio7", "gpio8", "gpio9", "gpio26", "gpio33", + "gpio53", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-d7800.dts new file mode 100644 index 00000000000..b8273c614ae --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-d7800.dts @@ -0,0 +1,394 @@ +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 D7800"; + compatible = "netgear,d7800", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + rsvd@5fe00000 { + reg = <0x5fe00000 0x200000>; + reusable; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>, <&precal_art_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(1)>; + }; + }; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>, <&precal_art_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(2)>; + }; + }; +}; + +&pcie2 { + status = "okay"; + reset-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie2_pins>; + pinctrl-names = "default"; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + precal_art_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_art_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + + ubi@1880000 { + label = "ubi"; + reg = <0x1880000 0x6080000>; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-db149.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-db149.dts new file mode 100644 index 00000000000..f628df919b4 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-db149.dts @@ -0,0 +1,179 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +/ { + model = "Qualcomm IPQ8064/DB149"; + compatible = "qcom,ipq8064-db149", "qcom,ipq8064"; + + aliases { + serial0 = &gsbi2_serial; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; +}; + +&qcom_pinmux { + rgmii0_pins: rgmii0_pins { + mux { + pins = "gpio2", "gpio66"; + drive-strength = <8>; + bias-disable; + }; + }; +}; + +&gsbi2 { + qcom,mode = ; + status = "okay"; + + gsbi2_serial: serial@12490000 { + status = "okay"; + }; +}; + +&gsbi4 { + status = "disabled"; +}; + +&gsbi4_serial { + status = "disabled"; +}; + +&flash { + m25p,fast-read; + + partition@0 { + label = "lowlevel_init"; + reg = <0x0 0x1b0000>; + }; + + partition@1 { + label = "u-boot"; + reg = <0x1b0000 0x80000>; + }; + + partition@2 { + label = "u-boot-env"; + reg = <0x230000 0x40000>; + }; + + partition@3 { + label = "caldata"; + reg = <0x270000 0x40000>; + }; + + partition@4 { + label = "firmware"; + reg = <0x2b0000 0x1d50000>; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + phy6: ethernet-phy@6 { + reg = <6>; + }; + + phy7: ethernet-phy@7 { + reg = <7>; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + phy-handle = <&phy4>; + + pinctrl-0 = <&rgmii0_pins>; + pinctrl-names = "default"; +}; + +&gmac1 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + phy-handle = <&phy6>; +}; + +&gmac3 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <3>; + phy-handle = <&phy7>; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts new file mode 100644 index 00000000000..9d82d52d273 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea7500-v1.dts @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-eax500.dtsi" + +/ { + model = "Linksys EA7500 V1 WiFi Router"; + compatible = "linksys,ea7500-v1", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + chosen { + /* look for root deviceblock nbr in this bootarg */ + find-rootblock = "ubi.mtd="; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power: power { + label = "white:power"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio65", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&partitions { + partition@5f80000 { + label = "sysdiag"; + reg = <0x5f80000 0x100000>; + }; + + partition@6080000 { + label = "syscfg"; + reg = <0x6080000 0x1f80000>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts new file mode 100644 index 00000000000..1c6a4bdacd0 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts @@ -0,0 +1,128 @@ +#include "qcom-ipq8064-eax500.dtsi" + +/ { + model = "Linksys EA8500 WiFi Router"; + compatible = "linksys,ea8500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &led_power; + led-failsafe = &led_power; + led-running = &led_power; + led-upgrade = &led_power; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + wps { + label = "green:wps"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + led_power: power { + label = "white:power"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + default-state = "keep"; + }; + + wifi { + label = "green:wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio65", "gpio67", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio53", "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&partitions { + partition@5f80000 { + label = "syscfg"; + reg = <0x5f80000 0x2080000>; + }; +}; + +&mdio0 { + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <1>; + qcom,rgmii_delay = <0>; + qcom,emulation = <0>; +}; + +/* LAN */ +&gmac2 { + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,emulation = <0>; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi new file mode 100644 index 00000000000..910bd86bc5f --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-eax500.dtsi @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + chosen { + bootargs = "console=ttyMSM0,115200n8"; + /* append to bootargs adding the root deviceblock nbr from bootloader */ + append-rootblock = "ubi.mtd="; + }; +}; + +&qcom_pinmux { + /* eax500 routers reuse the pcie2 reset pin for switch reset pin */ + switch_reset: switch_reset_pins { + mux { + pins = "gpio63"; + function = "gpio"; + drive-strength = <12>; + bias-pull-up; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + max-link-speed = <1>; +}; + +&pcie1 { + status = "okay"; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x0c80000>; + + partitions: partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + partition@40000 { + label = "MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + partition@180000 { + label = "SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + partition@2c0000 { + label = "SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + partition@540000 { + label = "DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + partition@660000 { + label = "SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + partition@780000 { + label = "TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + partition@a00000 { + label = "RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + art: partition@c80000 { + label = "art"; + reg = <0x0c80000 0x0140000>; + read-only; + }; + + partition@dc0000 { + label = "APPSBL"; + reg = <0x0dc0000 0x0100000>; + read-only; + }; + + partition@ec0000 { + label = "u_env"; + reg = <0x0ec0000 0x0040000>; + }; + + partition@f00000 { + label = "s_env"; + reg = <0x0f00000 0x0040000>; + }; + + partition@f40000 { + label = "devinfo"; + reg = <0x0f40000 0x0040000>; + }; + + partition@f80000 { + label = "kernel1"; + reg = <0x0f80000 0x2800000>; /* 4 MB, spill to rootfs */ + }; + + partition@1380000 { + label = "rootfs1"; + reg = <0x1380000 0x2400000>; + }; + + partition@3780000 { + label = "kernel2"; + reg = <0x3780000 0x2800000>; + }; + + partition@3b80000 { + label = "rootfs2"; + reg = <0x3b80000 0x2400000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + /* Switch from documentation require at least 10ms for reset */ + reset-gpios = <&qcom_pinmux 63 GPIO_ACTIVE_HIGH>; + reset-post-delay-us = <12000>; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x00010 0x2613a0 /* PWS_REG */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-g10.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-g10.dts new file mode 100644 index 00000000000..63a72b53ae7 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-g10.dts @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include +#include + +/ { + compatible = "asrock,g10", "qcom,ipq8064"; + model = "ASRock G10"; + + aliases { + ethernet0 = &gmac1; + ethernet1 = &gmac0; + + led-boot = &led_status_blue; + led-failsafe = &led_status_amber; + led-running = &led_status_blue; + led-upgrade = &led_status_amber; + }; + + chosen { + bootargs-override = "console=ttyMSM0,115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + /* + * this is a bit misleading. Because there are about seven + * multicolor LEDs connected all wired together in parallel. + */ + + status_yellow { + label = "yellow:status"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + led_status_amber: status_amber { + label = "amber:status"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + led_status_blue: status_blue { + label = "blue:status"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + /* + * LED is declared in vendors boardfile but it's not + * working and the manual doesn't mention anything + * about the LED being white. + + status_white { + label = "white:status"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + */ + }; + + i2c-gpio { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "i2c-gpio"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>, /* sda */ + <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>; /* scl */ + i2c-gpio,delay-us = <5>; + i2c-gpio,scl-output-only; + + mcu@50 { + reg = <0x50>; + compatible = "sonix,sn8f25e21"; + }; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + ir-remote { + label = "ir-remote"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps5g { + label = "wps5g"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps2g { + label = "wps2g"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1200000>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi5g: wifi@1,0 { + reg = <0x00010000 0 0 0 0>; + compatible = "qcom,ath10k"; + qcom,ath10k-calibration-variant = "ASRock-G10"; + }; + }; +}; + +&pcie1 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2g: wifi@1,0 { + reg = <0x00010000 0 0 0 0>; + compatible = "qcom,ath10k"; + qcom,ath10k-calibration-variant = "ASRock-G10"; + }; + }; +}; + +&qcom_pinmux { + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio26"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio15", "gpio16", "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; +}; + +&rpm { + pinctrl-0 = <&i2c4_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&tcsr { + qcom,usb-ctrl-select = ; +}; + +/delete-node/ &pcie2_pins; +/delete-node/ &pcie2; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-onhub.dtsi b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-onhub.dtsi new file mode 100644 index 00000000000..549c4620261 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-onhub.dtsi @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014 The ChromiumOS Authors + */ + +#include "qcom-ipq8064-smb208.dtsi" +#include +#include +#include + +/ { + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac2; + mdio-gpio0 = &mdio; + serial0 = &gsbi4_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + dev { + label = "dev"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + mdio: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>, + <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&mdio_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + }; + + soc { + rng@1a500000 { + status = "disabled"; + }; + + sound { + compatible = "google,storm-audio"; + qcom,model = "ipq806x-storm"; + cpu = <&lpass>; + codec = <&max98357a>; + }; + + lpass: lpass@28100000 { + status = "okay"; + pinctrl-names = "default", "idle"; + pinctrl-0 = <&mi2s_default>; + pinctrl-1 = <&mi2s_idle>; + }; + + max98357a: max98357a { + compatible = "maxim,max98357a"; + #sound-dai-cells = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmode_pins>; + sdmode-gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + rgmii0_pins: rgmii0_pins { + mux { + pins = "gpio2", "gpio66"; + drive-strength = <8>; + bias-disable; + }; + }; + mi2s_pins { + mi2s_default: mi2s_default { + dout { + pins = "gpio32"; + function = "mi2s"; + drive-strength = <16>; + bias-disable; + }; + sync { + pins = "gpio27"; + function = "mi2s"; + drive-strength = <16>; + bias-disable; + }; + clk { + pins = "gpio28"; + function = "mi2s"; + drive-strength = <16>; + bias-disable; + }; + }; + mi2s_idle: mi2s_idle { + dout { + pins = "gpio32"; + function = "mi2s"; + drive-strength = <2>; + bias-pull-down; + }; + sync { + pins = "gpio27"; + function = "mi2s"; + drive-strength = <2>; + bias-pull-down; + }; + clk { + pins = "gpio28"; + function = "mi2s"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + mdio_pins: mdio_pins { + mux { + pins = "gpio0", "gpio1"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + rst { + pins = "gpio26"; + output-low; + }; + }; + + sdmode_pins: sdmode_pinmux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + sdcc1_pins: sdcc1_pinmux { + mux { + pins = "gpio38", "gpio39", "gpio40", + "gpio41", "gpio42", "gpio43", + "gpio44", "gpio45", "gpio46", + "gpio47"; + function = "sdc1"; + }; + cmd { + pins = "gpio45"; + drive-strength = <10>; + bias-pull-up; + }; + data { + pins = "gpio38", "gpio39", "gpio40", + "gpio41", "gpio43", "gpio44", + "gpio46", "gpio47"; + drive-strength = <10>; + bias-pull-up; + }; + clk { + pins = "gpio42"; + drive-strength = <16>; + bias-pull-down; + }; + }; + + i2c1_pins: i2c1_pinmux { + pins = "gpio53", "gpio54"; + function = "gsbi1"; + bias-disable; + }; + + rpm_i2c_pinmux: rpm_i2c_pinmux { + mux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + drive-strength = <12>; + bias-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + /delete-property/ bias-none; + /delete-property/ drive-strength; + }; + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + fw_pinmux { + wp { + pins = "gpio17"; + output-low; + }; + }; + + button_pins: button_pins { + recovery { + pins = "gpio16"; + function = "gpio"; + bias-none; + }; + developer { + pins = "gpio15"; + function = "gpio"; + bias-none; + }; + }; + + spi6_pins: spi6_pins { + mux { + pins = "gpio55", "gpio56", "gpio58"; + function = "gsbi6"; + bias-pull-down; + }; + data { + pins = "gpio55", "gpio56"; + drive-strength = <10>; + }; + cs { + pins = "gpio57"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + clk { + pins = "gpio58"; + drive-strength = <12>; + }; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + phy-handle = <&phy1>; + + pinctrl-0 = <&rgmii0_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + phy-handle = <&phy0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi1 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi1_i2c { + status = "okay"; + + clock-frequency = <100000>; + + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + + tpm@20 { + compatible = "infineon,slb9645tt"; + reg = <0x20>; + powered-while-suspended; + }; +}; + +&gsbi4 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi4_serial { + status = "okay"; +}; + +&gsbi5 { + status = "okay"; + qcom,mode = ; + + spi4: spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 0>; + + flash: flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + }; + }; +}; + +&gsbi6 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi6_spi { + status = "okay"; + spi-max-frequency = <25000000>; + + pinctrl-0 = <&spi6_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>; + + dmas = <&adm_dma 8 0xb>, + <&adm_dma 7 0x14>; + dma-names = "rx", "tx"; + + /* + * This "spidev" was included in the manufacturer device tree. I suspect + * it's the (unused) Zigbee radio -- SiliconLabs EM3581 Zigbee? There's + * no driver or binding for this at the moment. + */ + spidev@0 { + compatible = "spidev"; + reg = <0>; + spi-max-frequency = <25000000>; + }; +}; + +&pcie0 { + status = "okay"; + + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + + ath10k@0,0 { + reg = <0 0 0 0 0>; + device_type = "pci"; + qcom,ath10k-sa-gpio = <2 3 4 0>; + qcom,ath10k-sa-gpio-func = <5 5 5 0>; + }; + }; +}; + +&pcie1 { + status = "okay"; + + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + + ath10k@0,0 { + reg = <0 0 0 0 0>; + device_type = "pci"; + qcom,ath10k-sa-gpio = <2 3 4 0>; + qcom,ath10k-sa-gpio-func = <5 5 5 0>; + }; + }; +}; + +&pcie2 { + status = "okay"; + + pcie@0 { + reg = <0 0 0 0 0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + device_type = "pci"; + + ath10k@0,0 { + reg = <0 0 0 0 0>; + device_type = "pci"; + }; + }; +}; + +&rpm { + pinctrl-0 = <&rpm_i2c_pinmux>; + pinctrl-names = "default"; +}; + +&sdcc1 { + status = "okay"; + pinctrl-0 = <&sdcc1_pins>; + pinctrl-names = "default"; + /delete-property/ mmc-ddr-1_8v; +}; + +&tcsr { + compatible = "qcom,tcsr-ipq8064", "qcom,tcsr", "syscon"; + qcom,usb-ctrl-select = ; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500.dts new file mode 100644 index 00000000000..7bea5b6bceb --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500.dts @@ -0,0 +1,327 @@ +#include "qcom-ipq8064-v1.0.dtsi" + +#include +#include + +/ { + model = "Netgear Nighthawk X4 R7500"; + compatible = "netgear,r7500", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0xe000000>; + device_type = "memory"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + rsvd@41200000 { + reg = <0x41200000 0x300000>; + no-map; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&gsbi5 { + status = "disabled"; + + spi@1a280000 { + status = "disabled"; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + }; + + kernel@1340000 { + label = "kernel"; + reg = <0x1340000 0x0400000>; + }; + + ubi@1740000 { + label = "ubi"; + reg = <0x1740000 0x1600000>; + }; + + netgear@2d40000 { + label = "netgear"; + reg = <0x2d40000 0x0c00000>; + read-only; + }; + + reserve@3940000 { + label = "reserve"; + reg = <0x3940000 0x46c0000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&tcsr { + qcom,usb-ctrl-select = ; + compatible = "qcom,tcsr"; +}; + +&adm_dma { + status = "okay"; +}; + +&art { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts new file mode 100644 index 00000000000..6f0ba09c872 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts @@ -0,0 +1,387 @@ +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + model = "Netgear Nighthawk X4 R7500v2"; + compatible = "netgear,r7500v2", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + rsvd@5fe00000 { + reg = <0x5fe00000 0x200000>; + reusable; + }; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb1 { + label = "amber:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb3 { + label = "amber:usb3"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + status { + label = "amber:status"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + internet { + label = "white:internet"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan { + label = "white:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23", + "gpio24","gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>, <&precal_art_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(1)>; + }; + }; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_art_6>, <&precal_art_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(2)>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1180000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + qcadata@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + APPSBL@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + APPSBLENV@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + precal_art_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_art_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + artbak: art@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + kernel@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + + ubi@1880000 { + label = "ubi"; + reg = <0x1880000 0x6080000>; + }; + + reserve@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-tplink-onhub.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-tplink-onhub.dts new file mode 100644 index 00000000000..6adc6be4aec --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-tplink-onhub.dts @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2014 The ChromiumOS Authors + */ + +#include "qcom-ipq8064-onhub.dtsi" +#include +#include +#include + +/ { + model = "TP-Link OnHub"; + compatible = "tplink,onhub", "google,whirlwind-sp5", "qcom,ipq8064"; +}; + +&qcom_pinmux { + i2c7_pins: i2c7_pinmux { + mux { + pins = "gpio8", "gpio9"; + function = "gsbi7"; + }; + data { + pins = "gpio8"; + bias-disable; + }; + clk { + pins = "gpio9"; + bias-disable; + }; + }; +}; + +&gsbi7 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi7_i2c { + status = "okay"; + clock-frequency = <100000>; + pinctrl-0 = <&i2c7_pins>; + pinctrl-names = "default"; + + led-controller@32 { + compatible = "national,lp5523"; + reg = <0x32>; + clock-mode = /bits/ 8 <1>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + chan-name = "red:status-0"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@1 { + reg = <1>; + color = ; + chan-name = "green:status-0"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@2 { + reg = <2>; + color = ; + chan-name = "blue:status-0"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@3 { + reg = <3>; + color = ; + chan-name = "red:status-1"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@4 { + reg = <4>; + color = ; + chan-name = "green:status-1"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@5 { + reg = <5>; + color = ; + chan-name = "blue:status-1"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@6 { + reg = <6>; + color = ; + chan-name = "red:status-2"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@7 { + reg = <7>; + color = ; + chan-name = "green:status-2"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@8 { + reg = <8>; + color = ; + chan-name = "blue:status-2"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + }; + + led-controller@33 { + compatible = "national,lp5523"; + reg = <0x33>; + clock-mode = /bits/ 8 <1>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + chan-name = "red:status-3"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@1 { + reg = <1>; + color = ; + chan-name = "green:status-3"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@2 { + reg = <2>; + color = ; + chan-name = "blue:status-3"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@3 { + reg = <3>; + color = ; + chan-name = "red:status-4"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@4 { + reg = <4>; + color = ; + chan-name = "green:status-4"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@5 { + reg = <5>; + color = ; + chan-name = "blue:status-4"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@6 { + reg = <6>; + color = ; + chan-name = "red:status-5"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@7 { + reg = <7>; + color = ; + chan-name = "green:status-5"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + + led@8 { + reg = <8>; + color = ; + chan-name = "blue:status-5"; + linux,default-trigger = "default-on"; + led-cur = /bits/ 8 <0x64>; + max-cur = /bits/ 8 <0x78>; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts new file mode 100644 index 00000000000..90927ddb856 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-unifi-ac-hd.dts @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include +#include + +/ { + model = "Ubiquiti UniFi AC HD"; + compatible = "ubnt,unifi-ac-hd", "qcom,ipq8064"; + + aliases { + label-mac-device = &gmac2; + led-boot = &led_dome_white; + led-failsafe = &led_dome_white; + led-running = &led_dome_blue; + led-upgrade = &led_dome_blue; + mdio-gpio0 = &mdio0; + ethernet0 = &gmac2; + ethernet1 = &gmac1; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_dome_blue: dome_blue { + label = "blue:dome"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + led_dome_white: dome_white { + label = "white:dome"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio9", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + drive-strength = <10>; + bias-none; + }; + + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; +}; + +&CPU_SPC { + status = "disabled"; +}; + +&gsbi5 { + status = "okay"; + + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + cs-gpios = <&qcom_pinmux 20 0>; + + flash@0 { + compatible = "mx25u25635f", "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + m25p,fast-read; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x20000 0x10000>; + read-only; + }; + + partition@30000 { + label = "SBL2"; + reg = <0x30000 0x20000>; + read-only; + }; + + partition@50000 { + label = "SBL3"; + reg = <0x50000 0x30000>; + read-only; + }; + + partition@80000 { + label = "DDRCONFIG"; + reg = <0x80000 0x10000>; + read-only; + }; + + partition@90000 { + label = "SSD"; + reg = <0x90000 0x10000>; + read-only; + }; + + partition@a0000 { + label = "TZ"; + reg = <0xa0000 0x30000>; + read-only; + }; + + partition@d0000 { + label = "RPM"; + reg = <0xd0000 0x20000>; + read-only; + }; + + partition@f0000 { + label = "APPSBL"; + reg = <0xf0000 0xc0000>; + read-only; + }; + + partition@1b0000 { + label = "APPSBLENV"; + reg = <0x1b0000 0x10000>; + read-only; + }; + + eeprom: partition@1c0000 { + label = "EEPROM"; + reg = <0x1c0000 0x10000>; + read-only; + }; + + partition@1d0000 { + label = "bootselect"; + reg = <0x1d0000 0x10000>; + }; + + partition@1e0000 { + compatible = "denx,fit"; + label = "firmware"; + reg = <0x1e0000 0xe70000>; + }; + + partition@1050000 { + label = "kernel1"; + reg = <0x1050000 0xe70000>; + read-only; + }; + + partition@1ec0000 { + label = "debug"; + reg = <0x1ec0000 0x100000>; + read-only; + }; + + partition@1fc0000 { + label = "cfg"; + reg = <0x1fc0000 0x40000>; + read-only; + }; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&nand { + status = "okay"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy4: ethernet-phy@4 { + reg = <4>; + }; + + phy5: ethernet-phy@5 { + reg = <5>; + }; +}; + +&gmac1 { + status = "okay"; + + mdiobus = <&mdio0>; + phy-handle = <&phy5>; + phy-mode = "sgmii"; + qcom,id = <1>; + + nvmem-cells = <&macaddr_eeprom_6>; + nvmem-cell-names = "mac-address"; +}; + +&gmac2 { + status = "okay"; + + mdiobus = <&mdio0>; + phy-handle = <&phy4>; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_eeprom_0>; + nvmem-cell-names = "mac-address"; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; +}; + +&tcsr { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&eeprom { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_eeprom_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_eeprom_6: macaddr@6 { + reg = <0x6 0x6>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts new file mode 100644 index 00000000000..b0db8c88635 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts @@ -0,0 +1,424 @@ +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + model = "TP-Link Archer VR2600v"; + compatible = "tplink,vr2600v", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power; + led-failsafe = &general; + led-running = &power; + led-upgrade = &general; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + dect { + label = "dect"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ledswitch { + label = "ledswitch"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + dsl { + label = "white:dsl"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "white:usb"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + lan { + label = "white:lan"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wlan2g { + label = "white:wlan2g"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan5g { + label = "white:wlan5g"; + gpios = <&qcom_pinmux 17 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + phone { + label = "white:phone"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + wan { + label = "white:wan"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + general: general { + label = "white:general"; + gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio16", "gpio17", + "gpio26", "gpio53", "gpio56", "gpio66"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio54", "gpio64", "gpio65", "gpio67", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + partition@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + partition@40000 { + label = "SBL2"; + reg = <0x40000 0x40000>; + read-only; + }; + + partition@80000 { + label = "SBL3"; + reg = <0x80000 0x80000>; + read-only; + }; + + partition@100000 { + label = "DDRCONFIG"; + reg = <0x100000 0x10000>; + read-only; + }; + + partition@110000 { + label = "SSD"; + reg = <0x110000 0x10000>; + read-only; + }; + + partition@120000 { + label = "TZ"; + reg = <0x120000 0x80000>; + read-only; + }; + + partition@1a0000 { + label = "RPM"; + reg = <0x1a0000 0x80000>; + read-only; + }; + + partition@220000 { + label = "APPSBL"; + reg = <0x220000 0x80000>; + read-only; + }; + + partition@2a0000 { + label = "APPSBLENV"; + reg = <0x2a0000 0x40000>; + read-only; + }; + + partition@2e0000 { + label = "OLDART"; + reg = <0x2e0000 0x40000>; + read-only; + }; + + partition@320000 { + label = "firmware"; + reg = <0x320000 0xc60000>; + compatible = "openwrt,uimage"; + openwrt,offset = <512>; /* account for pad-extra 512 */ + }; + + /* hole 0xf80000 - 0xfaf100 */ + + partition@faf100 { + label = "default-mac"; + reg = <0xfaf100 0x00200>; + read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_defaultmac_0: macaddr@0 { + reg = <0x0 0x6>; + }; + }; + + partition@fc0000 { + label = "ART"; + reg = <0xfc0000 0x40000>; + read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_defaultmac_0>, <&precal_ART_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(-1)>; + }; + }; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_defaultmac_0>, <&precal_ART_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_defaultmac_0>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_defaultmac_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts new file mode 100644 index 00000000000..431c9cd9af8 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wg2600hp.dts @@ -0,0 +1,463 @@ +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + model = "NEC Aterm WG2600HP"; + compatible = "nec,wg2600hp", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + + led-boot = &power_green; + led-failsafe = &power_red; + led-running = &power_green; + led-upgrade = &power_green; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + bridge { + label = "bridge"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + converter { + label = "converter"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + converter_green { + label = "green:converter"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_HIGH>; + }; + + power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + active_green { + label = "green:active"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + active_red { + label = "red:active"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 14 GPIO_ACTIVE_HIGH>; + }; + + converter_red { + label = "red:converter"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_red { + label = "red:wlan2g"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>; + }; + + wlan5g_red { + label = "red:wlan5g"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_HIGH>; + }; + + tv_green { + label = "green:tv"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + tv_red { + label = "red:tv"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&CPU_SPC { + status = "disabled"; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x06000000 /* PAD0_MODE */ + 0x0000c 0x00080080 /* PAD6_MODE */ + 0x000e4 0x0006a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x0000004e /* PORT0_STATUS */ + 0x00094 0x0000004e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_PRODUCTDATA_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_PRODUCTDATA_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi5 { + status = "okay"; + + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x20000>; + read-only; + }; + + MIBIB@20000 { + label = "MIBIB"; + reg = <0x20000 0x20000>; + read-only; + }; + + SBL2@40000 { + label = "SBL2"; + reg = <0x40000 0x40000>; + read-only; + }; + + SBL3@80000 { + label = "SBL3"; + reg = <0x80000 0x80000>; + read-only; + }; + + DDRCONFIG@100000 { + label = "DDRCONFIG"; + reg = <0x100000 0x10000>; + read-only; + }; + + SSD@110000 { + label = "SSD"; + reg = <0x110000 0x10000>; + read-only; + }; + + TZ@120000 { + label = "TZ"; + reg = <0x120000 0x80000>; + read-only; + }; + + RPM@1a0000 { + label = "RPM"; + reg = <0x1a0000 0x80000>; + read-only; + }; + + APPSBL@220000 { + label = "APPSBL"; + reg = <0x220000 0x80000>; + read-only; + }; + + APPSBLENV@2a0000 { + label = "APPSBLENV"; + reg = <0x2a0000 0x10000>; + }; + + PRODUCTDATA: PRODUCTDATA@2b0000 { + label = "PRODUCTDATA"; + reg = <0x2b0000 0x30000>; + read-only; + }; + + ART@2e0000 { + label = "ART"; + reg = <0x2e0000 0x40000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + TP@320000 { + label = "TP"; + reg = <0x320000 0x40000>; + read-only; + }; + + TINY@360000 { + label = "TINY"; + reg = <0x360000 0x500000>; + read-only; + }; + + firmware@860000 { + compatible = "denx,uimage"; + label = "firmware"; + reg = <0x860000 0x17a0000>; + }; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_PRODUCTDATA_12>, <&precal_ART_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_PRODUCTDATA_c>, <&precal_ART_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio16", "gpio54", "gpio24", "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio6", "gpio7", "gpio8", "gpio9", "gpio14", + "gpio15", "gpio55", "gpio56", "gpio57", "gpio58", + "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb_pwr_en_pins: usb_pwr_en_pins { + mux { + pins = "gpio22"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + output-high; + }; + }; +}; + +&PRODUCTDATA { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_PRODUCTDATA_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_PRODUCTDATA_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + macaddr_PRODUCTDATA_c: macaddr@c { + reg = <0xc 0x6>; + }; + + macaddr_PRODUCTDATA_12: macaddr@12 { + reg = <0x12 0x6>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts new file mode 100644 index 00000000000..359b4cd470c --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2017 Christian Mehlis + * Copyright (C) 2018 Mathias Kresin + * All rights reserved. + */ + +#include "qcom-ipq8064-v1.0.dtsi" + +#include +#include + +/ { + compatible = "compex,wpq864", "qcom,ipq8064"; + model = "Compex WPQ864"; + + aliases { + mdio-gpio0 = &mdio0; + ethernet0 = &gmac1; + ethernet1 = &gmac0; + + led-boot = &led_pass; + led-failsafe = &led_fail; + led-running = &led_pass; + led-upgrade = &led_pass; + }; + + leds { + compatible = "gpio-leds"; + + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + rss4 { + label = "green:rss4"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + rss3 { + label = "green:rss3"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + rss2 { + label = "orange:rss2"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>; + }; + + rss1 { + label = "red:rss1"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + led_pass: pass { + label = "green:pass"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + led_fail: fail { + label = "green:fail"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + usb { + label = "green:usb"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb-pcie { + label = "green:usb-pcie"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + beeper { + compatible = "gpio-beeper"; + + pinctrl-0 = <&beeper_pins>; + pinctrl-names = "default"; + + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; +}; + +&rpm { + pinctrl-0 = <&rpm_pins>; + pinctrl-names = "default"; +}; + +&nand { + status = "okay"; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + mt29f2g08abbeah4@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1180000 0x5340000 0x10c0000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + partition@40000 { + label = "0:MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + partition@180000 { + label = "0:SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + partition@2c0000 { + label = "0:SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + partition@540000 { + label = "0:DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + partition@660000 { + label = "0:SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + partition@780000 { + label = "0:TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + partition@a00000 { + label = "0:RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + partition@c80000 { + label = "0:APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + partition@1180000 { + label = "0:APPSBLENV"; + reg = <0x1180000 0x0080000>; + }; + + partition@1200000 { + label = "0:ART"; + reg = <0x1200000 0x0140000>; + }; + + partition@1340000 { + label = "ubi"; + reg = <0x1340000 0x4000000>; + }; + + partition@5340000 { + label = "0:BOOTCONFIG"; + reg = <0x5340000 0x0060000>; + }; + + partition@53a0000 { + label = "0:SBL2_1"; + reg = <0x53a0000 0x0140000>; + read-only; + }; + + partition@54e0000 { + label = "0:SBL3_1"; + reg = <0x54e0000 0x0280000>; + read-only; + }; + + partition@5760000 { + label = "0:DDRCONFIG_1"; + reg = <0x5760000 0x0120000>; + read-only; + }; + + partition@5880000 { + label = "0:SSD_1"; + reg = <0x5880000 0x0120000>; + read-only; + }; + + partition@59a0000 { + label = "0:TZ_1"; + reg = <0x59a0000 0x0280000>; + read-only; + }; + + partition@5c20000 { + label = "0:RPM_1"; + reg = <0x5c20000 0x0280000>; + read-only; + }; + + partition@5ea0000 { + label = "0:BOOTCONFIG1"; + reg = <0x5ea0000 0x0060000>; + }; + + partition@5f00000 { + label = "0:APPSBL_1"; + reg = <0x5f00000 0x0500000>; + read-only; + }; + + partition@6400000 { + label = "ubi_1"; + reg = <0x6400000 0x4000000>; + }; + + partition@a400000 { + label = "unused"; + reg = <0xa400000 0x5c00000>; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&flash { + compatible = "jedec,spi-nor"; +}; + +&sata_phy { + status = "disabled"; +}; + +&sata { + status = "disabled"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; + + rx_eq = <2>; + tx_deamp_3_5db = <32>; + mpll = <160>; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; + + rx_eq = <2>; + tx_deamp_3_5db = <32>; + mpll = <160>; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; +}; + +&pcie1 { + status = "okay"; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; +}; + +&qcom_pinmux { + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pinctrl0 { + pcie0_pcie2_perst { + pins = "gpio3"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + beeper_pins: beeper_pins { + mux { + pins = "gpio55"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + rpm_pins: rpm_pins { + mux { + pins = "gpio12", "gpio13"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <10>; + bias-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; +}; + +&tcsr { + qcom,usb-ctrl-select = ; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts new file mode 100644 index 00000000000..39fd81fe553 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8064-wxr-2533dhp.dts @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include + +/ { + model = "Buffalo WXR-2533DHP"; + compatible = "buffalo,wxr-2533dhp", "qcom,ipq8064"; + + memory@42000000 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &power; + led-failsafe = &diag; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + /* use "ubi_rootfs" volume in "ubi" partition as rootfs */ + bootargs = "ubi.block=0,1 root=/dev/ubiblock0_1 rootfstype=squashfs"; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + usb { + label = "green:usb"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "usbport"; + trigger-sources = <&hub_port0 &hub_port1>; + }; + + guestport { + label = "green:guestport"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + diag: diag { + label = "orange:diag"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + internet_orange { + label = "orange:internet"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + internet_white { + label = "white:internet"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wireless_orange { + label = "orange:wireless"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wireless_white { + label = "white:wireless"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + router_orange { + label = "orange:router"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>; + }; + + router_white { + label = "white:router"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + power { + label = "power"; + gpios = <&qcom_pinmux 58 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + eject { + label = "eject"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + guest { + label = "guest"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + ap { + label = "ap"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + router { + label = "router"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + auto { + label = "auto"; + gpios = <&qcom_pinmux 57 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + }; +}; + +&nand { + status = "okay"; + + cs@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + ubi@0 { + label = "ubi"; + reg = <0x0000000 0x4000000>; + }; + + rootfs_1@4000000 { + label = "rootfs_1"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x07600000 /* PAD0_MODE */ + 0x00008 0x01000000 /* PAD5_MODE */ + 0x0000c 0x00000080 /* PAD6_MODE */ + 0x00050 0xcc35cc35 /* LED_CTRL0 */ + 0x00054 0xca35ca35 /* LED_CTRL1 */ + 0x00058 0xc935c935 /* LED_CTRL2 */ + 0x0005c 0x03ffff00 /* LED_CTRL3 */ + 0x000e4 0x0006a545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x0000007e /* PORT0_STATUS */ + 0x00094 0x0000007e /* PORT6_STATUS */ + >; + }; + + ethernet-phy@4 { + reg = <4>; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_ART_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + + nvmem-cells = <&macaddr_ART_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gsbi4_serial { + pinctrl-0 = <&uart0_pins>; + pinctrl-names = "default"; +}; + +&gsbi5 { + status = "okay"; + qcom,mode = ; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "jedec,spi-nor"; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + SBL1@0 { + label = "SBL1"; + reg = <0x0 0x10000>; + read-only; + }; + + MIBIB@10000 { + label = "MIBIB"; + reg = <0x10000 0x20000>; + read-only; + }; + + SBL2@30000 { + label = "SBL2"; + reg = <0x30000 0x30000>; + read-only; + }; + + SBL3@60000 { + label = "SBL3"; + reg = <0x60000 0x30000>; + read-only; + }; + + DDRCONFIG@90000 { + label = "DDRCONFIG"; + reg = <0x90000 0x10000>; + read-only; + }; + + SSD@a0000 { + label = "SSD"; + reg = <0xa0000 0x10000>; + read-only; + }; + + TZ@b0000 { + label = "TZ"; + reg = <0xb0000 0x30000>; + read-only; + }; + + RPM@e0000 { + label = "RPM"; + reg = <0xe0000 0x20000>; + read-only; + }; + + APPSBL@100000 { + label = "APPSBL"; + reg = <0x100000 0x70000>; + read-only; + }; + + APPSBLENV@170000 { + label = "APPSBLENV"; + reg = <0x170000 0x10000>; + read-only; + }; + + ART@180000 { + label = "ART"; + reg = <0x180000 0x40000>; + read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_ART_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_ART_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + macaddr_ART_18: macaddr@18 { + reg = <0x18 0x6>; + }; + + macaddr_ART_1e: macaddr@1e { + reg = <0x1e 0x6>; + }; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + BOOTCONFIG@1c0000 { + label = "BOOTCONFIG"; + reg = <0x1c0000 0x10000>; + read-only; + }; + + APPSBL_1@1d0000 { + label = "APPSBL_1"; + reg = <0x1d0000 0x70000>; + read-only; + }; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&dwc3_0 { + #address-cells = <1>; + #size-cells = <0>; + + hub_port0: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; +}; + +&dwc3_1 { + #address-cells = <1>; + #size-cells = <0>; + + hub_port1: port@1 { + reg = <1>; + #trigger-source-cells = <0>; + }; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_ART_1e>, <&precal_ART_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&pcie1 { + status = "okay"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&macaddr_ART_18>, <&precal_ART_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio55", "gpio56", "gpio57", + "gpio58", "gpio64", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", "gpio16", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio53"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart0_pins: uart0_pins { + mux { + pins = "gpio10", "gpio11"; + function = "gsbi4"; + drive-strength = <12>; + bias-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs{ + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + usb_pwr_en_pins: usb_pwr_en_pins { + mux{ + pins = "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + output-high; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-ac400i.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-ac400i.dts new file mode 100644 index 00000000000..7151f8de525 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-ac400i.dts @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8065-smb208.dtsi" +#include + +/ { + model = "Nokia AC400i"; + compatible = "nokia,ac400i", "qcom,ipq8065", "qcom,ipq8064"; + + aliases { + mdio-gpio0 = &mdio0; + ethernet0 = &gmac0; + ethernet1 = &gmac1; + + led-boot = &pwr_red; + led-failsafe = &pwr_red; + led-running = &pwr_green; + led-upgrade = &pwr_green; + }; + + chosen { + bootargs-override = " console=ttyMSM0,115200n8 ubi.mtd=ubi root=/dev/ubiblock0_2"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 15 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + 5g_red { + label = "red:5g"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_HIGH>; + }; + + 5g_green { + label = "green:5g"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + 2g_red { + label = "red:2g"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + }; + + 2g_green { + label = "green:2g"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>; + }; + + eth1_red { + label = "red:eth1"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_HIGH>; + }; + + eth1_green { + label = "green:eth1"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_LOW>; + }; + + eth2_red { + label = "red:eth2"; + gpios = <&qcom_pinmux 67 GPIO_ACTIVE_HIGH>; + }; + + eth2_green { + label = "green:eth2"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_LOW>; + }; + + ctrl_red { + label = "red:ctrl"; + gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>; + }; + + ctrl_green { + label = "green:ctrl"; + gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>; + }; + + pwr_red: pwr_red { + label = "red:pwr"; + gpios = <&qcom_pinmux 2 GPIO_ACTIVE_LOW>; + }; + + pwr_green: pwr_green { + label = "green:pwr"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio65", "gpio64", + "gpio53", "gpio54", + "gpio68", "gpio22", + "gpio67", "gpio23", + "gpio55", "gpio56", + "gpio2", "gpio26"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Nokia-AC400i"; + }; + }; +}; + +&pcie1 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Nokia-AC400i"; + }; + }; +}; + +&mdio0 { + status = "okay"; + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; + +}; + +//POE +&gmac0 { + status = "okay"; + qcom,id = <0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + mdiobus = <&mdio0>; + phy-handle = <&phy0>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +//LAN1 +&gmac1 { + status = "okay"; + qcom,id = <1>; + + mdiobus = <&mdio0>; + phy-handle = <&phy1>; + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&nand { + status = "okay"; + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + rootfs@0 { + label = "rootfs"; + reg = <0x0000000 0x4000000>; + }; + + rootfs_1@4000000 { + label = "rootfs_1"; + reg = <0x4000000 0x4000000>; + }; + + cfg@8000000 { + label = "cfg"; + reg = <0x8000000 0x8000000>; + }; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts new file mode 100644 index 00000000000..162b28d27fb --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -0,0 +1,332 @@ +#include "qcom-ipq8065-smb208.dtsi" + +#include + +/ { + model = "ZyXEL NBG6817"; + compatible = "zyxel,nbg6817", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + mdio-gpio0 = &mdio0; + sdcc1 = &sdcc1; + + led-boot = &power; + led-failsafe = &power; + led-running = &power; + led-upgrade = &power; + }; + + chosen { + bootargs = "rootfstype=squashfs,ext4 rootwait noinitrd fstools_ignore_partname=1"; + append-rootblock = "root=/dev/mmcblk0p"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>; + linux,code = ; + linux,input-type = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + internet { + label = "white:internet"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + power: power { + label = "white:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + wifi2g { + label = "amber:wifi2g"; + gpios = <&qcom_pinmux 33 GPIO_ACTIVE_HIGH>; + }; + + /* wifi2g amber from the manual is missing */ + + wifi5g { + label = "amber:wifi5g"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; + + /* wifi5g amber from the manual is missing */ + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio53", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio9", "gpio26", "gpio33", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + mdio0_pins: mdio0-pins { + clk { + pins = "gpio1"; + input-disable; + }; + }; + + rgmii2_pins: rgmii2-pins { + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32" ; + input-disable; + }; + }; + + spi_pins: spi_pins { + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio16", "gpio17"; + function = "gpio"; + drive-strength = <12>; + }; + + pwr { + pins = "gpio17"; + bias-pull-down; + output-high; + }; + + ovc { + pins = "gpio16"; + bias-pull-up; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio14", "gpio15"; + function = "gpio"; + drive-strength = <12>; + }; + + pwr { + pins = "gpio14"; + bias-pull-down; + output-high; + }; + + ovc { + pins = "gpio15"; + bias-pull-up; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <51200000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00970 0x1e864443 /* QM_PORT0_CTRL0 */ + 0x00974 0x000001c6 /* QM_PORT0_CTRL1 */ + 0x00978 0x19008643 /* QM_PORT1_CTRL0 */ + 0x0097c 0x000001c6 /* QM_PORT1_CTRL1 */ + 0x00980 0x19008643 /* QM_PORT2_CTRL0 */ + 0x00984 0x000001c6 /* QM_PORT2_CTRL1 */ + 0x00988 0x19008643 /* QM_PORT3_CTRL0 */ + 0x0098c 0x000001c6 /* QM_PORT3_CTRL1 */ + 0x00990 0x19008643 /* QM_PORT4_CTRL0 */ + 0x00994 0x000001c6 /* QM_PORT4_CTRL1 */ + 0x00998 0x1e864443 /* QM_PORT5_CTRL0 */ + 0x0099c 0x000001c6 /* QM_PORT5_CTRL1 */ + 0x009a0 0x1e864443 /* QM_PORT6_CTRL0 */ + 0x009a4 0x000001c6 /* QM_PORT6_CTRL1 */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,ar8327-initvals = < + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x0000c 0x80 /* PAD6_MODE */ + >; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <1>; + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <0>; + qcom,rgmii_delay = <1>; + qcom,phy_mii_type = <0>; + qcom,emulation = <0>; + qcom,irq = <255>; + mdiobus = <&mdio0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <2>; + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,phy_mii_type = <1>; + qcom,emulation = <0>; + qcom,irq = <258>; + mdiobus = <&mdio0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&amba { + sdcc1: sdcc@12400000 { + status = "okay"; + }; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nighthawk.dtsi b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nighthawk.dtsi new file mode 100644 index 00000000000..2328c497ea1 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nighthawk.dtsi @@ -0,0 +1,466 @@ +#include "qcom-ipq8065-smb208.dtsi" + +#include + +/ { + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + reserved-memory { + rsvd@5fe00000 { + reg = <0x5fe00000 0x200000>; + reusable; + }; + + ramoops@42100000 { + compatible = "ramoops"; + reg = <0x42100000 0x40000>; + record-size = <0x4000>; + console-size = <0x4000>; + ftrace-size = <0x4000>; + pmsg-size = <0x4000>; + }; + }; + + aliases { + label-mac-device = &gmac2; + + led-boot = &power_white; + led-failsafe = &power_amber; + led-running = &power_white; + led-upgrade = &power_amber; + + mdio-gpio0 = &mdio0; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + wifi { + label = "wifi"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds: leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + power_white: power_white { + label = "white:power"; + gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + + power_amber: power_amber { + label = "amber:power"; + gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>; + }; + + wan_white { + label = "white:wan"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + wan_amber { + label = "amber:wan"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + wifi { + label = "white:wifi"; + gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>; + }; + + wps { + label = "white:wps"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54", "gpio65"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8", "gpio9", + "gpio22", "gpio23", "gpio24", + "gpio26", "gpio53", "gpio64"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + mdio0_pins: mdio0-pins { + clk { + pins = "gpio1"; + input-disable; + }; + }; + + rgmii2_pins: rgmii2-pins { + tx { + pins = "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32"; + input-disable; + }; + }; + + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; + function = "gsbi5"; + bias-pull-down; + }; + + data { + pins = "gpio18", "gpio19"; + drive-strength = <10>; + }; + + cs { + pins = "gpio20"; + drive-strength = <10>; + bias-pull-up; + }; + + clk { + pins = "gpio21"; + drive-strength = <12>; + }; + }; + + spi6_pins: spi6_pins { + mux { + pins = "gpio55", "gpio56", "gpio58"; + function = "gsbi6"; + bias-pull-down; + }; + + mosi { + pins = "gpio55"; + drive-strength = <12>; + }; + + miso { + pins = "gpio56"; + drive-strength = <14>; + }; + + cs { + pins = "gpio57"; + drive-strength = <12>; + bias-pull-up; + }; + + clk { + pins = "gpio58"; + drive-strength = <12>; + }; + + reset { + pins = "gpio33"; + drive-strength = <10>; + bias-pull-down; + output-high; + }; + }; + + usb0_pwr_en_pins: usb0_pwr_en_pins { + mux { + pins = "gpio15"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; + + usb1_pwr_en_pins: usb1_pwr_en_pins { + mux { + pins = "gpio16", "gpio68"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-high; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x1180000>; + + partitions: partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "qcadata"; + reg = <0x0000000 0x0c80000>; + read-only; + }; + + partition@c80000 { + label = "APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + partition@1180000 { + label = "APPSBLENV"; + reg = <0x1180000 0x0080000>; + read-only; + }; + + art: partition@1200000 { + label = "art"; + reg = <0x1200000 0x0140000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_art_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_art_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + precal_art_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_art_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + partition@1340000 { + label = "artbak"; + reg = <0x1340000 0x0140000>; + read-only; + }; + + partition@1480000 { + label = "kernel"; + reg = <0x1480000 0x0400000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00970 0x1e864443 /* QM_PORT0_CTRL0 */ + 0x00974 0x000001c6 /* QM_PORT0_CTRL1 */ + 0x00978 0x19008643 /* QM_PORT1_CTRL0 */ + 0x0097c 0x000001c6 /* QM_PORT1_CTRL1 */ + 0x00980 0x19008643 /* QM_PORT2_CTRL0 */ + 0x00984 0x000001c6 /* QM_PORT2_CTRL1 */ + 0x00988 0x19008643 /* QM_PORT3_CTRL0 */ + 0x0098c 0x000001c6 /* QM_PORT3_CTRL1 */ + 0x00990 0x19008643 /* QM_PORT4_CTRL0 */ + 0x00994 0x000001c6 /* QM_PORT4_CTRL1 */ + 0x00998 0x1e864443 /* QM_PORT5_CTRL0 */ + 0x0099c 0x000001c6 /* QM_PORT5_CTRL1 */ + 0x009a0 0x1e864443 /* QM_PORT6_CTRL0 */ + 0x009a4 0x000001c6 /* QM_PORT6_CTRL1 */ + >; + qca,ar8327-vlans = < + 0x1 0x5e /* VLAN1 Ports 1/2/3/4/6 */ + 0x2 0x21 /* VLAN2 Ports 0/5 */ + >; + }; + + phy4: ethernet-phy@4 { + reg = <4>; + qca,ar8327-initvals = < + 0x000e4 0x6a545 /* MAC_POWER_SEL */ + 0x0000c 0x80 /* PAD6_MODE */ + >; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + qcom,id = <1>; + qcom,phy_mdio_addr = <4>; + qcom,poll_required = <0>; + qcom,rgmii_delay = <1>; + qcom,phy_mii_type = <0>; + qcom,emulation = <0>; + qcom,irq = <255>; + mdiobus = <&mdio0>; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + nvmem-cells = <&macaddr_art_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac2 { + status = "okay"; + + phy-mode = "sgmii"; + qcom,id = <2>; + qcom,phy_mdio_addr = <0>; /* none */ + qcom,poll_required = <0>; /* no polling */ + qcom,rgmii_delay = <0>; + qcom,phy_mii_type = <1>; + qcom,emulation = <0>; + qcom,irq = <258>; + mdiobus = <&mdio0>; + + nvmem-cells = <&macaddr_art_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&sata_phy { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; + + pinctrl-0 = <&usb0_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; + + pinctrl-0 = <&usb1_pwr_en_pins>; + pinctrl-names = "default"; +}; + +&pcie0 { + status = "okay"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi0: wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + }; + }; +}; + +&pcie1 { + status = "okay"; + + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi1: wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-r7800.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-r7800.dts new file mode 100644 index 00000000000..bf7c963944b --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-r7800.dts @@ -0,0 +1,48 @@ +#include "qcom-ipq8065-nighthawk.dtsi" + +/ { + model = "Netgear Nighthawk X4S R7800"; + compatible = "netgear,r7800", "qcom,ipq8065", "qcom,ipq8064"; +}; + +&leds { + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + esata { + label = "white:esata"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; +}; + +&partitions { + partition@1880000 { + label = "ubi"; + reg = <0x1880000 0x6080000>; + }; + + partition@7900000 { + label = "reserve"; + reg = <0x7900000 0x0700000>; + read-only; + }; +}; + +&wifi0 { + nvmem-cells = <&macaddr_art_6>, <&precal_art_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(1)>; +}; + +&wifi1 { + nvmem-cells = <&macaddr_art_6>, <&precal_art_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; + mac-address-increment = <(2)>; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts new file mode 100644 index 00000000000..8d9601b6324 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-rt4230w-rev6.dts @@ -0,0 +1,418 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qcom-ipq8065-smb208.dtsi" +#include + +/ { + model = "Askey RT4230W REV6"; + compatible = "askey,rt4230w-rev6", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x3e000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &ledctrl3; + led-failsafe = &ledctrl1; + led-running = &ledctrl2; + led-upgrade = &ledctrl3; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + ledctrl1: ledctrl1 { + label = "ledctrl1"; + gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>; + }; + + ledctrl2: ledctrl2 { + label = "ledctrl2"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + ledctrl3: ledctrl3 { + label = "ledctrl3"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio54", "gpio68"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio22", "gpio23", "gpio24"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + rgmii2_pins: rgmii2-pins { + mux { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", + "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62"; + function = "rgmii2"; + drive-strength = <8>; + bias-disable; + }; + + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32"; + input-disable; + }; + }; + + spi_pins: spi_pins { + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "everspin,mr25h256"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <40000000>; + reg = <0>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + qcom,boot-partitions = <0x0 0x1180000 0x1340000 0x10c0000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + + partition@40000 { + label = "0:MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + + partition@180000 { + label = "0:SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + + partition@2c0000 { + label = "0:SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + + partition@540000 { + label = "0:DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + + partition@660000 { + label = "0:SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + + partition@780000 { + label = "0:TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + + partition@a00000 { + label = "0:RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + + partition@c80000 { + label = "0:APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + + partition@1180000 { + label = "0:APPSBLENV"; + reg = <0x1180000 0x0080000>; + }; + + partition@1200000 { + label = "0:ART"; + reg = <0x1200000 0x0140000>; + read-only; + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_ART_0: macaddr@0 { + reg = <0x0 0x6>; + }; + + macaddr_ART_6: macaddr@6 { + reg = <0x6 0x6>; + }; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + + partition@1340000 { + label = "0:BOOTCONFIG"; + reg = <0x1340000 0x0060000>; + read-only; + }; + + partition@13a0000 { + label = "0:SBL2_1"; + reg = <0x13a0000 0x0140000>; + read-only; + }; + + partition@14e0000 { + label = "0:SBL3_1"; + reg = <0x14e0000 0x0280000>; + read-only; + }; + + partition@1760000 { + label = "0:DDRCONFIG_1"; + reg = <0x1760000 0x0120000>; + read-only; + }; + + partition@1880000 { + label = "0:SSD_1"; + reg = <0x1880000 0x0120000>; + read-only; + }; + + partition@19a0000 { + label = "0:TZ_1"; + reg = <0x19a0000 0x0280000>; + read-only; + }; + + partition@1c20000 { + label = "0:RPM_1"; + reg = <0x1c20000 0x0280000>; + read-only; + }; + + partition@1ea0000 { + label = "0:BOOTCONFIG1"; + reg = <0x1ea0000 0x0060000>; + read-only; + }; + + partition@1f00000 { + label = "0:APPSBL_1"; + reg = <0x1f00000 0x0500000>; + read-only; + }; + + partition@2400000 { + label = "ubi"; + reg = <0x2400000 0x1a000000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0x0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + 0x00050 0xcf02cf02 /* LED_CTRL_0 */ + 0x00054 0xc832c832 /* LED_CTRL_1 */ + >; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + + nvmem-cells = <&macaddr_ART_0>; + nvmem-cell-names = "mac-address"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <1>; + + nvmem-cells = <&macaddr_ART_6>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi0: wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&precal_ART_1000>; + nvmem-cell-names = "pre-calibration"; + }; + }; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi1: wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&precal_ART_5000>; + nvmem-cell-names = "pre-calibration"; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts new file mode 100644 index 00000000000..7b236af253e --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-tr4400-v2.dts @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "qcom-ipq8065-smb208.dtsi" +#include + +/ { + model = "Arris TR4400 v2"; + compatible = "arris,tr4400-v2", "qcom,ipq8065", "qcom,ipq8064"; + + memory@0 { + reg = <0x42000000 0x1e000000>; + device_type = "memory"; + }; + + aliases { + led-boot = &led_status_blue; + led-failsafe = &led_status_red; + led-running = &led_status_blue; + led-upgrade = &led_status_red; + }; + + chosen { + bootargs = "rootfstype=squashfs noinitrd"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + + wps { + label = "wps"; + gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_status_red: status_red { + label = "red:status"; + gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>; + }; + + led_status_blue: status_blue { + label = "blue:status"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&qcom_pinmux { + button_pins: button_pins { + mux { + pins = "gpio6", "gpio54"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio7", "gpio8"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + rgmii2_pins: rgmii2-pins { + tx { + pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32"; + input-disable; + }; + }; + + spi_pins: spi_pins { + cs { + pins = "gpio20"; + drive-strength = <12>; + }; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi@1a280000 { + status = "okay"; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + flash@0 { + compatible = "everspin,mr25h256"; + spi-max-frequency = <40000000>; + reg = <0>; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + reg = <0>; + compatible = "qcom,nandcs"; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + qcom,boot-partitions = <0x0 0x1180000 0x5340000 0x10c0000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "0:SBL1"; + reg = <0x0000000 0x0040000>; + read-only; + }; + partition@40000 { + label = "0:MIBIB"; + reg = <0x0040000 0x0140000>; + read-only; + }; + partition@180000 { + label = "0:SBL2"; + reg = <0x0180000 0x0140000>; + read-only; + }; + partition@2c0000 { + label = "0:SBL3"; + reg = <0x02c0000 0x0280000>; + read-only; + }; + partition@540000 { + label = "0:DDRCONFIG"; + reg = <0x0540000 0x0120000>; + read-only; + }; + partition@660000 { + label = "0:SSD"; + reg = <0x0660000 0x0120000>; + read-only; + }; + partition@780000 { + label = "0:TZ"; + reg = <0x0780000 0x0280000>; + read-only; + }; + partition@a00000 { + label = "0:RPM"; + reg = <0x0a00000 0x0280000>; + read-only; + }; + partition@c80000 { + label = "0:APPSBL"; + reg = <0x0c80000 0x0500000>; + read-only; + }; + partition@1180000 { + label = "0:APPSBLENV"; + reg = <0x1180000 0x0080000>; + }; + partition@1200000 { + label = "0:ART"; + reg = <0x1200000 0x0140000>; + read-only; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + precal_ART_1000: precal@1000 { + reg = <0x1000 0x2f20>; + }; + precal_ART_5000: precal@5000 { + reg = <0x5000 0x2f20>; + }; + }; + stock_partition@1340000 { + label = "stock_rootfs"; + reg = <0x1340000 0x4000000>; + }; + partition@5340000 { + label = "0:BOOTCONFIG"; + reg = <0x5340000 0x0060000>; + read-only; + }; + partition@53a0000 { + label = "0:SBL2_1"; + reg = <0x53a0000 0x0140000>; + read-only; + }; + partition@54e0000 { + label = "0:SBL3_1"; + reg = <0x54e0000 0x0280000>; + read-only; + }; + partition@5760000 { + label = "0:DDRCONFIG_1"; + reg = <0x5760000 0x0120000>; + read-only; + }; + partition@5880000 { + label = "0:SSD_1"; + reg = <0x5880000 0x0120000>; + read-only; + }; + partition@59a0000 { + label = "0:TZ_1"; + reg = <0x59a0000 0x0280000>; + read-only; + }; + partition@5c20000 { + label = "0:RPM_1"; + reg = <0x5c20000 0x0280000>; + read-only; + }; + partition@5ea0000 { + label = "0:BOOTCONFIG1"; + reg = <0x5ea0000 0x0060000>; + read-only; + }; + partition@5f00000 { + label = "0:APPSBL_1"; + reg = <0x5f00000 0x0500000>; + read-only; + }; + stock_partition@6400000 { + label = "stock_rootfs_1"; + reg = <0x6400000 0x4000000>; + }; + stock_partition@a400000 { + label = "stock_fw_env"; + reg = <0xa400000 0x0100000>; + }; + stock_partition@a500000 { + label = "stock_config"; + reg = <0xa500000 0x0800000>; + }; + stock_partition@ad00000 { + label = "stock_PKI"; + reg = <0xad00000 0x0200000>; + }; + stock_partition@af00000 { + label = "stock_scfgmgr"; + reg = <0xaf00000 0x0100000>; + }; + + partition@6400000 { + label = "fw_env"; + reg = <0x6400000 0x0100000>; + + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_fw_env_0: macaddr@0 { + reg = <0x00 0x6>; + }; + macaddr_fw_env_6: macaddr@6 { + reg = <0x06 0x6>; + }; + macaddr_fw_env_c: macaddr@c { + reg = <0x0c 0x6>; + }; + macaddr_fw_env_12: macaddr@12 { + reg = <0x12 0x6>; + }; + macaddr_fw_env_18: macaddr@18 { + reg = <0x18 0x6>; + }; + }; + partition@6500000 { + label = "ubi"; + reg = <0x6500000 0x9b00000>; + }; + partition@1340000 { + label = "extra"; + reg = <0x1340000 0x4000000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + ethernet-phy@0 { + reg = <0x0>; + qca,ar8327-initvals = < + 0x00004 0x7600000 /* PAD0_MODE */ + 0x00008 0x1000000 /* PAD5_MODE */ + 0x0000c 0x80 /* PAD6_MODE */ + 0x000e4 0xaa545 /* MAC_POWER_SEL */ + 0x000e0 0xc74164de /* SGMII_CTRL */ + 0x0007c 0x4e /* PORT0_STATUS */ + 0x00094 0x4e /* PORT6_STATUS */ + >; + }; + + phy7: ethernet-phy@7 { + reg = <7>; + }; +}; + +&gmac0 { + status = "okay"; + phy-mode = "rgmii"; + qcom,id = <0>; + + nvmem-cells = <&macaddr_fw_env_18>; + nvmem-cell-names = "mac-address"; + + pinctrl-0 = <&rgmii2_pins>; + pinctrl-names = "default"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac1 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <1>; + + nvmem-cells = <&macaddr_fw_env_0>; + nvmem-cell-names = "mac-address"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&gmac3 { + status = "okay"; + phy-mode = "sgmii"; + qcom,id = <3>; + phy-handle = <&phy7>; + + nvmem-cells = <&macaddr_fw_env_6>; + nvmem-cell-names = "mac-address"; +}; + +&adm_dma { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie0 { + status = "okay"; + reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie0_pins>; + pinctrl-names = "default"; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi0: wifi@1,0 { + compatible = "pci168c,0046"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&precal_ART_1000>, <&macaddr_fw_env_12>; + nvmem-cell-names = "pre-calibration", "mac-address"; + }; + }; +}; + +&pcie1 { + status = "okay"; + reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&pcie1_pins>; + pinctrl-names = "default"; + max-link-speed = <1>; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi1: wifi@1,0 { + compatible = "pci168c,0040"; + reg = <0x00010000 0 0 0 0>; + + nvmem-cells = <&precal_ART_5000>, <&macaddr_fw_env_c>; + nvmem-cell-names = "pre-calibration", "mac-address"; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-xr500.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-xr500.dts new file mode 100644 index 00000000000..f584735e155 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-xr500.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8065-nighthawk.dtsi" + +/ { + model = "Netgear Nighthawk XR500"; + compatible = "netgear,xr500", "qcom,ipq8065", "qcom,ipq8064"; + +}; + +&leds { + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; +}; + +&partitions { + partition@1880000 { + label = "ubi"; + reg = <0x1880000 0xce00000>; + }; + + partition@e680000 { + label = "reserve"; + reg = <0xe680000 0x0780000>; + read-only; + }; +}; + +&wifi0 { + nvmem-cells = <&macaddr_art_c>, <&precal_art_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; +}; + +&wifi1 { + nvmem-cells = <&macaddr_art_0>, <&precal_art_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; +}; + +&art { + macaddr_art_c: macaddr@c { + reg = <0xc 0x6>; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-cryptid-common.dtsi b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-cryptid-common.dtsi new file mode 100644 index 00000000000..a8f43591f90 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-cryptid-common.dtsi @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +/ { + memory { + device_type = "memory"; + linux,usable-memory = <0x41500000 0x1ea00000>; + reg = <0x40000000 0x20000000>; + }; + + cpus { + idle-states { + CPU_SPC: spc { + status = "disabled"; + }; + }; + }; + + chosen { + bootargs-append = " console=ttyMSM0,115200n8 ubi.mtd=ubi ubi.mtd=art"; + }; +}; + +&qcom_pinmux { + mdio0_pins_active: mdio0_pins_active { + mux { + pins = "gpio0", "gpio1"; + function = "mdio"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + + clk { + pins = "gpio1"; + input-disable; + }; + }; + + phy_active: phy_active { + phy { + pins = "gpio6", "gpio7"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + output-high; + }; + }; + + uart1_pins: uart1_pins { + mux { + pins = "gpio51", "gpio52"; + function = "gsbi1"; + drive-strength = <4>; + bias-disable; + }; + }; +}; + +&gsbi1 { + status = "okay"; + qcom,mode = ; + + serial@12450000 { + status = "okay"; + + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; + }; +}; + +&pcie0 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x0 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi0: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x10000 0 0 0 0>; + }; + }; +}; + +&pcie1 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x0 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi1: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x10000 0 0 0 0>; + }; + }; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x0 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi2: wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x10000 0 0 0 0>; + }; + }; +}; + +&adm_dma { + status = "okay"; +}; + +&nand { + status = "okay"; + + nand@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + nand-is-boot-medium; + qcom,boot-partitions = <0x0 0x2140000>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "sbl1"; + reg = <0x0 0x40000>; + read-only; + }; + + partition@40000 { + label = "mibib"; + reg = <0x40000 0x140000>; + read-only; + }; + + partition@180000 { + label = "sbl2"; + reg = <0x180000 0x140000>; + read-only; + }; + + partition@2c0000 { + label = "sbl3"; + reg = <0x2c0000 0x280000>; + read-only; + }; + + partition@540000 { + label = "ddrconfig"; + reg = <0x540000 0x120000>; + read-only; + }; + + partition@660000 { + label = "ssd"; + reg = <0x660000 0x120000>; + read-only; + }; + + partition@780000 { + label = "tz"; + reg = <0x780000 0x280000>; + read-only; + }; + + partition@a00000 { + label = "rpm"; + reg = <0xa00000 0x280000>; + read-only; + }; + + partition@1fc0000 { + label = "u-boot"; + reg = <0x1fc0000 0x180000>; + read-only; + }; + + partition@21c0000 { + label = "bootkernel1"; + reg = <0x21c0000 0xa80000>; + }; + + partition@2c40000 { + label = "bootkernel2"; + reg = <0x2c40000 0xa80000>; + }; + + partition@36c0000 { + label = "ubi"; + reg = <0x36c0000 0x46c0000>; + }; + + partition@7d80000 { + label = "art"; + reg = <0x7d80000 0x200000>; + read-only; + }; + }; + }; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts new file mode 100644 index 00000000000..50c1d37c292 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-ecw5410.dts @@ -0,0 +1,329 @@ +#include "qcom-ipq8064-v2.0-smb208.dtsi" + +#include +#include + +/ { + model = "Edgecore ECW5410"; + compatible = "edgecore,ecw5410", "qcom,ipq8064"; + + reserved-memory { + nss@40000000 { + reg = <0x40000000 0x1000000>; + no-map; + }; + + smem: smem@41000000 { + reg = <0x41000000 0x200000>; + no-map; + }; + + wifi_dump@44000000 { + reg = <0x44000000 0x600000>; + no-map; + }; + }; + + cpus { + idle-states { + CPU_SPC: spc { + status = "disabled"; + }; + }; + }; + + aliases { + serial1 = &gsbi1_serial; + ethernet0 = &gmac2; + ethernet1 = &gmac3; + + led-boot = &led_power_green; + led-failsafe = &led_power_red; + led-running = &led_power_green; + led-upgrade = &led_power_green; + }; + + chosen { + bootargs-append = " console=ttyMSM0,115200n8 root=/dev/ubiblock0_1"; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power_green: power_green { + label = "green:power"; + gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>; + }; + + wlan2g_green { + label = "green:wlan2g"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_LOW>; + }; + + wlan2g_yellow { + label = "yellow:wlan2g"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_LOW>; + }; + + wlan5g_green { + label = "green:wlan5g"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + led_power_red: power_red { + label = "red:power"; + gpios = <&qcom_pinmux 28 GPIO_ACTIVE_LOW>; + }; + + wlan5g_yellow { + label = "yellow:wlan5g"; + gpios = <&qcom_pinmux 59 GPIO_ACTIVE_LOW>; + }; + }; +}; + + +&qcom_pinmux { + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19"; + function = "gsbi5"; + drive-strength = <10>; + bias-pull-down; + }; + + clk { + pins = "gpio21"; + function = "gsbi5"; + drive-strength = <12>; + bias-pull-down; + }; + + cs { + pins = "gpio20"; + function = "gpio"; + drive-strength = <10>; + bias-pull-up; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio16", "gpio23", "gpio24", "gpio26", + "gpio28", "gpio59"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart1_pins: uart1_pins { + mux { + pins = "gpio51", "gpio52", "gpio53", "gpio54"; + function = "gsbi1"; + drive-strength = <12>; + bias-none; + }; + }; +}; + +&gsbi1 { + qcom,mode = ; + status = "okay"; + + serial@12450000 { + status = "okay"; + + pinctrl-0 = <&uart1_pins>; + pinctrl-names = "default"; + }; +}; + +&gsbi5 { + qcom,mode = ; + status = "okay"; + + spi4: spi@1a280000 { + status = "okay"; + spi-max-frequency = <50000000>; + + pinctrl-0 = <&spi_pins>; + pinctrl-names = "default"; + + cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>; + + m25p80@0 { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + reg = <0>; + + partitions { + compatible = "qcom,smem-part"; + }; + }; + }; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&pcie1 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&pcie2 { + status = "okay"; + + /delete-property/ pinctrl-0; + /delete-property/ pinctrl-names; + /delete-property/ perst-gpios; + + bridge@0,0 { + reg = <0x00000000 0 0 0 0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; + + wifi@1,0 { + compatible = "qcom,ath10k"; + status = "okay"; + reg = <0x00010000 0 0 0 0>; + qcom,ath10k-calibration-variant = "Edgecore-ECW5410-L"; + }; + }; +}; + +&nand { + status = "okay"; + + nand@0 { + compatible = "qcom,nandcs"; + + reg = <0>; + + nand-ecc-strength = <4>; + nand-bus-width = <8>; + nand-ecc-step-size = <512>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + rootfs1@0 { + label = "rootfs1"; + reg = <0x0000000 0x4000000>; + }; + + rootfs2@4000000 { + label = "rootfs2"; + reg = <0x4000000 0x4000000>; + }; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + + phy0: ethernet-phy@0 { + reg = <0>; + }; + + phy1: ethernet-phy@1 { + reg = <1>; + }; +}; + +&gmac2 { + status = "okay"; + + qcom,id = <2>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy1>; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; +}; + +&adm_dma { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr42.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr42.dts new file mode 100644 index 00000000000..cfbfafb1793 --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr42.dts @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +#include "qcom-ipq8068-cryptid-common.dtsi" + +#include + +/ { + model = "Meraki MR42"; + compatible = "meraki,mr42", "qcom,ipq8064"; + + aliases { + serial1 = &gsbi1_serial; + ethernet0 = &gmac3; + + led-boot = &led_active; + led-failsafe = &led_power; + led-running = &led_active; + led-upgrade = &led_active; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power: power { + label = "orange:power"; + gpios = <&qcom_pinmux 31 GPIO_ACTIVE_HIGH>; + }; + + led_active: active { + label = "white:active"; + gpios = <&qcom_pinmux 32 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy2>; + + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; +}; + +&gsbi2 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi2_i2c { + status = "okay"; + + pinctrl-0 = <&i2c0_pins>; + pinctrl-names = "default"; + + ina2xx@40 { + compatible = "ina219"; + shunt-resistor = <40000>; + reg = <0x40>; + }; + + eeprom@56 { + compatible = "atmel,24c64"; + pagesize = <32>; + reg = <0x56>; + read-only; + #address-cells = <1>; + #size-cells = <1>; + + mac_address: mac-address@66 { + reg = <0x66 0x6>; + }; + }; +}; + +&gsbi6 { + qcom,mode = ; + status = "okay"; +}; + +&gsbi6_i2c { + status = "okay"; + + pinctrl-0 = <&i2c1_pins>; + pinctrl-names = "default"; + + tlc591xx@40 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tlc59108"; + reg = <0x40>; + + red@0 { + label = "red:user"; + reg = <0x0>; + }; + + green@1 { + label = "green:user"; + reg = <0x1>; + }; + + blue@2 { + label = "blue:user"; + reg = <0x2>; + }; + }; +}; + +&mdio0 { + status = "okay"; + + pinctrl-0 = <&mdio0_pins_active>, <&phy_active>; + pinctrl-names = "default"; + + phy2: ethernet-phy2 { + reg = <2>; + + reset-gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + reset-assert-us = <24000>; + + eee-broken-100tx; + eee-broken-1000t; + }; +}; + +&qcom_pinmux { + i2c0_pins: i2c0_pins { + mux { + pins = "gpio24", "gpio25"; + function = "gsbi2"; + drive-strength = <2>; + bias-pull-up; + input; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio26"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + i2c1_pins: i2c1_pins { + mux { + pins = "gpio29", "gpio30"; + function = "gsbi6"; + drive-strength = <2>; + bias-pull-up; + input; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio31", "gpio32"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-low; + }; + }; +}; + +&wifi0 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; +}; + +&wifi1 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <2>; +}; + +&wifi2 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <3>; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr52.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr52.dts new file mode 100644 index 00000000000..f81e3ef690d --- /dev/null +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8068-mr52.dts @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT + +#include "qcom-ipq8068-cryptid-common.dtsi" + +#include + +/ { + model = "Meraki MR52"; + compatible = "meraki,mr52", "qcom,ipq8064"; + + aliases { + serial1 = &gsbi1_serial; + mdio-gpio0 = &mdio_gpio0; + ethernet0 = &gmac2; + ethernet1 = &gmac3; + + led-boot = &led_active; + led-failsafe = &led_power; + led-running = &led_active; + led-upgrade = &led_active; + }; + + keys { + compatible = "gpio-keys"; + pinctrl-0 = <&button_pins>; + pinctrl-names = "default"; + + reset { + label = "reset"; + gpios = <&qcom_pinmux 25 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <60>; + wakeup-source; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&led_pins>; + pinctrl-names = "default"; + + led_power: power { + label = "orange:power"; + gpios = <&qcom_pinmux 19 GPIO_ACTIVE_HIGH>; + }; + + lan2_green { + label = "green:lan2"; + gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>; + }; + + lan1_green { + label = "green:lan1"; + gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>; + }; + + led_active: active { + label = "white:active"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>; + }; + + lan2_orange { + label = "orange:lan2"; + gpios = <&qcom_pinmux 60 GPIO_ACTIVE_HIGH>; + }; + + lan1_orange { + label = "orange:lan1"; + gpios = <&qcom_pinmux 62 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&gmac2 { + status = "okay"; + + qcom,id = <2>; + mdiobus = <&mdio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy0>; + + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; +}; + +&gmac3 { + status = "okay"; + + qcom,id = <3>; + mdiobus = <&mdio_gpio0>; + + phy-mode = "sgmii"; + phy-handle = <&phy4>; + + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <1>; +}; + +&gsbi7 { + status = "okay"; + qcom,mode = ; +}; + +&gsbi7_i2c { + status = "okay"; + + pinctrl-0 = <&i2c_pins>; + pinctrl-names = "default"; + + ina2xx@45 { + compatible = "ina219"; + shunt-resistor = <80000>; + reg = <0x45>; + }; + + tlc591xx@49 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tlc59108"; + reg = <0x49>; + + red@0 { + label = "red:user"; + reg = <0x0>; + }; + + green@1 { + label = "green:user"; + reg = <0x1>; + }; + + blue@2 { + label = "blue:user"; + reg = <0x2>; + }; + }; + + eeprom@52 { + compatible = "atmel,24c64"; + pagesize = <32>; + reg = <0x52>; + read-only; + #address-cells = <1>; + #size-cells = <1>; + + mac_address: mac-address@66 { + reg = <0x66 0x6>; + }; + }; +}; + +&qcom_pinmux { + i2c_pins: i2c_pins { + mux { + pins = "gpio8", "gpio9"; + function = "gsbi7"; + drive-strength = <2>; + bias-pull-up; + input; + }; + }; + + led_pins: led_pins { + mux { + pins = "gpio19", "gpio26"; + function = "gpio"; + drive-strength = <12>; + bias-pull-down; + output-low; + }; + }; + + button_pins: button_pins { + mux { + pins = "gpio25"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + input; + }; + }; +}; + +&soc { + mdio_gpio0: mdio { + compatible = "virtual,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + status = "okay"; + + pinctrl-0 = <&mdio0_pins_active>, <&phy_active>; + pinctrl-names = "default"; + + gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH + &qcom_pinmux 0 GPIO_ACTIVE_HIGH>; + + phy0: ethernet-phy0 { + reg = <0>; + reset-gpios = <&qcom_pinmux 7 GPIO_ACTIVE_LOW>; + reset-assert-us = <24000>; + }; + + phy4: ethernet-phy4 { + reg = <4>; + reset-gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>; + reset-assert-us = <24000>; + }; + }; +}; + +&wifi0 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <4>; +}; + +&wifi1 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <3>; +}; + +&wifi2 { + nvmem-cells = <&mac_address>; + nvmem-cell-names = "mac-address"; + mac-address-increment = <2>; +}; + +&hs_phy_0 { + status = "okay"; +}; + +&ss_phy_0 { + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&hs_phy_1 { + status = "okay"; +}; + +&ss_phy_1 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; diff --git a/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch new file mode 100644 index 00000000000..1860cef8003 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch @@ -0,0 +1,62 @@ +From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001 +From: Mathieu Olivari +Date: Wed, 29 Apr 2015 15:21:46 -0700 +Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom + +ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended +on most ARM architectures. This automatically calculate ZRELADDR by +masking PHYS_OFFSET with 0xf8000000. + +However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware +network accelerators, and the bootloader removes this section from the +layout passed from the ATAGS (when used). + +For newer bootloader, when DT is used, this is not a problem, we just +reserve this memory in the device tree. But if the bootloader doesn't +have DT support, then ATAGS have to be used. In this case, the ARM +decompressor will position the kernel in this low mem, which will not be +in the RAM section mapped by the bootloader, which means the kernel will +freeze in the middle of the boot process trying to map the memory. + +As a work around, this patch allows disabling AUTO_ZRELADDR when +ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders +which don't support device-tree, which is the case on certain early +IPQ806x based designs. + +Signed-off-by: Mathieu Olivari +--- + arch/arm/Kconfig | 2 +- + arch/arm/Makefile | 2 ++ + arch/arm/mach-qcom/Makefile.boot | 1 + + 3 files changed, 4 insertions(+), 1 deletion(-) + create mode 100644 arch/arm/mach-qcom/Makefile.boot + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -317,7 +317,7 @@ config ARCH_MULTIPLATFORM + select ARCH_SELECT_MEMORY_MODEL + select ARM_HAS_SG_CHAIN + select ARM_PATCH_PHYS_VIRT +- select AUTO_ZRELADDR ++ select AUTO_ZRELADDR if !ARCH_QCOM + select TIMER_OF + select COMMON_CLK + select GENERIC_IRQ_MULTI_HANDLER +--- a/arch/arm/Makefile ++++ b/arch/arm/Makefile +@@ -237,9 +237,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac + else + MACHINE := + endif ++ifeq ($(CONFIG_ARCH_QCOM),) + ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) + MACHINE := + endif ++endif + + machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) + platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) +--- /dev/null ++++ b/arch/arm/mach-qcom/Makefile.boot +@@ -0,0 +1 @@ ++zreladdr-y+= 0x42208000 diff --git a/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch new file mode 100644 index 00000000000..df5d4811a88 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -0,0 +1,280 @@ +From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001 +From: Adrian Panella +Date: Thu, 9 Mar 2017 09:37:17 +0100 +Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments + +The command-line arguments provided by the boot loader will be +appended to a new device tree property: bootloader-args. +If there is a property "append-rootblock" in DT under /chosen +and a root= option in bootloaders command line it will be parsed +and added to DT bootargs with the form: XX. +Only command line ATAG will be processed, the rest of the ATAGs +sent by bootloader will be ignored. +This is usefull in dual boot systems, to get the current root partition +without afecting the rest of the system. + +Signed-off-by: Adrian Panella +--- + arch/arm/Kconfig | 11 +++++ + arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++- + init/main.c | 16 ++++++++ + 3 files changed, 98 insertions(+), 1 deletion(-) + +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1727,6 +1727,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN + The command-line arguments provided by the boot loader will be + appended to the the device tree bootargs property. + ++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ bool "Append rootblock parsing bootloader's kernel arguments" ++ help ++ The command-line arguments provided by the boot loader will be ++ appended to a new device tree property: bootloader-args. ++ If there is a property "append-rootblock" in DT under /chosen ++ and a root= option in bootloaders command line it will be parsed ++ and added to DT bootargs with the form: XX. ++ Only command line ATAG will be processed, the rest of the ATAGs ++ sent by bootloader will be ignored. ++ + endchoice + + config CMDLINE +--- a/arch/arm/boot/compressed/atags_to_fdt.c ++++ b/arch/arm/boot/compressed/atags_to_fdt.c +@@ -5,6 +5,8 @@ + + #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND) + #define do_extend_cmdline 1 ++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#define do_extend_cmdline 1 + #else + #define do_extend_cmdline 0 + #endif +@@ -20,6 +22,7 @@ static int node_offset(void *fdt, const + return offset; + } + ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE + static int setprop(void *fdt, const char *node_path, const char *property, + void *val_array, int size) + { +@@ -28,6 +31,7 @@ static int setprop(void *fdt, const char + return offset; + return fdt_setprop(fdt, offset, property, val_array, size); + } ++#endif + + static int setprop_string(void *fdt, const char *node_path, + const char *property, const char *string) +@@ -38,6 +42,7 @@ static int setprop_string(void *fdt, con + return fdt_setprop_string(fdt, offset, property, string); + } + ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE + static int setprop_cell(void *fdt, const char *node_path, + const char *property, uint32_t val) + { +@@ -46,6 +51,7 @@ static int setprop_cell(void *fdt, const + return offset; + return fdt_setprop_cell(fdt, offset, property, val); + } ++#endif + + static const void *getprop(const void *fdt, const char *node_path, + const char *property, int *len) +@@ -58,6 +64,7 @@ static const void *getprop(const void *f + return fdt_getprop(fdt, offset, property, len); + } + ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE + static uint32_t get_cell_size(const void *fdt) + { + int len; +@@ -68,6 +75,81 @@ static uint32_t get_cell_size(const void + cell_size = fdt32_to_cpu(*size_len); + return cell_size; + } ++#endif ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++/** ++ * taken from arch/x86/boot/string.c ++ * local_strstr - Find the first substring in a %NUL terminated string ++ * @s1: The string to be searched ++ * @s2: The string to search for ++ */ ++static char *local_strstr(const char *s1, const char *s2) ++{ ++ size_t l1, l2; ++ ++ l2 = strlen(s2); ++ if (!l2) ++ return (char *)s1; ++ l1 = strlen(s1); ++ while (l1 >= l2) { ++ l1--; ++ if (!memcmp(s1, s2, l2)) ++ return (char *)s1; ++ s1++; ++ } ++ return NULL; ++} ++ ++static char *append_rootblock(char *dest, const char *str, int len, void *fdt) ++{ ++ char *ptr, *end, *tmp; ++ const char *root="root="; ++ const char *find_rootblock; ++ int i, l; ++ const char *rootblock; ++ ++ find_rootblock = getprop(fdt, "/chosen", "find-rootblock", &l); ++ if (!find_rootblock) ++ find_rootblock = root; ++ ++ //ARM doesn't have __HAVE_ARCH_STRSTR, so it was copied from x86 ++ ptr = local_strstr(str, find_rootblock); ++ ++ if(!ptr) ++ return dest; ++ ++ end = strchr(ptr, ' '); ++ end = end ? (end - 1) : (strchr(ptr, 0) - 1); ++ ++ // Some boards ubi.mtd=XX,ZZZZ, so let's check for '," too. ++ tmp = strchr(ptr, ','); ++ ++ if(tmp) ++ end = end < tmp ? end : tmp - 1; ++ ++ //find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX | ubi.mtd=XX,ZZZZ ) ++ for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++); ++ ptr = end + 1; ++ ++ /* if append-rootblock property is set use it to append to command line */ ++ rootblock = getprop(fdt, "/chosen", "append-rootblock", &l); ++ if(rootblock != NULL) { ++ if(*dest != ' ') { ++ *dest = ' '; ++ dest++; ++ len++; ++ } ++ if (len + l + i <= COMMAND_LINE_SIZE) { ++ memcpy(dest, rootblock, l); ++ dest += l - 1; ++ memcpy(dest, ptr, i); ++ dest += i; ++ } ++ } ++ return dest; ++} ++#endif + + static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline) + { +@@ -88,18 +170,28 @@ static void merge_fdt_bootargs(void *fdt + + /* and append the ATAG_CMDLINE */ + if (fdt_cmdline) { ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //save original bootloader args ++ //and append ubi.mtd with root partition number to current cmdline ++ setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline); ++ ptr = append_rootblock(ptr, fdt_cmdline, len, fdt); ++ ++#else + len = strlen(fdt_cmdline); + if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) { + *ptr++ = ' '; + memcpy(ptr, fdt_cmdline, len); + ptr += len; + } ++#endif + } + *ptr = '\0'; + + setprop_string(fdt, "/chosen", "bootargs", cmdline); + } + ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE + static void hex_str(char *out, uint32_t value) + { + uint32_t digit; +@@ -117,6 +209,7 @@ static void hex_str(char *out, uint32_t + } + *out = '\0'; + } ++#endif + + /* + * Convert and fold provided ATAGs into the provided FDT. +@@ -131,9 +224,11 @@ int atags_to_fdt(void *atag_list, void * + struct tag *atag = atag_list; + /* In the case of 64 bits memory size, need to reserve 2 cells for + * address and size for each bank */ ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE + __be32 mem_reg_property[2 * 2 * NR_BANKS]; +- int memcount = 0; +- int ret, memsize; ++ int memsize, memcount = 0; ++#endif ++ int ret; + + /* make sure we've got an aligned pointer */ + if ((u32)atag_list & 0x3) +@@ -168,7 +263,9 @@ int atags_to_fdt(void *atag_list, void * + else + setprop_string(fdt, "/chosen", "bootargs", + atag->u.cmdline.cmdline); +- } else if (atag->hdr.tag == ATAG_MEM) { ++ } ++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE ++ else if (atag->hdr.tag == ATAG_MEM) { + if (memcount >= sizeof(mem_reg_property)/4) + continue; + if (!atag->u.mem.size) +@@ -212,6 +309,10 @@ int atags_to_fdt(void *atag_list, void * + setprop(fdt, "/memory", "reg", mem_reg_property, + 4 * memcount * memsize); + } ++#else ++ ++ } ++#endif + + return fdt_pack(fdt); + } +--- a/init/main.c ++++ b/init/main.c +@@ -114,6 +114,10 @@ + + #include + ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++#include ++#endif ++ + static int kernel_init(void *); + + extern void init_IRQ(void); +@@ -993,6 +997,18 @@ asmlinkage __visible void __init __no_sa + pr_notice("Kernel command line: %s\n", saved_command_line); + /* parameters may set static keys */ + jump_label_init(); ++ ++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE) ++ //Show bootloader's original command line for reference ++ if(of_chosen) { ++ const char *prop = of_get_property(of_chosen, "bootloader-args", NULL); ++ if(prop) ++ pr_notice("Bootloader command line (ignored): %s\n", prop); ++ else ++ pr_notice("Bootloader command line not present\n"); ++ } ++#endif ++ + parse_early_param(); + after_dashes = parse_args("Booting kernel", + static_command_line, __start___param, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch new file mode 100644 index 00000000000..f3f3ea30da8 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch @@ -0,0 +1,109 @@ +From e95e825333eda345d812b461301dad50021d5487 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:24 +0100 +Subject: [PATCH 04/14] clk: qcom: gcc-ipq806x: fix wrong naming for + gcc_pxo_pll8_pll0 + +Parent gcc_pxo_pll8_pll0 had the parent definition and parent map +swapped. Fix this naming error. + +Signed-off-by: Ansuel Smith +Reviewed-by: Bjorn Andersson +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-5-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -291,13 +291,13 @@ static const char * const gcc_pxo_pll3[] + "pll3", + }; + +-static const struct parent_map gcc_pxo_pll8_pll0[] = { ++static const struct parent_map gcc_pxo_pll8_pll0_map[] = { + { P_PXO, 0 }, + { P_PLL8, 3 }, + { P_PLL0, 2 } + }; + +-static const char * const gcc_pxo_pll8_pll0_map[] = { ++static const char * const gcc_pxo_pll8_pll0[] = { + "pxo", + "pll8_vote", + "pll0_vote", +@@ -1993,7 +1993,7 @@ static struct clk_rcg usb30_master_clk_s + }, + .s = { + .src_sel_shift = 0, +- .parent_map = gcc_pxo_pll8_pll0, ++ .parent_map = gcc_pxo_pll8_pll0_map, + }, + .freq_tbl = clk_tbl_usb30_master, + .clkr = { +@@ -2001,7 +2001,7 @@ static struct clk_rcg usb30_master_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb30_master_ref_src", +- .parent_names = gcc_pxo_pll8_pll0_map, ++ .parent_names = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2063,7 +2063,7 @@ static struct clk_rcg usb30_utmi_clk = { + }, + .s = { + .src_sel_shift = 0, +- .parent_map = gcc_pxo_pll8_pll0, ++ .parent_map = gcc_pxo_pll8_pll0_map, + }, + .freq_tbl = clk_tbl_usb30_utmi, + .clkr = { +@@ -2071,7 +2071,7 @@ static struct clk_rcg usb30_utmi_clk = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb30_utmi_clk", +- .parent_names = gcc_pxo_pll8_pll0_map, ++ .parent_names = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2133,7 +2133,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s + }, + .s = { + .src_sel_shift = 0, +- .parent_map = gcc_pxo_pll8_pll0, ++ .parent_map = gcc_pxo_pll8_pll0_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { +@@ -2141,7 +2141,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_src", +- .parent_names = gcc_pxo_pll8_pll0_map, ++ .parent_names = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2197,7 +2197,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s + }, + .s = { + .src_sel_shift = 0, +- .parent_map = gcc_pxo_pll8_pll0, ++ .parent_map = gcc_pxo_pll8_pll0_map, + }, + .freq_tbl = clk_tbl_usb, + .clkr = { +@@ -2205,7 +2205,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_fs1_xcvr_src", +- .parent_names = gcc_pxo_pll8_pll0_map, ++ .parent_names = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch new file mode 100644 index 00000000000..d99ac9992f3 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch @@ -0,0 +1,921 @@ +From cb02866f9a740fb9fb8ff19698a69290da4057e5 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:25 +0100 +Subject: [PATCH 05/14] clk: qcom: gcc-ipq806x: convert parent_names to + parent_data + +Convert parent_names to parent_data to modernize the driver. +Where possible use parent_hws directly. + +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-6-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 286 ++++++++++++++++++++------------- + 1 file changed, 173 insertions(+), 113 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -25,6 +25,10 @@ + #include "clk-hfpll.h" + #include "reset.h" + ++static const struct clk_parent_data gcc_pxo[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++}; ++ + static struct clk_pll pll0 = { + .l_reg = 0x30c4, + .m_reg = 0x30c8, +@@ -35,7 +39,7 @@ static struct clk_pll pll0 = { + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll0", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -46,7 +50,9 @@ static struct clk_regmap pll0_vote = { + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "pll0_vote", +- .parent_names = (const char *[]){ "pll0" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pll0.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +@@ -62,7 +68,7 @@ static struct clk_pll pll3 = { + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll3", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -89,7 +95,7 @@ static struct clk_pll pll8 = { + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll8", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -100,7 +106,9 @@ static struct clk_regmap pll8_vote = { + .enable_mask = BIT(8), + .hw.init = &(struct clk_init_data){ + .name = "pll8_vote", +- .parent_names = (const char *[]){ "pll8" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pll8.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +@@ -123,7 +131,7 @@ static struct hfpll_data hfpll0_data = { + static struct clk_hfpll hfpll0 = { + .d = &hfpll0_data, + .clkr.hw.init = &(struct clk_init_data){ +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .name = "hfpll0", + .ops = &clk_ops_hfpll, +@@ -149,7 +157,7 @@ static struct hfpll_data hfpll1_data = { + static struct clk_hfpll hfpll1 = { + .d = &hfpll1_data, + .clkr.hw.init = &(struct clk_init_data){ +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .name = "hfpll1", + .ops = &clk_ops_hfpll, +@@ -175,7 +183,7 @@ static struct hfpll_data hfpll_l2_data = + static struct clk_hfpll hfpll_l2 = { + .d = &hfpll_l2_data, + .clkr.hw.init = &(struct clk_init_data){ +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .name = "hfpll_l2", + .ops = &clk_ops_hfpll, +@@ -194,7 +202,7 @@ static struct clk_pll pll14 = { + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll14", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -205,7 +213,9 @@ static struct clk_regmap pll14_vote = { + .enable_mask = BIT(14), + .hw.init = &(struct clk_init_data){ + .name = "pll14_vote", +- .parent_names = (const char *[]){ "pll14" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pll14.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +@@ -238,7 +248,7 @@ static struct clk_pll pll18 = { + .freq_tbl = pll18_freq_tbl, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll18", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -259,9 +269,9 @@ static const struct parent_map gcc_pxo_p + { P_PLL8, 3 } + }; + +-static const char * const gcc_pxo_pll8[] = { +- "pxo", +- "pll8_vote", ++static const struct clk_parent_data gcc_pxo_pll8[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .hw = &pll8_vote.hw }, + }; + + static const struct parent_map gcc_pxo_pll8_cxo_map[] = { +@@ -270,10 +280,10 @@ static const struct parent_map gcc_pxo_p + { P_CXO, 5 } + }; + +-static const char * const gcc_pxo_pll8_cxo[] = { +- "pxo", +- "pll8_vote", +- "cxo", ++static const struct clk_parent_data gcc_pxo_pll8_cxo[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .hw = &pll8_vote.hw }, ++ { .fw_name = "cxo", .name = "cxo" }, + }; + + static const struct parent_map gcc_pxo_pll3_map[] = { +@@ -286,9 +296,9 @@ static const struct parent_map gcc_pxo_p + { P_PLL3, 6 } + }; + +-static const char * const gcc_pxo_pll3[] = { +- "pxo", +- "pll3", ++static const struct clk_parent_data gcc_pxo_pll3[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .hw = &pll3.clkr.hw }, + }; + + static const struct parent_map gcc_pxo_pll8_pll0_map[] = { +@@ -297,10 +307,10 @@ static const struct parent_map gcc_pxo_p + { P_PLL0, 2 } + }; + +-static const char * const gcc_pxo_pll8_pll0[] = { +- "pxo", +- "pll8_vote", +- "pll0_vote", ++static const struct clk_parent_data gcc_pxo_pll8_pll0[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .hw = &pll8_vote.hw }, ++ { .hw = &pll0_vote.hw }, + }; + + static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = { +@@ -311,12 +321,12 @@ static const struct parent_map gcc_pxo_p + { P_PLL18, 1 } + }; + +-static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { +- "pxo", +- "pll8_vote", +- "pll0_vote", +- "pll14", +- "pll18", ++static const struct clk_parent_data gcc_pxo_pll8_pll14_pll18_pll0[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .hw = &pll8_vote.hw }, ++ { .hw = &pll0_vote.hw }, ++ { .hw = &pll14.clkr.hw }, ++ { .hw = &pll18.clkr.hw }, + }; + + static struct freq_tbl clk_tbl_gsbi_uart[] = { +@@ -362,7 +372,7 @@ static struct clk_rcg gsbi1_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -378,8 +388,8 @@ static struct clk_branch gsbi1_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi1_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi1_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -413,7 +423,7 @@ static struct clk_rcg gsbi2_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -429,8 +439,8 @@ static struct clk_branch gsbi2_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi2_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi2_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -464,7 +474,7 @@ static struct clk_rcg gsbi4_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -480,8 +490,8 @@ static struct clk_branch gsbi4_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi4_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi4_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -515,7 +525,7 @@ static struct clk_rcg gsbi5_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -531,8 +541,8 @@ static struct clk_branch gsbi5_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi5_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi5_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -566,7 +576,7 @@ static struct clk_rcg gsbi6_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -582,8 +592,8 @@ static struct clk_branch gsbi6_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi6_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi6_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -617,7 +627,7 @@ static struct clk_rcg gsbi7_uart_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_uart_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -633,8 +643,8 @@ static struct clk_branch gsbi7_uart_clk + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_uart_clk", +- .parent_names = (const char *[]){ +- "gsbi7_uart_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi7_uart_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -681,7 +691,7 @@ static struct clk_rcg gsbi1_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -697,7 +707,9 @@ static struct clk_branch gsbi1_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_clk", +- .parent_names = (const char *[]){ "gsbi1_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi1_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -730,7 +742,7 @@ static struct clk_rcg gsbi2_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -746,7 +758,9 @@ static struct clk_branch gsbi2_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_clk", +- .parent_names = (const char *[]){ "gsbi2_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi2_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -779,7 +793,7 @@ static struct clk_rcg gsbi4_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -795,7 +809,9 @@ static struct clk_branch gsbi4_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_clk", +- .parent_names = (const char *[]){ "gsbi4_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi4_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -828,7 +844,7 @@ static struct clk_rcg gsbi5_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -844,7 +860,9 @@ static struct clk_branch gsbi5_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_clk", +- .parent_names = (const char *[]){ "gsbi5_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi5_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -877,7 +895,7 @@ static struct clk_rcg gsbi6_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -893,7 +911,9 @@ static struct clk_branch gsbi6_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_qup_clk", +- .parent_names = (const char *[]){ "gsbi6_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi6_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -926,7 +946,7 @@ static struct clk_rcg gsbi7_qup_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_qup_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -942,7 +962,9 @@ static struct clk_branch gsbi7_qup_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_qup_clk", +- .parent_names = (const char *[]){ "gsbi7_qup_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gsbi7_qup_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1076,7 +1098,7 @@ static struct clk_rcg gp0_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp0_src", +- .parent_names = gcc_pxo_pll8_cxo, ++ .parent_data = gcc_pxo_pll8_cxo, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, +@@ -1092,7 +1114,9 @@ static struct clk_branch gp0_clk = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp0_clk", +- .parent_names = (const char *[]){ "gp0_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gp0_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1125,7 +1149,7 @@ static struct clk_rcg gp1_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp1_src", +- .parent_names = gcc_pxo_pll8_cxo, ++ .parent_data = gcc_pxo_pll8_cxo, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1141,7 +1165,9 @@ static struct clk_branch gp1_clk = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp1_clk", +- .parent_names = (const char *[]){ "gp1_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gp1_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1174,7 +1200,7 @@ static struct clk_rcg gp2_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "gp2_src", +- .parent_names = gcc_pxo_pll8_cxo, ++ .parent_data = gcc_pxo_pll8_cxo, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1190,7 +1216,9 @@ static struct clk_branch gp2_clk = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "gp2_clk", +- .parent_names = (const char *[]){ "gp2_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &gp2_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1228,7 +1256,7 @@ static struct clk_rcg prng_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "prng_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, +@@ -1244,7 +1272,9 @@ static struct clk_branch prng_clk = { + .enable_mask = BIT(10), + .hw.init = &(struct clk_init_data){ + .name = "prng_clk", +- .parent_names = (const char *[]){ "prng_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &prng_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + }, +@@ -1290,7 +1320,7 @@ static struct clk_rcg sdc1_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, +@@ -1305,7 +1335,9 @@ static struct clk_branch sdc1_clk = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc1_clk", +- .parent_names = (const char *[]){ "sdc1_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &sdc1_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1338,7 +1370,7 @@ static struct clk_rcg sdc3_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "sdc3_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, +@@ -1353,7 +1385,9 @@ static struct clk_branch sdc3_clk = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "sdc3_clk", +- .parent_names = (const char *[]){ "sdc3_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &sdc3_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1421,7 +1455,7 @@ static struct clk_rcg tsif_ref_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "tsif_ref_src", +- .parent_names = gcc_pxo_pll8, ++ .parent_data = gcc_pxo_pll8, + .num_parents = 2, + .ops = &clk_rcg_ops, + }, +@@ -1436,7 +1470,9 @@ static struct clk_branch tsif_ref_clk = + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "tsif_ref_clk", +- .parent_names = (const char *[]){ "tsif_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &tsif_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1583,7 +1619,7 @@ static struct clk_rcg pcie_ref_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref_src", +- .parent_names = gcc_pxo_pll3, ++ .parent_data = gcc_pxo_pll3, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1599,7 +1635,9 @@ static struct clk_branch pcie_ref_src_cl + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref_src_clk", +- .parent_names = (const char *[]){ "pcie_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pcie_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1675,7 +1713,7 @@ static struct clk_rcg pcie1_ref_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcie1_ref_src", +- .parent_names = gcc_pxo_pll3, ++ .parent_data = gcc_pxo_pll3, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1691,7 +1729,9 @@ static struct clk_branch pcie1_ref_src_c + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcie1_ref_src_clk", +- .parent_names = (const char *[]){ "pcie1_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pcie1_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1767,7 +1807,7 @@ static struct clk_rcg pcie2_ref_src = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcie2_ref_src", +- .parent_names = gcc_pxo_pll3, ++ .parent_data = gcc_pxo_pll3, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1783,7 +1823,9 @@ static struct clk_branch pcie2_ref_src_c + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcie2_ref_src_clk", +- .parent_names = (const char *[]){ "pcie2_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pcie2_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1864,7 +1906,7 @@ static struct clk_rcg sata_ref_src = { + .enable_mask = BIT(7), + .hw.init = &(struct clk_init_data){ + .name = "sata_ref_src", +- .parent_names = gcc_pxo_pll3, ++ .parent_data = gcc_pxo_pll3, + .num_parents = 2, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -1880,7 +1922,9 @@ static struct clk_branch sata_rxoob_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sata_rxoob_clk", +- .parent_names = (const char *[]){ "sata_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &sata_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1896,7 +1940,9 @@ static struct clk_branch sata_pmalive_cl + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sata_pmalive_clk", +- .parent_names = (const char *[]){ "sata_ref_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &sata_ref_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -1912,7 +1958,7 @@ static struct clk_branch sata_phy_ref_cl + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "sata_phy_ref_clk", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = gcc_pxo, + .num_parents = 1, + .ops = &clk_branch_ops, + }, +@@ -2001,7 +2047,7 @@ static struct clk_rcg usb30_master_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb30_master_ref_src", +- .parent_names = gcc_pxo_pll8_pll0, ++ .parent_data = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2017,7 +2063,9 @@ static struct clk_branch usb30_0_branch_ + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb30_0_branch_clk", +- .parent_names = (const char *[]){ "usb30_master_ref_src", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb30_master_clk_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2033,7 +2081,9 @@ static struct clk_branch usb30_1_branch_ + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb30_1_branch_clk", +- .parent_names = (const char *[]){ "usb30_master_ref_src", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb30_master_clk_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2071,7 +2121,7 @@ static struct clk_rcg usb30_utmi_clk = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb30_utmi_clk", +- .parent_names = gcc_pxo_pll8_pll0, ++ .parent_data = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2087,7 +2137,9 @@ static struct clk_branch usb30_0_utmi_cl + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb30_0_utmi_clk_ctl", +- .parent_names = (const char *[]){ "usb30_utmi_clk", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb30_utmi_clk.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2103,7 +2155,9 @@ static struct clk_branch usb30_1_utmi_cl + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb30_1_utmi_clk_ctl", +- .parent_names = (const char *[]){ "usb30_utmi_clk", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb30_utmi_clk.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2141,7 +2195,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_src", +- .parent_names = gcc_pxo_pll8_pll0, ++ .parent_data = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2157,7 +2211,9 @@ static struct clk_branch usb_hs1_xcvr_cl + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_clk", +- .parent_names = (const char *[]){ "usb_hs1_xcvr_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb_hs1_xcvr_clk_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2205,7 +2261,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "usb_fs1_xcvr_src", +- .parent_names = gcc_pxo_pll8_pll0, ++ .parent_data = gcc_pxo_pll8_pll0, + .num_parents = 3, + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, +@@ -2221,7 +2277,9 @@ static struct clk_branch usb_fs1_xcvr_cl + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "usb_fs1_xcvr_clk", +- .parent_names = (const char *[]){ "usb_fs1_xcvr_src", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb_fs1_xcvr_clk_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2237,7 +2295,9 @@ static struct clk_branch usb_fs1_sys_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "usb_fs1_sys_clk", +- .parent_names = (const char *[]){ "usb_fs1_xcvr_src", }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &usb_fs1_xcvr_clk_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -2337,7 +2397,7 @@ static struct clk_dyn_rcg gmac_core1_src + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core1_src", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, +@@ -2354,8 +2414,8 @@ static struct clk_branch gmac_core1_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core1_clk", +- .parent_names = (const char *[]){ +- "gmac_core1_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gmac_core1_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -2409,7 +2469,7 @@ static struct clk_dyn_rcg gmac_core2_src + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core2_src", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, +@@ -2426,8 +2486,8 @@ static struct clk_branch gmac_core2_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core2_clk", +- .parent_names = (const char *[]){ +- "gmac_core2_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gmac_core2_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -2481,7 +2541,7 @@ static struct clk_dyn_rcg gmac_core3_src + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core3_src", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, +@@ -2498,8 +2558,8 @@ static struct clk_branch gmac_core3_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core3_clk", +- .parent_names = (const char *[]){ +- "gmac_core3_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gmac_core3_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -2553,7 +2613,7 @@ static struct clk_dyn_rcg gmac_core4_src + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core4_src", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, +@@ -2570,8 +2630,8 @@ static struct clk_branch gmac_core4_clk + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gmac_core4_clk", +- .parent_names = (const char *[]){ +- "gmac_core4_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &gmac_core4_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -2613,7 +2673,7 @@ static struct clk_dyn_rcg nss_tcm_src = + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "nss_tcm_src", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + }, +@@ -2628,8 +2688,8 @@ static struct clk_branch nss_tcm_clk = { + .enable_mask = BIT(6) | BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "nss_tcm_clk", +- .parent_names = (const char *[]){ +- "nss_tcm_src", ++ .parent_hws = (const struct clk_hw*[]){ ++ &nss_tcm_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch_ops, +@@ -2691,7 +2751,7 @@ static struct clk_dyn_rcg ubi32_core1_sr + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core1_src_clk", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, +@@ -2744,7 +2804,7 @@ static struct clk_dyn_rcg ubi32_core2_sr + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core2_src_clk", +- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, ++ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, + .num_parents = 5, + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch new file mode 100644 index 00000000000..6e6cec7db5c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch @@ -0,0 +1,325 @@ +From a6aedd6532131bc81d47bbf63385dfcf2a0e9faa Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:26 +0100 +Subject: [PATCH 06/14] clk: qcom: gcc-ipq806x: use ARRAY_SIZE for num_parents + +Use ARRAY_SIZE for num_parents instead of hardcoding the value. + +Signed-off-by: Ansuel Smith +Reviewed-by: Bjorn Andersson +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-7-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 68 +++++++++++++++++----------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -373,7 +373,7 @@ static struct clk_rcg gsbi1_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -424,7 +424,7 @@ static struct clk_rcg gsbi2_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -475,7 +475,7 @@ static struct clk_rcg gsbi4_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -526,7 +526,7 @@ static struct clk_rcg gsbi5_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -577,7 +577,7 @@ static struct clk_rcg gsbi6_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -628,7 +628,7 @@ static struct clk_rcg gsbi7_uart_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_uart_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -692,7 +692,7 @@ static struct clk_rcg gsbi1_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi1_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -743,7 +743,7 @@ static struct clk_rcg gsbi2_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi2_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -794,7 +794,7 @@ static struct clk_rcg gsbi4_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -845,7 +845,7 @@ static struct clk_rcg gsbi5_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi5_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -896,7 +896,7 @@ static struct clk_rcg gsbi6_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi6_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -947,7 +947,7 @@ static struct clk_rcg gsbi7_qup_src = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi7_qup_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -1099,7 +1099,7 @@ static struct clk_rcg gp0_src = { + .hw.init = &(struct clk_init_data){ + .name = "gp0_src", + .parent_data = gcc_pxo_pll8_cxo, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), + .ops = &clk_rcg_ops, + .flags = CLK_SET_PARENT_GATE, + }, +@@ -1150,7 +1150,7 @@ static struct clk_rcg gp1_src = { + .hw.init = &(struct clk_init_data){ + .name = "gp1_src", + .parent_data = gcc_pxo_pll8_cxo, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -1201,7 +1201,7 @@ static struct clk_rcg gp2_src = { + .hw.init = &(struct clk_init_data){ + .name = "gp2_src", + .parent_data = gcc_pxo_pll8_cxo, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -1257,7 +1257,7 @@ static struct clk_rcg prng_src = { + .hw.init = &(struct clk_init_data){ + .name = "prng_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + }, + }, +@@ -1321,7 +1321,7 @@ static struct clk_rcg sdc1_src = { + .hw.init = &(struct clk_init_data){ + .name = "sdc1_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + }, + } +@@ -1371,7 +1371,7 @@ static struct clk_rcg sdc3_src = { + .hw.init = &(struct clk_init_data){ + .name = "sdc3_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + }, + } +@@ -1456,7 +1456,7 @@ static struct clk_rcg tsif_ref_src = { + .hw.init = &(struct clk_init_data){ + .name = "tsif_ref_src", + .parent_data = gcc_pxo_pll8, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, + }, + } +@@ -1620,7 +1620,7 @@ static struct clk_rcg pcie_ref_src = { + .hw.init = &(struct clk_init_data){ + .name = "pcie_ref_src", + .parent_data = gcc_pxo_pll3, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -1714,7 +1714,7 @@ static struct clk_rcg pcie1_ref_src = { + .hw.init = &(struct clk_init_data){ + .name = "pcie1_ref_src", + .parent_data = gcc_pxo_pll3, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -1808,7 +1808,7 @@ static struct clk_rcg pcie2_ref_src = { + .hw.init = &(struct clk_init_data){ + .name = "pcie2_ref_src", + .parent_data = gcc_pxo_pll3, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -1907,7 +1907,7 @@ static struct clk_rcg sata_ref_src = { + .hw.init = &(struct clk_init_data){ + .name = "sata_ref_src", + .parent_data = gcc_pxo_pll3, +- .num_parents = 2, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -2048,7 +2048,7 @@ static struct clk_rcg usb30_master_clk_s + .hw.init = &(struct clk_init_data){ + .name = "usb30_master_ref_src", + .parent_data = gcc_pxo_pll8_pll0, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -2122,7 +2122,7 @@ static struct clk_rcg usb30_utmi_clk = { + .hw.init = &(struct clk_init_data){ + .name = "usb30_utmi_clk", + .parent_data = gcc_pxo_pll8_pll0, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -2196,7 +2196,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s + .hw.init = &(struct clk_init_data){ + .name = "usb_hs1_xcvr_src", + .parent_data = gcc_pxo_pll8_pll0, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -2262,7 +2262,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s + .hw.init = &(struct clk_init_data){ + .name = "usb_fs1_xcvr_src", + .parent_data = gcc_pxo_pll8_pll0, +- .num_parents = 3, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -2398,7 +2398,7 @@ static struct clk_dyn_rcg gmac_core1_src + .hw.init = &(struct clk_init_data){ + .name = "gmac_core1_src", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + }, + }, +@@ -2470,7 +2470,7 @@ static struct clk_dyn_rcg gmac_core2_src + .hw.init = &(struct clk_init_data){ + .name = "gmac_core2_src", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + }, + }, +@@ -2542,7 +2542,7 @@ static struct clk_dyn_rcg gmac_core3_src + .hw.init = &(struct clk_init_data){ + .name = "gmac_core3_src", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + }, + }, +@@ -2614,7 +2614,7 @@ static struct clk_dyn_rcg gmac_core4_src + .hw.init = &(struct clk_init_data){ + .name = "gmac_core4_src", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + }, + }, +@@ -2674,7 +2674,7 @@ static struct clk_dyn_rcg nss_tcm_src = + .hw.init = &(struct clk_init_data){ + .name = "nss_tcm_src", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + }, + }, +@@ -2752,7 +2752,7 @@ static struct clk_dyn_rcg ubi32_core1_sr + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core1_src_clk", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, +@@ -2805,7 +2805,7 @@ static struct clk_dyn_rcg ubi32_core2_sr + .hw.init = &(struct clk_init_data){ + .name = "ubi32_core2_src_clk", + .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, +- .num_parents = 5, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), + .ops = &clk_dyn_rcg_ops, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + }, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch new file mode 100644 index 00000000000..b0f09ec34dc --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch @@ -0,0 +1,88 @@ +From 512ea2edfe15ffa2cd839b3a31d768145f2edc20 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:27 +0100 +Subject: [PATCH 07/14] clk: qcom: gcc-ipq806x: add additional freq nss cores + +Ipq8065 SoC (an evolution of ipq8064 SoC) contains nss cores that can be +clocked to 800MHz. Add these missing freq to the gcc driver. +Set the freq_tbl for the ubi32_cores to the correct values based on the +machine compatible. + +Signed-off-by: Ansuel Smith +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-8-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -232,7 +232,9 @@ static struct clk_regmap pll14_vote = { + + static struct pll_freq_tbl pll18_freq_tbl[] = { + NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), ++ NSS_PLL_RATE(600000000, 48, 0, 1, 0x01495625), + NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), ++ NSS_PLL_RATE(800000000, 64, 0, 1, 0x01495625), + }; + + static struct clk_pll pll18 = { +@@ -2698,7 +2700,7 @@ static struct clk_branch nss_tcm_clk = { + }, + }; + +-static const struct freq_tbl clk_tbl_nss[] = { ++static const struct freq_tbl clk_tbl_nss_ipq8064[] = { + { 110000000, P_PLL18, 1, 1, 5 }, + { 275000000, P_PLL18, 2, 0, 0 }, + { 550000000, P_PLL18, 1, 0, 0 }, +@@ -2706,6 +2708,14 @@ static const struct freq_tbl clk_tbl_nss + { } + }; + ++static const struct freq_tbl clk_tbl_nss_ipq8065[] = { ++ { 110000000, P_PLL18, 1, 1, 5 }, ++ { 275000000, P_PLL18, 2, 0, 0 }, ++ { 600000000, P_PLL18, 1, 0, 0 }, ++ { 800000000, P_PLL18, 1, 0, 0 }, ++ { } ++}; ++ + static struct clk_dyn_rcg ubi32_core1_src_clk = { + .ns_reg[0] = 0x3d2c, + .ns_reg[1] = 0x3d30, +@@ -2745,7 +2755,7 @@ static struct clk_dyn_rcg ubi32_core1_sr + .pre_div_width = 2, + }, + .mux_sel_bit = 0, +- .freq_tbl = clk_tbl_nss, ++ /* nss freq table is selected based on the SoC compatible */ + .clkr = { + .enable_reg = 0x3d20, + .enable_mask = BIT(1), +@@ -2798,7 +2808,7 @@ static struct clk_dyn_rcg ubi32_core2_sr + .pre_div_width = 2, + }, + .mux_sel_bit = 0, +- .freq_tbl = clk_tbl_nss, ++ /* nss freq table is selected based on the SoC compatible */ + .clkr = { + .enable_reg = 0x3d40, + .enable_mask = BIT(1), +@@ -3131,6 +3141,14 @@ static int gcc_ipq806x_probe(struct plat + if (ret) + return ret; + ++ if (of_machine_is_compatible("qcom,ipq8065")) { ++ ubi32_core1_src_clk.freq_tbl = clk_tbl_nss_ipq8065; ++ ubi32_core2_src_clk.freq_tbl = clk_tbl_nss_ipq8065; ++ } else { ++ ubi32_core1_src_clk.freq_tbl = clk_tbl_nss_ipq8064; ++ ubi32_core2_src_clk.freq_tbl = clk_tbl_nss_ipq8064; ++ } ++ + ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc); + if (ret) + return ret; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch new file mode 100644 index 00000000000..3d55cb421a1 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch @@ -0,0 +1,65 @@ +From 28aa450d38e521de45be951df052d2c49a17fae2 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:28 +0100 +Subject: [PATCH 08/14] clk: qcom: gcc-ipq806x: add unusued flag for critical + clock + +Some clocks are used by other devices present on the SoC. For example +the gsbi4_h_clk is used by RPM and is if disabled cause the RPM to +reject any regulator change command. These clock should never be +disabled. + +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-9-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -798,7 +798,7 @@ static struct clk_rcg gsbi4_qup_src = { + .parent_data = gcc_pxo_pll8, + .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -816,7 +816,7 @@ static struct clk_branch gsbi4_qup_clk = + }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -900,7 +900,7 @@ static struct clk_rcg gsbi6_qup_src = { + .parent_data = gcc_pxo_pll8, + .num_parents = ARRAY_SIZE(gcc_pxo_pll8), + .ops = &clk_rcg_ops, +- .flags = CLK_SET_PARENT_GATE, ++ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -969,7 +969,7 @@ static struct clk_branch gsbi7_qup_clk = + }, + .num_parents = 1, + .ops = &clk_branch_ops, +- .flags = CLK_SET_RATE_PARENT, ++ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, + }, + }; +@@ -1015,6 +1015,7 @@ static struct clk_branch gsbi4_h_clk = { + .hw.init = &(struct clk_init_data){ + .name = "gsbi4_h_clk", + .ops = &clk_branch_ops, ++ .flags = CLK_IGNORE_UNUSED, + }, + }, + }; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch new file mode 100644 index 00000000000..22bd040d1bf --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch @@ -0,0 +1,69 @@ +From 33958ad3fc02aeb06a4634e59689a9559d968e1f Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:29 +0100 +Subject: [PATCH 09/14] clk: qcom: clk-rcg: add clk_rcg_floor_ops ops + +Add clk_rcg_floor_ops for clock that can't provide a stable freq and +require to use a floor freq to provide the requested frequency. + +Signed-off-by: Ansuel Smith +Reviewed-by: Bjorn Andersson +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-10-ansuelsmth@gmail.com +--- + drivers/clk/qcom/clk-rcg.c | 24 ++++++++++++++++++++++++ + drivers/clk/qcom/clk-rcg.h | 1 + + 2 files changed, 25 insertions(+) + +--- a/drivers/clk/qcom/clk-rcg.c ++++ b/drivers/clk/qcom/clk-rcg.c +@@ -526,6 +526,19 @@ static int clk_rcg_set_rate(struct clk_h + return __clk_rcg_set_rate(rcg, f); + } + ++static int clk_rcg_set_floor_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct clk_rcg *rcg = to_clk_rcg(hw); ++ const struct freq_tbl *f; ++ ++ f = qcom_find_freq_floor(rcg->freq_tbl, rate); ++ if (!f) ++ return -EINVAL; ++ ++ return __clk_rcg_set_rate(rcg, f); ++} ++ + static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +@@ -816,6 +829,17 @@ const struct clk_ops clk_rcg_ops = { + }; + EXPORT_SYMBOL_GPL(clk_rcg_ops); + ++const struct clk_ops clk_rcg_floor_ops = { ++ .enable = clk_enable_regmap, ++ .disable = clk_disable_regmap, ++ .get_parent = clk_rcg_get_parent, ++ .set_parent = clk_rcg_set_parent, ++ .recalc_rate = clk_rcg_recalc_rate, ++ .determine_rate = clk_rcg_determine_rate, ++ .set_rate = clk_rcg_set_floor_rate, ++}; ++EXPORT_SYMBOL_GPL(clk_rcg_floor_ops); ++ + const struct clk_ops clk_rcg_bypass_ops = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, +--- a/drivers/clk/qcom/clk-rcg.h ++++ b/drivers/clk/qcom/clk-rcg.h +@@ -86,6 +86,7 @@ struct clk_rcg { + }; + + extern const struct clk_ops clk_rcg_ops; ++extern const struct clk_ops clk_rcg_floor_ops; + extern const struct clk_ops clk_rcg_bypass_ops; + extern const struct clk_ops clk_rcg_bypass2_ops; + extern const struct clk_ops clk_rcg_pixel_ops; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch new file mode 100644 index 00000000000..3bb5e57c87a --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch @@ -0,0 +1,38 @@ +From 7e726f34c782b2ca28a29ca9870e34e4319d65bc Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:30 +0100 +Subject: [PATCH 10/14] clk: qcom: gcc-ipq806x: add additional freq for sdc + table + +Add additional freq supported for the sdc table. The ops are changed to +the floor_ops to handle a freq request of 52kHz where we need to provide +a freq of 51.2kHz instead for stability reason. + +Signed-off-by: Ansuel Smith +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-11-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -1292,6 +1292,7 @@ static const struct freq_tbl clk_tbl_sdc + { 20210000, P_PLL8, 1, 1, 19 }, + { 24000000, P_PLL8, 4, 1, 4 }, + { 48000000, P_PLL8, 4, 1, 2 }, ++ { 51200000, P_PLL8, 1, 2, 15 }, + { 64000000, P_PLL8, 3, 1, 2 }, + { 96000000, P_PLL8, 4, 0, 0 }, + { 192000000, P_PLL8, 2, 0, 0 }, +@@ -1325,7 +1326,7 @@ static struct clk_rcg sdc1_src = { + .name = "sdc1_src", + .parent_data = gcc_pxo_pll8, + .num_parents = ARRAY_SIZE(gcc_pxo_pll8), +- .ops = &clk_rcg_ops, ++ .ops = &clk_rcg_floor_ops, + }, + } + }; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch new file mode 100644 index 00000000000..858c6f78a52 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch @@ -0,0 +1,39 @@ +From b565d66403e3df303a058c0d8d00d0fc6aeb2ddc Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:31 +0100 +Subject: [PATCH 11/14] dt-bindings: clock: add ipq8064 ce5 clk define + +Add ipq8064 ce5 clk define needed for CryptoEngine in gcc driver. +Define CE5_SRC is not used so it's OK to change and we align it to +the QSDK naming. + +Signed-off-by: Ansuel Smith +Acked-by: Rob Herring +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-12-ansuelsmth@gmail.com +--- + include/dt-bindings/clock/qcom,gcc-ipq806x.h | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h +@@ -240,7 +240,7 @@ + #define PLL14 232 + #define PLL14_VOTE 233 + #define PLL18 234 +-#define CE5_SRC 235 ++#define CE5_A_CLK 235 + #define CE5_H_CLK 236 + #define CE5_CORE_CLK 237 + #define CE3_SLEEP_CLK 238 +@@ -283,5 +283,8 @@ + #define EBI2_AON_CLK 281 + #define NSSTCM_CLK_SRC 282 + #define NSSTCM_CLK 283 ++#define CE5_A_CLK_SRC 285 ++#define CE5_H_CLK_SRC 286 ++#define CE5_CORE_CLK_SRC 287 + + #endif diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch new file mode 100644 index 00000000000..3ded707bf0c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch @@ -0,0 +1,304 @@ +From b293510f3961b90dcab59965f57779be93ceda7c Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:32 +0100 +Subject: [PATCH 12/14] clk: qcom: gcc-ipq806x: add CryptoEngine clocks + +Add missing CryptoEngine clocks and pll11 required clock. + +Signed-off-by: Ansuel Smith +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-13-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 244 +++++++++++++++++++++++++++++++++ + 1 file changed, 244 insertions(+) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -256,6 +256,24 @@ static struct clk_pll pll18 = { + }, + }; + ++static struct clk_pll pll11 = { ++ .l_reg = 0x3184, ++ .m_reg = 0x3188, ++ .n_reg = 0x318c, ++ .config_reg = 0x3194, ++ .mode_reg = 0x3180, ++ .status_reg = 0x3198, ++ .status_bit = 16, ++ .clkr.hw.init = &(struct clk_init_data){ ++ .name = "pll11", ++ .parent_data = &(const struct clk_parent_data){ ++ .fw_name = "pxo", ++ }, ++ .num_parents = 1, ++ .ops = &clk_pll_ops, ++ }, ++}; ++ + enum { + P_PXO, + P_PLL8, +@@ -264,6 +282,7 @@ enum { + P_CXO, + P_PLL14, + P_PLL18, ++ P_PLL11, + }; + + static const struct parent_map gcc_pxo_pll8_map[] = { +@@ -331,6 +350,44 @@ static const struct clk_parent_data gcc_ + { .hw = &pll18.clkr.hw }, + }; + ++static const struct parent_map gcc_pxo_pll8_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL8, 4 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const struct clk_parent_data gcc_pxo_pll8_pll0_pll14_pll18_pll11[] = { ++ { .fw_name = "pxo" }, ++ { .hw = &pll8_vote.hw }, ++ { .hw = &pll0_vote.hw }, ++ { .hw = &pll14.clkr.hw }, ++ { .hw = &pll18.clkr.hw }, ++ { .hw = &pll11.clkr.hw }, ++ ++}; ++ ++static const struct parent_map gcc_pxo_pll3_pll0_pll14_pll18_pll11_map[] = { ++ { P_PXO, 0 }, ++ { P_PLL3, 6 }, ++ { P_PLL0, 2 }, ++ { P_PLL14, 5 }, ++ { P_PLL18, 1 }, ++ { P_PLL11, 3 }, ++}; ++ ++static const struct clk_parent_data gcc_pxo_pll3_pll0_pll14_pll18_pll11[] = { ++ { .fw_name = "pxo" }, ++ { .hw = &pll3.clkr.hw }, ++ { .hw = &pll0_vote.hw }, ++ { .hw = &pll14.clkr.hw }, ++ { .hw = &pll18.clkr.hw }, ++ { .hw = &pll11.clkr.hw }, ++ ++}; ++ + static struct freq_tbl clk_tbl_gsbi_uart[] = { + { 1843200, P_PLL8, 2, 6, 625 }, + { 3686400, P_PLL8, 2, 12, 625 }, +@@ -2824,6 +2881,186 @@ static struct clk_dyn_rcg ubi32_core2_sr + }, + }; + ++static const struct freq_tbl clk_tbl_ce5_core[] = { ++ { 150000000, P_PLL3, 8, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_core_src = { ++ .ns_reg[0] = 0x36C4, ++ .ns_reg[1] = 0x36C8, ++ .bank_reg = 0x36C0, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_core, ++ .clkr = { ++ .enable_reg = 0x36C0, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_src", ++ .parent_data = gcc_pxo_pll3_pll0_pll14_pll18_pll11, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll3_pll0_pll14_pll18_pll11), ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_core_clk = { ++ .halt_reg = 0x2FDC, ++ .halt_bit = 5, ++ .hwcg_reg = 0x36CC, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x36CC, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_core_clk", ++ .parent_hws = (const struct clk_hw*[]){ ++ &ce5_core_src.clkr.hw, ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_a_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_a_clk_src = { ++ .ns_reg[0] = 0x3d84, ++ .ns_reg[1] = 0x3d88, ++ .bank_reg = 0x3d80, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_a_clk, ++ .clkr = { ++ .enable_reg = 0x3d80, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk_src", ++ .parent_data = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0_pll14_pll18_pll11), ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_a_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 12, ++ .hwcg_reg = 0x3d8c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3d8c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_a_clk", ++ .parent_hws = (const struct clk_hw*[]){ ++ &ce5_a_clk_src.clkr.hw, ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ ++static const struct freq_tbl clk_tbl_ce5_h_clk[] = { ++ { 160000000, P_PLL0, 5, 1, 1 }, ++ { 213200000, P_PLL11, 5, 1, 1 }, ++ { } ++}; ++ ++static struct clk_dyn_rcg ce5_h_clk_src = { ++ .ns_reg[0] = 0x3c64, ++ .ns_reg[1] = 0x3c68, ++ .bank_reg = 0x3c60, ++ .s[0] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .s[1] = { ++ .src_sel_shift = 0, ++ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, ++ }, ++ .p[0] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .p[1] = { ++ .pre_div_shift = 3, ++ .pre_div_width = 4, ++ }, ++ .mux_sel_bit = 0, ++ .freq_tbl = clk_tbl_ce5_h_clk, ++ .clkr = { ++ .enable_reg = 0x3c60, ++ .enable_mask = BIT(1), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk_src", ++ .parent_data = gcc_pxo_pll8_pll0_pll14_pll18_pll11, ++ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0_pll14_pll18_pll11), ++ .ops = &clk_dyn_rcg_ops, ++ }, ++ }, ++}; ++ ++static struct clk_branch ce5_h_clk = { ++ .halt_reg = 0x3c20, ++ .halt_bit = 11, ++ .hwcg_reg = 0x3c6c, ++ .hwcg_bit = 6, ++ .clkr = { ++ .enable_reg = 0x3c6c, ++ .enable_mask = BIT(4), ++ .hw.init = &(struct clk_init_data){ ++ .name = "ce5_h_clk", ++ .parent_hws = (const struct clk_hw*[]){ ++ &ce5_h_clk_src.clkr.hw, ++ }, ++ .num_parents = 1, ++ .ops = &clk_branch_ops, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++ }, ++}; ++ + static struct clk_regmap *gcc_ipq806x_clks[] = { + [PLL0] = &pll0.clkr, + [PLL0_VOTE] = &pll0_vote, +@@ -2831,6 +3068,7 @@ static struct clk_regmap *gcc_ipq806x_cl + [PLL4_VOTE] = &pll4_vote, + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, ++ [PLL11] = &pll11.clkr, + [PLL14] = &pll14.clkr, + [PLL14_VOTE] = &pll14_vote, + [PLL18] = &pll18.clkr, +@@ -2945,6 +3183,12 @@ static struct clk_regmap *gcc_ipq806x_cl + [PLL9] = &hfpll0.clkr, + [PLL10] = &hfpll1.clkr, + [PLL12] = &hfpll_l2.clkr, ++ [CE5_A_CLK_SRC] = &ce5_a_clk_src.clkr, ++ [CE5_A_CLK] = &ce5_a_clk.clkr, ++ [CE5_H_CLK_SRC] = &ce5_h_clk_src.clkr, ++ [CE5_H_CLK] = &ce5_h_clk.clkr, ++ [CE5_CORE_CLK_SRC] = &ce5_core_src.clkr, ++ [CE5_CORE_CLK] = &ce5_core_clk.clkr, + }; + + static const struct qcom_reset_map gcc_ipq806x_resets[] = { diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch new file mode 100644 index 00000000000..5d05c2b3af3 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch @@ -0,0 +1,29 @@ +From f4a7e56f4956f0450b9f671ed93d45ffcc15aa62 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 18 Jan 2022 01:22:05 +0100 +Subject: [PATCH v6 13/15] dt-bindings: reset: add ipq8064 ce5 resets + +Add ipq8064 ce5 resets needed for CryptoEngine gcc driver. + +Signed-off-by: Ansuel Smith +Reviewed-by: Bjorn Andersson +Acked-by: Philipp Zabel +Acked-by: Rob Herring +Reviewed-by: Stephen Boyd +--- + include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h ++++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h +@@ -163,5 +163,10 @@ + #define NSS_CAL_PRBS_RST_N_RESET 154 + #define NSS_LCKDT_RST_N_RESET 155 + #define NSS_SRDS_N_RESET 156 ++#define CRYPTO_ENG1_RESET 157 ++#define CRYPTO_ENG2_RESET 158 ++#define CRYPTO_ENG3_RESET 159 ++#define CRYPTO_ENG4_RESET 160 ++#define CRYPTO_AHB_RESET 161 + + #endif diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch new file mode 100644 index 00000000000..a26f67e36e0 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch @@ -0,0 +1,30 @@ +From 4f865bdcb44fb18951de94be5c2ec37a891a8d03 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:34 +0100 +Subject: [PATCH 14/14] clk: qcom: gcc-ipq806x: add CryptoEngine resets + +Add missing CryptoEngine resets. + +Signed-off-by: Ansuel Smith +Reviewed-by: Stephen Boyd +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-15-ansuelsmth@gmail.com +--- + drivers/clk/qcom/gcc-ipq806x.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -3320,6 +3320,11 @@ static const struct qcom_reset_map gcc_i + [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, + [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, + [GMAC_AHB_RESET] = { 0x3e24, 0 }, ++ [CRYPTO_ENG1_RESET] = { 0x3e00, 0}, ++ [CRYPTO_ENG2_RESET] = { 0x3e04, 0}, ++ [CRYPTO_ENG3_RESET] = { 0x3e08, 0}, ++ [CRYPTO_ENG4_RESET] = { 0x3e0c, 0}, ++ [CRYPTO_AHB_RESET] = { 0x3e10, 0}, + [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, + [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, + [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, diff --git a/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch b/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch new file mode 100644 index 00000000000..bd492ca1ecd --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch @@ -0,0 +1,151 @@ +From 9ec092d2feb69045dd289845024301fb91c064ee Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Tue, 14 Jun 2022 13:22:27 +0200 +Subject: [PATCH 1/2] net: ethernet: stmmac: add missing sgmii configure for + ipq806x + +The different gmacid require different configuration based on the soc +and on the gmac id. Add these missing configuration taken from the +original driver. + +Signed-off-by: Christian 'Ansuel' Marangi +Link: https://lore.kernel.org/r/20220614112228.1998-1-ansuelsmth@gmail.com +Signed-off-by: Paolo Abeni +--- + drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 + + .../ethernet/stmicro/stmmac/dwmac-ipq806x.c | 93 +++++++++++++++---- + 2 files changed, 78 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -83,6 +83,7 @@ config DWMAC_IPQ806X + default ARCH_QCOM + depends on OF && (ARCH_QCOM || COMPILE_TEST) + select MFD_SYSCON ++ select QCOM_SOCINFO + help + Support for QCA IPQ806X DWMAC Ethernet. + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -27,6 +27,8 @@ + #include + #include + #include ++#include ++#include + + #include "stmmac_platform.h" + +@@ -75,11 +77,20 @@ + #define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2) + #define QSGMII_PHY_TX_DRIVER_EN BIT(3) + #define QSGMII_PHY_QSGMII_EN BIT(7) +-#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12 +-#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18 +-#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20 +-#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22 +-#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28 ++#define QSGMII_PHY_DEEMPHASIS_LVL_MASK GENMASK(11, 10) ++#define QSGMII_PHY_DEEMPHASIS_LVL(x) FIELD_PREP(QSGMII_PHY_DEEMPHASIS_LVL_MASK, (x)) ++#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK GENMASK(14, 12) ++#define QSGMII_PHY_PHASE_LOOP_GAIN(x) FIELD_PREP(QSGMII_PHY_PHASE_LOOP_GAIN_MASK, (x)) ++#define QSGMII_PHY_RX_DC_BIAS_MASK GENMASK(19, 18) ++#define QSGMII_PHY_RX_DC_BIAS(x) FIELD_PREP(QSGMII_PHY_RX_DC_BIAS_MASK, (x)) ++#define QSGMII_PHY_RX_INPUT_EQU_MASK GENMASK(21, 20) ++#define QSGMII_PHY_RX_INPUT_EQU(x) FIELD_PREP(QSGMII_PHY_RX_INPUT_EQU_MASK, (x)) ++#define QSGMII_PHY_CDR_PI_SLEW_MASK GENMASK(23, 22) ++#define QSGMII_PHY_CDR_PI_SLEW(x) FIELD_PREP(QSGMII_PHY_CDR_PI_SLEW_MASK, (x)) ++#define QSGMII_PHY_TX_SLEW_MASK GENMASK(27, 26) ++#define QSGMII_PHY_TX_SLEW(x) FIELD_PREP(QSGMII_PHY_TX_SLEW_MASK, (x)) ++#define QSGMII_PHY_TX_DRV_AMP_MASK GENMASK(31, 28) ++#define QSGMII_PHY_TX_DRV_AMP(x) FIELD_PREP(QSGMII_PHY_TX_DRV_AMP_MASK, (x)) + + struct ipq806x_gmac { + struct platform_device *pdev; +@@ -242,6 +253,64 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = { ++ { ++ .revision = "1.*", ++ }, ++ { ++ /* sentinel */ ++ } ++}; ++ ++static int ++ipq806x_gmac_configure_qsgmii_params(struct ipq806x_gmac *gmac) ++{ ++ struct platform_device *pdev = gmac->pdev; ++ const struct soc_device_attribute *soc; ++ struct device *dev = &pdev->dev; ++ u32 qsgmii_param; ++ ++ switch (gmac->id) { ++ case 1: ++ soc = soc_device_match(ipq806x_gmac_soc_v1); ++ ++ if (soc) ++ qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xc) | ++ QSGMII_PHY_TX_SLEW(0x2) | ++ QSGMII_PHY_DEEMPHASIS_LVL(0x2); ++ else ++ qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xd) | ++ QSGMII_PHY_TX_SLEW(0x0) | ++ QSGMII_PHY_DEEMPHASIS_LVL(0x0); ++ ++ qsgmii_param |= QSGMII_PHY_RX_DC_BIAS(0x2); ++ break; ++ case 2: ++ case 3: ++ qsgmii_param = QSGMII_PHY_RX_DC_BIAS(0x3) | ++ QSGMII_PHY_TX_DRV_AMP(0xc); ++ break; ++ default: /* gmac 0 can't be set in SGMII mode */ ++ dev_err(dev, "gmac id %d can't be in SGMII mode", gmac->id); ++ return -EINVAL; ++ } ++ ++ /* Common params across all gmac id */ ++ qsgmii_param |= QSGMII_PHY_CDR_EN | ++ QSGMII_PHY_RX_FRONT_EN | ++ QSGMII_PHY_RX_SIGNAL_DETECT_EN | ++ QSGMII_PHY_TX_DRIVER_EN | ++ QSGMII_PHY_QSGMII_EN | ++ QSGMII_PHY_PHASE_LOOP_GAIN(0x4) | ++ QSGMII_PHY_RX_INPUT_EQU(0x1) | ++ QSGMII_PHY_CDR_PI_SLEW(0x2); ++ ++ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), ++ qsgmii_param); ++ ++ return 0; ++} ++ + static int ipq806x_gmac_probe(struct platform_device *pdev) + { + struct plat_stmmacenet_data *plat_dat; +@@ -328,17 +397,9 @@ static int ipq806x_gmac_probe(struct pla + regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); + + if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) { +- regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), +- QSGMII_PHY_CDR_EN | +- QSGMII_PHY_RX_FRONT_EN | +- QSGMII_PHY_RX_SIGNAL_DETECT_EN | +- QSGMII_PHY_TX_DRIVER_EN | +- QSGMII_PHY_QSGMII_EN | +- 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | +- 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET | +- 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | +- 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | +- 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ err = ipq806x_gmac_configure_qsgmii_params(gmac); ++ if (err) ++ goto err_remove_config_dt; + } + + plat_dat->has_gmac = true; diff --git a/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch b/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch new file mode 100644 index 00000000000..d444553452c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch @@ -0,0 +1,110 @@ +From 8bca458990dd8c6d001b2fb52063aa18e8ca7444 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Tue, 14 Jun 2022 13:22:28 +0200 +Subject: [PATCH 2/2] net: ethernet: stmmac: reset force speed bit for ipq806x + +Some bootloader may set the force speed regs even if the actual +interface should use autonegotiation between PCS and PHY. +This cause the complete malfuction of the interface. + +To fix this correctly reset the force speed regs if a fixed-link is not +defined in the DTS. With a fixed-link node correctly configure the +forced speed regs to handle any misconfiguration by the bootloader. + +Reported-by: Mark Mentovai +Co-developed-by: Mark Mentovai +Signed-off-by: Mark Mentovai +Signed-off-by: Christian 'Ansuel' Marangi +Link: https://lore.kernel.org/r/20220614112228.1998-2-ansuelsmth@gmail.com +Signed-off-by: Paolo Abeni +--- + .../ethernet/stmicro/stmmac/dwmac-ipq806x.c | 64 +++++++++++++++++++ + 1 file changed, 64 insertions(+) + +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -66,6 +66,17 @@ + #define NSS_COMMON_CLK_DIV_SGMII_100 4 + #define NSS_COMMON_CLK_DIV_SGMII_10 49 + ++#define QSGMII_PCS_ALL_CH_CTL 0x80 ++#define QSGMII_PCS_CH_SPEED_FORCE BIT(1) ++#define QSGMII_PCS_CH_SPEED_10 0x0 ++#define QSGMII_PCS_CH_SPEED_100 BIT(2) ++#define QSGMII_PCS_CH_SPEED_1000 BIT(3) ++#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ ++ QSGMII_PCS_CH_SPEED_10 | \ ++ QSGMII_PCS_CH_SPEED_100 | \ ++ QSGMII_PCS_CH_SPEED_1000) ++#define QSGMII_PCS_CH_SPEED_SHIFT(x) ((x) * 4) ++ + #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 + #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) + +@@ -253,6 +264,55 @@ static void ipq806x_gmac_fix_mac_speed(v + ipq806x_gmac_set_speed(gmac, speed); + } + ++static int ++ipq806x_gmac_configure_qsgmii_pcs_speed(struct ipq806x_gmac *gmac) ++{ ++ struct platform_device *pdev = gmac->pdev; ++ struct device *dev = &pdev->dev; ++ struct device_node *dn; ++ int link_speed; ++ int val = 0; ++ int ret; ++ ++ /* Some bootloader may apply wrong configuration and cause ++ * not functioning port. If fixed link is not set, ++ * reset the force speed bit. ++ */ ++ if (!of_phy_is_fixed_link(pdev->dev.of_node)) ++ goto write; ++ ++ dn = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); ++ ret = of_property_read_u32(dn, "speed", &link_speed); ++ of_node_put(dn); ++ if (ret) { ++ dev_err(dev, "found fixed-link node with no speed"); ++ return ret; ++ } ++ ++ val = QSGMII_PCS_CH_SPEED_FORCE; ++ ++ switch (link_speed) { ++ case SPEED_1000: ++ val |= QSGMII_PCS_CH_SPEED_1000; ++ break; ++ case SPEED_100: ++ val |= QSGMII_PCS_CH_SPEED_100; ++ break; ++ case SPEED_10: ++ val |= QSGMII_PCS_CH_SPEED_10; ++ break; ++ } ++ ++write: ++ regmap_update_bits(gmac->qsgmii_csr, QSGMII_PCS_ALL_CH_CTL, ++ QSGMII_PCS_CH_SPEED_MASK << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), ++ val << ++ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); ++ ++ return 0; ++} ++ + static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = { + { + .revision = "1.*", +@@ -400,6 +460,10 @@ static int ipq806x_gmac_probe(struct pla + err = ipq806x_gmac_configure_qsgmii_params(gmac); + if (err) + goto err_remove_config_dt; ++ ++ err = ipq806x_gmac_configure_qsgmii_pcs_speed(gmac); ++ if (err) ++ goto err_remove_config_dt; + } + + plat_dat->has_gmac = true; diff --git a/target/linux/ipq806x/patches-6.1/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-6.1/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch new file mode 100644 index 00000000000..e0c195f1ab9 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/102-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch @@ -0,0 +1,25 @@ +From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 9 Mar 2017 09:31:44 +0100 +Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting + +Signed-off-by: John Crispin +--- + drivers/mtd/mtdpart.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -51,7 +51,11 @@ static struct mtd_info *allocate_partiti + + /* allocate the partition structure */ + child = kzalloc(sizeof(*child), GFP_KERNEL); +- name = kstrdup(part->name, GFP_KERNEL); ++ /* "rootfs" conflicts with OpenWrt auto mounting */ ++ if (mtd_type_is_nand(parent) && !strcmp(part->name, "rootfs")) ++ name = "ubi"; ++ else ++ name = kstrdup(part->name, GFP_KERNEL); + if (!name || !child) { + printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n", + parent->name); diff --git a/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch b/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch new file mode 100644 index 00000000000..2ce526b6ca7 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch @@ -0,0 +1,48 @@ +From a5ba119455c77a07e05f2fe0af446c8bf43d1a00 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 26 Feb 2022 14:52:35 +0100 +Subject: [PATCH] ARM: dts: qcom: add syscon and cxo/pxo clock to gcc node for + ipq8064 + +Add syscon compatible required for tsens driver to correctly probe driver +and access the reg. Also add cxo and pxo tag and declare them as gcc clock +now requires them for the ipq8064 gcc driver that has now been modernized. + +Signed-off-by: Ansuel Smith +Reviewed-by: Bjorn Andersson +Reviewed-by: Stephen Boyd +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220226135235.10051-16-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -298,13 +298,13 @@ + }; + + clocks { +- cxo_board { ++ cxo_board: cxo_board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; + +- pxo_board { ++ pxo_board: pxo_board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; +@@ -736,7 +736,9 @@ + }; + + gcc: clock-controller@900000 { +- compatible = "qcom,gcc-ipq8064"; ++ compatible = "qcom,gcc-ipq8064", "syscon"; ++ clocks = <&pxo_board>, <&cxo_board>; ++ clock-names = "pxo", "cxo"; + reg = <0x00900000 0x4000>; + #clock-cells = <1>; + #reset-cells = <1>; diff --git a/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch b/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch new file mode 100644 index 00000000000..d0bc34c07fa --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch @@ -0,0 +1,29 @@ +From eb9e93937756a05787977875830c0dc482cb57e0 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 30 Apr 2022 07:51:17 +0200 +Subject: [PATCH] ARM: dts: qcom: replace gcc PXO with pxo_board fixed clock + +Replace gcc PXO phandle to pxo_board fixed clock declared in the dts. +gcc driver doesn't provide PXO_SRC as it's a fixed-clock. This cause a +kernel panic if any driver actually try to use it. + +Fixes: 40cf5c884a96 ("ARM: dts: qcom: add L2CC and RPM for IPQ8064") +Signed-off-by: Ansuel Smith +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220430055118.1947-2-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -784,7 +784,7 @@ + l2cc: clock-controller@2011000 { + compatible = "qcom,kpss-gcc", "syscon"; + reg = <0x2011000 0x1000>; +- clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; ++ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu_l2_aux"; + }; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch new file mode 100644 index 00000000000..5dad164e3c2 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch @@ -0,0 +1,101 @@ +From 4af1defb305798d1a064a5ea0d0c9b30e5eee185 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:35 +0200 +Subject: [PATCH 1/8] ARM: dts: qcom: ipq8064: add multiple missing pin + definition + +Add missing definition for mdio0 pins used for gpio-bitbang driver,i2c4 +pins and rgmii2 pins for ipq8064. + +Drop i2c4_pins node from ipq8064-ap148 dts as it's now moved to ipq8064 +dtsi. + +Drop mdio0_pins node from ipq8064-rb3011 dts as it's now moved to +ipq8064 dtsi. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-2-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 6 ----- + arch/arm/boot/dts/qcom-ipq8064-rb3011.dts | 9 ------- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 32 +++++++++++++++++++++++ + 3 files changed, 32 insertions(+), 15 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts ++++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +@@ -305,15 +305,6 @@ + }; + }; + +- mdio0_pins: mdio0_pins { +- mux { +- pins = "gpio0", "gpio1"; +- function = "gpio"; +- drive-strength = <8>; +- bias-disable; +- }; +- }; +- + mdio1_pins: mdio1_pins { + mux { + pins = "gpio10", "gpio11"; +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -382,6 +382,13 @@ + }; + }; + ++ i2c4_pins: i2c4-default { ++ pins = "gpio12", "gpio13"; ++ function = "gsbi4"; ++ drive-strength = <12>; ++ bias-disable; ++ }; ++ + spi_pins: spi_pins { + mux { + pins = "gpio18", "gpio19", "gpio21"; +@@ -424,6 +431,8 @@ + + pullups { + pins = "gpio39"; ++ function = "nand"; ++ drive-strength = <10>; + bias-pull-up; + }; + +@@ -431,9 +440,32 @@ + pins = "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47"; ++ function = "nand"; ++ drive-strength = <10>; + bias-bus-hold; + }; + }; ++ ++ mdio0_pins: mdio0-pins { ++ mux { ++ pins = "gpio0", "gpio1"; ++ function = "mdio"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; ++ ++ rgmii2_pins: rgmii2-pins { ++ mux { ++ pins = "gpio27", "gpio28", "gpio29", ++ "gpio30", "gpio31", "gpio32", ++ "gpio51", "gpio52", "gpio59", ++ "gpio60", "gpio61", "gpio62"; ++ function = "rgmii2"; ++ drive-strength = <8>; ++ bias-disable; ++ }; ++ }; + }; + + intc: interrupt-controller@2000000 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch new file mode 100644 index 00000000000..1f4e288fb81 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch @@ -0,0 +1,67 @@ +From d883a12a547b6d42e795ff3b5ac87cfd013b5423 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:36 +0200 +Subject: [PATCH 2/8] ARM: dts: qcom: ipq8064: add gsbi6 missing definition + +Add gsbi6 missing definition for ipq8064. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-3-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 43 +++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -663,6 +663,49 @@ + }; + }; + ++ gsbi6: gsbi@16500000 { ++ compatible = "qcom,gsbi-v1.0.0"; ++ reg = <0x16500000 0x100>; ++ cell-index = <6>; ++ clocks = <&gcc GSBI6_H_CLK>; ++ clock-names = "iface"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ syscon-tcsr = <&tcsr>; ++ ++ status = "disabled"; ++ ++ gsbi6_i2c: i2c@16580000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x16580000 0x1000>; ++ interrupts = ; ++ ++ clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>; ++ clock-names = "core", "iface"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ ++ gsbi6_spi: spi@16580000 { ++ compatible = "qcom,spi-qup-v1.1.1"; ++ reg = <0x16580000 0x1000>; ++ interrupts = ; ++ ++ clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>; ++ clock-names = "core", "iface"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ }; ++ + gsbi7: gsbi@16600000 { + status = "disabled"; + compatible = "qcom,gsbi-v1.0.0"; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch new file mode 100644 index 00000000000..dbba722caaf --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch @@ -0,0 +1,66 @@ +From 5c47a46d5e942ea6b041c8b7727b201817c1ff76 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:37 +0200 +Subject: [PATCH 3/8] ARM: dts: qcom: ipq8064: add specific dtsi with smb208 + rpm regulators + +Add specific ipq8064 dtsi with smb208 rpm regulators. + +Qcom advise to use this configuration but it's not mandatory and OEM +can decide to implement their own regulators. +smb208 regulators are used to scale CPU voltage, L2 cache voltage and +Ubi32 cores. + +There regulators are controlled by rpm and to correctly works gsbi4-i2c +require to be NEVER disabled or rpm will reject any regulator change +request. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-4-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi | 37 ++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + create mode 100644 arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi + +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "qcom-ipq8064.dtsi" ++ ++&rpm { ++ smb208_regulators: regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++}; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch new file mode 100644 index 00000000000..1a3185f500d --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch @@ -0,0 +1,56 @@ +From 0ce34e0c13e99c239cce6099f64b0e95697f36b1 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:38 +0200 +Subject: [PATCH 4/8] ARM: dts: qcom: ipq8064: add missing snps,dwmac + compatible for gmac + +Add missing snps,dwmac compatible for gmac ipq8064 dtsi. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Reviewed-by: Krzysztof Kozlowski +Reviewed-by: Konrad Dybcio +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-5-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1042,7 +1042,7 @@ + + gmac0: ethernet@37000000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37000000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -1066,7 +1066,7 @@ + + gmac1: ethernet@37200000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37200000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -1090,7 +1090,7 @@ + + gmac2: ethernet@37400000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37400000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; +@@ -1114,7 +1114,7 @@ + + gmac3: ethernet@37600000 { + device_type = "network"; +- compatible = "qcom,ipq806x-gmac"; ++ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; + reg = <0x37600000 0x200000>; + interrupts = ; + interrupt-names = "macirq"; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch new file mode 100644 index 00000000000..43dac4b7fa2 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch @@ -0,0 +1,37 @@ +From d63d3124c0a5cdbe8b91d81b922fe56b2462e1b9 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:39 +0200 +Subject: [PATCH 5/8] ARM: dts: qcom: ipq8064: disable usb phy by default + +Disable usb phy by default. When the usb phy were pushed, half of them +were flagged as disabled by mistake. +Correctly disable all usb phy and enable them only if a device actually +use them. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-6-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1188,6 +1188,8 @@ + clocks = <&gcc USB30_1_UTMI_CLK>; + clock-names = "ref"; + #phy-cells = <0>; ++ ++ status = "disabled"; + }; + + ss_phy_1: phy@110f8830 { +@@ -1196,6 +1198,8 @@ + clocks = <&gcc USB30_1_MASTER_CLK>; + clock-names = "ref"; + #phy-cells = <0>; ++ ++ status = "disabled"; + }; + + usb3_1: usb3@110f8800 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch new file mode 100644 index 00000000000..ca5e5aa3c4c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch @@ -0,0 +1,94 @@ +From 6c421a9c08286389bb331fe783e2625c9efcc187 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:41 +0200 +Subject: [PATCH 7/8] ARM: dts: qcom: ipq8064: fix and add some missing gsbi + node + +Add some tag for gsbi to make them usable for ipq8064 SoC. Add missing +gsbi7 i2c node and gsbi1 node. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-8-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 54 ++++++++++++++++++++++++++++- + 1 file changed, 53 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -539,6 +539,44 @@ + regulator; + }; + ++ gsbi1: gsbi@12440000 { ++ compatible = "qcom,gsbi-v1.0.0"; ++ reg = <0x12440000 0x100>; ++ cell-index = <1>; ++ clocks = <&gcc GSBI1_H_CLK>; ++ clock-names = "iface"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ syscon-tcsr = <&tcsr>; ++ ++ status = "disabled"; ++ ++ gsbi1_serial: serial@12450000 { ++ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; ++ reg = <0x12450000 0x100>, ++ <0x12400000 0x03>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ ++ status = "disabled"; ++ }; ++ ++ gsbi1_i2c: i2c@12460000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x12460000 0x1000>; ++ interrupts = ; ++ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>; ++ clock-names = "core", "iface"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; ++ }; ++ + gsbi2: gsbi@12480000 { + compatible = "qcom,gsbi-v1.0.0"; + cell-index = <2>; +@@ -562,7 +600,7 @@ + status = "disabled"; + }; + +- i2c@124a0000 { ++ gsbi2_i2c: i2c@124a0000 { + compatible = "qcom,i2c-qup-v1.1.1"; + reg = <0x124a0000 0x1000>; + interrupts = ; +@@ -727,6 +765,20 @@ + clock-names = "core", "iface"; + status = "disabled"; + }; ++ ++ gsbi7_i2c: i2c@16680000 { ++ compatible = "qcom,i2c-qup-v1.1.1"; ++ reg = <0x16680000 0x1000>; ++ interrupts = ; ++ ++ clocks = <&gcc GSBI7_QUP_CLK>, <&gcc GSBI7_H_CLK>; ++ clock-names = "core", "iface"; ++ ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ status = "disabled"; ++ }; + }; + + rng@1a500000 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch new file mode 100644 index 00000000000..463c3d4a658 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch @@ -0,0 +1,28 @@ +From 7f5aecdd4ffcc018f73171bc0e028cd4e3361acd Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 03:09:43 +0200 +Subject: [PATCH 8/8] ARM: dts: qcom: ipq8064: add speedbin efuse nvmem node + +Add speedbin efuse nvmem cell needed for the opp table for the CPU +freqs. + +Signed-off-by: Christian Marangi +Tested-by: Jonathan McDowell +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707010943.20857-10-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -854,6 +854,9 @@ + reg = <0x00700000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; ++ speedbin_efuse: speedbin@c0 { ++ reg = <0xc0 0x4>; ++ }; + tsens_calib: calib@400 { + reg = <0x400 0xb>; + }; diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch new file mode 100644 index 00000000000..2c6f6b10c48 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch @@ -0,0 +1,71 @@ +From cdab30b44518513003607ecfc8a22de3dbbb78ed Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 12:20:38 +0200 +Subject: [PATCH 1/1] hwspinlock: qcom: Add support for mmio usage to + sfpb-mutex + +Allow sfpb-mutex to use mmio in addition to syscon. + +Signed-off-by: Christian Marangi +Reviewed-by: Bjorn Andersson +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707102040.1859-1-ansuelsmth@gmail.com +--- + drivers/hwspinlock/qcom_hwspinlock.c | 28 +++++++++++++++++++++++----- + 1 file changed, 23 insertions(+), 5 deletions(-) + +--- a/drivers/hwspinlock/qcom_hwspinlock.c ++++ b/drivers/hwspinlock/qcom_hwspinlock.c +@@ -19,6 +19,11 @@ + #define QCOM_MUTEX_APPS_PROC_ID 1 + #define QCOM_MUTEX_NUM_LOCKS 32 + ++struct qcom_hwspinlock_of_data { ++ u32 offset; ++ u32 stride; ++}; ++ + static int qcom_hwspinlock_trylock(struct hwspinlock *lock) + { + struct regmap_field *field = lock->priv; +@@ -63,9 +68,20 @@ static const struct hwspinlock_ops qcom_ + .unlock = qcom_hwspinlock_unlock, + }; + ++static const struct qcom_hwspinlock_of_data of_sfpb_mutex = { ++ .offset = 0x4, ++ .stride = 0x4, ++}; ++ ++/* All modern platform has offset 0 and stride of 4k */ ++static const struct qcom_hwspinlock_of_data of_tcsr_mutex = { ++ .offset = 0, ++ .stride = 0x1000, ++}; ++ + static const struct of_device_id qcom_hwspinlock_of_match[] = { +- { .compatible = "qcom,sfpb-mutex" }, +- { .compatible = "qcom,tcsr-mutex" }, ++ { .compatible = "qcom,sfpb-mutex", .data = &of_sfpb_mutex }, ++ { .compatible = "qcom,tcsr-mutex", .data = &of_tcsr_mutex }, + { } + }; + MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); +@@ -112,12 +128,14 @@ static const struct regmap_config tcsr_m + static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev, + u32 *offset, u32 *stride) + { ++ const struct qcom_hwspinlock_of_data *data; + struct device *dev = &pdev->dev; + void __iomem *base; + +- /* All modern platform has offset 0 and stride of 4k */ +- *offset = 0; +- *stride = 0x1000; ++ data = of_device_get_match_data(dev); ++ ++ *offset = data->offset; ++ *stride = data->stride; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch new file mode 100644 index 00000000000..d8303442f7e --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch @@ -0,0 +1,31 @@ +From fbe4be367b2169602f6a5949a20d2917b25714d4 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 12:20:39 +0200 +Subject: [PATCH 1/2] ARM: dts: qcom: ipq8064: add missing hwlock + +Add missing hwlock for ipq8064 dtsi provided by qcom,sfpb-mutex. + +Signed-off-by: Christian Marangi +Acked-by: Krzysztof Kozlowski +[bjorn: Moved the node inside /soc] +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707102040.1859-2-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1357,5 +1357,12 @@ + dma-names = "tx", "rx"; + }; + }; ++ ++ sfpb_mutex: hwlock@1200600 { ++ compatible = "qcom,sfpb-mutex"; ++ reg = <0x01200600 0x100>; ++ ++ #hwlock-cells = <1>; ++ }; + }; + }; diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch new file mode 100644 index 00000000000..8b91eeb5116 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch @@ -0,0 +1,30 @@ +From 4fefb5434c4b735daf913abaef12431405368031 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 12:20:40 +0200 +Subject: [PATCH 2/2] ARM: dts: qcom: ipq8064: add missing smem compatible + +Add missing smem compatible and hwlocks phandle for ipq8064 dtsi +smem node. + +Signed-off-by: Christian Marangi +Acked-by: Krzysztof Kozlowski +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220707102040.1859-3-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -292,8 +292,11 @@ + }; + + smem: smem@41000000 { ++ compatible = "qcom,smem"; + reg = <0x41000000 0x200000>; + no-map; ++ ++ hwlocks = <&sfpb_mutex 3>; + }; + }; + diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch new file mode 100644 index 00000000000..8b20a550f6f --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch @@ -0,0 +1,129 @@ +From 9f7097a8b1948533a6db1b53b5c0480cc75bbd16 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 18 Jul 2022 18:05:16 +0200 +Subject: [PATCH 1/3] ARM: dts: qcom: ipq8064: add v2 dtsi variant + +Add ipq8064-v2.0 dtsi variant that differ from original ipq8064 SoC for +some additional pcie, sata and usb configuration values, additional +reserved memory and serial output. + +Signed-off-by: Christian Marangi +--- + .../boot/dts/qcom-ipq8064-v2.0-smb208.dtsi | 37 ++++++++++ + arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi | 69 +++++++++++++++++++ + 2 files changed, 106 insertions(+) + create mode 100644 arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi + create mode 100644 arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi + +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "qcom-ipq8064-v2.0.dtsi" ++ ++&rpm { ++ smb208_regulators: regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1250000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi +@@ -0,0 +1,69 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "qcom-ipq8064.dtsi" ++ ++/ { ++ model = "Qualcomm Technologies, Inc. IPQ8064-v2.0"; ++ ++ aliases { ++ serial0 = &gsbi4_serial; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ reserved-memory { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges; ++ ++ rsvd@41200000 { ++ reg = <0x41200000 0x300000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&gsbi4 { ++ qcom,mode = ; ++ status = "okay"; ++ ++ serial@16340000 { ++ status = "okay"; ++ }; ++ /* ++ * The i2c device on gsbi4 should not be enabled. ++ * On ipq806x designs gsbi4 i2c is meant for exclusive ++ * RPM usage. Turning this on in kernel manifests as ++ * i2c failure for the RPM. ++ */ ++}; ++ ++&pcie0 { ++ compatible = "qcom,pcie-ipq8064-v2"; ++}; ++ ++&pcie1 { ++ compatible = "qcom,pcie-ipq8064-v2"; ++}; ++ ++&pcie2 { ++ compatible = "qcom,pcie-ipq8064-v2"; ++}; ++ ++&sata { ++ ports-implemented = <0x1>; ++}; ++ ++&ss_phy_0 { ++ qcom,rx-eq = <2>; ++ qcom,tx-deamp_3_5db = <32>; ++ qcom,mpll = <5>; ++}; ++ ++&ss_phy_1 { ++ qcom,rx-eq = <2>; ++ qcom,tx-deamp_3_5db = <32>; ++ qcom,mpll = <5>; ++}; diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch new file mode 100644 index 00000000000..fdff292480e --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch @@ -0,0 +1,67 @@ +From 41d9fa8de7845bd92d9c963196fdfd7ea9232bb2 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 18 Jul 2022 18:07:26 +0200 +Subject: [PATCH 2/3] ARM: dts: qcom: ipq8064: add ipq8062 variant + +ipq8062 SoC is based on ipq8064-v2.0 with lower supported freq, lack of +usb port and a reduced voltage output with the smb208 regulators. + +Signed-off-by: Christian Marangi +--- + arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi | 37 ++++++++++++++++++++++ + arch/arm/boot/dts/qcom-ipq8062.dtsi | 8 +++++ + 2 files changed, 45 insertions(+) + create mode 100644 arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi + create mode 100644 arch/arm/boot/dts/qcom-ipq8062.dtsi + +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include "qcom-ipq8062.dtsi" ++ ++&rpm { ++ smb208_regulators: regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = < 800000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8062.dtsi +@@ -0,0 +1,8 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include "qcom-ipq8064-v2.0.dtsi" ++ ++/ { ++ model = "Qualcomm Technologies, Inc. IPQ8062"; ++ compatible = "qcom,ipq8062", "qcom,ipq8064"; ++}; diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch new file mode 100644 index 00000000000..bccc577b91c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch @@ -0,0 +1,67 @@ +From 01e7aa3fe6f76f7960f2382038136235eee9c6cd Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 18 Jul 2022 18:09:35 +0200 +Subject: [PATCH 3/3] ARM: dts: qcom: ipq8064: add ipq8065 variant + +ipq8065 SoC is based on ipq8064-v2.0 with a more clocked CPU and +an increased voltage output with the smb208 regulators. + +Signed-off-by: Christian Marangi +--- + arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi | 37 ++++++++++++++++++++++ + arch/arm/boot/dts/qcom-ipq8065.dtsi | 8 +++++ + 2 files changed, 45 insertions(+) + create mode 100644 arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi + create mode 100644 arch/arm/boot/dts/qcom-ipq8065.dtsi + +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi +@@ -0,0 +1,37 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "qcom-ipq8065.dtsi" ++ ++&rpm { ++ smb208_regulators: regulators { ++ compatible = "qcom,rpm-smb208-regulators"; ++ ++ smb208_s1a: s1a { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s1b: s1b { ++ regulator-min-microvolt = <1050000>; ++ regulator-max-microvolt = <1150000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2a: s2a { ++ regulator-min-microvolt = <775000>; ++ regulator-max-microvolt = <1275000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ ++ smb208_s2b: s2b { ++ regulator-min-microvolt = <775000>; ++ regulator-max-microvolt = <1275000>; ++ ++ qcom,switch-mode-frequency = <1200000>; ++ }; ++ }; ++}; +--- /dev/null ++++ b/arch/arm/boot/dts/qcom-ipq8065.dtsi +@@ -0,0 +1,8 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include "qcom-ipq8064-v2.0.dtsi" ++ ++/ { ++ model = "Qualcomm Technologies, Inc. IPQ8065"; ++ compatible = "qcom,ipq8065", "qcom,ipq8064"; ++}; diff --git a/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch new file mode 100644 index 00000000000..418d6b26ce7 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch @@ -0,0 +1,95 @@ +From bef5018abb7cf94efafdc05087b4c998891ae4ec Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 17 Jan 2022 23:39:34 +0100 +Subject: [PATCH v3 10/18] ARM: dts: qcom: add saw for l2 cache and kraitcc for + ipq8064 + +Add saw compatible for l2 cache and kraitcc node for ipq8064 dtsi. +Also declare clock-output-names for acc0 and acc1 and qsb fixed clock +for the secondary mux. + +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 34 +++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -301,6 +301,12 @@ + }; + + clocks { ++ qsb: qsb { ++ compatible = "fixed-clock"; ++ clock-frequency = <225000000>; ++ #clock-cells = <0>; ++ }; ++ + cxo_board: cxo_board { + compatible = "fixed-clock"; + #clock-cells = <0>; +@@ -503,11 +509,19 @@ + acc0: clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu0_aux"; ++ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; ++ clock-names = "pll8_vote", "pxo"; ++ #clock-cells = <0>; + }; + + acc1: clock-controller@2098000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02098000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu1_aux"; ++ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; ++ clock-names = "pll8_vote", "pxo"; ++ #clock-cells = <0>; + }; + + adm_dma: dma-controller@18300000 { +@@ -531,17 +545,23 @@ + }; + + saw0: regulator@2089000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + + saw1: regulator@2099000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + ++ saw_l2: regulator@02012000 { ++ compatible = "qcom,saw2", "syscon"; ++ reg = <0x02012000 0x1000>; ++ regulator; ++ }; ++ + gsbi1: gsbi@12440000 { + compatible = "qcom,gsbi-v1.0.0"; + reg = <0x12440000 0x100>; +@@ -920,6 +940,17 @@ + clocks = <&gcc PLL8_VOTE>, <&pxo_board>; + clock-names = "pll8_vote", "pxo"; + clock-output-names = "acpu_l2_aux"; ++ #clock-cells = <0>; ++ }; ++ ++ kraitcc: clock-controller { ++ compatible = "qcom,krait-cc-v1"; ++ clocks = <&gcc PLL9>, <&gcc PLL10>, <&gcc PLL12>, ++ <&acc0>, <&acc1>, <&l2cc>, <&qsb>, <&pxo_board>; ++ clock-names = "hfpll0", "hfpll1", "hfpll_l2", ++ "acpu0_aux", "acpu1_aux", "acpu_l2_aux", ++ "qsb", "pxo"; ++ #clock-cells = <1>; + }; + + lcc: clock-controller@28000000 { diff --git a/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch b/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch new file mode 100644 index 00000000000..f3c8f18f1de --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch @@ -0,0 +1,268 @@ +From 076ebb6e1799c4c7a1d2e07510d88b9e9b57b551 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 18 Jan 2022 00:03:47 +0100 +Subject: [PATCH v3 13/18] ARM: dts: qcom: add opp table for cpu and l2 for + ipq8064 + +Add opp table for cpu and l2 cache. While the current cpufreq is +the generic one that doesn't scale the L2 cache, we add the l2 +cache opp anyway for the sake of completeness. This will be handy in the +future when a dedicated cpufreq driver is introduced for krait cores +that will correctly scale l2 cache with the core freq. + +Opp-level is set based on the logic of +0: idle level +1: normal level +2: turbo level + +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 99 +++++++++++++++++++++++++++++ + 1 file changed, 99 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -48,6 +48,105 @@ + }; + }; + ++ opp_table_l2: opp_table_l2 { ++ compatible = "operating-points-v2"; ++ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt = <1100000>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ ++ opp_table0: opp_table0 { ++ compatible = "operating-points-v2-kryo-cpu"; ++ nvmem-cells = <&speedbin_efuse>; ++ ++ /* ++ * Voltage thresholds are ++ */ ++ opp-384000000 { ++ opp-hz = /bits/ 64 <384000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1000000 950000 1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <925000 878750 971250>; ++ opp-microvolt-speed0-pvs2-v0 = <875000 831250 918750>; ++ opp-microvolt-speed0-pvs3-v0 = <800000 760000 840000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <0>; ++ }; ++ ++ opp-600000000 { ++ opp-hz = /bits/ 64 <600000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1050000 997500 1102500>; ++ opp-microvolt-speed0-pvs1-v0 = <975000 926250 1023750>; ++ opp-microvolt-speed0-pvs2-v0 = <925000 878750 971250>; ++ opp-microvolt-speed0-pvs3-v0 = <850000 807500 892500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1100000 1045000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs2-v0 = <995000 945250 1044750>; ++ opp-microvolt-speed0-pvs3-v0 = <900000 855000 945000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1000000000 { ++ opp-hz = /bits/ 64 <1000000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1150000 1092500 1207500>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000 1021250 1128750>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs3-v0 = <950000 902500 997500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <1>; ++ }; ++ ++ opp-1200000000 { ++ opp-hz = /bits/ 64 <1200000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1200000 1140000 1260000>; ++ opp-microvolt-speed0-pvs1-v0 = <1125000 1068750 1181250>; ++ opp-microvolt-speed0-pvs2-v0 = <1075000 1021250 1128750>; ++ opp-microvolt-speed0-pvs3-v0 = <1000000 950000 1050000>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1250000 1187500 1312500>; ++ opp-microvolt-speed0-pvs1-v0 = <1175000 1116250 1233750>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000 1068750 1181250>; ++ opp-microvolt-speed0-pvs3-v0 = <1050000 997500 1102500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++ }; ++ + thermal-zones { + tsens_tz_sensor0 { + polling-delay-passive = <0>; +--- a/arch/arm/boot/dts/qcom-ipq8065.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8065.dtsi +@@ -6,3 +6,92 @@ + model = "Qualcomm Technologies, Inc. IPQ8065"; + compatible = "qcom,ipq8065", "qcom,ipq8064"; + }; ++ ++&opp_table_l2 { ++ /delete-node/opp-1200000000; ++ ++ opp-1400000000 { ++ opp-hz = /bits/ 64 <1400000000>; ++ opp-microvolt = <1150000>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++}; ++ ++&opp_table0 { ++ /* ++ * On ipq8065 1.2 ghz freq is not present ++ * Remove it to make cpufreq work and not ++ * complain for missing definition ++ */ ++ ++ /delete-node/opp-1200000000; ++ ++ /* ++ * Voltage thresholds are ++ */ ++ opp-384000000 { ++ opp-microvolt-speed0-pvs0-v0 = <975000 926250 1023750>; ++ opp-microvolt-speed0-pvs1-v0 = <950000 902500 997500>; ++ opp-microvolt-speed0-pvs2-v0 = <925000 878750 971250>; ++ opp-microvolt-speed0-pvs3-v0 = <900000 855000 945000>; ++ opp-microvolt-speed0-pvs4-v0 = <875000 831250 918750>; ++ opp-microvolt-speed0-pvs5-v0 = <825000 783750 866250>; ++ opp-microvolt-speed0-pvs6-v0 = <775000 736250 813750>; ++ }; ++ ++ opp-600000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1000000 950000 1050000>; ++ opp-microvolt-speed0-pvs1-v0 = <975000 926250 1023750>; ++ opp-microvolt-speed0-pvs2-v0 = <950000 902500 997500>; ++ opp-microvolt-speed0-pvs3-v0 = <925000 878750 971250>; ++ opp-microvolt-speed0-pvs4-v0 = <900000 855000 945000>; ++ opp-microvolt-speed0-pvs5-v0 = <850000 807500 892500>; ++ opp-microvolt-speed0-pvs6-v0 = <800000 760000 840000>; ++ }; ++ ++ opp-800000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1050000 997500 1102500>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs2-v0 = <1000000 950000 1050000>; ++ opp-microvolt-speed0-pvs3-v0 = <975000 926250 1023750>; ++ opp-microvolt-speed0-pvs4-v0 = <950000 902500 997500>; ++ opp-microvolt-speed0-pvs5-v0 = <900000 855000 945000>; ++ opp-microvolt-speed0-pvs6-v0 = <850000 807500 892500>; ++ }; ++ ++ opp-1000000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1100000 1045000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000 1021250 1128750>; ++ opp-microvolt-speed0-pvs2-v0 = <1050000 997500 1102500>; ++ opp-microvolt-speed0-pvs3-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs4-v0 = <1000000 950000 1050000>; ++ opp-microvolt-speed0-pvs5-v0 = <950000 902500 997500>; ++ opp-microvolt-speed0-pvs6-v0 = <900000 855000 945000>; ++ }; ++ ++ opp-1400000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1175000 1116250 1233750>; ++ opp-microvolt-speed0-pvs1-v0 = <1150000 1092500 1207500>; ++ opp-microvolt-speed0-pvs2-v0 = <1125000 1068750 1181250>; ++ opp-microvolt-speed0-pvs3-v0 = <1100000 1045000 1155000>; ++ opp-microvolt-speed0-pvs4-v0 = <1075000 1021250 1128750>; ++ opp-microvolt-speed0-pvs5-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs6-v0 = <975000 926250 1023750>; ++ opp-level = <1>; ++ }; ++ ++ opp-1725000000 { ++ opp-hz = /bits/ 64 <1725000000>; ++ opp-microvolt-speed0-pvs0-v0 = <1262500 1199375 1325625>; ++ opp-microvolt-speed0-pvs1-v0 = <1225000 1163750 1286250>; ++ opp-microvolt-speed0-pvs2-v0 = <1200000 1140000 1260000>; ++ opp-microvolt-speed0-pvs3-v0 = <1175000 1116250 1233750>; ++ opp-microvolt-speed0-pvs4-v0 = <1150000 1092500 1207500>; ++ opp-microvolt-speed0-pvs5-v0 = <1100000 1045000 1155000>; ++ opp-microvolt-speed0-pvs6-v0 = <1050000 997500 1102500>; ++ opp-supported-hw = <0x1>; ++ clock-latency-ns = <100000>; ++ opp-level = <2>; ++ }; ++}; +--- a/arch/arm/boot/dts/qcom-ipq8062.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8062.dtsi +@@ -6,3 +6,39 @@ + model = "Qualcomm Technologies, Inc. IPQ8062"; + compatible = "qcom,ipq8062", "qcom,ipq8064"; + }; ++ ++&opp_table0 { ++ /delete-node/opp-1200000000; ++ /delete-node/opp-1400000000; ++ ++ /* ++ * Voltage thresholds are ++ */ ++ opp-384000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1000000 950000 1050000>; ++ opp-microvolt-speed0-pvs1-v0 = < 925000 878750 971250>; ++ opp-microvolt-speed0-pvs2-v0 = < 875000 831250 918750>; ++ opp-microvolt-speed0-pvs3-v0 = < 800000 760000 840000>; ++ }; ++ ++ opp-600000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1050000 997500 1102500>; ++ opp-microvolt-speed0-pvs1-v0 = < 975000 926250 1023750>; ++ opp-microvolt-speed0-pvs2-v0 = < 925000 878750 971250>; ++ opp-microvolt-speed0-pvs3-v0 = < 850000 807500 892500>; ++ }; ++ ++ opp-800000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1100000 1045000 1155000>; ++ opp-microvolt-speed0-pvs1-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs2-v0 = < 995000 945250 1044750>; ++ opp-microvolt-speed0-pvs3-v0 = < 900000 855000 945000>; ++ }; ++ ++ opp-1000000000 { ++ opp-microvolt-speed0-pvs0-v0 = <1150000 1092500 1207500>; ++ opp-microvolt-speed0-pvs1-v0 = <1075000 1021250 1128750>; ++ opp-microvolt-speed0-pvs2-v0 = <1025000 973750 1076250>; ++ opp-microvolt-speed0-pvs3-v0 = < 950000 902500 997500>; ++ }; ++}; diff --git a/target/linux/ipq806x/patches-6.1/107-15-ARM-dts-qcom-add-multiple-missing-binding-for-cpu.patch b/target/linux/ipq806x/patches-6.1/107-15-ARM-dts-qcom-add-multiple-missing-binding-for-cpu.patch new file mode 100644 index 00000000000..cf27aaa08b6 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/107-15-ARM-dts-qcom-add-multiple-missing-binding-for-cpu.patch @@ -0,0 +1,153 @@ +From 211fc0c0a63c99b68663a27182e643316c2d8cbe Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Tue, 18 Jan 2022 00:07:57 +0100 +Subject: [PATCH v3 15/18] ARM: dts: qcom: add multiple missing binding for cpu + and l2 for ipq8064 + +Add multiple binding for cpu node, l2 node and add idle-states +definition for ipq8064 dtsi. + +Signed-off-by: Ansuel Smith +Tested-by: Jonathan McDowell +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 36 +++++++++++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -30,6 +30,15 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc0>; + qcom,saw = <&saw0>; ++ clocks = <&kraitcc 0>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; + }; + + cpu1: cpu@1 { +@@ -40,11 +49,35 @@ + next-level-cache = <&L2>; + qcom,acc = <&acc1>; + qcom,saw = <&saw1>; ++ clocks = <&kraitcc 1>, <&kraitcc 4>; ++ clock-names = "cpu", "l2"; ++ clock-latency = <100000>; ++ operating-points-v2 = <&opp_table0>; ++ voltage-tolerance = <5>; ++ cooling-min-state = <0>; ++ cooling-max-state = <10>; ++ #cooling-cells = <2>; ++ cpu-idle-states = <&CPU_SPC>; ++ }; ++ ++ idle-states { ++ CPU_SPC: spc { ++ compatible = "qcom,idle-state-spc"; ++ status = "disabled"; ++ entry-latency-us = <400>; ++ exit-latency-us = <900>; ++ min-residency-us = <3000>; ++ }; + }; + + L2: l2-cache { + compatible = "cache"; + cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ operating-points-v2 = <&opp_table_l2>; + }; + }; + +--- a/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi +@@ -2,6 +2,18 @@ + + #include "qcom-ipq8064.dtsi" + ++&cpu0 { ++ cpu-supply = <&smb208_s2a>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&smb208_s2b>; ++}; ++ ++&L2 { ++ l2-supply = <&smb208_s1a>; ++}; ++ + &rpm { + smb208_regulators: regulators { + compatible = "qcom,rpm-smb208-regulators"; +--- a/arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi +@@ -2,6 +2,18 @@ + + #include "qcom-ipq8064-v2.0.dtsi" + ++&cpu0 { ++ cpu-supply = <&smb208_s2a>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&smb208_s2b>; ++}; ++ ++&L2 { ++ l2-supply = <&smb208_s1a>; ++}; ++ + &rpm { + smb208_regulators: regulators { + compatible = "qcom,rpm-smb208-regulators"; +--- a/arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi +@@ -2,6 +2,18 @@ + + #include "qcom-ipq8062.dtsi" + ++&cpu0 { ++ cpu-supply = <&smb208_s2a>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&smb208_s2b>; ++}; ++ ++&L2 { ++ l2-supply = <&smb208_s1a>; ++}; ++ + &rpm { + smb208_regulators: regulators { + compatible = "qcom,rpm-smb208-regulators"; +--- a/arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi +@@ -2,6 +2,18 @@ + + #include "qcom-ipq8065.dtsi" + ++&cpu0 { ++ cpu-supply = <&smb208_s2a>; ++}; ++ ++&cpu1 { ++ cpu-supply = <&smb208_s2b>; ++}; ++ ++&L2 { ++ l2-supply = <&smb208_s1a>; ++}; ++ + &rpm { + smb208_regulators: regulators { + compatible = "qcom,rpm-smb208-regulators"; diff --git a/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch b/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch new file mode 100644 index 00000000000..d3f821a6a0f --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch @@ -0,0 +1,29 @@ +From 6c94e0184e56f9e9f1f5d5f54b20758433e498d2 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Wed, 15 Jun 2022 16:47:09 +0200 +Subject: [PATCH 1/2] ARM: dts: qcom: fix wrong nad_pins definition for ipq806x + +Fix wrong nand_pings definition for bias-disable pins. + +Signed-off-by: Christian 'Ansuel' Marangi +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -559,12 +559,9 @@ + }; + + nand_pins: nand_pins { +- mux { ++ disable { + pins = "gpio34", "gpio35", "gpio36", +- "gpio37", "gpio38", "gpio39", +- "gpio40", "gpio41", "gpio42", +- "gpio43", "gpio44", "gpio45", +- "gpio46", "gpio47"; ++ "gpio37", "gpio38"; + function = "nand"; + drive-strength = <10>; + bias-disable; diff --git a/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch b/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch new file mode 100644 index 00000000000..4a57fc0330b --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch @@ -0,0 +1,188 @@ +From 504188183408fac0f61b59f5ed8ea1773fe43669 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Wed, 15 Jun 2022 16:59:30 +0200 +Subject: [PATCH 2/2] ARM: dts: qcom: add MDIO dedicated controller node for + ipq806x + +Add MDIO dedicated controller attached to gmac0 and fix rb3011 dts to +correctly use the new tag. + +Signed-off-by: Christian 'Ansuel' Marangi +--- + arch/arm/boot/dts/qcom-ipq8064-rb3011.dts | 134 +++++++++++----------- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 14 +++ + 2 files changed, 81 insertions(+), 67 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts ++++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +@@ -24,73 +24,6 @@ + device_type = "memory"; + }; + +- mdio0: mdio-0 { +- status = "okay"; +- compatible = "virtual,mdio-gpio"; +- gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>, +- <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- pinctrl-0 = <&mdio0_pins>; +- pinctrl-names = "default"; +- +- switch0: switch@10 { +- compatible = "qca,qca8337"; +- #address-cells = <1>; +- #size-cells = <0>; +- +- dsa,member = <0 0>; +- +- pinctrl-0 = <&sw0_reset_pin>; +- pinctrl-names = "default"; +- +- reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; +- reg = <0x10>; +- +- ports { +- #address-cells = <1>; +- #size-cells = <0>; +- +- switch0cpu: port@0 { +- reg = <0>; +- label = "cpu"; +- ethernet = <&gmac0>; +- phy-mode = "rgmii-id"; +- fixed-link { +- speed = <1000>; +- full-duplex; +- }; +- }; +- +- port@1 { +- reg = <1>; +- label = "sw1"; +- }; +- +- port@2 { +- reg = <2>; +- label = "sw2"; +- }; +- +- port@3 { +- reg = <3>; +- label = "sw3"; +- }; +- +- port@4 { +- reg = <4>; +- label = "sw4"; +- }; +- +- port@5 { +- reg = <5>; +- label = "sw5"; +- }; +- }; +- }; +- }; +- + mdio1: mdio-1 { + status = "okay"; + compatible = "virtual,mdio-gpio"; +@@ -220,6 +153,73 @@ + status = "okay"; + }; + ++&mdio0 { ++ status = "okay"; ++ compatible = "virtual,mdio-gpio"; ++ gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH>, ++ <&qcom_pinmux 0 GPIO_ACTIVE_HIGH>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pinctrl-0 = <&mdio0_pins>; ++ pinctrl-names = "default"; ++ ++ switch0: switch@10 { ++ compatible = "qca,qca8337"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dsa,member = <0 0>; ++ ++ pinctrl-0 = <&sw0_reset_pin>; ++ pinctrl-names = "default"; ++ ++ reset-gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>; ++ reg = <0x10>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ switch0cpu: port@0 { ++ reg = <0>; ++ label = "cpu"; ++ ethernet = <&gmac0>; ++ phy-mode = "rgmii-id"; ++ fixed-link { ++ speed = <1000>; ++ full-duplex; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ label = "sw1"; ++ }; ++ ++ port@2 { ++ reg = <2>; ++ label = "sw2"; ++ }; ++ ++ port@3 { ++ reg = <3>; ++ label = "sw3"; ++ }; ++ ++ port@4 { ++ reg = <4>; ++ label = "sw4"; ++ }; ++ ++ port@5 { ++ reg = <5>; ++ label = "sw5"; ++ }; ++ }; ++ }; ++}; ++ + &gmac0 { + status = "okay"; + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1446,6 +1446,20 @@ + }; + }; + ++ mdio0: mdio@37000000 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ compatible = "qcom,ipq8064-mdio", "syscon"; ++ reg = <0x37000000 0x200000>; ++ resets = <&gcc GMAC_CORE1_RESET>; ++ reset-names = "stmmaceth"; ++ clocks = <&gcc GMAC_CORE1_CLK>; ++ clock-names = "stmmaceth"; ++ ++ status = "disabled"; ++ }; ++ + vsdcc_fixed: vsdcc-regulator { + compatible = "regulator-fixed"; + regulator-name = "SDCC Power"; diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch new file mode 100644 index 00000000000..72e70b613c8 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch @@ -0,0 +1,29 @@ +From fc7dc1d0c10e8e3d72b68ddae8a61c8aa02a62c1 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 15 Jun 2022 17:13:32 +0200 +Subject: [PATCH v4 1/3] dt-bindings: clock: add pcm reset for ipq806x lcc + +Add pcm reset define for ipq806x lcc. + +Signed-off-by: Christian Marangi +Reviewed-by: Dmitry Baryshkov +Acked-by: Rob Herring +--- +v3: + - Added review tag + - Added ack tag +v2: + - Fix Sob tag + + include/dt-bindings/clock/qcom,lcc-ipq806x.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h ++++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h +@@ -19,4 +19,6 @@ + #define SPDIF_CLK 10 + #define AHBIX_CLK 11 + ++#define LCC_PCM_RESET 0 ++ + #endif diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch new file mode 100644 index 00000000000..23936513064 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch @@ -0,0 +1,48 @@ +From 3587d768bdf4683a53244be1acca5d095044671f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 15 Jun 2022 17:19:55 +0200 +Subject: [PATCH v4 2/3] clk: qcom: lcc-ipq806x: add reset definition + +Add reset definition for lcc-ipq806x. + +Signed-off-by: Christian Marangi +Reviewed-by: Dmitry Baryshkov +--- +v3: + - Added review tag +v2: + - Fix Sob tag + + drivers/clk/qcom/lcc-ipq806x.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/clk/qcom/lcc-ipq806x.c ++++ b/drivers/clk/qcom/lcc-ipq806x.c +@@ -22,6 +22,7 @@ + #include "clk-branch.h" + #include "clk-regmap-divider.h" + #include "clk-regmap-mux.h" ++#include "reset.h" + + static struct clk_pll pll4 = { + .l_reg = 0x4, +@@ -405,6 +406,10 @@ static struct clk_regmap *lcc_ipq806x_cl + [AHBIX_CLK] = &ahbix_clk.clkr, + }; + ++static const struct qcom_reset_map lcc_ipq806x_resets[] = { ++ [LCC_PCM_RESET] = { 0x54, 13 }, ++}; ++ + static const struct regmap_config lcc_ipq806x_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, +@@ -417,6 +422,8 @@ static const struct qcom_cc_desc lcc_ipq + .config = &lcc_ipq806x_regmap_config, + .clks = lcc_ipq806x_clks, + .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), ++ .resets = lcc_ipq806x_resets, ++ .num_resets = ARRAY_SIZE(lcc_ipq806x_resets), + }; + + static const struct of_device_id lcc_ipq806x_match_table[] = { diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch new file mode 100644 index 00000000000..905dc5bf40b --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch @@ -0,0 +1,217 @@ +From 92ef900a4a53b62e0dc32554eb088a422657606c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 15 Jun 2022 17:35:13 +0200 +Subject: [PATCH v5 3/3] clk: qcom: lcc-ipq806x: convert to parent data + +Convert lcc-ipq806x driver to parent_data API. + +Signed-off-by: Christian Marangi +--- +v5: +- Fix the same compilation error (don't know what the hell happen + to my buildroot) +v4: +- Fix compilation error +v3: + - Inline pxo pll4 parent + - Change .name from pxo to pxo_board + + drivers/clk/qcom/lcc-ipq806x.c | 77 ++++++++++++++++++---------------- + 1 file changed, 42 insertions(+), 35 deletions(-) + +--- a/drivers/clk/qcom/lcc-ipq806x.c ++++ b/drivers/clk/qcom/lcc-ipq806x.c +@@ -34,7 +34,9 @@ static struct clk_pll pll4 = { + .status_bit = 16, + .clkr.hw.init = &(struct clk_init_data){ + .name = "pll4", +- .parent_names = (const char *[]){ "pxo" }, ++ .parent_data = &(const struct clk_parent_data) { ++ .fw_name = "pxo", .name = "pxo_board", ++ }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +@@ -64,9 +66,9 @@ static const struct parent_map lcc_pxo_p + { P_PLL4, 2 } + }; + +-static const char * const lcc_pxo_pll4[] = { +- "pxo", +- "pll4_vote", ++static const struct clk_parent_data lcc_pxo_pll4[] = { ++ { .fw_name = "pxo", .name = "pxo" }, ++ { .fw_name = "pll4_vote", .name = "pll4_vote" }, + }; + + static struct freq_tbl clk_tbl_aif_mi2s[] = { +@@ -131,18 +133,14 @@ static struct clk_rcg mi2s_osr_src = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_src", +- .parent_names = lcc_pxo_pll4, +- .num_parents = 2, ++ .parent_data = lcc_pxo_pll4, ++ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, + }; + +-static const char * const lcc_mi2s_parents[] = { +- "mi2s_osr_src", +-}; +- + static struct clk_branch mi2s_osr_clk = { + .halt_reg = 0x50, + .halt_bit = 1, +@@ -152,7 +150,9 @@ static struct clk_branch mi2s_osr_clk = + .enable_mask = BIT(17), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_osr_clk", +- .parent_names = lcc_mi2s_parents, ++ .parent_hws = (const struct clk_hw*[]){ ++ &mi2s_osr_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -167,7 +167,9 @@ static struct clk_regmap_div mi2s_div_cl + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mi2s_div_clk", +- .parent_names = lcc_mi2s_parents, ++ .parent_hws = (const struct clk_hw*[]){ ++ &mi2s_osr_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, +@@ -183,7 +185,9 @@ static struct clk_branch mi2s_bit_div_cl + .enable_mask = BIT(15), + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_div_clk", +- .parent_names = (const char *[]){ "mi2s_div_clk" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &mi2s_div_clk.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -191,6 +195,10 @@ static struct clk_branch mi2s_bit_div_cl + }, + }; + ++static const struct clk_parent_data lcc_mi2s_bit_div_codec_clk[] = { ++ { .hw = &mi2s_bit_div_clk.clkr.hw, }, ++ { .fw_name = "mi2s_codec_clk", .name = "mi2s_codec_clk" }, ++}; + + static struct clk_regmap_mux mi2s_bit_clk = { + .reg = 0x48, +@@ -199,11 +207,8 @@ static struct clk_regmap_mux mi2s_bit_cl + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mi2s_bit_clk", +- .parent_names = (const char *[]){ +- "mi2s_bit_div_clk", +- "mi2s_codec_clk", +- }, +- .num_parents = 2, ++ .parent_data = lcc_mi2s_bit_div_codec_clk, ++ .num_parents = ARRAY_SIZE(lcc_mi2s_bit_div_codec_clk), + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -245,8 +250,8 @@ static struct clk_rcg pcm_src = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "pcm_src", +- .parent_names = lcc_pxo_pll4, +- .num_parents = 2, ++ .parent_data = lcc_pxo_pll4, ++ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, +@@ -262,7 +267,9 @@ static struct clk_branch pcm_clk_out = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk_out", +- .parent_names = (const char *[]){ "pcm_src" }, ++ .parent_hws = (const struct clk_hw*[]){ ++ &pcm_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -270,6 +277,11 @@ static struct clk_branch pcm_clk_out = { + }, + }; + ++static const struct clk_parent_data lcc_pcm_clk_out_codec_clk[] = { ++ { .hw = &pcm_clk_out.clkr.hw, }, ++ { .fw_name = "pcm_codec_clk", .name = "pcm_codec_clk" }, ++}; ++ + static struct clk_regmap_mux pcm_clk = { + .reg = 0x54, + .shift = 10, +@@ -277,11 +289,8 @@ static struct clk_regmap_mux pcm_clk = { + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "pcm_clk", +- .parent_names = (const char *[]){ +- "pcm_clk_out", +- "pcm_codec_clk", +- }, +- .num_parents = 2, ++ .parent_data = lcc_pcm_clk_out_codec_clk, ++ .num_parents = ARRAY_SIZE(lcc_pcm_clk_out_codec_clk), + .ops = &clk_regmap_mux_closest_ops, + .flags = CLK_SET_RATE_PARENT, + }, +@@ -325,18 +334,14 @@ static struct clk_rcg spdif_src = { + .enable_mask = BIT(9), + .hw.init = &(struct clk_init_data){ + .name = "spdif_src", +- .parent_names = lcc_pxo_pll4, +- .num_parents = 2, ++ .parent_data = lcc_pxo_pll4, ++ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), + .ops = &clk_rcg_ops, + .flags = CLK_SET_RATE_GATE, + }, + }, + }; + +-static const char * const lcc_spdif_parents[] = { +- "spdif_src", +-}; +- + static struct clk_branch spdif_clk = { + .halt_reg = 0xd4, + .halt_bit = 1, +@@ -346,7 +351,9 @@ static struct clk_branch spdif_clk = { + .enable_mask = BIT(12), + .hw.init = &(struct clk_init_data){ + .name = "spdif_clk", +- .parent_names = lcc_spdif_parents, ++ .parent_hws = (const struct clk_hw*[]){ ++ &spdif_src.clkr.hw, ++ }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, +@@ -384,8 +391,8 @@ static struct clk_rcg ahbix_clk = { + .enable_mask = BIT(11), + .hw.init = &(struct clk_init_data){ + .name = "ahbix", +- .parent_names = lcc_pxo_pll4, +- .num_parents = 2, ++ .parent_data = lcc_pxo_pll4, ++ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), + .ops = &clk_rcg_lcc_ops, + }, + }, diff --git a/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch b/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch new file mode 100644 index 00000000000..4caa2a9560e --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch @@ -0,0 +1,41 @@ +From 8f32d48a309246a80bdca505968085a484d54408 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 19 Apr 2021 03:01:53 +0200 +Subject: [thermal-next PATCH v2 1/2] thermal: qcom: tsens: init debugfs only with + successful probe + +calibrate and tsens_register can fail or PROBE_DEFER. This will cause a +double or a wrong init of the debugfs information. Init debugfs only +with successful probe fixing warning about directory already present. + +Signed-off-by: Ansuel Smith +Acked-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -917,8 +917,6 @@ int __init init_common(struct tsens_priv + if (tsens_version(priv) >= VER_0_1) + tsens_enable_irq(priv); + +- tsens_debug_init(op); +- + err_put_device: + put_device(&op->dev); + return ret; +@@ -1163,7 +1161,12 @@ static int tsens_probe(struct platform_d + } + } + +- return tsens_register(priv); ++ ret = tsens_register(priv); ++ ++ if (!ret) ++ tsens_debug_init(pdev); ++ ++ return ret; + } + + static int tsens_remove(struct platform_device *pdev) diff --git a/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch b/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch new file mode 100644 index 00000000000..add2ab45987 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch @@ -0,0 +1,54 @@ +From 4204f22060f7a5d42c6ccb4d4c25a6a875571099 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Mon, 19 Apr 2021 03:08:37 +0200 +Subject: [thermal-next PATCH v2 2/2] thermal: qcom: tsens: simplify debugfs init + function + +Simplify debugfs init function. +- Add check for existing dev directory. +- Fix wrong version in dbg_version_show (with version 0.0.0, 0.1.0 was + incorrectly reported) + +Signed-off-by: Ansuel Smith +Reviewed-by: Thara Gopinath +--- + drivers/thermal/qcom/tsens.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -691,7 +691,7 @@ static int dbg_version_show(struct seq_f + return ret; + seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver); + } else { +- seq_puts(s, "0.1.0\n"); ++ seq_printf(s, "0.%d.0\n", priv->feat->ver_major); + } + + return 0; +@@ -703,21 +703,17 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors); + static void tsens_debug_init(struct platform_device *pdev) + { + struct tsens_priv *priv = platform_get_drvdata(pdev); +- struct dentry *root, *file; + +- root = debugfs_lookup("tsens", NULL); +- if (!root) ++ priv->debug_root = debugfs_lookup("tsens", NULL); ++ if (!priv->debug_root) + priv->debug_root = debugfs_create_dir("tsens", NULL); +- else +- priv->debug_root = root; + +- file = debugfs_lookup("version", priv->debug_root); +- if (!file) ++ if (!debugfs_lookup("version", priv->debug_root)) + debugfs_create_file("version", 0444, priv->debug_root, + pdev, &dbg_version_fops); + + /* A directory for each instance of the TSENS IP */ +- priv->debug = debugfs_create_dir(dev_name(&pdev->dev), priv->debug_root); ++ priv->debug = debugfs_lookup(dev_name(&pdev->dev), priv->debug_root); + debugfs_create_file("sensors", 0444, priv->debug, pdev, &dbg_sensors_fops); + } + #else diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch new file mode 100644 index 00000000000..6b7a68952ea --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch @@ -0,0 +1,113 @@ +From 713472e53e6e53c985e283782b0fd76b8ecfd47e Mon Sep 17 00:00:00 2001 +From: Chanwoo Choi +Date: Mon, 1 Mar 2021 02:07:29 +0900 +Subject: [PATCH 1/5] PM / devfreq: Export devfreq_get_freq_range symbol within + devfreq + +In order to get frequency range within devfreq governors, +export devfreq_get_freq_range symbol within devfreq. + +Reviewed-by: Matthias Kaehlcke +Tested-by: Chen-Yu Tsai +Tested-by: Johnson Wang +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/devfreq.c | 20 ++++++++++++-------- + drivers/devfreq/governor.h | 2 ++ + 2 files changed, 14 insertions(+), 8 deletions(-) + +--- a/drivers/devfreq/devfreq.c ++++ b/drivers/devfreq/devfreq.c +@@ -112,16 +112,16 @@ static unsigned long find_available_max_ + } + + /** +- * get_freq_range() - Get the current freq range ++ * devfreq_get_freq_range() - Get the current freq range + * @devfreq: the devfreq instance + * @min_freq: the min frequency + * @max_freq: the max frequency + * + * This takes into consideration all constraints. + */ +-static void get_freq_range(struct devfreq *devfreq, +- unsigned long *min_freq, +- unsigned long *max_freq) ++void devfreq_get_freq_range(struct devfreq *devfreq, ++ unsigned long *min_freq, ++ unsigned long *max_freq) + { + unsigned long *freq_table = devfreq->profile->freq_table; + s32 qos_min_freq, qos_max_freq; +@@ -158,6 +158,7 @@ static void get_freq_range(struct devfre + if (*min_freq > *max_freq) + *min_freq = *max_freq; + } ++EXPORT_SYMBOL(devfreq_get_freq_range); + + /** + * devfreq_get_freq_level() - Lookup freq_table for the frequency +@@ -418,7 +419,7 @@ int devfreq_update_target(struct devfreq + err = devfreq->governor->get_target_freq(devfreq, &freq); + if (err) + return err; +- get_freq_range(devfreq, &min_freq, &max_freq); ++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); + + if (freq < min_freq) { + freq = min_freq; +@@ -784,6 +785,7 @@ struct devfreq *devfreq_add_device(struc + { + struct devfreq *devfreq; + struct devfreq_governor *governor; ++ unsigned long min_freq, max_freq; + int err = 0; + + if (!dev || !profile || !governor_name) { +@@ -848,6 +850,8 @@ struct devfreq *devfreq_add_device(struc + goto err_dev; + } + ++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); ++ + devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); + devfreq->opp_table = dev_pm_opp_get_opp_table(dev); + if (IS_ERR(devfreq->opp_table)) +@@ -1559,7 +1563,7 @@ static ssize_t min_freq_show(struct devi + unsigned long min_freq, max_freq; + + mutex_lock(&df->lock); +- get_freq_range(df, &min_freq, &max_freq); ++ devfreq_get_freq_range(df, &min_freq, &max_freq); + mutex_unlock(&df->lock); + + return sprintf(buf, "%lu\n", min_freq); +@@ -1613,7 +1617,7 @@ static ssize_t max_freq_show(struct devi + unsigned long min_freq, max_freq; + + mutex_lock(&df->lock); +- get_freq_range(df, &min_freq, &max_freq); ++ devfreq_get_freq_range(df, &min_freq, &max_freq); + mutex_unlock(&df->lock); + + return sprintf(buf, "%lu\n", max_freq); +@@ -1927,7 +1931,7 @@ static int devfreq_summary_show(struct s + + mutex_lock(&devfreq->lock); + cur_freq = devfreq->previous_freq; +- get_freq_range(devfreq, &min_freq, &max_freq); ++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); + timer = devfreq->profile->timer; + + if (IS_SUPPORTED_ATTR(devfreq->governor->attrs, POLLING_INTERVAL)) +--- a/drivers/devfreq/governor.h ++++ b/drivers/devfreq/governor.h +@@ -86,6 +86,8 @@ int devfreq_remove_governor(struct devfr + + int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); + int devfreq_update_target(struct devfreq *devfreq, unsigned long freq); ++void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq, ++ unsigned long *max_freq); + + static inline int devfreq_update_stats(struct devfreq *df) + { diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch new file mode 100644 index 00000000000..3dd61985b28 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch @@ -0,0 +1,461 @@ +From a03dacb0316f74400846aaf144d6c73f4217ca08 Mon Sep 17 00:00:00 2001 +From: Saravana Kannan +Date: Tue, 2 Mar 2021 15:58:21 +0900 +Subject: [PATCH 2/5] PM / devfreq: Add cpu based scaling support to passive + governor + +Many CPU architectures have caches that can scale independent of the +CPUs. Frequency scaling of the caches is necessary to make sure that the +cache is not a performance bottleneck that leads to poor performance and +power. The same idea applies for RAM/DDR. + +To achieve this, this patch adds support for cpu based scaling to the +passive governor. This is accomplished by taking the current frequency +of each CPU frequency domain and then adjust the frequency of the cache +(or any devfreq device) based on the frequency of the CPUs. It listens +to CPU frequency transition notifiers to keep itself up to date on the +current CPU frequency. + +To decide the frequency of the device, the governor does one of the +following: +* Derives the optimal devfreq device opp from required-opps property of + the parent cpu opp_table. + +* Scales the device frequency in proportion to the CPU frequency. So, if + the CPUs are running at their max frequency, the device runs at its + max frequency. If the CPUs are running at their min frequency, the + device runs at its min frequency. It is interpolated for frequencies + in between. + +Tested-by: Chen-Yu Tsai +Tested-by: Johnson Wang +Signed-off-by: Saravana Kannan +[Sibi: Integrated cpu-freqmap governor into passive_governor] +Signed-off-by: Sibi Sankar +[Chanwoo: Fix conflict with latest code and cleanup code] +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/governor.h | 22 +++ + drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++++++++++-- + include/linux/devfreq.h | 17 +- + 3 files changed, 323 insertions(+), 14 deletions(-) + +--- a/drivers/devfreq/governor.h ++++ b/drivers/devfreq/governor.h +@@ -48,6 +48,28 @@ + #define DEVFREQ_GOV_ATTR_TIMER BIT(1) + + /** ++ * struct devfreq_cpu_data - Hold the per-cpu data ++ * @dev: reference to cpu device. ++ * @first_cpu: the cpumask of the first cpu of a policy. ++ * @opp_table: reference to cpu opp table. ++ * @cur_freq: the current frequency of the cpu. ++ * @min_freq: the min frequency of the cpu. ++ * @max_freq: the max frequency of the cpu. ++ * ++ * This structure stores the required cpu_data of a cpu. ++ * This is auto-populated by the governor. ++ */ ++struct devfreq_cpu_data { ++ struct device *dev; ++ unsigned int first_cpu; ++ ++ struct opp_table *opp_table; ++ unsigned int cur_freq; ++ unsigned int min_freq; ++ unsigned int max_freq; ++}; ++ ++/** + * struct devfreq_governor - Devfreq policy governor + * @node: list node - contains registered devfreq governors + * @name: Governor's name +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -8,11 +8,85 @@ + */ + + #include ++#include ++#include ++#include ++#include + #include + #include + #include "governor.h" + +-static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ++#define HZ_PER_KHZ 1000 ++ ++static unsigned long get_target_freq_by_required_opp(struct device *p_dev, ++ struct opp_table *p_opp_table, ++ struct opp_table *opp_table, ++ unsigned long *freq) ++{ ++ struct dev_pm_opp *opp = NULL, *p_opp = NULL; ++ unsigned long target_freq; ++ ++ if (!p_dev || !p_opp_table || !opp_table || !freq) ++ return 0; ++ ++ p_opp = devfreq_recommended_opp(p_dev, freq, 0); ++ if (IS_ERR(p_opp)) ++ return 0; ++ ++ opp = dev_pm_opp_xlate_required_opp(p_opp_table, opp_table, p_opp); ++ dev_pm_opp_put(p_opp); ++ ++ if (IS_ERR(opp)) ++ return 0; ++ ++ target_freq = dev_pm_opp_get_freq(opp); ++ dev_pm_opp_put(opp); ++ ++ return target_freq; ++} ++ ++static int get_target_freq_with_cpufreq(struct devfreq *devfreq, ++ unsigned long *target_freq) ++{ ++ struct devfreq_passive_data *p_data = ++ (struct devfreq_passive_data *)devfreq->data; ++ struct devfreq_cpu_data *parent_cpu_data; ++ unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent; ++ unsigned long dev_min, dev_max; ++ unsigned long freq = 0; ++ ++ for_each_online_cpu(cpu) { ++ parent_cpu_data = p_data->parent_cpu_data[cpu]; ++ if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu) ++ continue; ++ ++ /* Get target freq via required opps */ ++ cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ; ++ freq = get_target_freq_by_required_opp(parent_cpu_data->dev, ++ parent_cpu_data->opp_table, ++ devfreq->opp_table, &cpu_cur); ++ if (freq) { ++ *target_freq = max(freq, *target_freq); ++ continue; ++ } ++ ++ /* Use interpolation if required opps is not available */ ++ devfreq_get_freq_range(devfreq, &dev_min, &dev_max); ++ ++ cpu_min = parent_cpu_data->min_freq; ++ cpu_max = parent_cpu_data->max_freq; ++ cpu_cur = parent_cpu_data->cur_freq; ++ ++ cpu_percent = ((cpu_cur - cpu_min) * 100) / (cpu_max - cpu_min); ++ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); ++ ++ *target_freq = max(freq, *target_freq); ++ } ++ ++ return 0; ++} ++ ++static int get_target_freq_with_devfreq(struct devfreq *devfreq, + unsigned long *freq) + { + struct devfreq_passive_data *p_data +@@ -99,6 +173,181 @@ no_required_opp: + return 0; + } + ++static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ++ unsigned long *freq) ++{ ++ struct devfreq_passive_data *p_data = ++ (struct devfreq_passive_data *)devfreq->data; ++ int ret; ++ ++ if (!p_data) ++ return -EINVAL; ++ ++ /* ++ * If the devfreq device with passive governor has the specific method ++ * to determine the next frequency, should use the get_target_freq() ++ * of struct devfreq_passive_data. ++ */ ++ if (p_data->get_target_freq) ++ return p_data->get_target_freq(devfreq, freq); ++ ++ switch (p_data->parent_type) { ++ case DEVFREQ_PARENT_DEV: ++ ret = get_target_freq_with_devfreq(devfreq, freq); ++ break; ++ case CPUFREQ_PARENT_DEV: ++ ret = get_target_freq_with_cpufreq(devfreq, freq); ++ break; ++ default: ++ ret = -EINVAL; ++ dev_err(&devfreq->dev, "Invalid parent type\n"); ++ break; ++ } ++ ++ return ret; ++} ++ ++static int cpufreq_passive_notifier_call(struct notifier_block *nb, ++ unsigned long event, void *ptr) ++{ ++ struct devfreq_passive_data *p_data = ++ container_of(nb, struct devfreq_passive_data, nb); ++ struct devfreq *devfreq = (struct devfreq *)p_data->this; ++ struct devfreq_cpu_data *parent_cpu_data; ++ struct cpufreq_freqs *freqs = ptr; ++ unsigned int cur_freq; ++ int ret; ++ ++ if (event != CPUFREQ_POSTCHANGE || !freqs || ++ !p_data->parent_cpu_data[freqs->policy->cpu]) ++ return 0; ++ ++ parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu]; ++ if (parent_cpu_data->cur_freq == freqs->new) ++ return 0; ++ ++ cur_freq = parent_cpu_data->cur_freq; ++ parent_cpu_data->cur_freq = freqs->new; ++ ++ mutex_lock(&devfreq->lock); ++ ret = devfreq_update_target(devfreq, freqs->new); ++ mutex_unlock(&devfreq->lock); ++ if (ret) { ++ parent_cpu_data->cur_freq = cur_freq; ++ dev_err(&devfreq->dev, "failed to update the frequency.\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq) ++{ ++ struct devfreq_passive_data *p_data ++ = (struct devfreq_passive_data *)devfreq->data; ++ struct devfreq_cpu_data *parent_cpu_data; ++ int cpu, ret; ++ ++ if (p_data->nb.notifier_call) { ++ ret = cpufreq_unregister_notifier(&p_data->nb, ++ CPUFREQ_TRANSITION_NOTIFIER); ++ if (ret < 0) ++ return ret; ++ } ++ ++ for_each_possible_cpu(cpu) { ++ parent_cpu_data = p_data->parent_cpu_data[cpu]; ++ if (!parent_cpu_data) ++ continue; ++ ++ if (parent_cpu_data->opp_table) ++ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); ++ kfree(parent_cpu_data); ++ } ++ ++ return 0; ++} ++ ++static int cpufreq_passive_register_notifier(struct devfreq *devfreq) ++{ ++ struct devfreq_passive_data *p_data ++ = (struct devfreq_passive_data *)devfreq->data; ++ struct device *dev = devfreq->dev.parent; ++ struct opp_table *opp_table = NULL; ++ struct devfreq_cpu_data *parent_cpu_data; ++ struct cpufreq_policy *policy; ++ struct device *cpu_dev; ++ unsigned int cpu; ++ int ret; ++ ++ p_data->nb.notifier_call = cpufreq_passive_notifier_call; ++ ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER); ++ if (ret) { ++ dev_err(dev, "failed to register cpufreq notifier\n"); ++ p_data->nb.notifier_call = NULL; ++ goto err; ++ } ++ ++ for_each_possible_cpu(cpu) { ++ if (p_data->parent_cpu_data[cpu]) ++ continue; ++ ++ policy = cpufreq_cpu_get(cpu); ++ if (!policy) { ++ ret = -EPROBE_DEFER; ++ goto err; ++ } ++ ++ parent_cpu_data = kzalloc(sizeof(*parent_cpu_data), ++ GFP_KERNEL); ++ if (!parent_cpu_data) { ++ ret = -ENOMEM; ++ goto err_put_policy; ++ } ++ ++ cpu_dev = get_cpu_device(cpu); ++ if (!cpu_dev) { ++ dev_err(dev, "failed to get cpu device\n"); ++ ret = -ENODEV; ++ goto err_free_cpu_data; ++ } ++ ++ opp_table = dev_pm_opp_get_opp_table(cpu_dev); ++ if (IS_ERR(opp_table)) { ++ dev_err(dev, "failed to get opp_table of cpu%d\n", cpu); ++ ret = PTR_ERR(opp_table); ++ goto err_free_cpu_data; ++ } ++ ++ parent_cpu_data->dev = cpu_dev; ++ parent_cpu_data->opp_table = opp_table; ++ parent_cpu_data->first_cpu = cpumask_first(policy->related_cpus); ++ parent_cpu_data->cur_freq = policy->cur; ++ parent_cpu_data->min_freq = policy->cpuinfo.min_freq; ++ parent_cpu_data->max_freq = policy->cpuinfo.max_freq; ++ ++ p_data->parent_cpu_data[cpu] = parent_cpu_data; ++ cpufreq_cpu_put(policy); ++ } ++ ++ mutex_lock(&devfreq->lock); ++ ret = devfreq_update_target(devfreq, 0L); ++ mutex_unlock(&devfreq->lock); ++ if (ret) ++ dev_err(dev, "failed to update the frequency\n"); ++ ++ return ret; ++ ++err_free_cpu_data: ++ kfree(parent_cpu_data); ++err_put_policy: ++ cpufreq_cpu_put(policy); ++err: ++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); ++ ++ return ret; ++} ++ + static int devfreq_passive_notifier_call(struct notifier_block *nb, + unsigned long event, void *ptr) + { +@@ -131,30 +380,55 @@ static int devfreq_passive_notifier_call + return NOTIFY_DONE; + } + +-static int devfreq_passive_event_handler(struct devfreq *devfreq, +- unsigned int event, void *data) ++static int devfreq_passive_unregister_notifier(struct devfreq *devfreq) ++{ ++ struct devfreq_passive_data *p_data ++ = (struct devfreq_passive_data *)devfreq->data; ++ struct devfreq *parent = (struct devfreq *)p_data->parent; ++ struct notifier_block *nb = &p_data->nb; ++ ++ return devfreq_unregister_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER); ++} ++ ++static int devfreq_passive_register_notifier(struct devfreq *devfreq) + { + struct devfreq_passive_data *p_data + = (struct devfreq_passive_data *)devfreq->data; + struct devfreq *parent = (struct devfreq *)p_data->parent; + struct notifier_block *nb = &p_data->nb; +- int ret = 0; + + if (!parent) + return -EPROBE_DEFER; + ++ nb->notifier_call = devfreq_passive_notifier_call; ++ return devfreq_register_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER); ++} ++ ++static int devfreq_passive_event_handler(struct devfreq *devfreq, ++ unsigned int event, void *data) ++{ ++ struct devfreq_passive_data *p_data ++ = (struct devfreq_passive_data *)devfreq->data; ++ int ret = -EINVAL; ++ ++ if (!p_data) ++ return -EINVAL; ++ ++ if (!p_data->this) ++ p_data->this = devfreq; ++ + switch (event) { + case DEVFREQ_GOV_START: +- if (!p_data->this) +- p_data->this = devfreq; +- +- nb->notifier_call = devfreq_passive_notifier_call; +- ret = devfreq_register_notifier(parent, nb, +- DEVFREQ_TRANSITION_NOTIFIER); ++ if (p_data->parent_type == DEVFREQ_PARENT_DEV) ++ ret = devfreq_passive_register_notifier(devfreq); ++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV) ++ ret = cpufreq_passive_register_notifier(devfreq); + break; + case DEVFREQ_GOV_STOP: +- WARN_ON(devfreq_unregister_notifier(parent, nb, +- DEVFREQ_TRANSITION_NOTIFIER)); ++ if (p_data->parent_type == DEVFREQ_PARENT_DEV) ++ WARN_ON(devfreq_passive_unregister_notifier(devfreq)); ++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV) ++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); + break; + default: + break; +--- a/include/linux/devfreq.h ++++ b/include/linux/devfreq.h +@@ -38,6 +38,7 @@ enum devfreq_timer { + + struct devfreq; + struct devfreq_governor; ++struct devfreq_cpu_data; + struct thermal_cooling_device; + + /** +@@ -289,6 +290,11 @@ struct devfreq_simple_ondemand_data { + #endif + + #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE) ++enum devfreq_parent_dev_type { ++ DEVFREQ_PARENT_DEV, ++ CPUFREQ_PARENT_DEV, ++}; ++ + /** + * struct devfreq_passive_data - ``void *data`` fed to struct devfreq + * and devfreq_add_device +@@ -300,8 +306,11 @@ struct devfreq_simple_ondemand_data { + * using governors except for passive governor. + * If the devfreq device has the specific method to decide + * the next frequency, should use this callback. +- * @this: the devfreq instance of own device. +- * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list ++ * @parent_type: the parent type of the device. ++ * @this: the devfreq instance of own device. ++ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or ++ * CPUFREQ_TRANSITION_NOTIFIER list. ++ * @parent_cpu_data: the state min/max/current frequency of all online cpu's. + * + * The devfreq_passive_data have to set the devfreq instance of parent + * device with governors except for the passive governor. But, don't need to +@@ -315,9 +324,13 @@ struct devfreq_passive_data { + /* Optional callback to decide the next frequency of passvice device */ + int (*get_target_freq)(struct devfreq *this, unsigned long *freq); + ++ /* Should set the type of parent device */ ++ enum devfreq_parent_dev_type parent_type; ++ + /* For passive governor's internal use. Don't need to set them */ + struct devfreq *this; + struct notifier_block nb; ++ struct devfreq_cpu_data *parent_cpu_data[NR_CPUS]; + }; + #endif + diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch new file mode 100644 index 00000000000..cb10bd1b62c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch @@ -0,0 +1,110 @@ +From 05723e71234b60a1a47313ea1a889797ec648f1c Mon Sep 17 00:00:00 2001 +From: Chanwoo Choi +Date: Tue, 2 Mar 2021 17:22:50 +0900 +Subject: [PATCH 3/5] PM / devfreq: passive: Reduce duplicate code when + passive_devfreq case + +In order to keep the consistent coding style between passive_devfreq +and passive_cpufreq, use common code for handling required opp property. +Also remove the unneed conditional statement and unify the comment +of both passive_devfreq and passive_cpufreq when getting the target frequency. + +Tested-by: Chen-Yu Tsai +Tested-by: Johnson Wang +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/governor_passive.c | 66 ++++-------------------------- + 1 file changed, 8 insertions(+), 58 deletions(-) + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -93,65 +93,16 @@ static int get_target_freq_with_devfreq( + = (struct devfreq_passive_data *)devfreq->data; + struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent; + unsigned long child_freq = ULONG_MAX; +- struct dev_pm_opp *opp, *p_opp; + int i, count; + +- /* +- * If the devfreq device with passive governor has the specific method +- * to determine the next frequency, should use the get_target_freq() +- * of struct devfreq_passive_data. +- */ +- if (p_data->get_target_freq) +- return p_data->get_target_freq(devfreq, freq); +- +- /* +- * If the parent and passive devfreq device uses the OPP table, +- * get the next frequency by using the OPP table. +- */ +- +- /* +- * - parent devfreq device uses the governors except for passive. +- * - passive devfreq device uses the passive governor. +- * +- * Each devfreq has the OPP table. After deciding the new frequency +- * from the governor of parent devfreq device, the passive governor +- * need to get the index of new frequency on OPP table of parent +- * device. And then the index is used for getting the suitable +- * new frequency for passive devfreq device. +- */ +- if (!devfreq->profile || !devfreq->profile->freq_table +- || devfreq->profile->max_state <= 0) +- return -EINVAL; +- +- /* +- * The passive governor have to get the correct frequency from OPP +- * list of parent device. Because in this case, *freq is temporary +- * value which is decided by ondemand governor. +- */ +- if (devfreq->opp_table && parent_devfreq->opp_table) { +- p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent, +- freq, 0); +- if (IS_ERR(p_opp)) +- return PTR_ERR(p_opp); +- +- opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table, +- devfreq->opp_table, p_opp); +- dev_pm_opp_put(p_opp); +- +- if (IS_ERR(opp)) +- goto no_required_opp; +- +- *freq = dev_pm_opp_get_freq(opp); +- dev_pm_opp_put(opp); +- +- return 0; +- } ++ /* Get target freq via required opps */ ++ child_freq = get_target_freq_by_required_opp(parent_devfreq->dev.parent, ++ parent_devfreq->opp_table, ++ devfreq->opp_table, freq); ++ if (child_freq) ++ goto out; + +-no_required_opp: +- /* +- * Get the OPP table's index of decided frequency by governor +- * of parent device. +- */ ++ /* Use interpolation if required opps is not available */ + for (i = 0; i < parent_devfreq->profile->max_state; i++) + if (parent_devfreq->profile->freq_table[i] == *freq) + break; +@@ -159,7 +110,6 @@ no_required_opp: + if (i == parent_devfreq->profile->max_state) + return -EINVAL; + +- /* Get the suitable frequency by using index of parent device. */ + if (i < devfreq->profile->max_state) { + child_freq = devfreq->profile->freq_table[i]; + } else { +@@ -167,7 +117,7 @@ no_required_opp: + child_freq = devfreq->profile->freq_table[count - 1]; + } + +- /* Return the suitable frequency for passive device. */ ++out: + *freq = child_freq; + + return 0; diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch new file mode 100644 index 00000000000..9ef02d0ea35 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch @@ -0,0 +1,232 @@ +From 26984d9d581e5049bd75091d2e789b9cc3ea12e0 Mon Sep 17 00:00:00 2001 +From: Chanwoo Choi +Date: Wed, 27 Apr 2022 03:49:19 +0900 +Subject: [PATCH 4/5] PM / devfreq: passive: Keep cpufreq_policy for possible + cpus + +The passive governor requires the cpu data to get the next target frequency +of devfreq device if depending on cpu. In order to reduce the unnecessary +memory data, keep cpufreq_policy data for possible cpus instead of NR_CPU. + +Tested-by: Chen-Yu Tsai +Tested-by: Johnson Wang +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/governor.h | 3 ++ + drivers/devfreq/governor_passive.c | 75 +++++++++++++++++++++++------- + include/linux/devfreq.h | 4 +- + 3 files changed, 64 insertions(+), 18 deletions(-) + +--- a/drivers/devfreq/governor.h ++++ b/drivers/devfreq/governor.h +@@ -49,6 +49,7 @@ + + /** + * struct devfreq_cpu_data - Hold the per-cpu data ++ * @node: list node + * @dev: reference to cpu device. + * @first_cpu: the cpumask of the first cpu of a policy. + * @opp_table: reference to cpu opp table. +@@ -60,6 +61,8 @@ + * This is auto-populated by the governor. + */ + struct devfreq_cpu_data { ++ struct list_head node; ++ + struct device *dev; + unsigned int first_cpu; + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0-only ++ // SPDX-License-Identifier: GPL-2.0-only + /* + * linux/drivers/devfreq/governor_passive.c + * +@@ -18,6 +18,22 @@ + + #define HZ_PER_KHZ 1000 + ++static struct devfreq_cpu_data * ++get_parent_cpu_data(struct devfreq_passive_data *p_data, ++ struct cpufreq_policy *policy) ++{ ++ struct devfreq_cpu_data *parent_cpu_data; ++ ++ if (!p_data || !policy) ++ return NULL; ++ ++ list_for_each_entry(parent_cpu_data, &p_data->cpu_data_list, node) ++ if (parent_cpu_data->first_cpu == cpumask_first(policy->related_cpus)) ++ return parent_cpu_data; ++ ++ return NULL; ++} ++ + static unsigned long get_target_freq_by_required_opp(struct device *p_dev, + struct opp_table *p_opp_table, + struct opp_table *opp_table, +@@ -51,14 +67,24 @@ static int get_target_freq_with_cpufreq( + struct devfreq_passive_data *p_data = + (struct devfreq_passive_data *)devfreq->data; + struct devfreq_cpu_data *parent_cpu_data; ++ struct cpufreq_policy *policy; + unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent; + unsigned long dev_min, dev_max; + unsigned long freq = 0; ++ int ret = 0; + + for_each_online_cpu(cpu) { +- parent_cpu_data = p_data->parent_cpu_data[cpu]; +- if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu) ++ policy = cpufreq_cpu_get(cpu); ++ if (!policy) { ++ ret = -EINVAL; ++ continue; ++ } ++ ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (!parent_cpu_data) { ++ cpufreq_cpu_put(policy); + continue; ++ } + + /* Get target freq via required opps */ + cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ; +@@ -67,6 +93,7 @@ static int get_target_freq_with_cpufreq( + devfreq->opp_table, &cpu_cur); + if (freq) { + *target_freq = max(freq, *target_freq); ++ cpufreq_cpu_put(policy); + continue; + } + +@@ -81,9 +108,10 @@ static int get_target_freq_with_cpufreq( + freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); + + *target_freq = max(freq, *target_freq); ++ cpufreq_cpu_put(policy); + } + +- return 0; ++ return ret; + } + + static int get_target_freq_with_devfreq(struct devfreq *devfreq, +@@ -168,12 +196,11 @@ static int cpufreq_passive_notifier_call + unsigned int cur_freq; + int ret; + +- if (event != CPUFREQ_POSTCHANGE || !freqs || +- !p_data->parent_cpu_data[freqs->policy->cpu]) ++ if (event != CPUFREQ_POSTCHANGE || !freqs) + return 0; + +- parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu]; +- if (parent_cpu_data->cur_freq == freqs->new) ++ parent_cpu_data = get_parent_cpu_data(p_data, freqs->policy); ++ if (!parent_cpu_data || parent_cpu_data->cur_freq == freqs->new) + return 0; + + cur_freq = parent_cpu_data->cur_freq; +@@ -196,7 +223,7 @@ static int cpufreq_passive_unregister_no + struct devfreq_passive_data *p_data + = (struct devfreq_passive_data *)devfreq->data; + struct devfreq_cpu_data *parent_cpu_data; +- int cpu, ret; ++ int cpu, ret = 0; + + if (p_data->nb.notifier_call) { + ret = cpufreq_unregister_notifier(&p_data->nb, +@@ -206,16 +233,26 @@ static int cpufreq_passive_unregister_no + } + + for_each_possible_cpu(cpu) { +- parent_cpu_data = p_data->parent_cpu_data[cpu]; +- if (!parent_cpu_data) ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ if (!policy) { ++ ret = -EINVAL; ++ continue; ++ } ++ ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (!parent_cpu_data) { ++ cpufreq_cpu_put(policy); + continue; ++ } + ++ list_del(&parent_cpu_data->node); + if (parent_cpu_data->opp_table) + dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); + kfree(parent_cpu_data); ++ cpufreq_cpu_put(policy); + } + +- return 0; ++ return ret; + } + + static int cpufreq_passive_register_notifier(struct devfreq *devfreq) +@@ -230,6 +267,9 @@ static int cpufreq_passive_register_noti + unsigned int cpu; + int ret; + ++ p_data->cpu_data_list ++ = (struct list_head)LIST_HEAD_INIT(p_data->cpu_data_list); ++ + p_data->nb.notifier_call = cpufreq_passive_notifier_call; + ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER); + if (ret) { +@@ -239,15 +279,18 @@ static int cpufreq_passive_register_noti + } + + for_each_possible_cpu(cpu) { +- if (p_data->parent_cpu_data[cpu]) +- continue; +- + policy = cpufreq_cpu_get(cpu); + if (!policy) { + ret = -EPROBE_DEFER; + goto err; + } + ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (parent_cpu_data) { ++ cpufreq_cpu_put(policy); ++ continue; ++ } ++ + parent_cpu_data = kzalloc(sizeof(*parent_cpu_data), + GFP_KERNEL); + if (!parent_cpu_data) { +@@ -276,7 +319,7 @@ static int cpufreq_passive_register_noti + parent_cpu_data->min_freq = policy->cpuinfo.min_freq; + parent_cpu_data->max_freq = policy->cpuinfo.max_freq; + +- p_data->parent_cpu_data[cpu] = parent_cpu_data; ++ list_add_tail(&parent_cpu_data->node, &p_data->cpu_data_list); + cpufreq_cpu_put(policy); + } + +--- a/include/linux/devfreq.h ++++ b/include/linux/devfreq.h +@@ -310,7 +310,7 @@ enum devfreq_parent_dev_type { + * @this: the devfreq instance of own device. + * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or + * CPUFREQ_TRANSITION_NOTIFIER list. +- * @parent_cpu_data: the state min/max/current frequency of all online cpu's. ++ * @cpu_data_list: the list of cpu frequency data for all cpufreq_policy. + * + * The devfreq_passive_data have to set the devfreq instance of parent + * device with governors except for the passive governor. But, don't need to +@@ -330,7 +330,7 @@ struct devfreq_passive_data { + /* For passive governor's internal use. Don't need to set them */ + struct devfreq *this; + struct notifier_block nb; +- struct devfreq_cpu_data *parent_cpu_data[NR_CPUS]; ++ struct list_head cpu_data_list; + }; + #endif + diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch new file mode 100644 index 00000000000..69160fd77a5 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch @@ -0,0 +1,31 @@ +From 42d2607d91c4ec37ea1970899c2d614824f3014b Mon Sep 17 00:00:00 2001 +From: Chanwoo Choi +Date: Thu, 19 May 2022 10:07:53 +0900 +Subject: [PATCH 5/5] PM / devfreq: passive: Return non-error when + not-supported event is required + +Each devfreq governor specifies the supported governor event +such as GOV_START and GOV_STOP. When not-supported event is required, +just return non-error. But, commit ce9a0d88d97a ("PM / devfreq: Add +cpu based scaling support to passive governor") returned the error +value. So that return non-error value when not-supported event is required. + +Fixes: ce9a0d88d97a ("PM / devfreq: Add cpu based scaling support to passive governor") +Reported-by: Marek Szyprowski +Signed-off-by: Chanwoo Choi +Signed-off-by: Rafael J. Wysocki +--- + drivers/devfreq/governor_passive.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -402,7 +402,7 @@ static int devfreq_passive_event_handler + { + struct devfreq_passive_data *p_data + = (struct devfreq_passive_data *)devfreq->data; +- int ret = -EINVAL; ++ int ret = 0; + + if (!p_data) + return -EINVAL; diff --git a/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch b/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch new file mode 100644 index 00000000000..3d2bb2de05b --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch @@ -0,0 +1,31 @@ +From 82c66d2bbbeda9e493487e7413769087a0b46250 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Mon, 20 Jun 2022 00:29:39 +0200 +Subject: [PATCH 1/1] PM / devfreq: Fix kernel warning with cpufreq passive + register fail + +Remove cpufreq_passive_unregister_notifier from +cpufreq_passive_register_notifier in case of error as devfreq core +already call unregister on GOV_START fail. + +This fix the kernel always printing a WARN on governor PROBE_DEFER as +cpufreq_passive_unregister_notifier is called two times and return +error on the second call as the cpufreq is already unregistered. + +Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") +Signed-off-by: Christian Marangi +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/governor_passive.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -336,7 +336,6 @@ err_free_cpu_data: + err_put_policy: + cpufreq_cpu_put(policy); + err: +- WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); + + return ret; + } diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch new file mode 100644 index 00000000000..08834245486 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch @@ -0,0 +1,85 @@ +From 8953603eb5447be52f6fc3d8fcae1b3ce9899189 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Mon, 6 Jun 2022 11:58:49 +0200 +Subject: [PATCH v4 1/4] PM / devfreq: Fix cpufreq passive unregister erroring + on PROBE_DEFER + +With the passive governor, the cpu based scaling can PROBE_DEFER due to +the fact that CPU policy are not ready. +The cpufreq passive unregister notifier is called both from the +GOV_START errors and for the GOV_STOP and assume the notifier is +successfully registred every time. With GOV_START failing it's wrong to +loop over each possible CPU since the register path has failed for +some CPU policy not ready. Change the logic and unregister the notifer +based on the current allocated parent_cpu_data list to correctly handle +errors and the governor unregister path. + +Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") +Signed-off-by: Christian 'Ansuel' Marangi +--- + drivers/devfreq/governor_passive.c | 39 +++++++++++++----------------- + 1 file changed, 17 insertions(+), 22 deletions(-) + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -34,6 +34,20 @@ get_parent_cpu_data(struct devfreq_passi + return NULL; + } + ++static void delete_parent_cpu_data(struct devfreq_passive_data *p_data) ++{ ++ struct devfreq_cpu_data *parent_cpu_data, *tmp; ++ ++ list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) { ++ list_del(&parent_cpu_data->node); ++ ++ if (parent_cpu_data->opp_table) ++ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); ++ ++ kfree(parent_cpu_data); ++ } ++} ++ + static unsigned long get_target_freq_by_required_opp(struct device *p_dev, + struct opp_table *p_opp_table, + struct opp_table *opp_table, +@@ -222,8 +236,7 @@ static int cpufreq_passive_unregister_no + { + struct devfreq_passive_data *p_data + = (struct devfreq_passive_data *)devfreq->data; +- struct devfreq_cpu_data *parent_cpu_data; +- int cpu, ret = 0; ++ int ret; + + if (p_data->nb.notifier_call) { + ret = cpufreq_unregister_notifier(&p_data->nb, +@@ -232,27 +245,9 @@ static int cpufreq_passive_unregister_no + return ret; + } + +- for_each_possible_cpu(cpu) { +- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); +- if (!policy) { +- ret = -EINVAL; +- continue; +- } +- +- parent_cpu_data = get_parent_cpu_data(p_data, policy); +- if (!parent_cpu_data) { +- cpufreq_cpu_put(policy); +- continue; +- } +- +- list_del(&parent_cpu_data->node); +- if (parent_cpu_data->opp_table) +- dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); +- kfree(parent_cpu_data); +- cpufreq_cpu_put(policy); +- } ++ delete_parent_cpu_data(p_data); + +- return ret; ++ return 0; + } + + static int cpufreq_passive_register_notifier(struct devfreq *devfreq) diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch new file mode 100644 index 00000000000..867ea83e0c9 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch @@ -0,0 +1,34 @@ +From 57e00b40033a376de3f3cf0bb9bf7590d2dd679d Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Tue, 14 Jun 2022 13:06:59 +0200 +Subject: [PATCH 1/1] PM / devfreq: Fix kernel panic with cpu based scaling to + passive gov + +The cpufreq passive register notifier can PROBE_DEFER and the devfreq +struct is freed and then reallocaed on probe retry. +The current logic assume that the code can't PROBE_DEFER so the devfreq +struct in the this variable in devfreq_passive_data is assumed to be +(if already set) always correct. +This cause kernel panic as the code try to access the wrong address. +To correctly handle this, update the this variable in +devfreq_passive_data to the devfreq reallocated struct. + +Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") +Signed-off-by: Christian 'Ansuel' Marangi +Signed-off-by: Chanwoo Choi +--- + drivers/devfreq/governor_passive.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -401,8 +401,7 @@ static int devfreq_passive_event_handler + if (!p_data) + return -EINVAL; + +- if (!p_data->this) +- p_data->this = devfreq; ++ p_data->this = devfreq; + + switch (event) { + case DEVFREQ_GOV_START: diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch new file mode 100644 index 00000000000..210f57bd7e6 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch @@ -0,0 +1,269 @@ +From 46d05776a1a5dd8eb479e868f5ff4f4b97d68238 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Mon, 6 Jun 2022 12:39:19 +0200 +Subject: [PATCH v4 3/4] PM / devfreq: Rework freq_table to be local to devfreq + struct + +Currently we reference the freq_table to the profile defined one and we +make changes on it. Devfreq never supported PROBE_DEFER before the cpu +based scaling support to the passive governor and assumed that a devfreq +device could only had error and be done with it. +Now that a device can PROBE_DEFER a rework to the freq_table logic is +required. + +If a device PROBE_DEFER on the GOV_START, the freq_table is already set +in the device profile struct and its init is skipped. This is due to the +fact that it's common for devs to declare this kind of struct static. +This cause the devfreq logic to find a freq table declared (freq_table +not NULL) with random data and poiting to the old addrs freed by devm. + +This problem CAN be solved by devs by clearing the freq_table in their +profile struct on driver exit path but it should not be trusted and it +looks to use a flawed logic. + +A better solution is to move the freq_table and max_state to the +devfreq struct and never change the profile struct. +This permit to correctly handle PROBE_DEFER since the devfreq struct is +reallocated and contains new values. +Also the profile struct should only be used to init the driver and should +not be used by the devfreq to write the freq_table if it's not provided +by the driver. + +Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") +Signed-off-by: Christian 'Ansuel' Marangi +--- + drivers/devfreq/devfreq.c | 71 ++++++++++++++---------------- + drivers/devfreq/governor_passive.c | 14 +++--- + include/linux/devfreq.h | 4 ++ + 3 files changed, 45 insertions(+), 44 deletions(-) + +--- a/drivers/devfreq/devfreq.c ++++ b/drivers/devfreq/devfreq.c +@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfr + unsigned long *min_freq, + unsigned long *max_freq) + { +- unsigned long *freq_table = devfreq->profile->freq_table; ++ unsigned long *freq_table = devfreq->freq_table; + s32 qos_min_freq, qos_max_freq; + + lockdep_assert_held(&devfreq->lock); +@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfr + * The devfreq drivers can initialize this in either ascending or + * descending order and devfreq core supports both. + */ +- if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) { ++ if (freq_table[0] < freq_table[devfreq->max_state - 1]) { + *min_freq = freq_table[0]; +- *max_freq = freq_table[devfreq->profile->max_state - 1]; ++ *max_freq = freq_table[devfreq->max_state - 1]; + } else { +- *min_freq = freq_table[devfreq->profile->max_state - 1]; ++ *min_freq = freq_table[devfreq->max_state - 1]; + *max_freq = freq_table[0]; + } + +@@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct + { + int lev; + +- for (lev = 0; lev < devfreq->profile->max_state; lev++) +- if (freq == devfreq->profile->freq_table[lev]) ++ for (lev = 0; lev < devfreq->max_state; lev++) ++ if (freq == devfreq->freq_table[lev]) + return lev; + + return -EINVAL; +@@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct + + static int set_freq_table(struct devfreq *devfreq) + { +- struct devfreq_dev_profile *profile = devfreq->profile; + struct dev_pm_opp *opp; + unsigned long freq; + int i, count; +@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq + if (count <= 0) + return -EINVAL; + +- profile->max_state = count; +- profile->freq_table = devm_kcalloc(devfreq->dev.parent, +- profile->max_state, +- sizeof(*profile->freq_table), +- GFP_KERNEL); +- if (!profile->freq_table) { +- profile->max_state = 0; ++ devfreq->max_state = count; ++ devfreq->freq_table = devm_kcalloc(devfreq->dev.parent, ++ devfreq->max_state, ++ sizeof(*devfreq->freq_table), ++ GFP_KERNEL); ++ if (!devfreq->freq_table) + return -ENOMEM; +- } + +- for (i = 0, freq = 0; i < profile->max_state; i++, freq++) { ++ for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) { + opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq); + if (IS_ERR(opp)) { +- devm_kfree(devfreq->dev.parent, profile->freq_table); +- profile->max_state = 0; ++ devm_kfree(devfreq->dev.parent, devfreq->freq_table); + return PTR_ERR(opp); + } + dev_pm_opp_put(opp); +- profile->freq_table[i] = freq; ++ devfreq->freq_table[i] = freq; + } + + return 0; +@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq + + if (lev != prev_lev) { + devfreq->stats.trans_table[ +- (prev_lev * devfreq->profile->max_state) + lev]++; ++ (prev_lev * devfreq->max_state) + lev]++; + devfreq->stats.total_trans++; + } + +@@ -834,6 +830,9 @@ struct devfreq *devfreq_add_device(struc + if (err < 0) + goto err_dev; + mutex_lock(&devfreq->lock); ++ } else { ++ devfreq->freq_table = devfreq->profile->freq_table; ++ devfreq->max_state = devfreq->profile->max_state; + } + + devfreq->scaling_min_freq = find_available_min_freq(devfreq); +@@ -869,8 +868,8 @@ struct devfreq *devfreq_add_device(struc + + devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev, + array3_size(sizeof(unsigned int), +- devfreq->profile->max_state, +- devfreq->profile->max_state), ++ devfreq->max_state, ++ devfreq->max_state), + GFP_KERNEL); + if (!devfreq->stats.trans_table) { + mutex_unlock(&devfreq->lock); +@@ -879,7 +878,7 @@ struct devfreq *devfreq_add_device(struc + } + + devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev, +- devfreq->profile->max_state, ++ devfreq->max_state, + sizeof(*devfreq->stats.time_in_state), + GFP_KERNEL); + if (!devfreq->stats.time_in_state) { +@@ -1637,9 +1636,9 @@ static ssize_t available_frequencies_sho + + mutex_lock(&df->lock); + +- for (i = 0; i < df->profile->max_state; i++) ++ for (i = 0; i < df->max_state; i++) + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), +- "%lu ", df->profile->freq_table[i]); ++ "%lu ", df->freq_table[i]); + + mutex_unlock(&df->lock); + /* Truncate the trailing space */ +@@ -1662,7 +1661,7 @@ static ssize_t trans_stat_show(struct de + + if (!df->profile) + return -EINVAL; +- max_state = df->profile->max_state; ++ max_state = df->max_state; + + if (max_state == 0) + return sprintf(buf, "Not Supported.\n"); +@@ -1679,19 +1678,17 @@ static ssize_t trans_stat_show(struct de + len += sprintf(buf + len, " :"); + for (i = 0; i < max_state; i++) + len += sprintf(buf + len, "%10lu", +- df->profile->freq_table[i]); ++ df->freq_table[i]); + + len += sprintf(buf + len, " time(ms)\n"); + + for (i = 0; i < max_state; i++) { +- if (df->profile->freq_table[i] +- == df->previous_freq) { ++ if (df->freq_table[i] == df->previous_freq) + len += sprintf(buf + len, "*"); +- } else { ++ else + len += sprintf(buf + len, " "); +- } +- len += sprintf(buf + len, "%10lu:", +- df->profile->freq_table[i]); ++ ++ len += sprintf(buf + len, "%10lu:", df->freq_table[i]); + for (j = 0; j < max_state; j++) + len += sprintf(buf + len, "%10u", + df->stats.trans_table[(i * max_state) + j]); +@@ -1715,7 +1712,7 @@ static ssize_t trans_stat_store(struct d + if (!df->profile) + return -EINVAL; + +- if (df->profile->max_state == 0) ++ if (df->max_state == 0) + return count; + + err = kstrtoint(buf, 10, &value); +@@ -1723,11 +1720,11 @@ static ssize_t trans_stat_store(struct d + return -EINVAL; + + mutex_lock(&df->lock); +- memset(df->stats.time_in_state, 0, (df->profile->max_state * ++ memset(df->stats.time_in_state, 0, (df->max_state * + sizeof(*df->stats.time_in_state))); + memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int), +- df->profile->max_state, +- df->profile->max_state)); ++ df->max_state, ++ df->max_state)); + df->stats.total_trans = 0; + df->stats.last_update = get_jiffies_64(); + mutex_unlock(&df->lock); +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -145,18 +145,18 @@ static int get_target_freq_with_devfreq( + goto out; + + /* Use interpolation if required opps is not available */ +- for (i = 0; i < parent_devfreq->profile->max_state; i++) +- if (parent_devfreq->profile->freq_table[i] == *freq) ++ for (i = 0; i < parent_devfreq->max_state; i++) ++ if (parent_devfreq->freq_table[i] == *freq) + break; + +- if (i == parent_devfreq->profile->max_state) ++ if (i == parent_devfreq->max_state) + return -EINVAL; + +- if (i < devfreq->profile->max_state) { +- child_freq = devfreq->profile->freq_table[i]; ++ if (i < devfreq->max_state) { ++ child_freq = devfreq->freq_table[i]; + } else { +- count = devfreq->profile->max_state; +- child_freq = devfreq->profile->freq_table[count - 1]; ++ count = devfreq->max_state; ++ child_freq = devfreq->freq_table[count - 1]; + } + + out: +--- a/include/linux/devfreq.h ++++ b/include/linux/devfreq.h +@@ -185,6 +185,10 @@ struct devfreq { + struct notifier_block nb; + struct delayed_work work; + ++ /* devfreq local freq_table */ ++ unsigned long *freq_table; ++ unsigned int max_state; ++ + unsigned long previous_freq; + struct devfreq_dev_status last_status; + diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch new file mode 100644 index 00000000000..591340c6f22 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch @@ -0,0 +1,28 @@ +From eee9f767c41b03a2744d4b0f0c1a144e4ff41e78 Mon Sep 17 00:00:00 2001 +From: Christian 'Ansuel' Marangi +Date: Mon, 6 Jun 2022 13:01:02 +0200 +Subject: [PATCH v4 4/4] PM / devfreq: Mute warning on governor PROBE_DEFER + +Don't print warning when a governor PROBE_DEFER as it's not a real +GOV_START fail. + +Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") +Signed-off-by: Christian 'Ansuel' Marangi +--- + drivers/devfreq/devfreq.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/drivers/devfreq/devfreq.c ++++ b/drivers/devfreq/devfreq.c +@@ -930,8 +930,9 @@ struct devfreq *devfreq_add_device(struc + err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, + NULL); + if (err) { +- dev_err(dev, "%s: Unable to start governor for the device\n", +- __func__); ++ dev_err_probe(dev, err, ++ "%s: Unable to start governor for the device\n", ++ __func__); + goto err_init; + } + create_sysfs_files(devfreq, devfreq->governor); diff --git a/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch new file mode 100644 index 00000000000..85feb89148b --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch @@ -0,0 +1,242 @@ +From b044ae89862132a86fb511648e9c52ea3cdf8c30 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 5 Aug 2020 14:19:23 +0200 +Subject: [PATCH 1/4] devfreq: qcom: Add L2 Krait Cache devfreq scaling driver + +Qcom L2 Krait CPUs use the generic cpufreq-dt driver and doesn't actually +scale the Cache frequency when the CPU frequency is changed. This +devfreq driver register with the cpu notifier and scale the Cache +based on the max Freq across all core as the CPU cache is shared across +all of them. If provided this also scale the voltage of the regulator +attached to the CPU cache. The scaling logic is based on the CPU freq +and the 3 scaling interval are set by the device dts. + +Signed-off-by: Christian Marangi +--- + drivers/devfreq/Kconfig | 11 ++ + drivers/devfreq/Makefile | 1 + + drivers/devfreq/krait-cache-devfreq.c | 188 ++++++++++++++++++++++++++ + 3 files changed, 200 insertions(+) + create mode 100644 drivers/devfreq/krait-cache-devfreq.c + +--- a/drivers/devfreq/Kconfig ++++ b/drivers/devfreq/Kconfig +@@ -132,6 +132,17 @@ config ARM_RK3399_DMC_DEVFREQ + It sets the frequency for the memory controller and reads the usage counts + from hardware. + ++config ARM_KRAIT_CACHE_DEVFREQ ++ tristate "Scaling support for Krait CPU Cache Devfreq" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select DEVFREQ_GOV_PASSIVE ++ help ++ This adds the DEVFREQ driver for the Krait CPU L2 Cache shared by all cores. ++ ++ The driver register with the cpufreq notifier and find the right frequency ++ based on the max frequency across all core and the range set in the device ++ dts. If provided this scale also the regulator attached to the l2 cache. ++ + source "drivers/devfreq/event/Kconfig" + + endif # PM_DEVFREQ +--- a/drivers/devfreq/Makefile ++++ b/drivers/devfreq/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx + obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o + obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o + obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o ++obj-$(CONFIG_ARM_KRAIT_CACHE_DEVFREQ) += krait-cache-devfreq.o + + # DEVFREQ Event Drivers + obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ +--- /dev/null ++++ b/drivers/devfreq/krait-cache-devfreq.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "governor.h" ++ ++struct krait_cache_data { ++ struct clk *clk; ++ unsigned long idle_freq; ++}; ++ ++static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++{ ++ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; ++ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; ++ struct regulator *reg = data->regulators[0]; ++ struct krait_cache_data *kdata; ++ struct clk *clk = data->clk; ++ unsigned long idle_freq; ++ int ret; ++ ++ kdata = dev_get_drvdata(data->dev); ++ idle_freq = kdata->idle_freq; ++ ++ if (reg) { ++ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, ++ supply->u_volt, ++ supply->u_volt_max); ++ if (ret) ++ goto exit; ++ } ++ ++ /* ++ * Set to idle bin if switching from normal to high bin ++ * or vice versa. It has been notice that a bug is triggered ++ * in cache scaling when more than one bin is scaled, to fix ++ * this we first need to transition to the base rate and then ++ * to target rate ++ */ ++ if (likely(freq != idle_freq && old_freq != idle_freq)) { ++ ret = clk_set_rate(clk, idle_freq); ++ if (ret) ++ goto exit; ++ } ++ ++ ret = clk_set_rate(clk, freq); ++ if (ret) ++ goto exit; ++ ++exit: ++ return ret; ++}; ++ ++static int krait_cache_get_cur_freq(struct device *dev, unsigned long *freq) ++{ ++ struct krait_cache_data *data = dev_get_drvdata(dev); ++ ++ *freq = clk_get_rate(data->clk); ++ ++ return 0; ++}; ++ ++static int krait_cache_target(struct device *dev, unsigned long *freq, ++ u32 flags) ++{ ++ struct dev_pm_opp *opp; ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, freq); ++ if (unlikely(IS_ERR(opp))) ++ return PTR_ERR(opp); ++ ++ dev_pm_opp_put(opp); ++ ++ return dev_pm_opp_set_rate(dev, *freq); ++}; ++ ++static int krait_cache_get_dev_status(struct device *dev, ++ struct devfreq_dev_status *stat) ++{ ++ struct krait_cache_data *data = dev_get_drvdata(dev); ++ ++ stat->busy_time = 0; ++ stat->total_time = 0; ++ stat->current_frequency = clk_get_rate(data->clk); ++ ++ return 0; ++}; ++ ++static struct devfreq_dev_profile krait_cache_devfreq_profile = { ++ .target = krait_cache_target, ++ .get_dev_status = krait_cache_get_dev_status, ++ .get_cur_freq = krait_cache_get_cur_freq ++}; ++ ++static struct devfreq_passive_data devfreq_gov_data = { ++ .parent_type = CPUFREQ_PARENT_DEV, ++}; ++ ++static int krait_cache_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct krait_cache_data *data; ++ struct opp_table *table; ++ struct devfreq *devfreq; ++ struct dev_pm_opp *opp; ++ struct clk *clk; ++ int ret; ++ ++ krait_cache_devfreq_profile.freq_table = NULL; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ clk = devm_clk_get(dev, "l2"); ++ if (IS_ERR(clk)) ++ return PTR_ERR(clk); ++ ++ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); ++ if (IS_ERR(table)) { ++ ret = PTR_ERR(table); ++ dev_err_probe(dev, -EPROBE_DEFER, "failed to set regulators %d\n", ret); ++ return ret; ++ } ++ ++ ret = PTR_ERR_OR_ZERO( ++ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ if (ret) ++ return ret; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse L2 freq thresholds\n"); ++ return ret; ++ } ++ ++ data->clk = clk; ++ opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ dev_pm_opp_put(opp); ++ ++ dev_set_drvdata(dev, data); ++ ++ devfreq = devm_devfreq_add_device(&pdev->dev, &krait_cache_devfreq_profile, ++ DEVFREQ_GOV_PASSIVE, &devfreq_gov_data); ++ if (IS_ERR(devfreq)) { ++ dev_pm_opp_remove_table(dev); ++ dev_pm_opp_put_regulators(table); ++ dev_pm_opp_unregister_set_opp_helper(table); ++ } ++ ++ return PTR_ERR_OR_ZERO(devfreq); ++}; ++ ++static int krait_cache_remove(struct platform_device *pdev) ++{ ++ dev_pm_opp_remove_table(&pdev->dev); ++ ++ return 0; ++}; ++ ++static const struct of_device_id krait_cache_match_table[] = { ++ { .compatible = "qcom,krait-cache" }, ++ {} ++}; ++ ++static struct platform_driver krait_cache_driver = { ++ .probe = krait_cache_probe, ++ .remove = krait_cache_remove, ++ .driver = { ++ .name = "krait-cache-scaling", ++ .of_match_table = krait_cache_match_table, ++ }, ++}; ++module_platform_driver(krait_cache_driver); ++ ++MODULE_DESCRIPTION("Krait CPU Cache Scaling driver"); ++MODULE_AUTHOR("Christian 'Ansuel' Marangi "); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch b/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch new file mode 100644 index 00000000000..f42729fd509 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch @@ -0,0 +1,50 @@ +From ef124ad0ff8abfbf4ebe3fe6d7dcef4541dec13a Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 16 Jun 2022 18:39:21 +0200 +Subject: [PATCH] ARM: dts: qcom: add krait-cache compatible for ipq806x dtsi + +Add qcom,krait-cache compatible to enable cache devfreq driver for +ipq806x SoC and move the L2 node to the soc node to make the devfreq +driver correctly probe. + +Signed-off-by: Christian Marangi +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -69,16 +69,6 @@ + min-residency-us = <3000>; + }; + }; +- +- L2: l2-cache { +- compatible = "cache"; +- cache-level = <2>; +- qcom,saw = <&saw_l2>; +- +- clocks = <&kraitcc 4>; +- clock-names = "l2"; +- operating-points-v2 = <&opp_table_l2>; +- }; + }; + + opp_table_l2: opp_table_l2 { +@@ -470,6 +460,16 @@ + ranges; + compatible = "simple-bus"; + ++ L2: l2-cache { ++ compatible = "cache", "qcom,krait-cache"; ++ cache-level = <2>; ++ qcom,saw = <&saw_l2>; ++ ++ clocks = <&kraitcc 4>; ++ clock-names = "l2"; ++ operating-points-v2 = <&opp_table_l2>; ++ }; ++ + lpass@28100000 { + compatible = "qcom,lpass-cpu"; + status = "disabled"; diff --git a/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch b/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch new file mode 100644 index 00000000000..340c58a0c18 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch @@ -0,0 +1,203 @@ +From 13f075999935bb696dbab63243923179f06fa05e Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 16 Jun 2022 19:56:08 +0200 +Subject: [PATCH 3/4] devfreq: add ipq806x fabric scaling driver + +Add ipq806x fabric scaling driver using the devfreq passive governor. + +Signed-off-by: Christian Marangi +--- + drivers/devfreq/Kconfig | 11 ++ + drivers/devfreq/Makefile | 1 + + drivers/devfreq/ipq806x-fab-devfreq.c | 155 ++++++++++++++++++++++++++ + 3 files changed, 167 insertions(+) + create mode 100644 drivers/devfreq/ipq806x-fab-devfreq.c + +--- a/drivers/devfreq/Kconfig ++++ b/drivers/devfreq/Kconfig +@@ -143,6 +143,17 @@ config ARM_KRAIT_CACHE_DEVFREQ + based on the max frequency across all core and the range set in the device + dts. If provided this scale also the regulator attached to the l2 cache. + ++config ARM_IPQ806X_FAB_DEVFREQ ++ tristate "Scaling support for ipq806x Soc Fabric" ++ depends on ARCH_QCOM || COMPILE_TEST ++ select DEVFREQ_GOV_PASSIVE ++ help ++ This adds the DEVFREQ driver for the ipq806x Soc Fabric. ++ ++ The driver register with the cpufreq notifier and find the right frequency ++ based on the max frequency across all core and the range set in the device ++ dts. ++ + source "drivers/devfreq/event/Kconfig" + + endif # PM_DEVFREQ +--- a/drivers/devfreq/Makefile ++++ b/drivers/devfreq/Makefile +@@ -14,6 +14,7 @@ obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += + obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o + obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o + obj-$(CONFIG_ARM_KRAIT_CACHE_DEVFREQ) += krait-cache-devfreq.o ++obj-$(CONFIG_ARM_IPQ806X_FAB_DEVFREQ) += ipq806x-fab-devfreq.o + + # DEVFREQ Event Drivers + obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ +--- /dev/null ++++ b/drivers/devfreq/ipq806x-fab-devfreq.c +@@ -0,0 +1,155 @@ ++// SPDX-License-Identifier: GPL-2.0 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "governor.h" ++ ++struct ipq806x_fab_data { ++ struct clk *fab_clk; ++ struct clk *ddr_clk; ++}; ++ ++static int ipq806x_fab_get_cur_freq(struct device *dev, unsigned long *freq) ++{ ++ struct ipq806x_fab_data *data = dev_get_drvdata(dev); ++ ++ *freq = clk_get_rate(data->fab_clk); ++ ++ return 0; ++}; ++ ++static int ipq806x_fab_target(struct device *dev, unsigned long *freq, ++ u32 flags) ++{ ++ struct ipq806x_fab_data *data = dev_get_drvdata(dev); ++ struct dev_pm_opp *opp; ++ int ret; ++ ++ opp = dev_pm_opp_find_freq_ceil(dev, freq); ++ if (unlikely(IS_ERR(opp))) ++ return PTR_ERR(opp); ++ ++ dev_pm_opp_put(opp); ++ ++ ret = clk_set_rate(data->fab_clk, *freq); ++ if (ret) ++ return ret; ++ ++ return clk_set_rate(data->ddr_clk, *freq); ++}; ++ ++static int ipq806x_fab_get_dev_status(struct device *dev, ++ struct devfreq_dev_status *stat) ++{ ++ struct ipq806x_fab_data *data = dev_get_drvdata(dev); ++ ++ stat->busy_time = 0; ++ stat->total_time = 0; ++ stat->current_frequency = clk_get_rate(data->fab_clk); ++ ++ return 0; ++}; ++ ++static struct devfreq_dev_profile ipq806x_fab_devfreq_profile = { ++ .target = ipq806x_fab_target, ++ .get_dev_status = ipq806x_fab_get_dev_status, ++ .get_cur_freq = ipq806x_fab_get_cur_freq ++}; ++ ++static struct devfreq_passive_data devfreq_gov_data = { ++ .parent_type = CPUFREQ_PARENT_DEV, ++}; ++ ++static int ipq806x_fab_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct ipq806x_fab_data *data; ++ struct devfreq *devfreq; ++ struct clk *clk; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ clk = devm_clk_get(dev, "apps-fab-clk"); ++ if (IS_ERR(clk)) { ++ dev_err_probe(dev, PTR_ERR(clk), "failed to get apps fab clk\n"); ++ return PTR_ERR(clk); ++ } ++ ++ clk_prepare_enable(clk); ++ data->fab_clk = clk; ++ ++ clk = devm_clk_get(dev, "ddr-fab-clk"); ++ if (IS_ERR(clk)) { ++ dev_err_probe(dev, PTR_ERR(clk), "failed to get ddr fab clk\n"); ++ goto err_ddr; ++ } ++ ++ clk_prepare_enable(clk); ++ data->ddr_clk = clk; ++ ++ ret = dev_pm_opp_of_add_table(dev); ++ if (ret) { ++ dev_err(dev, "failed to parse fab freq thresholds\n"); ++ return ret; ++ } ++ ++ dev_set_drvdata(dev, data); ++ ++ devfreq = devm_devfreq_add_device(&pdev->dev, &ipq806x_fab_devfreq_profile, ++ DEVFREQ_GOV_PASSIVE, &devfreq_gov_data); ++ if (IS_ERR(devfreq)) ++ dev_pm_opp_remove_table(dev); ++ ++ return PTR_ERR_OR_ZERO(devfreq); ++ ++err_ddr: ++ clk_unprepare(data->fab_clk); ++ clk_put(data->fab_clk); ++ return PTR_ERR(clk); ++}; ++ ++static int ipq806x_fab_remove(struct platform_device *pdev) ++{ ++ struct ipq806x_fab_data *data = dev_get_drvdata(&pdev->dev); ++ ++ clk_unprepare(data->fab_clk); ++ clk_put(data->fab_clk); ++ ++ clk_unprepare(data->ddr_clk); ++ clk_put(data->ddr_clk); ++ ++ dev_pm_opp_remove_table(&pdev->dev); ++ ++ return 0; ++}; ++ ++static const struct of_device_id ipq806x_fab_match_table[] = { ++ { .compatible = "qcom,fab-scaling" }, ++ {} ++}; ++ ++static struct platform_driver ipq806x_fab_driver = { ++ .probe = ipq806x_fab_probe, ++ .remove = ipq806x_fab_remove, ++ .driver = { ++ .name = "ipq806x-fab-scaling", ++ .of_match_table = ipq806x_fab_match_table, ++ }, ++}; ++module_platform_driver(ipq806x_fab_driver); ++ ++MODULE_DESCRIPTION("ipq806x Fab Scaling driver"); ++MODULE_AUTHOR("Christian Marangi "); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch b/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch new file mode 100644 index 00000000000..f4de1dbb52c --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch @@ -0,0 +1,48 @@ +From c3573f0907dadb0a6e9933aae2a46a489abcbd48 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 16 Jun 2022 20:03:05 +0200 +Subject: [PATCH 4/4] ARM: dts: qcom: add fab scaling node for ipq806x + +Add fabric scaling node for ipq806x to correctly scale apps and ddr +fabric clk. + +Signed-off-by: Christian Marangi +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -170,6 +170,18 @@ + }; + }; + ++ opp_table_fab: opp_table_fab { ++ compatible = "operating-points-v2"; ++ ++ opp-533000000 { ++ opp-hz = /bits/ 64 <533000000>; ++ }; ++ ++ opp-400000000 { ++ opp-hz = /bits/ 64 <400000000>; ++ }; ++ }; ++ + thermal-zones { + tsens_tz_sensor0 { + polling-delay-passive = <0>; +@@ -470,6 +482,13 @@ + operating-points-v2 = <&opp_table_l2>; + }; + ++ fab-scaling { ++ compatible = "qcom,fab-scaling"; ++ clocks = <&rpmcc RPM_APPS_FABRIC_A_CLK>, <&rpmcc RPM_EBI1_A_CLK>; ++ clock-names = "apps-fab-clk", "ddr-fab-clk"; ++ operating-points-v2 = <&opp_table_fab>; ++ }; ++ + lpass@28100000 { + compatible = "qcom,lpass-cpu"; + status = "disabled"; diff --git a/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch b/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch new file mode 100644 index 00000000000..c595b10dd74 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch @@ -0,0 +1,268 @@ +From b360514edb4743cbf86fc377699c75e98b1264c7 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 16 Jun 2022 02:18:33 +0200 +Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: reorder qcom_nand_host struct + +Reorder structs in nandc driver to save holes. + +Signed-off-by: Christian Marangi +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-2-ansuelsmth@gmail.com +--- + drivers/mtd/nand/raw/qcom_nandc.c | 107 +++++++++++++++++------------- + 1 file changed, 62 insertions(+), 45 deletions(-) + +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -237,6 +237,9 @@ nandc_set_reg(chip, reg, \ + * @bam_ce - the array of BAM command elements + * @cmd_sgl - sgl for NAND BAM command pipe + * @data_sgl - sgl for NAND BAM consumer/producer pipe ++ * @last_data_desc - last DMA desc in data channel (tx/rx). ++ * @last_cmd_desc - last DMA desc in command channel. ++ * @txn_done - completion for NAND transfer. + * @bam_ce_pos - the index in bam_ce which is available for next sgl + * @bam_ce_start - the index in bam_ce which marks the start position ce + * for current sgl. It will be used for size calculation +@@ -249,14 +252,14 @@ nandc_set_reg(chip, reg, \ + * @rx_sgl_start - start index in data sgl for rx. + * @wait_second_completion - wait for second DMA desc completion before making + * the NAND transfer completion. +- * @txn_done - completion for NAND transfer. +- * @last_data_desc - last DMA desc in data channel (tx/rx). +- * @last_cmd_desc - last DMA desc in command channel. + */ + struct bam_transaction { + struct bam_cmd_element *bam_ce; + struct scatterlist *cmd_sgl; + struct scatterlist *data_sgl; ++ struct dma_async_tx_descriptor *last_data_desc; ++ struct dma_async_tx_descriptor *last_cmd_desc; ++ struct completion txn_done; + u32 bam_ce_pos; + u32 bam_ce_start; + u32 cmd_sgl_pos; +@@ -266,25 +269,23 @@ struct bam_transaction { + u32 rx_sgl_pos; + u32 rx_sgl_start; + bool wait_second_completion; +- struct completion txn_done; +- struct dma_async_tx_descriptor *last_data_desc; +- struct dma_async_tx_descriptor *last_cmd_desc; + }; + + /* + * This data type corresponds to the nand dma descriptor ++ * @dma_desc - low level DMA engine descriptor + * @list - list for desc_info +- * @dir - DMA transfer direction ++ * + * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by + * ADM + * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM + * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM +- * @dma_desc - low level DMA engine descriptor ++ * @dir - DMA transfer direction + */ + struct desc_info { ++ struct dma_async_tx_descriptor *dma_desc; + struct list_head node; + +- enum dma_data_direction dir; + union { + struct scatterlist adm_sgl; + struct { +@@ -292,7 +293,7 @@ struct desc_info { + int sgl_cnt; + }; + }; +- struct dma_async_tx_descriptor *dma_desc; ++ enum dma_data_direction dir; + }; + + /* +@@ -336,52 +337,64 @@ struct nandc_regs { + /* + * NAND controller data struct + * +- * @controller: base controller structure +- * @host_list: list containing all the chips attached to the +- * controller + * @dev: parent device ++ * + * @base: MMIO base +- * @base_phys: physical base address of controller registers +- * @base_dma: dma base address of controller registers ++ * + * @core_clk: controller clock + * @aon_clk: another controller clock + * ++ * @regs: a contiguous chunk of memory for DMA register ++ * writes. contains the register values to be ++ * written to controller ++ * ++ * @props: properties of current NAND controller, ++ * initialized via DT match data ++ * ++ * @controller: base controller structure ++ * @host_list: list containing all the chips attached to the ++ * controller ++ * + * @chan: dma channel + * @cmd_crci: ADM DMA CRCI for command flow control + * @data_crci: ADM DMA CRCI for data flow control ++ * + * @desc_list: DMA descriptor list (list of desc_infos) + * + * @data_buffer: our local DMA buffer for page read/writes, + * used when we can't use the buffer provided + * by upper layers directly +- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf +- * functions + * @reg_read_buf: local buffer for reading back registers via DMA ++ * ++ * @base_phys: physical base address of controller registers ++ * @base_dma: dma base address of controller registers + * @reg_read_dma: contains dma address for register read buffer +- * @reg_read_pos: marker for data read in reg_read_buf + * +- * @regs: a contiguous chunk of memory for DMA register +- * writes. contains the register values to be +- * written to controller +- * @cmd1/vld: some fixed controller register values +- * @props: properties of current NAND controller, +- * initialized via DT match data ++ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf ++ * functions + * @max_cwperpage: maximum QPIC codewords required. calculated + * from all connected NAND devices pagesize ++ * ++ * @reg_read_pos: marker for data read in reg_read_buf ++ * ++ * @cmd1/vld: some fixed controller register values + */ + struct qcom_nand_controller { +- struct nand_controller controller; +- struct list_head host_list; +- + struct device *dev; + + void __iomem *base; +- phys_addr_t base_phys; +- dma_addr_t base_dma; + + struct clk *core_clk; + struct clk *aon_clk; + ++ struct nandc_regs *regs; ++ struct bam_transaction *bam_txn; ++ ++ const struct qcom_nandc_props *props; ++ ++ struct nand_controller controller; ++ struct list_head host_list; ++ + union { + /* will be used only by QPIC for BAM DMA */ + struct { +@@ -399,22 +412,22 @@ struct qcom_nand_controller { + }; + + struct list_head desc_list; +- struct bam_transaction *bam_txn; + + u8 *data_buffer; ++ __le32 *reg_read_buf; ++ ++ phys_addr_t base_phys; ++ dma_addr_t base_dma; ++ dma_addr_t reg_read_dma; ++ + int buf_size; + int buf_count; + int buf_start; + unsigned int max_cwperpage; + +- __le32 *reg_read_buf; +- dma_addr_t reg_read_dma; + int reg_read_pos; + +- struct nandc_regs *regs; +- + u32 cmd1, vld; +- const struct qcom_nandc_props *props; + }; + + /* +@@ -430,19 +443,21 @@ struct qcom_nand_controller { + * and reserved bytes + * @cw_data: the number of bytes within a codeword protected + * by ECC +- * @use_ecc: request the controller to use ECC for the +- * upcoming read/write +- * @bch_enabled: flag to tell whether BCH ECC mode is used + * @ecc_bytes_hw: ECC bytes used by controller hardware for this + * chip +- * @status: value to be returned if NAND_CMD_STATUS command +- * is executed ++ * + * @last_command: keeps track of last command on this chip. used + * for reading correct status + * + * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for + * ecc/non-ecc mode for the current nand flash + * device ++ * ++ * @status: value to be returned if NAND_CMD_STATUS command ++ * is executed ++ * @use_ecc: request the controller to use ECC for the ++ * upcoming read/write ++ * @bch_enabled: flag to tell whether BCH ECC mode is used + */ + struct qcom_nand_host { + struct nand_chip chip; +@@ -451,12 +466,10 @@ struct qcom_nand_host { + int cs; + int cw_size; + int cw_data; +- bool use_ecc; +- bool bch_enabled; + int ecc_bytes_hw; + int spare_bytes; + int bbm_size; +- u8 status; ++ + int last_command; + + u32 cfg0, cfg1; +@@ -465,23 +478,27 @@ struct qcom_nand_host { + u32 ecc_bch_cfg; + u32 clrflashstatus; + u32 clrreadstatus; ++ ++ u8 status; ++ bool use_ecc; ++ bool bch_enabled; + }; + + /* + * This data type corresponds to the NAND controller properties which varies + * among different NAND controllers. + * @ecc_modes - ecc mode for NAND ++ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP + * @qpic_v2 - flag to indicate QPIC IP version 2 +- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset + */ + struct qcom_nandc_props { + u32 ecc_modes; ++ u32 dev_cmd_reg_start; + bool is_bam; + bool is_qpic; + bool qpic_v2; +- u32 dev_cmd_reg_start; + }; + + /* Frees the BAM transaction memory */ diff --git a/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch b/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch new file mode 100644 index 00000000000..2a661953044 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch @@ -0,0 +1,406 @@ +From 862bdedd7f4b8aebf00fdb422062e64896e97809 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 16 Jun 2022 02:18:34 +0200 +Subject: [PATCH 2/2] mtd: nand: raw: qcom_nandc: add support for unprotected + spare data pages + +IPQ8064 nand have special pages where a different layout scheme is used. +These special page are used by boot partition and on reading them +lots of warning are reported about wrong ECC data and if written to +results in broken data and not bootable device. + +The layout scheme used by these special page consist in using 512 bytes +as the codeword size (even for the last codeword) while writing to CFG0 +register. This forces the NAND controller to unprotect the 4 bytes of +spare data. + +Since the kernel is unaware of this different layout for these special +page, it does try to protect the spare data too during read/write and +warn about CRC errors. + +Add support for this by permitting the user to declare these special +pages in dts by declaring offset and size of the partition. The driver +internally will convert these value to nand pages. + +On user read/write the page is checked and if it's a boot page the +correct layout is used. + +Signed-off-by: Christian Marangi +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-3-ansuelsmth@gmail.com +--- + drivers/mtd/nand/raw/qcom_nandc.c | 199 +++++++++++++++++++++++++++++- + 1 file changed, 194 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -79,8 +79,10 @@ + #define DISABLE_STATUS_AFTER_WRITE 4 + #define CW_PER_PAGE 6 + #define UD_SIZE_BYTES 9 ++#define UD_SIZE_BYTES_MASK GENMASK(18, 9) + #define ECC_PARITY_SIZE_BYTES_RS 19 + #define SPARE_SIZE_BYTES 23 ++#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) + #define NUM_ADDR_CYCLES 27 + #define STATUS_BFR_READ 30 + #define SET_RD_MODE_AFTER_STATUS 31 +@@ -101,6 +103,7 @@ + #define ECC_MODE 4 + #define ECC_PARITY_SIZE_BYTES_BCH 8 + #define ECC_NUM_DATA_BYTES 16 ++#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) + #define ECC_FORCE_CLK_OPEN 30 + + /* NAND_DEV_CMD1 bits */ +@@ -431,12 +434,31 @@ struct qcom_nand_controller { + }; + + /* ++ * NAND special boot partitions ++ * ++ * @page_offset: offset of the partition where spare data is not protected ++ * by ECC (value in pages) ++ * @page_offset: size of the partition where spare data is not protected ++ * by ECC (value in pages) ++ */ ++struct qcom_nand_boot_partition { ++ u32 page_offset; ++ u32 page_size; ++}; ++ ++/* + * NAND chip structure + * ++ * @boot_partitions: array of boot partitions where offset and size of the ++ * boot partitions are stored ++ * + * @chip: base NAND chip structure + * @node: list node to add itself to host_list in + * qcom_nand_controller + * ++ * @nr_boot_partitions: count of the boot partitions where spare data is not ++ * protected by ECC ++ * + * @cs: chip select value for this chip + * @cw_size: the number of bytes in a single step/codeword + * of a page, consisting of all data, ecc, spare +@@ -455,14 +477,20 @@ struct qcom_nand_controller { + * + * @status: value to be returned if NAND_CMD_STATUS command + * is executed ++ * @codeword_fixup: keep track of the current layout used by ++ * the driver for read/write operation. + * @use_ecc: request the controller to use ECC for the + * upcoming read/write + * @bch_enabled: flag to tell whether BCH ECC mode is used + */ + struct qcom_nand_host { ++ struct qcom_nand_boot_partition *boot_partitions; ++ + struct nand_chip chip; + struct list_head node; + ++ int nr_boot_partitions; ++ + int cs; + int cw_size; + int cw_data; +@@ -480,6 +508,7 @@ struct qcom_nand_host { + u32 clrreadstatus; + + u8 status; ++ bool codeword_fixup; + bool use_ecc; + bool bch_enabled; + }; +@@ -492,6 +521,7 @@ struct qcom_nand_host { + * @is_bam - whether NAND controller is using BAM + * @is_qpic - whether NAND CTRL is part of qpic IP + * @qpic_v2 - flag to indicate QPIC IP version 2 ++ * @use_codeword_fixup - whether NAND has different layout for boot partitions + */ + struct qcom_nandc_props { + u32 ecc_modes; +@@ -499,6 +529,7 @@ struct qcom_nandc_props { + bool is_bam; + bool is_qpic; + bool qpic_v2; ++ bool use_codeword_fixup; + }; + + /* Frees the BAM transaction memory */ +@@ -1708,7 +1739,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (qcom_nandc_is_last_cw(ecc, cw)) { ++ if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) * 4); + oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + +@@ -1789,7 +1820,7 @@ check_for_erased_page(struct qcom_nand_h + } + + for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { +- if (qcom_nandc_is_last_cw(ecc, cw)) { ++ if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { + data_size = ecc->size - ((ecc->steps - 1) * 4); + oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; + } else { +@@ -1947,7 +1978,7 @@ static int read_page_ecc(struct qcom_nan + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (qcom_nandc_is_last_cw(ecc, i)) { ++ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -2044,6 +2075,69 @@ static int copy_last_cw(struct qcom_nand + return ret; + } + ++static bool qcom_nandc_is_boot_partition(struct qcom_nand_host *host, int page) ++{ ++ struct qcom_nand_boot_partition *boot_partition; ++ u32 start, end; ++ int i; ++ ++ /* ++ * Since the frequent access will be to the non-boot partitions like rootfs, ++ * optimize the page check by: ++ * ++ * 1. Checking if the page lies after the last boot partition. ++ * 2. Checking from the boot partition end. ++ */ ++ ++ /* First check the last boot partition */ ++ boot_partition = &host->boot_partitions[host->nr_boot_partitions - 1]; ++ start = boot_partition->page_offset; ++ end = start + boot_partition->page_size; ++ ++ /* Page is after the last boot partition end. This is NOT a boot partition */ ++ if (page > end) ++ return false; ++ ++ /* Actually check if it's a boot partition */ ++ if (page < end && page >= start) ++ return true; ++ ++ /* Check the other boot partitions starting from the second-last partition */ ++ for (i = host->nr_boot_partitions - 2; i >= 0; i--) { ++ boot_partition = &host->boot_partitions[i]; ++ start = boot_partition->page_offset; ++ end = start + boot_partition->page_size; ++ ++ if (page < end && page >= start) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page) ++{ ++ bool codeword_fixup = qcom_nandc_is_boot_partition(host, page); ++ ++ /* Skip conf write if we are already in the correct mode */ ++ if (codeword_fixup == host->codeword_fixup) ++ return; ++ ++ host->codeword_fixup = codeword_fixup; ++ ++ host->cw_data = codeword_fixup ? 512 : 516; ++ host->spare_bytes = host->cw_size - host->ecc_bytes_hw - ++ host->bbm_size - host->cw_data; ++ ++ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); ++ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | ++ host->cw_data << UD_SIZE_BYTES; ++ ++ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; ++ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; ++ host->ecc_buf_cfg = (host->cw_data - 1) << NUM_STEPS; ++} ++ + /* implements ecc->read_page() */ + static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) +@@ -2052,6 +2146,9 @@ static int qcom_nandc_read_page(struct n + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + u8 *data_buf, *oob_buf = NULL; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + nand_read_page_op(chip, page, 0, NULL, 0); + data_buf = buf; + oob_buf = oob_required ? chip->oob_poi : NULL; +@@ -2071,6 +2168,9 @@ static int qcom_nandc_read_page_raw(stru + int cw, ret; + u8 *data_buf = buf, *oob_buf = chip->oob_poi; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + for (cw = 0; cw < ecc->steps; cw++) { + ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, + page, cw); +@@ -2091,6 +2191,9 @@ static int qcom_nandc_read_oob(struct na + struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); + struct nand_ecc_ctrl *ecc = &chip->ecc; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + clear_read_regs(nandc); + clear_bam_transaction(nandc); + +@@ -2111,6 +2214,9 @@ static int qcom_nandc_write_page(struct + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + + clear_read_regs(nandc); +@@ -2126,7 +2232,7 @@ static int qcom_nandc_write_page(struct + for (i = 0; i < ecc->steps; i++) { + int data_size, oob_size; + +- if (qcom_nandc_is_last_cw(ecc, i)) { ++ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { + data_size = ecc->size - ((ecc->steps - 1) << 2); + oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + + host->spare_bytes; +@@ -2183,6 +2289,9 @@ static int qcom_nandc_write_page_raw(str + u8 *data_buf, *oob_buf; + int i, ret; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + nand_prog_page_begin_op(chip, page, 0, NULL, 0); + clear_read_regs(nandc); + clear_bam_transaction(nandc); +@@ -2201,7 +2310,7 @@ static int qcom_nandc_write_page_raw(str + data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); + oob_size1 = host->bbm_size; + +- if (qcom_nandc_is_last_cw(ecc, i)) { ++ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { + data_size2 = ecc->size - data_size1 - + ((ecc->steps - 1) << 2); + oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + +@@ -2261,6 +2370,9 @@ static int qcom_nandc_write_oob(struct n + int data_size, oob_size; + int ret; + ++ if (host->nr_boot_partitions) ++ qcom_nandc_codeword_fixup(host, page); ++ + host->use_ecc = true; + clear_bam_transaction(nandc); + +@@ -2922,6 +3034,74 @@ static int qcom_nandc_setup(struct qcom_ + + static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL }; + ++static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nandc, ++ struct qcom_nand_host *host, ++ struct device_node *dn) ++{ ++ struct nand_chip *chip = &host->chip; ++ struct mtd_info *mtd = nand_to_mtd(chip); ++ struct qcom_nand_boot_partition *boot_partition; ++ struct device *dev = nandc->dev; ++ int partitions_count, i, j, ret; ++ ++ if (!of_find_property(dn, "qcom,boot-partitions", NULL)) ++ return 0; ++ ++ partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions"); ++ if (partitions_count <= 0) { ++ dev_err(dev, "Error parsing boot partition\n"); ++ return partitions_count ? partitions_count : -EINVAL; ++ } ++ ++ host->nr_boot_partitions = partitions_count / 2; ++ host->boot_partitions = devm_kcalloc(dev, host->nr_boot_partitions, ++ sizeof(*host->boot_partitions), GFP_KERNEL); ++ if (!host->boot_partitions) { ++ host->nr_boot_partitions = 0; ++ return -ENOMEM; ++ } ++ ++ for (i = 0, j = 0; i < host->nr_boot_partitions; i++, j += 2) { ++ boot_partition = &host->boot_partitions[i]; ++ ++ ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j, ++ &boot_partition->page_offset); ++ if (ret) { ++ dev_err(dev, "Error parsing boot partition offset at index %d\n", i); ++ host->nr_boot_partitions = 0; ++ return ret; ++ } ++ ++ if (boot_partition->page_offset % mtd->writesize) { ++ dev_err(dev, "Boot partition offset not multiple of writesize at index %i\n", ++ i); ++ host->nr_boot_partitions = 0; ++ return -EINVAL; ++ } ++ /* Convert offset to nand pages */ ++ boot_partition->page_offset /= mtd->writesize; ++ ++ ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j + 1, ++ &boot_partition->page_size); ++ if (ret) { ++ dev_err(dev, "Error parsing boot partition size at index %d\n", i); ++ host->nr_boot_partitions = 0; ++ return ret; ++ } ++ ++ if (boot_partition->page_size % mtd->writesize) { ++ dev_err(dev, "Boot partition size not multiple of writesize at index %i\n", ++ i); ++ host->nr_boot_partitions = 0; ++ return -EINVAL; ++ } ++ /* Convert size to nand pages */ ++ boot_partition->page_size /= mtd->writesize; ++ } ++ ++ return 0; ++} ++ + static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, + struct qcom_nand_host *host, + struct device_node *dn) +@@ -2979,6 +3159,14 @@ static int qcom_nand_host_init_and_regis + if (ret) + nand_cleanup(chip); + ++ if (nandc->props->use_codeword_fixup) { ++ ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn); ++ if (ret) { ++ nand_cleanup(chip); ++ return ret; ++ } ++ } ++ + return ret; + } + +@@ -3144,6 +3332,7 @@ static int qcom_nandc_remove(struct plat + static const struct qcom_nandc_props ipq806x_nandc_props = { + .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), + .is_bam = false, ++ .use_codeword_fixup = true, + .dev_cmd_reg_start = 0x0, + }; + diff --git a/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch b/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch new file mode 100644 index 00000000000..3008fff9b7f --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch @@ -0,0 +1,41 @@ +From fcfbfe373d41b4728ffec075f8f91b6572a88c27 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 30 Apr 2022 07:44:56 +0200 +Subject: [PATCH 1/3] clk: qcom: clk-hfpll: use poll_timeout macro + +Use regmap_read_poll_timeout macro instead of do-while structure to tidy +things up. Also set a timeout to prevent any sort of system stall. + +Signed-off-by: Ansuel Smith +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220430054458.31321-2-ansuelsmth@gmail.com +--- + drivers/clk/qcom/clk-hfpll.c | 15 +++++++++------ + 1 file changed, 9 insertions(+), 6 deletions(-) + +--- a/drivers/clk/qcom/clk-hfpll.c ++++ b/drivers/clk/qcom/clk-hfpll.c +@@ -72,13 +72,16 @@ static void __clk_hfpll_enable(struct cl + regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N); + + /* Wait for PLL to lock. */ +- if (hd->status_reg) { +- do { +- regmap_read(regmap, hd->status_reg, &val); +- } while (!(val & BIT(hd->lock_bit))); +- } else { ++ if (hd->status_reg) ++ /* ++ * Busy wait. Should never timeout, we add a timeout to ++ * prevent any sort of stall. ++ */ ++ regmap_read_poll_timeout(regmap, hd->status_reg, val, ++ !(val & BIT(hd->lock_bit)), 0, ++ 100 * USEC_PER_MSEC); ++ else + udelay(60); +- } + + /* Enable PLL output. */ + regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL); diff --git a/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch b/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch new file mode 100644 index 00000000000..4012e16f9bc --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch @@ -0,0 +1,86 @@ +From 898d0d6483a9360f1968e0a900465c1fa152a4a9 Mon Sep 17 00:00:00 2001 +From: Ansuel Smith +Date: Sat, 30 Apr 2022 07:44:58 +0200 +Subject: [PATCH 3/3] clk: qcom: clk-krait: add apq/ipq8064 errata workaround + +Add apq/ipq8064 errata workaround where the sec_src clock gating needs to +be disabled during switching. krait-cc compatible is not enough to +handle this and limit this workaround to apq/ipq8064. We check machine +compatible to handle this. + +Signed-off-by: Ansuel Smith +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220430054458.31321-4-ansuelsmth@gmail.com +--- + drivers/clk/qcom/clk-krait.c | 16 ++++++++++++++++ + drivers/clk/qcom/clk-krait.h | 1 + + drivers/clk/qcom/krait-cc.c | 8 ++++++++ + 3 files changed, 25 insertions(+) + +--- a/drivers/clk/qcom/clk-krait.c ++++ b/drivers/clk/qcom/clk-krait.c +@@ -18,13 +18,23 @@ + static DEFINE_SPINLOCK(krait_clock_reg_lock); + + #define LPL_SHIFT 8 ++#define SECCLKAGD BIT(4) ++ + static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel) + { + unsigned long flags; + u32 regval; + + spin_lock_irqsave(&krait_clock_reg_lock, flags); ++ + regval = krait_get_l2_indirect_reg(mux->offset); ++ ++ /* apq/ipq8064 Errata: disable sec_src clock gating during switch. */ ++ if (mux->disable_sec_src_gating) { ++ regval |= SECCLKAGD; ++ krait_set_l2_indirect_reg(mux->offset, regval); ++ } ++ + regval &= ~(mux->mask << mux->shift); + regval |= (sel & mux->mask) << mux->shift; + if (mux->lpl) { +@@ -33,6 +43,12 @@ static void __krait_mux_set_sel(struct k + } + krait_set_l2_indirect_reg(mux->offset, regval); + ++ /* apq/ipq8064 Errata: re-enabled sec_src clock gating. */ ++ if (mux->disable_sec_src_gating) { ++ regval &= ~SECCLKAGD; ++ krait_set_l2_indirect_reg(mux->offset, regval); ++ } ++ + /* Wait for switch to complete. */ + mb(); + udelay(1); +--- a/drivers/clk/qcom/clk-krait.h ++++ b/drivers/clk/qcom/clk-krait.h +@@ -15,6 +15,7 @@ struct krait_mux_clk { + u8 safe_sel; + u8 old_index; + bool reparent; ++ bool disable_sec_src_gating; + + struct clk_hw hw; + struct notifier_block clk_nb; +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -139,6 +139,14 @@ krait_add_sec_mux(struct device *dev, in + mux->hw.init = &init; + mux->safe_sel = 0; + ++ /* Checking for qcom,krait-cc-v1 or qcom,krait-cc-v2 is not ++ * enough to limit this to apq/ipq8064. Directly check machine ++ * compatible to correctly handle this errata. ++ */ ++ if (of_machine_is_compatible("qcom,ipq8064") || ++ of_machine_is_compatible("qcom,apq8064")) ++ mux->disable_sec_src_gating = true; ++ + init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); + if (!init.name) + return -ENOMEM; diff --git a/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch b/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch new file mode 100644 index 00000000000..8567d0802bc --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch @@ -0,0 +1,46 @@ +From e4cacac0cae3ce7399b70df3bce92eac03151624 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 12 Apr 2022 16:48:39 +0200 +Subject: [PATCH 3/4] clk: introduce (devm_)hw_register_mux_parent_data_table + API + +Introduce (devm_)hw_register_mux_parent_data_table new API. We have +basic support for clk_register_mux using parent_data but we lack any API +to provide a custom parent_map. Add these 2 new API to correctly handle +these special configuration instead of using the generic +__(devm_)clk_hw_register_mux API. + +Signed-off-by: Christian Marangi +--- + include/linux/clk-provider.h | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +--- a/include/linux/clk-provider.h ++++ b/include/linux/clk-provider.h +@@ -955,12 +955,26 @@ struct clk *clk_register_mux_table(struc + __clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, NULL, \ + (parent_data), (flags), (reg), (shift), \ + BIT((width)) - 1, (clk_mux_flags), NULL, (lock)) ++#define clk_hw_register_mux_parent_data_table(dev, name, parent_data, \ ++ num_parents, flags, reg, shift, \ ++ width, clk_mux_flags, table, \ ++ lock) \ ++ __clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, NULL, \ ++ (parent_data), (flags), (reg), (shift), \ ++ BIT((width)) - 1, (clk_mux_flags), table, (lock)) + #define devm_clk_hw_register_mux(dev, name, parent_names, num_parents, flags, reg, \ + shift, width, clk_mux_flags, lock) \ + __devm_clk_hw_register_mux((dev), NULL, (name), (num_parents), \ + (parent_names), NULL, NULL, (flags), (reg), \ + (shift), BIT((width)) - 1, (clk_mux_flags), \ + NULL, (lock)) ++#define devm_clk_hw_register_mux_parent_data_table(dev, name, parent_data, \ ++ num_parents, flags, reg, shift, \ ++ width, clk_mux_flags, table, \ ++ lock) \ ++ __devm_clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, \ ++ NULL, (parent_data), (flags), (reg), (shift), \ ++ BIT((width)) - 1, (clk_mux_flags), table, (lock)) + + int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, + unsigned int val); diff --git a/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch b/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch new file mode 100644 index 00000000000..6c5f5ea96b2 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch @@ -0,0 +1,70 @@ +From d08c79b818767f24c3c9cbba585d8a3ec896c1a1 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 17 Feb 2022 22:43:34 +0100 +Subject: [PATCH 4/4] clk: qcom: kpss-xcc: convert to parent data API + +Convert the driver to parent data API. From the Documentation pll8_vote +and pxo should be declared in the DTS so fw_name can be used instead of +parent_names. Name is still used to save regression on old definition. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/kpss-xcc.c | 26 +++++++++----------------- + 1 file changed, 9 insertions(+), 17 deletions(-) + +--- a/drivers/clk/qcom/kpss-xcc.c ++++ b/drivers/clk/qcom/kpss-xcc.c +@@ -12,9 +12,9 @@ + #include + #include + +-static const char *aux_parents[] = { +- "pll8_vote", +- "pxo", ++static const struct clk_parent_data aux_parents[] = { ++ { .name = "pll8_vote", .fw_name = "pll8_vote" }, ++ { .name = "pxo", .fw_name = "pxo" }, + }; + + static unsigned int aux_parent_map[] = { +@@ -32,9 +32,9 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_t + static int kpss_xcc_driver_probe(struct platform_device *pdev) + { + const struct of_device_id *id; +- struct clk *clk; + struct resource *res; + void __iomem *base; ++ struct clk_hw *hw; + const char *name; + + id = of_match_device(kpss_xcc_match_table, &pdev->dev); +@@ -57,24 +57,16 @@ static int kpss_xcc_driver_probe(struct + base += 0x28; + } + +- clk = clk_register_mux_table(&pdev->dev, name, aux_parents, +- ARRAY_SIZE(aux_parents), 0, base, 0, 0x3, +- 0, aux_parent_map, NULL); ++ hw = devm_clk_hw_register_mux_parent_data_table(&pdev->dev, name, aux_parents, ++ ARRAY_SIZE(aux_parents), 0, ++ base, 0, 0x3, ++ 0, aux_parent_map, NULL); + +- platform_set_drvdata(pdev, clk); +- +- return PTR_ERR_OR_ZERO(clk); +-} +- +-static int kpss_xcc_driver_remove(struct platform_device *pdev) +-{ +- clk_unregister_mux(platform_get_drvdata(pdev)); +- return 0; ++ return PTR_ERR_OR_ZERO(hw); + } + + static struct platform_driver kpss_xcc_driver = { + .probe = kpss_xcc_driver_probe, +- .remove = kpss_xcc_driver_remove, + .driver = { + .name = "kpss-xcc", + .of_match_table = kpss_xcc_match_table, diff --git a/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch b/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch new file mode 100644 index 00000000000..f853b5d2f24 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch @@ -0,0 +1,61 @@ +From aa7fd3bb6017b343585e97a909f9b7d2fe174018 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 00:53:19 +0200 +Subject: [PATCH] ARM: dts: qcom: add rpmcc missing clocks for apq/ipq8064 and + msm8660 + +Add missing rpmcc pxo and cxo clock for apq8064, ipq8064 and +msm8660 dtsi. + +Signed-off-by: Christian Marangi +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220706225321.26215-3-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-apq8064.dtsi | 2 ++ + arch/arm/boot/dts/qcom-ipq8064.dtsi | 2 ++ + arch/arm/boot/dts/qcom-msm8660.dtsi | 4 +++- + 3 files changed, 7 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-apq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-apq8064.dtsi +@@ -862,6 +862,8 @@ + rpmcc: clock-controller { + compatible = "qcom,rpmcc-apq8064", "qcom,rpmcc"; + #clock-cells = <1>; ++ clocks = <&pxo_board>, <&cxo_board>; ++ clock-names = "pxo", "cxo"; + }; + + regulators { +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1074,6 +1074,8 @@ + rpmcc: clock-controller { + compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; + #clock-cells = <1>; ++ clocks = <&pxo_board>; ++ clock-names = "pxo"; + }; + }; + +--- a/arch/arm/boot/dts/qcom-msm8660.dtsi ++++ b/arch/arm/boot/dts/qcom-msm8660.dtsi +@@ -56,7 +56,7 @@ + clock-frequency = <19200000>; + }; + +- pxo_board { ++ pxo_board: pxo_board { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; +@@ -420,6 +420,8 @@ + rpmcc: clock-controller { + compatible = "qcom,rpmcc-msm8660", "qcom,rpmcc"; + #clock-cells = <1>; ++ clocks = <&pxo_board>; ++ clock-names = "pxo"; + }; + + pm8901-regulators { diff --git a/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch b/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch new file mode 100644 index 00000000000..8481b636708 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch @@ -0,0 +1,78 @@ +From 129d9cd9c25041f8b8681fd6e8584fa47c385f3b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 7 Jul 2022 00:53:20 +0200 +Subject: [PATCH] clk: qcom: clk-rpm: convert to parent_data API + +Convert clk-rpm driver to parent_data API. +We keep the old pxo/cxo_board parent naming to keep compatibility with +old DT and we use the new pxo/cxo for new implementation where these +clock are defined in DTS. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20220706225321.26215-4-ansuelsmth@gmail.com +--- + drivers/clk/qcom/clk-rpm.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +--- a/drivers/clk/qcom/clk-rpm.c ++++ b/drivers/clk/qcom/clk-rpm.c +@@ -23,6 +23,14 @@ + #define QCOM_RPM_SCALING_ENABLE_ID 0x2 + #define QCOM_RPM_XO_MODE_ON 0x2 + ++static const struct clk_parent_data gcc_pxo[] = { ++ { .fw_name = "pxo", .name = "pxo_board" }, ++}; ++ ++static const struct clk_parent_data gcc_cxo[] = { ++ { .fw_name = "cxo", .name = "cxo_board" }, ++}; ++ + #define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ + static struct clk_rpm _platform##_##_active; \ + static struct clk_rpm _platform##_##_name = { \ +@@ -32,8 +40,8 @@ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_name, \ +- .parent_names = (const char *[]){ "pxo_board" }, \ +- .num_parents = 1, \ ++ .parent_data = gcc_pxo, \ ++ .num_parents = ARRAY_SIZE(gcc_pxo), \ + }, \ + }; \ + static struct clk_rpm _platform##_##_active = { \ +@@ -44,8 +52,8 @@ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_ops, \ + .name = #_active, \ +- .parent_names = (const char *[]){ "pxo_board" }, \ +- .num_parents = 1, \ ++ .parent_data = gcc_pxo, \ ++ .num_parents = ARRAY_SIZE(gcc_pxo), \ + }, \ + } + +@@ -56,8 +64,8 @@ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_xo_ops, \ + .name = #_name, \ +- .parent_names = (const char *[]){ "cxo_board" }, \ +- .num_parents = 1, \ ++ .parent_data = gcc_cxo, \ ++ .num_parents = ARRAY_SIZE(gcc_cxo), \ + }, \ + } + +@@ -68,8 +76,8 @@ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_fixed_ops, \ + .name = #_name, \ +- .parent_names = (const char *[]){ "pxo" }, \ +- .num_parents = 1, \ ++ .parent_data = gcc_pxo, \ ++ .num_parents = ARRAY_SIZE(gcc_pxo), \ + }, \ + } + diff --git a/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch new file mode 100644 index 00000000000..ace313663d5 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch @@ -0,0 +1,61 @@ +From 09be1a39e685d8c5edd471fd1cac9a8f8280d2de Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 8 Nov 2022 22:17:34 +0100 +Subject: [PATCH] clk: qcom: kpss-xcc: register it as clk provider + +krait-cc use this driver for the secondary mux. Register it as a clk +provider to correctly use this clk in other drivers. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com +--- + drivers/clk/qcom/kpss-xcc.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/kpss-xcc.c ++++ b/drivers/clk/qcom/kpss-xcc.c +@@ -31,13 +31,14 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_t + + static int kpss_xcc_driver_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + const struct of_device_id *id; + struct resource *res; + void __iomem *base; + struct clk_hw *hw; + const char *name; + +- id = of_match_device(kpss_xcc_match_table, &pdev->dev); ++ id = of_match_device(kpss_xcc_match_table, dev); + if (!id) + return -ENODEV; + +@@ -47,7 +48,7 @@ static int kpss_xcc_driver_probe(struct + return PTR_ERR(base); + + if (id->data) { +- if (of_property_read_string_index(pdev->dev.of_node, ++ if (of_property_read_string_index(dev->of_node, + "clock-output-names", + 0, &name)) + return -ENODEV; +@@ -57,12 +58,16 @@ static int kpss_xcc_driver_probe(struct + base += 0x28; + } + +- hw = devm_clk_hw_register_mux_parent_data_table(&pdev->dev, name, aux_parents, ++ hw = devm_clk_hw_register_mux_parent_data_table(dev, name, aux_parents, + ARRAY_SIZE(aux_parents), 0, + base, 0, 0x3, + 0, aux_parent_map, NULL); ++ if (IS_ERR(hw)) ++ return PTR_ERR(hw); + +- return PTR_ERR_OR_ZERO(hw); ++ of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get, hw); ++ ++ return 0; + } + + static struct platform_driver kpss_xcc_driver = { diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch new file mode 100644 index 00000000000..65c1fc17f21 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch @@ -0,0 +1,27 @@ +From 3198106a99e73dbc4c02bd5128cec0997c73af82 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 8 Nov 2022 22:58:27 +0100 +Subject: [PATCH 1/6] clk: qcom: krait-cc: use devm variant for clk notifier + register + +Use devm variant for clk notifier register and correctly handle free +resource on driver remove. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221108215827.30475-1-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -62,7 +62,7 @@ static int krait_notifier_register(struc + int ret = 0; + + mux->clk_nb.notifier_call = krait_notifier_cb; +- ret = clk_notifier_register(clk, &mux->clk_nb); ++ ret = devm_clk_notifier_register(dev, clk, &mux->clk_nb); + if (ret) + dev_err(dev, "failed to register clock notifier: %d\n", ret); + diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-02-clk-qcom-krait-cc-fix-wrong-parent-order-for-seconda.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-02-clk-qcom-krait-cc-fix-wrong-parent-order-for-seconda.patch new file mode 100644 index 00000000000..2dcb69399cf --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-02-clk-qcom-krait-cc-fix-wrong-parent-order-for-seconda.patch @@ -0,0 +1,46 @@ +From 8e456411abcbf899c04740b9dbb3dcefcd61c946 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 9 Nov 2022 01:56:27 +0100 +Subject: [PATCH 2/6] clk: qcom: krait-cc: fix wrong parent order for secondary + mux + +The secondary mux parent order is swapped. +This currently doesn't cause problems as the secondary mux is used for idle +clk and as a safe clk source while reprogramming the hfpll. + +Each mux have 2 or more output but he always have a safe source to +switch while reprogramming the connected pll. We use a clk notifier to +switch to the correct parent before clk core can apply the correct rate. +The parent to switch is hardcoded in the mux struct. + +For the secondary mux the safe source to use is the qsb parent as it's +the only fixed clk as the acpus_aux is a pll that can source from pxo or +from pll8. + +The hardcoded safe parent for the secondary mux is set to index 0 that +in the secondary mux map is set to 2. + +But the index 0 is actually acpu_aux in the parent list. + +Fix the swapped parents to correctly handle idle frequency and output a +sane clk_summary report. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221109005631.3189-1-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -116,8 +116,8 @@ krait_add_sec_mux(struct device *dev, in + int ret; + struct krait_mux_clk *mux; + static const char *sec_mux_list[] = { +- "acpu_aux", + "qsb", ++ "acpu_aux", + }; + struct clk_init_data init = { + .parent_names = sec_mux_list, diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-03-clk-qcom-krait-cc-also-enable-secondary-mux-and-div-.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-03-clk-qcom-krait-cc-also-enable-secondary-mux-and-div-.patch new file mode 100644 index 00000000000..6261a940d71 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-03-clk-qcom-krait-cc-also-enable-secondary-mux-and-div-.patch @@ -0,0 +1,68 @@ +From 18ae57b1e8abee6c453381470f6e18991d2901a8 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 9 Nov 2022 01:56:28 +0100 +Subject: [PATCH 3/6] clk: qcom: krait-cc: also enable secondary mux and div + clk + +clk-krait ignore any rate change if clk is not flagged as enabled. +Correctly enable the secondary mux and div clk to correctly change rate +instead of silently ignoring the request. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221109005631.3189-2-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -80,6 +80,7 @@ krait_add_div(struct device *dev, int id + }; + const char *p_names[1]; + struct clk *clk; ++ int cpu; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) +@@ -103,6 +104,17 @@ krait_add_div(struct device *dev, int id + } + + clk = devm_clk_register(dev, &div->hw); ++ if (IS_ERR(clk)) ++ goto err; ++ ++ /* clk-krait ignore any rate change if mux is not flagged as enabled */ ++ if (id < 0) ++ for_each_online_cpu(cpu) ++ clk_prepare_enable(div->hw.clk); ++ else ++ clk_prepare_enable(div->hw.clk); ++ ++err: + kfree(p_names[0]); + kfree(init.name); + +@@ -113,7 +125,7 @@ static int + krait_add_sec_mux(struct device *dev, int id, const char *s, + unsigned int offset, bool unique_aux) + { +- int ret; ++ int cpu, ret; + struct krait_mux_clk *mux; + static const char *sec_mux_list[] = { + "qsb", +@@ -165,6 +177,13 @@ krait_add_sec_mux(struct device *dev, in + if (ret) + goto unique_aux; + ++ /* clk-krait ignore any rate change if mux is not flagged as enabled */ ++ if (id < 0) ++ for_each_online_cpu(cpu) ++ clk_prepare_enable(mux->hw.clk); ++ else ++ clk_prepare_enable(mux->hw.clk); ++ + unique_aux: + if (unique_aux) + kfree(sec_mux_list[0]); diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-04-clk-qcom-krait-cc-handle-secondary-mux-sourcing-out-.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-04-clk-qcom-krait-cc-handle-secondary-mux-sourcing-out-.patch new file mode 100644 index 00000000000..fabb299f427 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-04-clk-qcom-krait-cc-handle-secondary-mux-sourcing-out-.patch @@ -0,0 +1,48 @@ +From e5dc1a4c01510da8438dddfdf4200b79d73990dc Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 9 Nov 2022 01:56:29 +0100 +Subject: [PATCH 4/6] clk: qcom: krait-cc: handle secondary mux sourcing out of + acpu_aux + +Some bootloader may leave the system in an even more undefined state +with the secondary mux of L2 or other cores sourcing out of the acpu_aux +parent. This results in the clk set to the PXO rate or a PLL8 rate. + +The current logic to reset the mux and set them to a defined state only +handle if the mux are configured to source out of QSB. Change this and +force a new and defined state if the current clk is lower than the aux +rate. This way we can handle any wrong configuration where the mux is +sourcing out of QSB (rate 225MHz, currently set to a virtual rate of 1), +PXO rate (rate 25MHz) or PLL8 (needs to be configured to run at 384Mhz). + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221109005631.3189-3-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -383,8 +383,8 @@ static int krait_cc_probe(struct platfor + */ + cur_rate = clk_get_rate(l2_pri_mux_clk); + aux_rate = 384000000; +- if (cur_rate == 1) { +- pr_info("L2 @ QSB rate. Forcing new rate.\n"); ++ if (cur_rate < aux_rate) { ++ pr_info("L2 @ Undefined rate. Forcing new rate.\n"); + cur_rate = aux_rate; + } + clk_set_rate(l2_pri_mux_clk, aux_rate); +@@ -394,8 +394,8 @@ static int krait_cc_probe(struct platfor + for_each_possible_cpu(cpu) { + clk = clks[cpu]; + cur_rate = clk_get_rate(clk); +- if (cur_rate == 1) { +- pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu); ++ if (cur_rate < aux_rate) { ++ pr_info("CPU%d @ Undefined rate. Forcing new rate.\n", cpu); + cur_rate = aux_rate; + } + diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-05-clk-qcom-krait-cc-convert-to-devm_clk_hw_register.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-05-clk-qcom-krait-cc-convert-to-devm_clk_hw_register.patch new file mode 100644 index 00000000000..049b1fa49f1 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-05-clk-qcom-krait-cc-convert-to-devm_clk_hw_register.patch @@ -0,0 +1,104 @@ +From 8ea9fb841a7e528bc8ae79d726ce951dcf7b46e2 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 9 Nov 2022 01:56:30 +0100 +Subject: [PATCH 5/6] clk: qcom: krait-cc: convert to devm_clk_hw_register + +clk_register is now deprecated. Convert the driver to devm_clk_hw_register. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221109005631.3189-4-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 31 +++++++++++++++++++------------ + 1 file changed, 19 insertions(+), 12 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -79,8 +79,7 @@ krait_add_div(struct device *dev, int id + .flags = CLK_SET_RATE_PARENT, + }; + const char *p_names[1]; +- struct clk *clk; +- int cpu; ++ int cpu, ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) +@@ -103,8 +102,8 @@ krait_add_div(struct device *dev, int id + return -ENOMEM; + } + +- clk = devm_clk_register(dev, &div->hw); +- if (IS_ERR(clk)) ++ ret = devm_clk_hw_register(dev, &div->hw); ++ if (ret) + goto err; + + /* clk-krait ignore any rate change if mux is not flagged as enabled */ +@@ -118,7 +117,7 @@ err: + kfree(p_names[0]); + kfree(init.name); + +- return PTR_ERR_OR_ZERO(clk); ++ return ret; + } + + static int +@@ -137,7 +136,6 @@ krait_add_sec_mux(struct device *dev, in + .ops = &krait_mux_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }; +- struct clk *clk; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) +@@ -166,14 +164,16 @@ krait_add_sec_mux(struct device *dev, in + if (unique_aux) { + sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s); + if (!sec_mux_list[0]) { +- clk = ERR_PTR(-ENOMEM); ++ ret = -ENOMEM; + goto err_aux; + } + } + +- clk = devm_clk_register(dev, &mux->hw); ++ ret = devm_clk_hw_register(dev, &mux->hw); ++ if (ret) ++ goto unique_aux; + +- ret = krait_notifier_register(dev, clk, mux); ++ ret = krait_notifier_register(dev, mux->hw.clk, mux); + if (ret) + goto unique_aux; + +@@ -189,7 +189,7 @@ unique_aux: + kfree(sec_mux_list[0]); + err_aux: + kfree(init.name); +- return PTR_ERR_OR_ZERO(clk); ++ return ret; + } + + static struct clk * +@@ -241,11 +241,18 @@ krait_add_pri_mux(struct device *dev, in + goto err_p2; + } + +- clk = devm_clk_register(dev, &mux->hw); ++ ret = devm_clk_hw_register(dev, &mux->hw); ++ if (ret) { ++ clk = ERR_PTR(ret); ++ goto err_p3; ++ } ++ ++ clk = mux->hw.clk; + + ret = krait_notifier_register(dev, clk, mux); + if (ret) +- goto err_p3; ++ clk = ERR_PTR(ret); ++ + err_p3: + kfree(p_names[2]); + err_p2: diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-06-clk-qcom-krait-cc-convert-to-parent_data-API.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-06-clk-qcom-krait-cc-convert-to-parent_data-API.patch new file mode 100644 index 00000000000..453a37dfc08 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-06-clk-qcom-krait-cc-convert-to-parent_data-API.patch @@ -0,0 +1,414 @@ +From 56a655e1c41a86445cf2de656649ad93424b2a63 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Wed, 9 Nov 2022 01:56:31 +0100 +Subject: [PATCH 6/6] clk: qcom: krait-cc: convert to parent_data API + +Modernize the krait-cc driver to parent-data API and refactor to drop +any use of parent_names. From Documentation all the required clocks should +be declared in DTS so fw_name can be correctly used to get the parents +for all the muxes. .name is also declared to save compatibility with old +DT. + +While at it also drop some hardcoded index and introduce an enum to make +index values more clear. + +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221109005631.3189-5-ansuelsmth@gmail.com +--- + drivers/clk/qcom/krait-cc.c | 202 ++++++++++++++++++++---------------- + 1 file changed, 112 insertions(+), 90 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -15,6 +15,16 @@ + + #include "clk-krait.h" + ++enum { ++ cpu0_mux = 0, ++ cpu1_mux, ++ cpu2_mux, ++ cpu3_mux, ++ l2_mux, ++ ++ clks_max, ++}; ++ + static unsigned int sec_mux_map[] = { + 2, + 0, +@@ -69,21 +79,23 @@ static int krait_notifier_register(struc + return ret; + } + +-static int ++static struct clk_hw * + krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) + { + struct krait_div2_clk *div; ++ static struct clk_parent_data p_data[1]; + struct clk_init_data init = { +- .num_parents = 1, ++ .num_parents = ARRAY_SIZE(p_data), + .ops = &krait_div2_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }; +- const char *p_names[1]; ++ struct clk_hw *clk; ++ char *parent_name; + int cpu, ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + div->width = 2; + div->shift = 6; +@@ -93,18 +105,25 @@ krait_add_div(struct device *dev, int id + + init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s); + if (!init.name) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + +- init.parent_names = p_names; +- p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); +- if (!p_names[0]) { +- kfree(init.name); +- return -ENOMEM; ++ init.parent_data = p_data; ++ parent_name = kasprintf(GFP_KERNEL, "hfpll%s", s); ++ if (!parent_name) { ++ clk = ERR_PTR(-ENOMEM); ++ goto err_parent_name; + } + ++ p_data[0].fw_name = parent_name; ++ p_data[0].name = parent_name; ++ + ret = devm_clk_hw_register(dev, &div->hw); +- if (ret) +- goto err; ++ if (ret) { ++ clk = ERR_PTR(ret); ++ goto err_clk; ++ } ++ ++ clk = &div->hw; + + /* clk-krait ignore any rate change if mux is not flagged as enabled */ + if (id < 0) +@@ -113,33 +132,36 @@ krait_add_div(struct device *dev, int id + else + clk_prepare_enable(div->hw.clk); + +-err: +- kfree(p_names[0]); ++err_clk: ++ kfree(parent_name); ++err_parent_name: + kfree(init.name); + +- return ret; ++ return clk; + } + +-static int ++static struct clk_hw * + krait_add_sec_mux(struct device *dev, int id, const char *s, + unsigned int offset, bool unique_aux) + { + int cpu, ret; + struct krait_mux_clk *mux; +- static const char *sec_mux_list[] = { +- "qsb", +- "acpu_aux", ++ static struct clk_parent_data sec_mux_list[2] = { ++ { .name = "qsb", .fw_name = "qsb" }, ++ {}, + }; + struct clk_init_data init = { +- .parent_names = sec_mux_list, ++ .parent_data = sec_mux_list, + .num_parents = ARRAY_SIZE(sec_mux_list), + .ops = &krait_mux_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }; ++ struct clk_hw *clk; ++ char *parent_name; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + mux->offset = offset; + mux->lpl = id >= 0; +@@ -159,23 +181,33 @@ krait_add_sec_mux(struct device *dev, in + + init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); + if (!init.name) +- return -ENOMEM; ++ return ERR_PTR(-ENOMEM); + + if (unique_aux) { +- sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s); +- if (!sec_mux_list[0]) { +- ret = -ENOMEM; ++ parent_name = kasprintf(GFP_KERNEL, "acpu%s_aux", s); ++ if (!parent_name) { ++ clk = ERR_PTR(-ENOMEM); + goto err_aux; + } ++ sec_mux_list[1].fw_name = parent_name; ++ sec_mux_list[1].name = parent_name; ++ } else { ++ sec_mux_list[1].name = "apu_aux"; + } + + ret = devm_clk_hw_register(dev, &mux->hw); +- if (ret) +- goto unique_aux; ++ if (ret) { ++ clk = ERR_PTR(ret); ++ goto err_clk; ++ } ++ ++ clk = &mux->hw; + + ret = krait_notifier_register(dev, mux->hw.clk, mux); +- if (ret) +- goto unique_aux; ++ if (ret) { ++ clk = ERR_PTR(ret); ++ goto err_clk; ++ } + + /* clk-krait ignore any rate change if mux is not flagged as enabled */ + if (id < 0) +@@ -184,28 +216,29 @@ krait_add_sec_mux(struct device *dev, in + else + clk_prepare_enable(mux->hw.clk); + +-unique_aux: ++err_clk: + if (unique_aux) +- kfree(sec_mux_list[0]); ++ kfree(parent_name); + err_aux: + kfree(init.name); +- return ret; ++ return clk; + } + +-static struct clk * +-krait_add_pri_mux(struct device *dev, int id, const char *s, +- unsigned int offset) ++static struct clk_hw * ++krait_add_pri_mux(struct device *dev, struct clk_hw *hfpll_div, struct clk_hw *sec_mux, ++ int id, const char *s, unsigned int offset) + { + int ret; + struct krait_mux_clk *mux; +- const char *p_names[3]; ++ static struct clk_parent_data p_data[3]; + struct clk_init_data init = { +- .parent_names = p_names, +- .num_parents = ARRAY_SIZE(p_names), ++ .parent_data = p_data, ++ .num_parents = ARRAY_SIZE(p_data), + .ops = &krait_mux_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }; +- struct clk *clk; ++ struct clk_hw *clk; ++ char *hfpll_name; + + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) +@@ -223,55 +256,44 @@ krait_add_pri_mux(struct device *dev, in + if (!init.name) + return ERR_PTR(-ENOMEM); + +- p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s); +- if (!p_names[0]) { ++ hfpll_name = kasprintf(GFP_KERNEL, "hfpll%s", s); ++ if (!hfpll_name) { + clk = ERR_PTR(-ENOMEM); +- goto err_p0; ++ goto err_hfpll; + } + +- p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s); +- if (!p_names[1]) { +- clk = ERR_PTR(-ENOMEM); +- goto err_p1; +- } ++ p_data[0].fw_name = hfpll_name; ++ p_data[0].name = hfpll_name; + +- p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); +- if (!p_names[2]) { +- clk = ERR_PTR(-ENOMEM); +- goto err_p2; +- } ++ p_data[1].hw = hfpll_div; ++ p_data[2].hw = sec_mux; + + ret = devm_clk_hw_register(dev, &mux->hw); + if (ret) { + clk = ERR_PTR(ret); +- goto err_p3; ++ goto err_clk; + } + +- clk = mux->hw.clk; ++ clk = &mux->hw; + +- ret = krait_notifier_register(dev, clk, mux); ++ ret = krait_notifier_register(dev, mux->hw.clk, mux); + if (ret) + clk = ERR_PTR(ret); + +-err_p3: +- kfree(p_names[2]); +-err_p2: +- kfree(p_names[1]); +-err_p1: +- kfree(p_names[0]); +-err_p0: ++err_clk: ++ kfree(hfpll_name); ++err_hfpll: + kfree(init.name); + return clk; + } + + /* id < 0 for L2, otherwise id == physical CPU number */ +-static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux) ++static struct clk_hw *krait_add_clks(struct device *dev, int id, bool unique_aux) + { +- int ret; ++ struct clk_hw *hfpll_div, *sec_mux, *pri_mux; + unsigned int offset; + void *p = NULL; + const char *s; +- struct clk *clk; + + if (id >= 0) { + offset = 0x4501 + (0x1000 * id); +@@ -283,22 +305,23 @@ static struct clk *krait_add_clks(struct + s = "_l2"; + } + +- ret = krait_add_div(dev, id, s, offset); +- if (ret) { +- clk = ERR_PTR(ret); ++ hfpll_div = krait_add_div(dev, id, s, offset); ++ if (IS_ERR(hfpll_div)) { ++ pri_mux = hfpll_div; + goto err; + } + +- ret = krait_add_sec_mux(dev, id, s, offset, unique_aux); +- if (ret) { +- clk = ERR_PTR(ret); ++ sec_mux = krait_add_sec_mux(dev, id, s, offset, unique_aux); ++ if (IS_ERR(sec_mux)) { ++ pri_mux = sec_mux; + goto err; + } + +- clk = krait_add_pri_mux(dev, id, s, offset); ++ pri_mux = krait_add_pri_mux(dev, hfpll_div, sec_mux, id, s, offset); ++ + err: + kfree(p); +- return clk; ++ return pri_mux; + } + + static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data) +@@ -306,7 +329,7 @@ static struct clk *krait_of_get(struct o + unsigned int idx = clkspec->args[0]; + struct clk **clks = data; + +- if (idx >= 5) { ++ if (idx >= clks_max) { + pr_err("%s: invalid clock index %d\n", __func__, idx); + return ERR_PTR(-EINVAL); + } +@@ -327,9 +350,8 @@ static int krait_cc_probe(struct platfor + const struct of_device_id *id; + unsigned long cur_rate, aux_rate; + int cpu; +- struct clk *clk; +- struct clk **clks; +- struct clk *l2_pri_mux_clk; ++ struct clk_hw *mux, *l2_pri_mux; ++ struct clk *clk, **clks; + + id = of_match_device(krait_cc_match_table, dev); + if (!id) +@@ -348,21 +370,21 @@ static int krait_cc_probe(struct platfor + } + + /* Krait configurations have at most 4 CPUs and one L2 */ +- clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL); ++ clks = devm_kcalloc(dev, clks_max, sizeof(*clks), GFP_KERNEL); + if (!clks) + return -ENOMEM; + + for_each_possible_cpu(cpu) { +- clk = krait_add_clks(dev, cpu, id->data); ++ mux = krait_add_clks(dev, cpu, id->data); + if (IS_ERR(clk)) + return PTR_ERR(clk); +- clks[cpu] = clk; ++ clks[cpu] = mux->clk; + } + +- l2_pri_mux_clk = krait_add_clks(dev, -1, id->data); +- if (IS_ERR(l2_pri_mux_clk)) +- return PTR_ERR(l2_pri_mux_clk); +- clks[4] = l2_pri_mux_clk; ++ l2_pri_mux = krait_add_clks(dev, -1, id->data); ++ if (IS_ERR(l2_pri_mux)) ++ return PTR_ERR(l2_pri_mux); ++ clks[l2_mux] = l2_pri_mux->clk; + + /* + * We don't want the CPU or L2 clocks to be turned off at late init +@@ -372,7 +394,7 @@ static int krait_cc_probe(struct platfor + * they take over. + */ + for_each_online_cpu(cpu) { +- clk_prepare_enable(l2_pri_mux_clk); ++ clk_prepare_enable(clks[l2_mux]); + WARN(clk_prepare_enable(clks[cpu]), + "Unable to turn on CPU%d clock", cpu); + } +@@ -388,16 +410,16 @@ static int krait_cc_probe(struct platfor + * two different rates to force a HFPLL reinit under all + * circumstances. + */ +- cur_rate = clk_get_rate(l2_pri_mux_clk); ++ cur_rate = clk_get_rate(clks[l2_mux]); + aux_rate = 384000000; + if (cur_rate < aux_rate) { + pr_info("L2 @ Undefined rate. Forcing new rate.\n"); + cur_rate = aux_rate; + } +- clk_set_rate(l2_pri_mux_clk, aux_rate); +- clk_set_rate(l2_pri_mux_clk, 2); +- clk_set_rate(l2_pri_mux_clk, cur_rate); +- pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000); ++ clk_set_rate(clks[l2_mux], aux_rate); ++ clk_set_rate(clks[l2_mux], 2); ++ clk_set_rate(clks[l2_mux], cur_rate); ++ pr_info("L2 @ %lu KHz\n", clk_get_rate(clks[l2_mux]) / 1000); + for_each_possible_cpu(cpu) { + clk = clks[cpu]; + cur_rate = clk_get_rate(clk); diff --git a/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch new file mode 100644 index 00000000000..c30c245d0a5 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch @@ -0,0 +1,47 @@ +From 666c1b745e93ccddde841d5057c33f97b29a316a Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 15 Sep 2022 02:19:28 +0200 +Subject: [PATCH 3/9] clk: qcom: krait-cc: handle qsb clock defined in DTS + +qsb fixed clk may be defined in DTS and correctly passed in the clocks +list. Add related code to handle this and modify the logic to +dynamically read qsb clock frequency. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/krait-cc.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -348,7 +348,7 @@ static int krait_cc_probe(struct platfor + { + struct device *dev = &pdev->dev; + const struct of_device_id *id; +- unsigned long cur_rate, aux_rate; ++ unsigned long cur_rate, aux_rate, qsb_rate; + int cpu; + struct clk_hw *mux, *l2_pri_mux; + struct clk *clk, **clks; +@@ -357,11 +357,19 @@ static int krait_cc_probe(struct platfor + if (!id) + return -ENODEV; + +- /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */ +- clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1); ++ /* ++ * Per Documentation qsb should be provided from DTS. ++ * To address old implementation, register the fixed clock anyway. ++ * Rate is 1 because 0 causes problems for __clk_mux_determine_rate ++ */ ++ clk = clk_get(dev, "qsb"); ++ if (IS_ERR(clk)) ++ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1); + if (IS_ERR(clk)) + return PTR_ERR(clk); + ++ qsb_rate = clk_get_rate(clk); ++ + if (!id->data) { + clk = clk_register_fixed_factor(dev, "acpu_aux", + "gpll0_vote", 0, 1, 2); diff --git a/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch new file mode 100644 index 00000000000..e2f78f79fb1 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch @@ -0,0 +1,36 @@ +From fca6f185a9d9ef0892a719bc6da955b22d326ec7 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 15 Sep 2022 02:24:33 +0200 +Subject: [PATCH 4/9] clk: qcom: krait-cc: register REAL qsb fixed clock + +With some tools it was discovered the real frequency of the qsb fixed +clock. While not 100% correct it's still better than using 1 as a dummy +frequency. +Correctly register the qsb fixed clock with the frequency of 225 MHz +instead of 1. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/krait-cc.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -25,6 +25,8 @@ enum { + clks_max, + }; + ++#define QSB_RATE 2250000000 ++ + static unsigned int sec_mux_map[] = { + 2, + 0, +@@ -364,7 +366,7 @@ static int krait_cc_probe(struct platfor + */ + clk = clk_get(dev, "qsb"); + if (IS_ERR(clk)) +- clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1); ++ clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, QSB_RATE); + if (IS_ERR(clk)) + return PTR_ERR(clk); + diff --git a/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch new file mode 100644 index 00000000000..d95a63fc44f --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch @@ -0,0 +1,44 @@ +From 2399d181557d94ae9a2686926cd25768f132e4b4 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 18 Mar 2022 16:12:14 +0100 +Subject: [PATCH 7/9] clk: qcom: krait-cc: drop pr_info and use dev_info + +Replace pr_info() with dev_info() to provide better diagnostics. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/krait-cc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -423,25 +423,25 @@ static int krait_cc_probe(struct platfor + cur_rate = clk_get_rate(clks[l2_mux]); + aux_rate = 384000000; + if (cur_rate < aux_rate) { +- pr_info("L2 @ Undefined rate. Forcing new rate.\n"); ++ dev_info(dev, "L2 @ Undefined rate. Forcing new rate.\n"); + cur_rate = aux_rate; + } + clk_set_rate(clks[l2_mux], aux_rate); + clk_set_rate(clks[l2_mux], 2); + clk_set_rate(clks[l2_mux], cur_rate); +- pr_info("L2 @ %lu KHz\n", clk_get_rate(clks[l2_mux]) / 1000); ++ dev_info(dev, "L2 @ %lu KHz\n", clk_get_rate(clks[l2_mux]) / 1000); + for_each_possible_cpu(cpu) { + clk = clks[cpu]; + cur_rate = clk_get_rate(clk); + if (cur_rate < aux_rate) { +- pr_info("CPU%d @ Undefined rate. Forcing new rate.\n", cpu); ++ dev_info(dev, "CPU%d @ Undefined rate. Forcing new rate.\n", cpu); + cur_rate = aux_rate; + } + + clk_set_rate(clk, aux_rate); + clk_set_rate(clk, 2); + clk_set_rate(clk, cur_rate); +- pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000); ++ dev_info(dev, "CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000); + } + + of_clk_add_provider(dev->of_node, krait_of_get, clks); diff --git a/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch new file mode 100644 index 00000000000..8f88e069912 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch @@ -0,0 +1,88 @@ +From 6a77cf3f5f95ec0058e1b4d1ada018748cb0b83b Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Thu, 15 Sep 2022 03:33:13 +0200 +Subject: [PATCH 9/9] clk: qcom: krait-cc: rework mux reset logic and reset + hfpll + +Rework and clean mux reset logic. +Compact it to a for loop to handle both CPU and L2 in one place. +Move hardcoded aux_rate to define and add a new hfpll_rate value to +reset hfpll settings. +Change logic to now reset the hfpll to the lowest value of 600 Mhz and +then restoring the previous frequency. This permits to reset the hfpll if +the primary mux was set to source out of the secondary mux. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/krait-cc.c | 50 +++++++++++++++++-------------------- + 1 file changed, 23 insertions(+), 27 deletions(-) + +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -25,7 +25,9 @@ enum { + clks_max, + }; + +-#define QSB_RATE 2250000000 ++#define QSB_RATE 225000000 ++#define AUX_RATE 384000000 ++#define HFPLL_RATE 600000000 + + static unsigned int sec_mux_map[] = { + 2, +@@ -350,7 +352,7 @@ static int krait_cc_probe(struct platfor + { + struct device *dev = &pdev->dev; + const struct of_device_id *id; +- unsigned long cur_rate, aux_rate, qsb_rate; ++ unsigned long cur_rate, qsb_rate; + int cpu; + struct clk_hw *mux, *l2_pri_mux; + struct clk *clk, **clks; +@@ -420,28 +422,29 @@ static int krait_cc_probe(struct platfor + * two different rates to force a HFPLL reinit under all + * circumstances. + */ +- cur_rate = clk_get_rate(clks[l2_mux]); +- aux_rate = 384000000; +- if (cur_rate < aux_rate) { +- dev_info(dev, "L2 @ Undefined rate. Forcing new rate.\n"); +- cur_rate = aux_rate; +- } +- clk_set_rate(clks[l2_mux], aux_rate); +- clk_set_rate(clks[l2_mux], 2); +- clk_set_rate(clks[l2_mux], cur_rate); +- dev_info(dev, "L2 @ %lu KHz\n", clk_get_rate(clks[l2_mux]) / 1000); +- for_each_possible_cpu(cpu) { ++ for (cpu = 0; cpu < 5; cpu++) { ++ const char *l2_s = "L2"; ++ char cpu_s[5]; ++ + clk = clks[cpu]; ++ if (!clk) ++ continue; ++ ++ if (cpu < 4) ++ snprintf(cpu_s, 5, "CPU%d", cpu); ++ + cur_rate = clk_get_rate(clk); +- if (cur_rate < aux_rate) { +- dev_info(dev, "CPU%d @ Undefined rate. Forcing new rate.\n", cpu); +- cur_rate = aux_rate; ++ if (cur_rate < AUX_RATE) { ++ dev_info(dev, "%s @ Undefined rate. Forcing new rate.\n", ++ cpu < 4 ? cpu_s : l2_s); ++ cur_rate = AUX_RATE; + } + +- clk_set_rate(clk, aux_rate); +- clk_set_rate(clk, 2); ++ clk_set_rate(clk, AUX_RATE); ++ clk_set_rate(clk, HFPLL_RATE); + clk_set_rate(clk, cur_rate); +- dev_info(dev, "CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000); ++ dev_info(dev, "%s @ %lu KHz\n", cpu < 4 ? cpu_s : l2_s, ++ clk_get_rate(clk) / 1000); + } + + of_clk_add_provider(dev->of_node, krait_of_get, clks); diff --git a/target/linux/ipq806x/patches-6.1/122-05-clk-qcom-clk-krait-generilize-div-functions.patch b/target/linux/ipq806x/patches-6.1/122-05-clk-qcom-clk-krait-generilize-div-functions.patch new file mode 100644 index 00000000000..a7c0f046c84 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/122-05-clk-qcom-clk-krait-generilize-div-functions.patch @@ -0,0 +1,156 @@ +From 908c361b3c3a139eb3e6a798cb620a6da7514d5c Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 23 Sep 2022 19:05:39 +0200 +Subject: [PATCH 2/4] clk: qcom: clk-krait: generilize div functions + +Generilize div functions and remove hardcode to a divisor of 2. +This is just a cleanup and permit to make it more clear the settings of +the devisor when used by the krait-cc driver. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/clk-krait.c | 57 ++++++++++++++++++++---------------- + drivers/clk/qcom/clk-krait.h | 11 ++++--- + drivers/clk/qcom/krait-cc.c | 7 +++-- + 3 files changed, 42 insertions(+), 33 deletions(-) + +--- a/drivers/clk/qcom/clk-krait.c ++++ b/drivers/clk/qcom/clk-krait.c +@@ -97,53 +97,58 @@ const struct clk_ops krait_mux_clk_ops = + EXPORT_SYMBOL_GPL(krait_mux_clk_ops); + + /* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */ +-static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate, ++static long krait_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +- *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2); +- return DIV_ROUND_UP(*parent_rate, 2); ++ struct krait_div_clk *d = to_krait_div_clk(hw); ++ ++ *parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), ++ rate * d->divisor); ++ ++ return DIV_ROUND_UP(*parent_rate, d->divisor); + } + +-static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate, ++static int krait_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) + { +- struct krait_div2_clk *d = to_krait_div2_clk(hw); ++ struct krait_div_clk *d = to_krait_div_clk(hw); ++ u8 div_val = krait_div_to_val(d->divisor); + unsigned long flags; +- u32 val; +- u32 mask = BIT(d->width) - 1; +- +- if (d->lpl) +- mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift; +- else +- mask <<= d->shift; ++ u32 regval; + + spin_lock_irqsave(&krait_clock_reg_lock, flags); +- val = krait_get_l2_indirect_reg(d->offset); +- val &= ~mask; +- krait_set_l2_indirect_reg(d->offset, val); ++ regval = krait_get_l2_indirect_reg(d->offset); ++ ++ regval &= ~(d->mask << d->shift); ++ regval |= (div_val & d->mask) << d->shift; ++ ++ if (d->lpl) { ++ regval &= ~(d->mask << (d->shift + LPL_SHIFT)); ++ regval |= (div_val & d->mask) << (d->shift + LPL_SHIFT); ++ } ++ ++ krait_set_l2_indirect_reg(d->offset, regval); + spin_unlock_irqrestore(&krait_clock_reg_lock, flags); + + return 0; + } + + static unsigned long +-krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) ++krait_div_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) + { +- struct krait_div2_clk *d = to_krait_div2_clk(hw); +- u32 mask = BIT(d->width) - 1; ++ struct krait_div_clk *d = to_krait_div_clk(hw); + u32 div; + + div = krait_get_l2_indirect_reg(d->offset); + div >>= d->shift; +- div &= mask; +- div = (div + 1) * 2; ++ div &= d->mask; + +- return DIV_ROUND_UP(parent_rate, div); ++ return DIV_ROUND_UP(parent_rate, krait_val_to_div(div)); + } + +-const struct clk_ops krait_div2_clk_ops = { +- .round_rate = krait_div2_round_rate, +- .set_rate = krait_div2_set_rate, +- .recalc_rate = krait_div2_recalc_rate, ++const struct clk_ops krait_div_clk_ops = { ++ .round_rate = krait_div_round_rate, ++ .set_rate = krait_div_set_rate, ++ .recalc_rate = krait_div_recalc_rate, + }; +-EXPORT_SYMBOL_GPL(krait_div2_clk_ops); ++EXPORT_SYMBOL_GPL(krait_div_clk_ops); +--- a/drivers/clk/qcom/clk-krait.h ++++ b/drivers/clk/qcom/clk-krait.h +@@ -25,17 +25,20 @@ struct krait_mux_clk { + + extern const struct clk_ops krait_mux_clk_ops; + +-struct krait_div2_clk { ++struct krait_div_clk { + u32 offset; +- u8 width; ++ u32 mask; ++ u8 divisor; + u32 shift; + bool lpl; + + struct clk_hw hw; + }; + +-#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw) ++#define to_krait_div_clk(_hw) container_of(_hw, struct krait_div_clk, hw) ++#define krait_div_to_val(_div) ((_div) / 2) - 1 ++#define krait_val_to_div(_val) ((_val) + 1) * 2 + +-extern const struct clk_ops krait_div2_clk_ops; ++extern const struct clk_ops krait_div_clk_ops; + + #endif +--- a/drivers/clk/qcom/krait-cc.c ++++ b/drivers/clk/qcom/krait-cc.c +@@ -86,11 +86,11 @@ static int krait_notifier_register(struc + static struct clk_hw * + krait_add_div(struct device *dev, int id, const char *s, unsigned int offset) + { +- struct krait_div2_clk *div; ++ struct krait_div_clk *div; + static struct clk_parent_data p_data[1]; + struct clk_init_data init = { + .num_parents = ARRAY_SIZE(p_data), +- .ops = &krait_div2_clk_ops, ++ .ops = &krait_div_clk_ops, + .flags = CLK_SET_RATE_PARENT, + }; + struct clk_hw *clk; +@@ -101,7 +101,8 @@ krait_add_div(struct device *dev, int id + if (!div) + return ERR_PTR(-ENOMEM); + +- div->width = 2; ++ div->mask = 0x3; ++ div->divisor = 2; + div->shift = 6; + div->lpl = id >= 0; + div->offset = offset; diff --git a/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch b/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch new file mode 100644 index 00000000000..20e7440ace8 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch @@ -0,0 +1,31 @@ +From ac84ac819a2e8fd3d87122b452c502a386c54437 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 5 Jul 2022 18:30:18 +0200 +Subject: [PATCH v2 4/4] clk: qcom: gcc-ipq806x: remove cc_register_board for + pxo and cxo + +Now that these clock are defined as fixed clk in dts, we can drop the +register_board_clk for cxo_board and pxo_board in gcc_ipq806x_probe. + +Signed-off-by: Christian Marangi +--- + drivers/clk/qcom/gcc-ipq806x.c | 8 -------- + 1 file changed, 8 deletions(-) + +--- a/drivers/clk/qcom/gcc-ipq806x.c ++++ b/drivers/clk/qcom/gcc-ipq806x.c +@@ -3384,14 +3384,6 @@ static int gcc_ipq806x_probe(struct plat + struct regmap *regmap; + int ret; + +- ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 25000000); +- if (ret) +- return ret; +- +- ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 25000000); +- if (ret) +- return ret; +- + if (of_machine_is_compatible("qcom,ipq8065")) { + ubi32_core1_src_clk.freq_tbl = clk_tbl_nss_ipq8065; + ubi32_core2_src_clk.freq_tbl = clk_tbl_nss_ipq8065; diff --git a/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch b/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch new file mode 100644 index 00000000000..2e7e6833bb8 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch @@ -0,0 +1,55 @@ +From 7df140e84a75c89962feef659d686303d3ce75e5 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Fri, 21 Oct 2022 18:53:04 +0200 +Subject: [PATCH] mtd: rawnand: qcom: handle ret from parse with codeword_fixup + +With use_codeword_fixup enabled, any return from +mtd_device_parse_register gets overwritten. Aside from the clear bug, this +is also problematic as a parser can EPROBE_DEFER and because this is not +correctly handled, the nand is never rescanned later in the bootup +process. + +An example of this problem is when smem requires additional time to be +probed and nandc use qcomsmempart as parser. Parser will return +EPROBE_DEFER but in the current code this ret gets overwritten by +qcom_nand_host_parse_boot_partitions and qcom_nand_host_init_and_register +return 0. + +Correctly handle the return code from mtd_device_parse_register so that +any error from this function is not ignored. + +Fixes: 862bdedd7f4b ("mtd: nand: raw: qcom_nandc: add support for unprotected spare data pages") +Cc: stable@vger.kernel.org # v6.0+ +Signed-off-by: Christian Marangi +Signed-off-by: Miquel Raynal +Link: https://lore.kernel.org/linux-mtd/20221021165304.19991-1-ansuelsmth@gmail.com +--- + drivers/mtd/nand/raw/qcom_nandc.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +--- a/drivers/mtd/nand/raw/qcom_nandc.c ++++ b/drivers/mtd/nand/raw/qcom_nandc.c +@@ -3157,16 +3157,18 @@ static int qcom_nand_host_init_and_regis + + ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0); + if (ret) +- nand_cleanup(chip); ++ goto err; + + if (nandc->props->use_codeword_fixup) { + ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn); +- if (ret) { +- nand_cleanup(chip); +- return ret; +- } ++ if (ret) ++ goto err; + } + ++ return 0; ++ ++err: ++ nand_cleanup(chip); + return ret; + } + diff --git a/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch b/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch new file mode 100644 index 00000000000..8493f380fe0 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch @@ -0,0 +1,28 @@ +From c9713e4ede1e5d044b64fe4d3cbb84223625637f Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 25 Oct 2022 01:38:17 +0200 +Subject: [PATCH] ARM: dts: qcom: ipq8064: disable mmc-ddr-1_8v for sdcc1 + +It was reported non working mmc with this option enabled. +Both mmc for ipq8064 are supplied by a fixed 3.3v regulator so mmc can't +be run at 1.8v. +Disable it to restore correct functionality of this SoC feature. + +Tested-by: Hendrik Koerner +Signed-off-by: Christian Marangi +Signed-off-by: Bjorn Andersson +Link: https://lore.kernel.org/r/20221024233817.27410-1-ansuelsmth@gmail.com +--- + arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 - + 1 file changed, 1 deletion(-) + +--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi ++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi +@@ -1529,7 +1529,6 @@ + non-removable; + cap-sd-highspeed; + cap-mmc-highspeed; +- mmc-ddr-1_8v; + vmmc-supply = <&vsdcc_fixed>; + dmas = <&sdcc1bam 2>, <&sdcc1bam 1>; + dma-names = "tx", "rx"; diff --git a/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch new file mode 100644 index 00000000000..0d983410ec1 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch @@ -0,0 +1,121 @@ +From: Christian Lamparter +Subject: SoC: add qualcomm syscon +--- a/drivers/soc/qcom/Makefile ++++ b/drivers/soc/qcom/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o + obj-$(CONFIG_QCOM_SMSM) += smsm.o + obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o + obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o ++obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o + obj-$(CONFIG_QCOM_APR) += apr.o + obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o + obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o +--- a/drivers/soc/qcom/Kconfig ++++ b/drivers/soc/qcom/Kconfig +@@ -192,6 +192,13 @@ config QCOM_SOCINFO + Say yes here to support the Qualcomm socinfo driver, providing + information about the SoC to user space. + ++config QCOM_TCSR ++ tristate "QCOM Top Control and Status Registers" ++ depends on ARCH_QCOM ++ help ++ Say y here to enable TCSR support. The TCSR provides control ++ functions for various peripherals. ++ + config QCOM_WCNSS_CTRL + tristate "Qualcomm WCNSS control driver" + depends on ARCH_QCOM || COMPILE_TEST +--- /dev/null ++++ b/drivers/soc/qcom/qcom_tcsr.c +@@ -0,0 +1,64 @@ ++/* ++ * Copyright (c) 2014, The Linux foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License rev 2 and ++ * only rev 2 as published by the free Software foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define TCSR_USB_PORT_SEL 0xb0 ++ ++static int tcsr_probe(struct platform_device *pdev) ++{ ++ struct resource *res; ++ const struct device_node *node = pdev->dev.of_node; ++ void __iomem *base; ++ u32 val; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) { ++ dev_err(&pdev->dev, "setting usb port select = %d\n", val); ++ writel(val, base + TCSR_USB_PORT_SEL); ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id tcsr_dt_match[] = { ++ { .compatible = "qcom,tcsr", }, ++ { }, ++}; ++ ++MODULE_DEVICE_TABLE(of, tcsr_dt_match); ++ ++static struct platform_driver tcsr_driver = { ++ .driver = { ++ .name = "tcsr", ++ .owner = THIS_MODULE, ++ .of_match_table = tcsr_dt_match, ++ }, ++ .probe = tcsr_probe, ++}; ++ ++module_platform_driver(tcsr_driver); ++ ++MODULE_AUTHOR("Andy Gross "); ++MODULE_DESCRIPTION("QCOM TCSR driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/include/dt-bindings/soc/qcom,tcsr.h +@@ -0,0 +1,23 @@ ++/* Copyright (c) 2014, The Linux Foundation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#ifndef __DT_BINDINGS_QCOM_TCSR_H ++#define __DT_BINDINGS_QCOM_TCSR_H ++ ++#define TCSR_USB_SELECT_USB3_P0 0x1 ++#define TCSR_USB_SELECT_USB3_P1 0x2 ++#define TCSR_USB_SELECT_USB3_DUAL 0x3 ++ ++/* TCSR A/B REG */ ++#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL 0 ++#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL 1 ++ ++#endif diff --git a/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch new file mode 100644 index 00000000000..23cec10f445 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch @@ -0,0 +1,37 @@ +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -1740,6 +1740,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL + + endchoice + ++config CMDLINE_OVERRIDE ++ bool "Use alternative cmdline from device tree" ++ help ++ Some bootloaders may have uneditable bootargs. While CMDLINE_FORCE can ++ be used, this is not a good option for kernels that are shared across ++ devices. This setting enables using "chosen/cmdline-override" as the ++ cmdline if it exists in the device tree. ++ + config CMDLINE + string "Default kernel command string" + default "" +--- a/drivers/of/fdt.c ++++ b/drivers/of/fdt.c +@@ -1162,6 +1162,17 @@ int __init early_init_dt_scan_chosen(uns + if (p != NULL && l > 0) + strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + ++ /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different ++ * device tree option of chosen/bootargs-override. This is ++ * helpful on boards where u-boot sets bootargs, and is unable ++ * to be modified. ++ */ ++#ifdef CONFIG_CMDLINE_OVERRIDE ++ p = of_get_flat_dt_prop(node, "bootargs-override", &l); ++ if (p != NULL && l > 0) ++ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++#endif ++ + /* + * CONFIG_CMDLINE is meant to be a default in case nothing else + * managed to set the command line, unless CONFIG_CMDLINE_FORCE From d06b859ada9bb50889338f42d9e6bda0c89768a1 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:48:45 +0200 Subject: [PATCH 82/88] ipq806x: 6.1: drop upstream patch Drop patch that got merged upstream. Signed-off-by: Christian Marangi --- ...806x-fix-wrong-naming-for-gcc_pxo_pl.patch | 109 --- ...806x-convert-parent_names-to-parent_.patch | 921 ------------------ ...q806x-use-ARRAY_SIZE-for-num_parents.patch | 325 ------ ...pq806x-add-additional-freq-nss-cores.patch | 88 -- ...806x-add-unusued-flag-for-critical-c.patch | 65 -- ...om-clk-rcg-add-clk_rcg_floor_ops-ops.patch | 69 -- ...806x-add-additional-freq-for-sdc-tab.patch | 38 - ...ngs-clock-add-ipq8064-ce5-clk-define.patch | 39 - ...-gcc-ipq806x-add-CryptoEngine-clocks.patch | 304 ------ ...indings-reset-add-ipq8064-ce5-resets.patch | 29 - ...-gcc-ipq806x-add-CryptoEngine-resets.patch | 30 - ...mac-add-missing-sgmii-configure-for-.patch | 151 --- ...mac-reset-force-speed-bit-for-ipq806.patch | 110 --- ...-syscon-and-cxo-pxo-clock-to-gcc-nod.patch | 48 - ...lace-gcc-PXO-with-pxo_board-fixed-cl.patch | 29 - ...8064-add-multiple-missing-pin-defini.patch | 101 -- ...ipq8064-add-gsbi6-missing-definition.patch | 67 -- ...8064-add-specific-dtsi-with-smb208-r.patch | 66 -- ...8064-add-missing-snps-dwmac-compatib.patch | 56 -- ...m-ipq8064-disable-usb-phy-by-default.patch | 37 - ...8064-fix-and-add-some-missing-gsbi-n.patch | 94 -- ...pq8064-add-speedbin-efuse-nvmem-node.patch | 28 - ...Add-support-for-mmio-usage-to-sfpb-m.patch | 71 -- ...-dts-qcom-ipq8064-add-missing-hwlock.patch | 31 - ...-ipq8064-add-missing-smem-compatible.patch | 30 - ...dts-qcom-ipq8064-add-v2-dtsi-variant.patch | 129 --- ...dts-qcom-ipq8064-add-ipq8062-variant.patch | 67 -- ...dts-qcom-ipq8064-add-ipq8065-variant.patch | 67 -- ...-clock-add-pcm-reset-for-ipq806x-lcc.patch | 29 - ...com-lcc-ipq806x-add-reset-definition.patch | 48 - ...m-lcc-ipq806x-convert-to-parent-data.patch | 217 ----- ...t-devfreq_get_freq_range-symbol-with.patch | 113 --- ...pu-based-scaling-support-to-passive-.patch | 461 --------- ...ve-Reduce-duplicate-code-when-passiv.patch | 110 --- ...ve-Keep-cpufreq_policy-for-possible-.patch | 232 ----- ...ve-Return-non-error-when-not-support.patch | 31 - ...ernel-warning-with-cpufreq-passive-r.patch | 31 - ...x-cpufreq-passive-unregister-errorin.patch | 85 -- ...ernel-panic-with-cpu-based-scaling-t.patch | 34 - ...work-freq_table-to-be-local-to-devfr.patch | 269 ----- ...Mute-warning-on-governor-PROBE_DEFER.patch | 28 - ...m_nandc-reorder-qcom_nand_host-struc.patch | 268 ----- ...m_nandc-add-support-for-unprotected-.patch | 406 -------- ...com-clk-hfpll-use-poll_timeout-macro.patch | 41 - ...it-add-apq-ipq8064-errata-workaround.patch | 86 -- ...vm_-hw_register_mux_parent_data_tabl.patch | 46 - ...-kpss-xcc-convert-to-parent-data-API.patch | 70 -- ...-rpmcc-missing-clocks-for-apq-ipq806.patch | 61 -- ...m-clk-rpm-convert-to-parent_data-API.patch | 78 -- ...-handle-ret-from-parse-with-codeword.patch | 55 -- 50 files changed, 5998 deletions(-) delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch delete mode 100644 target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch delete mode 100644 target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch delete mode 100644 target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch delete mode 100644 target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch delete mode 100644 target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch delete mode 100644 target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch delete mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch delete mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch delete mode 100644 target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch delete mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch delete mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch delete mode 100644 target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch delete mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch delete mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch delete mode 100644 target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch delete mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch delete mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch delete mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch delete mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch delete mode 100644 target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch delete mode 100644 target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch delete mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch delete mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch delete mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch delete mode 100644 target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch delete mode 100644 target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch delete mode 100644 target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch delete mode 100644 target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch delete mode 100644 target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch delete mode 100644 target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch delete mode 100644 target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch delete mode 100644 target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch delete mode 100644 target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch delete mode 100644 target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch deleted file mode 100644 index f3f3ea30da8..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-04-linux-next-clk-qcom-gcc-ipq806x-fix-wrong-naming-for-gcc_pxo_pl.patch +++ /dev/null @@ -1,109 +0,0 @@ -From e95e825333eda345d812b461301dad50021d5487 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:24 +0100 -Subject: [PATCH 04/14] clk: qcom: gcc-ipq806x: fix wrong naming for - gcc_pxo_pll8_pll0 - -Parent gcc_pxo_pll8_pll0 had the parent definition and parent map -swapped. Fix this naming error. - -Signed-off-by: Ansuel Smith -Reviewed-by: Bjorn Andersson -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-5-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 20 ++++++++++---------- - 1 file changed, 10 insertions(+), 10 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -291,13 +291,13 @@ static const char * const gcc_pxo_pll3[] - "pll3", - }; - --static const struct parent_map gcc_pxo_pll8_pll0[] = { -+static const struct parent_map gcc_pxo_pll8_pll0_map[] = { - { P_PXO, 0 }, - { P_PLL8, 3 }, - { P_PLL0, 2 } - }; - --static const char * const gcc_pxo_pll8_pll0_map[] = { -+static const char * const gcc_pxo_pll8_pll0[] = { - "pxo", - "pll8_vote", - "pll0_vote", -@@ -1993,7 +1993,7 @@ static struct clk_rcg usb30_master_clk_s - }, - .s = { - .src_sel_shift = 0, -- .parent_map = gcc_pxo_pll8_pll0, -+ .parent_map = gcc_pxo_pll8_pll0_map, - }, - .freq_tbl = clk_tbl_usb30_master, - .clkr = { -@@ -2001,7 +2001,7 @@ static struct clk_rcg usb30_master_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb30_master_ref_src", -- .parent_names = gcc_pxo_pll8_pll0_map, -+ .parent_names = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2063,7 +2063,7 @@ static struct clk_rcg usb30_utmi_clk = { - }, - .s = { - .src_sel_shift = 0, -- .parent_map = gcc_pxo_pll8_pll0, -+ .parent_map = gcc_pxo_pll8_pll0_map, - }, - .freq_tbl = clk_tbl_usb30_utmi, - .clkr = { -@@ -2071,7 +2071,7 @@ static struct clk_rcg usb30_utmi_clk = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb30_utmi_clk", -- .parent_names = gcc_pxo_pll8_pll0_map, -+ .parent_names = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2133,7 +2133,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s - }, - .s = { - .src_sel_shift = 0, -- .parent_map = gcc_pxo_pll8_pll0, -+ .parent_map = gcc_pxo_pll8_pll0_map, - }, - .freq_tbl = clk_tbl_usb, - .clkr = { -@@ -2141,7 +2141,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb_hs1_xcvr_src", -- .parent_names = gcc_pxo_pll8_pll0_map, -+ .parent_names = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2197,7 +2197,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s - }, - .s = { - .src_sel_shift = 0, -- .parent_map = gcc_pxo_pll8_pll0, -+ .parent_map = gcc_pxo_pll8_pll0_map, - }, - .freq_tbl = clk_tbl_usb, - .clkr = { -@@ -2205,7 +2205,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb_fs1_xcvr_src", -- .parent_names = gcc_pxo_pll8_pll0_map, -+ .parent_names = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch deleted file mode 100644 index d99ac9992f3..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-05-linux-next-clk-qcom-gcc-ipq806x-convert-parent_names-to-parent_.patch +++ /dev/null @@ -1,921 +0,0 @@ -From cb02866f9a740fb9fb8ff19698a69290da4057e5 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:25 +0100 -Subject: [PATCH 05/14] clk: qcom: gcc-ipq806x: convert parent_names to - parent_data - -Convert parent_names to parent_data to modernize the driver. -Where possible use parent_hws directly. - -Signed-off-by: Ansuel Smith -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-6-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 286 ++++++++++++++++++++------------- - 1 file changed, 173 insertions(+), 113 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -25,6 +25,10 @@ - #include "clk-hfpll.h" - #include "reset.h" - -+static const struct clk_parent_data gcc_pxo[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+}; -+ - static struct clk_pll pll0 = { - .l_reg = 0x30c4, - .m_reg = 0x30c8, -@@ -35,7 +39,7 @@ static struct clk_pll pll0 = { - .status_bit = 16, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll0", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -46,7 +50,9 @@ static struct clk_regmap pll0_vote = { - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "pll0_vote", -- .parent_names = (const char *[]){ "pll0" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pll0.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_pll_vote_ops, - }, -@@ -62,7 +68,7 @@ static struct clk_pll pll3 = { - .status_bit = 16, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll3", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -89,7 +95,7 @@ static struct clk_pll pll8 = { - .status_bit = 16, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll8", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -100,7 +106,9 @@ static struct clk_regmap pll8_vote = { - .enable_mask = BIT(8), - .hw.init = &(struct clk_init_data){ - .name = "pll8_vote", -- .parent_names = (const char *[]){ "pll8" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pll8.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_pll_vote_ops, - }, -@@ -123,7 +131,7 @@ static struct hfpll_data hfpll0_data = { - static struct clk_hfpll hfpll0 = { - .d = &hfpll0_data, - .clkr.hw.init = &(struct clk_init_data){ -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .name = "hfpll0", - .ops = &clk_ops_hfpll, -@@ -149,7 +157,7 @@ static struct hfpll_data hfpll1_data = { - static struct clk_hfpll hfpll1 = { - .d = &hfpll1_data, - .clkr.hw.init = &(struct clk_init_data){ -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .name = "hfpll1", - .ops = &clk_ops_hfpll, -@@ -175,7 +183,7 @@ static struct hfpll_data hfpll_l2_data = - static struct clk_hfpll hfpll_l2 = { - .d = &hfpll_l2_data, - .clkr.hw.init = &(struct clk_init_data){ -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .name = "hfpll_l2", - .ops = &clk_ops_hfpll, -@@ -194,7 +202,7 @@ static struct clk_pll pll14 = { - .status_bit = 16, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll14", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -205,7 +213,9 @@ static struct clk_regmap pll14_vote = { - .enable_mask = BIT(14), - .hw.init = &(struct clk_init_data){ - .name = "pll14_vote", -- .parent_names = (const char *[]){ "pll14" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pll14.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_pll_vote_ops, - }, -@@ -238,7 +248,7 @@ static struct clk_pll pll18 = { - .freq_tbl = pll18_freq_tbl, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll18", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -259,9 +269,9 @@ static const struct parent_map gcc_pxo_p - { P_PLL8, 3 } - }; - --static const char * const gcc_pxo_pll8[] = { -- "pxo", -- "pll8_vote", -+static const struct clk_parent_data gcc_pxo_pll8[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .hw = &pll8_vote.hw }, - }; - - static const struct parent_map gcc_pxo_pll8_cxo_map[] = { -@@ -270,10 +280,10 @@ static const struct parent_map gcc_pxo_p - { P_CXO, 5 } - }; - --static const char * const gcc_pxo_pll8_cxo[] = { -- "pxo", -- "pll8_vote", -- "cxo", -+static const struct clk_parent_data gcc_pxo_pll8_cxo[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .hw = &pll8_vote.hw }, -+ { .fw_name = "cxo", .name = "cxo" }, - }; - - static const struct parent_map gcc_pxo_pll3_map[] = { -@@ -286,9 +296,9 @@ static const struct parent_map gcc_pxo_p - { P_PLL3, 6 } - }; - --static const char * const gcc_pxo_pll3[] = { -- "pxo", -- "pll3", -+static const struct clk_parent_data gcc_pxo_pll3[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .hw = &pll3.clkr.hw }, - }; - - static const struct parent_map gcc_pxo_pll8_pll0_map[] = { -@@ -297,10 +307,10 @@ static const struct parent_map gcc_pxo_p - { P_PLL0, 2 } - }; - --static const char * const gcc_pxo_pll8_pll0[] = { -- "pxo", -- "pll8_vote", -- "pll0_vote", -+static const struct clk_parent_data gcc_pxo_pll8_pll0[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .hw = &pll8_vote.hw }, -+ { .hw = &pll0_vote.hw }, - }; - - static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = { -@@ -311,12 +321,12 @@ static const struct parent_map gcc_pxo_p - { P_PLL18, 1 } - }; - --static const char * const gcc_pxo_pll8_pll14_pll18_pll0[] = { -- "pxo", -- "pll8_vote", -- "pll0_vote", -- "pll14", -- "pll18", -+static const struct clk_parent_data gcc_pxo_pll8_pll14_pll18_pll0[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .hw = &pll8_vote.hw }, -+ { .hw = &pll0_vote.hw }, -+ { .hw = &pll14.clkr.hw }, -+ { .hw = &pll18.clkr.hw }, - }; - - static struct freq_tbl clk_tbl_gsbi_uart[] = { -@@ -362,7 +372,7 @@ static struct clk_rcg gsbi1_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -378,8 +388,8 @@ static struct clk_branch gsbi1_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi1_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi1_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -413,7 +423,7 @@ static struct clk_rcg gsbi2_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -429,8 +439,8 @@ static struct clk_branch gsbi2_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi2_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi2_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -464,7 +474,7 @@ static struct clk_rcg gsbi4_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -480,8 +490,8 @@ static struct clk_branch gsbi4_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi4_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi4_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -515,7 +525,7 @@ static struct clk_rcg gsbi5_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -531,8 +541,8 @@ static struct clk_branch gsbi5_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi5_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi5_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -566,7 +576,7 @@ static struct clk_rcg gsbi6_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -582,8 +592,8 @@ static struct clk_branch gsbi6_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi6_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi6_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -617,7 +627,7 @@ static struct clk_rcg gsbi7_uart_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_uart_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -633,8 +643,8 @@ static struct clk_branch gsbi7_uart_clk - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_uart_clk", -- .parent_names = (const char *[]){ -- "gsbi7_uart_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi7_uart_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -681,7 +691,7 @@ static struct clk_rcg gsbi1_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -697,7 +707,9 @@ static struct clk_branch gsbi1_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_qup_clk", -- .parent_names = (const char *[]){ "gsbi1_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi1_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -730,7 +742,7 @@ static struct clk_rcg gsbi2_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -746,7 +758,9 @@ static struct clk_branch gsbi2_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_qup_clk", -- .parent_names = (const char *[]){ "gsbi2_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi2_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -779,7 +793,7 @@ static struct clk_rcg gsbi4_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -795,7 +809,9 @@ static struct clk_branch gsbi4_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_qup_clk", -- .parent_names = (const char *[]){ "gsbi4_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi4_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -828,7 +844,7 @@ static struct clk_rcg gsbi5_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -844,7 +860,9 @@ static struct clk_branch gsbi5_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_qup_clk", -- .parent_names = (const char *[]){ "gsbi5_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi5_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -877,7 +895,7 @@ static struct clk_rcg gsbi6_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -893,7 +911,9 @@ static struct clk_branch gsbi6_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_qup_clk", -- .parent_names = (const char *[]){ "gsbi6_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi6_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -926,7 +946,7 @@ static struct clk_rcg gsbi7_qup_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_qup_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -942,7 +962,9 @@ static struct clk_branch gsbi7_qup_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_qup_clk", -- .parent_names = (const char *[]){ "gsbi7_qup_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gsbi7_qup_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1076,7 +1098,7 @@ static struct clk_rcg gp0_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gp0_src", -- .parent_names = gcc_pxo_pll8_cxo, -+ .parent_data = gcc_pxo_pll8_cxo, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, -@@ -1092,7 +1114,9 @@ static struct clk_branch gp0_clk = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gp0_clk", -- .parent_names = (const char *[]){ "gp0_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gp0_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1125,7 +1149,7 @@ static struct clk_rcg gp1_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gp1_src", -- .parent_names = gcc_pxo_pll8_cxo, -+ .parent_data = gcc_pxo_pll8_cxo, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1141,7 +1165,9 @@ static struct clk_branch gp1_clk = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gp1_clk", -- .parent_names = (const char *[]){ "gp1_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gp1_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1174,7 +1200,7 @@ static struct clk_rcg gp2_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "gp2_src", -- .parent_names = gcc_pxo_pll8_cxo, -+ .parent_data = gcc_pxo_pll8_cxo, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1190,7 +1216,9 @@ static struct clk_branch gp2_clk = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "gp2_clk", -- .parent_names = (const char *[]){ "gp2_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &gp2_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1228,7 +1256,7 @@ static struct clk_rcg prng_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "prng_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - }, -@@ -1244,7 +1272,9 @@ static struct clk_branch prng_clk = { - .enable_mask = BIT(10), - .hw.init = &(struct clk_init_data){ - .name = "prng_clk", -- .parent_names = (const char *[]){ "prng_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &prng_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - }, -@@ -1290,7 +1320,7 @@ static struct clk_rcg sdc1_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "sdc1_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - }, -@@ -1305,7 +1335,9 @@ static struct clk_branch sdc1_clk = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "sdc1_clk", -- .parent_names = (const char *[]){ "sdc1_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &sdc1_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1338,7 +1370,7 @@ static struct clk_rcg sdc3_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "sdc3_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - }, -@@ -1353,7 +1385,9 @@ static struct clk_branch sdc3_clk = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "sdc3_clk", -- .parent_names = (const char *[]){ "sdc3_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &sdc3_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1421,7 +1455,7 @@ static struct clk_rcg tsif_ref_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "tsif_ref_src", -- .parent_names = gcc_pxo_pll8, -+ .parent_data = gcc_pxo_pll8, - .num_parents = 2, - .ops = &clk_rcg_ops, - }, -@@ -1436,7 +1470,9 @@ static struct clk_branch tsif_ref_clk = - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "tsif_ref_clk", -- .parent_names = (const char *[]){ "tsif_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &tsif_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1583,7 +1619,7 @@ static struct clk_rcg pcie_ref_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "pcie_ref_src", -- .parent_names = gcc_pxo_pll3, -+ .parent_data = gcc_pxo_pll3, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1599,7 +1635,9 @@ static struct clk_branch pcie_ref_src_cl - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "pcie_ref_src_clk", -- .parent_names = (const char *[]){ "pcie_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pcie_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1675,7 +1713,7 @@ static struct clk_rcg pcie1_ref_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "pcie1_ref_src", -- .parent_names = gcc_pxo_pll3, -+ .parent_data = gcc_pxo_pll3, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1691,7 +1729,9 @@ static struct clk_branch pcie1_ref_src_c - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "pcie1_ref_src_clk", -- .parent_names = (const char *[]){ "pcie1_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pcie1_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1767,7 +1807,7 @@ static struct clk_rcg pcie2_ref_src = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "pcie2_ref_src", -- .parent_names = gcc_pxo_pll3, -+ .parent_data = gcc_pxo_pll3, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1783,7 +1823,9 @@ static struct clk_branch pcie2_ref_src_c - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "pcie2_ref_src_clk", -- .parent_names = (const char *[]){ "pcie2_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pcie2_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1864,7 +1906,7 @@ static struct clk_rcg sata_ref_src = { - .enable_mask = BIT(7), - .hw.init = &(struct clk_init_data){ - .name = "sata_ref_src", -- .parent_names = gcc_pxo_pll3, -+ .parent_data = gcc_pxo_pll3, - .num_parents = 2, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -1880,7 +1922,9 @@ static struct clk_branch sata_rxoob_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "sata_rxoob_clk", -- .parent_names = (const char *[]){ "sata_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &sata_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1896,7 +1940,9 @@ static struct clk_branch sata_pmalive_cl - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "sata_pmalive_clk", -- .parent_names = (const char *[]){ "sata_ref_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &sata_ref_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -1912,7 +1958,7 @@ static struct clk_branch sata_phy_ref_cl - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "sata_phy_ref_clk", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = gcc_pxo, - .num_parents = 1, - .ops = &clk_branch_ops, - }, -@@ -2001,7 +2047,7 @@ static struct clk_rcg usb30_master_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb30_master_ref_src", -- .parent_names = gcc_pxo_pll8_pll0, -+ .parent_data = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2017,7 +2063,9 @@ static struct clk_branch usb30_0_branch_ - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "usb30_0_branch_clk", -- .parent_names = (const char *[]){ "usb30_master_ref_src", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb30_master_clk_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2033,7 +2081,9 @@ static struct clk_branch usb30_1_branch_ - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "usb30_1_branch_clk", -- .parent_names = (const char *[]){ "usb30_master_ref_src", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb30_master_clk_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2071,7 +2121,7 @@ static struct clk_rcg usb30_utmi_clk = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb30_utmi_clk", -- .parent_names = gcc_pxo_pll8_pll0, -+ .parent_data = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2087,7 +2137,9 @@ static struct clk_branch usb30_0_utmi_cl - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "usb30_0_utmi_clk_ctl", -- .parent_names = (const char *[]){ "usb30_utmi_clk", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb30_utmi_clk.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2103,7 +2155,9 @@ static struct clk_branch usb30_1_utmi_cl - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "usb30_1_utmi_clk_ctl", -- .parent_names = (const char *[]){ "usb30_utmi_clk", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb30_utmi_clk.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2141,7 +2195,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb_hs1_xcvr_src", -- .parent_names = gcc_pxo_pll8_pll0, -+ .parent_data = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2157,7 +2211,9 @@ static struct clk_branch usb_hs1_xcvr_cl - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "usb_hs1_xcvr_clk", -- .parent_names = (const char *[]){ "usb_hs1_xcvr_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb_hs1_xcvr_clk_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2205,7 +2261,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "usb_fs1_xcvr_src", -- .parent_names = gcc_pxo_pll8_pll0, -+ .parent_data = gcc_pxo_pll8_pll0, - .num_parents = 3, - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, -@@ -2221,7 +2277,9 @@ static struct clk_branch usb_fs1_xcvr_cl - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "usb_fs1_xcvr_clk", -- .parent_names = (const char *[]){ "usb_fs1_xcvr_src", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb_fs1_xcvr_clk_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2237,7 +2295,9 @@ static struct clk_branch usb_fs1_sys_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "usb_fs1_sys_clk", -- .parent_names = (const char *[]){ "usb_fs1_xcvr_src", }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &usb_fs1_xcvr_clk_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -2337,7 +2397,7 @@ static struct clk_dyn_rcg gmac_core1_src - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core1_src", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - }, -@@ -2354,8 +2414,8 @@ static struct clk_branch gmac_core1_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core1_clk", -- .parent_names = (const char *[]){ -- "gmac_core1_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gmac_core1_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -2409,7 +2469,7 @@ static struct clk_dyn_rcg gmac_core2_src - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core2_src", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - }, -@@ -2426,8 +2486,8 @@ static struct clk_branch gmac_core2_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core2_clk", -- .parent_names = (const char *[]){ -- "gmac_core2_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gmac_core2_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -2481,7 +2541,7 @@ static struct clk_dyn_rcg gmac_core3_src - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core3_src", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - }, -@@ -2498,8 +2558,8 @@ static struct clk_branch gmac_core3_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core3_clk", -- .parent_names = (const char *[]){ -- "gmac_core3_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gmac_core3_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -2553,7 +2613,7 @@ static struct clk_dyn_rcg gmac_core4_src - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core4_src", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - }, -@@ -2570,8 +2630,8 @@ static struct clk_branch gmac_core4_clk - .enable_mask = BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "gmac_core4_clk", -- .parent_names = (const char *[]){ -- "gmac_core4_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &gmac_core4_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -2613,7 +2673,7 @@ static struct clk_dyn_rcg nss_tcm_src = - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "nss_tcm_src", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - }, -@@ -2628,8 +2688,8 @@ static struct clk_branch nss_tcm_clk = { - .enable_mask = BIT(6) | BIT(4), - .hw.init = &(struct clk_init_data){ - .name = "nss_tcm_clk", -- .parent_names = (const char *[]){ -- "nss_tcm_src", -+ .parent_hws = (const struct clk_hw*[]){ -+ &nss_tcm_src.clkr.hw, - }, - .num_parents = 1, - .ops = &clk_branch_ops, -@@ -2691,7 +2751,7 @@ static struct clk_dyn_rcg ubi32_core1_sr - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "ubi32_core1_src_clk", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, -@@ -2744,7 +2804,7 @@ static struct clk_dyn_rcg ubi32_core2_sr - .enable_mask = BIT(1), - .hw.init = &(struct clk_init_data){ - .name = "ubi32_core2_src_clk", -- .parent_names = gcc_pxo_pll8_pll14_pll18_pll0, -+ .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, - .num_parents = 5, - .ops = &clk_dyn_rcg_ops, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch deleted file mode 100644 index 6e6cec7db5c..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-06-linux-next-clk-qcom-gcc-ipq806x-use-ARRAY_SIZE-for-num_parents.patch +++ /dev/null @@ -1,325 +0,0 @@ -From a6aedd6532131bc81d47bbf63385dfcf2a0e9faa Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:26 +0100 -Subject: [PATCH 06/14] clk: qcom: gcc-ipq806x: use ARRAY_SIZE for num_parents - -Use ARRAY_SIZE for num_parents instead of hardcoding the value. - -Signed-off-by: Ansuel Smith -Reviewed-by: Bjorn Andersson -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-7-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 68 +++++++++++++++++----------------- - 1 file changed, 34 insertions(+), 34 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -373,7 +373,7 @@ static struct clk_rcg gsbi1_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -424,7 +424,7 @@ static struct clk_rcg gsbi2_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -475,7 +475,7 @@ static struct clk_rcg gsbi4_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -526,7 +526,7 @@ static struct clk_rcg gsbi5_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -577,7 +577,7 @@ static struct clk_rcg gsbi6_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -628,7 +628,7 @@ static struct clk_rcg gsbi7_uart_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_uart_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -692,7 +692,7 @@ static struct clk_rcg gsbi1_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi1_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -743,7 +743,7 @@ static struct clk_rcg gsbi2_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi2_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -794,7 +794,7 @@ static struct clk_rcg gsbi4_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -845,7 +845,7 @@ static struct clk_rcg gsbi5_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi5_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -896,7 +896,7 @@ static struct clk_rcg gsbi6_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi6_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -947,7 +947,7 @@ static struct clk_rcg gsbi7_qup_src = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi7_qup_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -1099,7 +1099,7 @@ static struct clk_rcg gp0_src = { - .hw.init = &(struct clk_init_data){ - .name = "gp0_src", - .parent_data = gcc_pxo_pll8_cxo, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), - .ops = &clk_rcg_ops, - .flags = CLK_SET_PARENT_GATE, - }, -@@ -1150,7 +1150,7 @@ static struct clk_rcg gp1_src = { - .hw.init = &(struct clk_init_data){ - .name = "gp1_src", - .parent_data = gcc_pxo_pll8_cxo, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -1201,7 +1201,7 @@ static struct clk_rcg gp2_src = { - .hw.init = &(struct clk_init_data){ - .name = "gp2_src", - .parent_data = gcc_pxo_pll8_cxo, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_cxo), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -1257,7 +1257,7 @@ static struct clk_rcg prng_src = { - .hw.init = &(struct clk_init_data){ - .name = "prng_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - }, - }, -@@ -1321,7 +1321,7 @@ static struct clk_rcg sdc1_src = { - .hw.init = &(struct clk_init_data){ - .name = "sdc1_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - }, - } -@@ -1371,7 +1371,7 @@ static struct clk_rcg sdc3_src = { - .hw.init = &(struct clk_init_data){ - .name = "sdc3_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - }, - } -@@ -1456,7 +1456,7 @@ static struct clk_rcg tsif_ref_src = { - .hw.init = &(struct clk_init_data){ - .name = "tsif_ref_src", - .parent_data = gcc_pxo_pll8, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, - }, - } -@@ -1620,7 +1620,7 @@ static struct clk_rcg pcie_ref_src = { - .hw.init = &(struct clk_init_data){ - .name = "pcie_ref_src", - .parent_data = gcc_pxo_pll3, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -1714,7 +1714,7 @@ static struct clk_rcg pcie1_ref_src = { - .hw.init = &(struct clk_init_data){ - .name = "pcie1_ref_src", - .parent_data = gcc_pxo_pll3, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -1808,7 +1808,7 @@ static struct clk_rcg pcie2_ref_src = { - .hw.init = &(struct clk_init_data){ - .name = "pcie2_ref_src", - .parent_data = gcc_pxo_pll3, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -1907,7 +1907,7 @@ static struct clk_rcg sata_ref_src = { - .hw.init = &(struct clk_init_data){ - .name = "sata_ref_src", - .parent_data = gcc_pxo_pll3, -- .num_parents = 2, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll3), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -2048,7 +2048,7 @@ static struct clk_rcg usb30_master_clk_s - .hw.init = &(struct clk_init_data){ - .name = "usb30_master_ref_src", - .parent_data = gcc_pxo_pll8_pll0, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -2122,7 +2122,7 @@ static struct clk_rcg usb30_utmi_clk = { - .hw.init = &(struct clk_init_data){ - .name = "usb30_utmi_clk", - .parent_data = gcc_pxo_pll8_pll0, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -2196,7 +2196,7 @@ static struct clk_rcg usb_hs1_xcvr_clk_s - .hw.init = &(struct clk_init_data){ - .name = "usb_hs1_xcvr_src", - .parent_data = gcc_pxo_pll8_pll0, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -2262,7 +2262,7 @@ static struct clk_rcg usb_fs1_xcvr_clk_s - .hw.init = &(struct clk_init_data){ - .name = "usb_fs1_xcvr_src", - .parent_data = gcc_pxo_pll8_pll0, -- .num_parents = 3, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -2398,7 +2398,7 @@ static struct clk_dyn_rcg gmac_core1_src - .hw.init = &(struct clk_init_data){ - .name = "gmac_core1_src", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - }, - }, -@@ -2470,7 +2470,7 @@ static struct clk_dyn_rcg gmac_core2_src - .hw.init = &(struct clk_init_data){ - .name = "gmac_core2_src", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - }, - }, -@@ -2542,7 +2542,7 @@ static struct clk_dyn_rcg gmac_core3_src - .hw.init = &(struct clk_init_data){ - .name = "gmac_core3_src", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - }, - }, -@@ -2614,7 +2614,7 @@ static struct clk_dyn_rcg gmac_core4_src - .hw.init = &(struct clk_init_data){ - .name = "gmac_core4_src", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - }, - }, -@@ -2674,7 +2674,7 @@ static struct clk_dyn_rcg nss_tcm_src = - .hw.init = &(struct clk_init_data){ - .name = "nss_tcm_src", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - }, - }, -@@ -2752,7 +2752,7 @@ static struct clk_dyn_rcg ubi32_core1_sr - .hw.init = &(struct clk_init_data){ - .name = "ubi32_core1_src_clk", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, - }, -@@ -2805,7 +2805,7 @@ static struct clk_dyn_rcg ubi32_core2_sr - .hw.init = &(struct clk_init_data){ - .name = "ubi32_core2_src_clk", - .parent_data = gcc_pxo_pll8_pll14_pll18_pll0, -- .num_parents = 5, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll14_pll18_pll0), - .ops = &clk_dyn_rcg_ops, - .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, - }, diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch deleted file mode 100644 index b0f09ec34dc..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-07-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-nss-cores.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 512ea2edfe15ffa2cd839b3a31d768145f2edc20 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:27 +0100 -Subject: [PATCH 07/14] clk: qcom: gcc-ipq806x: add additional freq nss cores - -Ipq8065 SoC (an evolution of ipq8064 SoC) contains nss cores that can be -clocked to 800MHz. Add these missing freq to the gcc driver. -Set the freq_tbl for the ubi32_cores to the correct values based on the -machine compatible. - -Signed-off-by: Ansuel Smith -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-8-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 24 +++++++++++++++++++++--- - 1 file changed, 21 insertions(+), 3 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -232,7 +232,9 @@ static struct clk_regmap pll14_vote = { - - static struct pll_freq_tbl pll18_freq_tbl[] = { - NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625), -+ NSS_PLL_RATE(600000000, 48, 0, 1, 0x01495625), - NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625), -+ NSS_PLL_RATE(800000000, 64, 0, 1, 0x01495625), - }; - - static struct clk_pll pll18 = { -@@ -2698,7 +2700,7 @@ static struct clk_branch nss_tcm_clk = { - }, - }; - --static const struct freq_tbl clk_tbl_nss[] = { -+static const struct freq_tbl clk_tbl_nss_ipq8064[] = { - { 110000000, P_PLL18, 1, 1, 5 }, - { 275000000, P_PLL18, 2, 0, 0 }, - { 550000000, P_PLL18, 1, 0, 0 }, -@@ -2706,6 +2708,14 @@ static const struct freq_tbl clk_tbl_nss - { } - }; - -+static const struct freq_tbl clk_tbl_nss_ipq8065[] = { -+ { 110000000, P_PLL18, 1, 1, 5 }, -+ { 275000000, P_PLL18, 2, 0, 0 }, -+ { 600000000, P_PLL18, 1, 0, 0 }, -+ { 800000000, P_PLL18, 1, 0, 0 }, -+ { } -+}; -+ - static struct clk_dyn_rcg ubi32_core1_src_clk = { - .ns_reg[0] = 0x3d2c, - .ns_reg[1] = 0x3d30, -@@ -2745,7 +2755,7 @@ static struct clk_dyn_rcg ubi32_core1_sr - .pre_div_width = 2, - }, - .mux_sel_bit = 0, -- .freq_tbl = clk_tbl_nss, -+ /* nss freq table is selected based on the SoC compatible */ - .clkr = { - .enable_reg = 0x3d20, - .enable_mask = BIT(1), -@@ -2798,7 +2808,7 @@ static struct clk_dyn_rcg ubi32_core2_sr - .pre_div_width = 2, - }, - .mux_sel_bit = 0, -- .freq_tbl = clk_tbl_nss, -+ /* nss freq table is selected based on the SoC compatible */ - .clkr = { - .enable_reg = 0x3d40, - .enable_mask = BIT(1), -@@ -3131,6 +3141,14 @@ static int gcc_ipq806x_probe(struct plat - if (ret) - return ret; - -+ if (of_machine_is_compatible("qcom,ipq8065")) { -+ ubi32_core1_src_clk.freq_tbl = clk_tbl_nss_ipq8065; -+ ubi32_core2_src_clk.freq_tbl = clk_tbl_nss_ipq8065; -+ } else { -+ ubi32_core1_src_clk.freq_tbl = clk_tbl_nss_ipq8064; -+ ubi32_core2_src_clk.freq_tbl = clk_tbl_nss_ipq8064; -+ } -+ - ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc); - if (ret) - return ret; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch deleted file mode 100644 index 3d55cb421a1..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-08-linux-next-clk-qcom-gcc-ipq806x-add-unusued-flag-for-critical-c.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 28aa450d38e521de45be951df052d2c49a17fae2 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:28 +0100 -Subject: [PATCH 08/14] clk: qcom: gcc-ipq806x: add unusued flag for critical - clock - -Some clocks are used by other devices present on the SoC. For example -the gsbi4_h_clk is used by RPM and is if disabled cause the RPM to -reject any regulator change command. These clock should never be -disabled. - -Signed-off-by: Ansuel Smith -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-9-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -798,7 +798,7 @@ static struct clk_rcg gsbi4_qup_src = { - .parent_data = gcc_pxo_pll8, - .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, -- .flags = CLK_SET_PARENT_GATE, -+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -816,7 +816,7 @@ static struct clk_branch gsbi4_qup_clk = - }, - .num_parents = 1, - .ops = &clk_branch_ops, -- .flags = CLK_SET_RATE_PARENT, -+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -900,7 +900,7 @@ static struct clk_rcg gsbi6_qup_src = { - .parent_data = gcc_pxo_pll8, - .num_parents = ARRAY_SIZE(gcc_pxo_pll8), - .ops = &clk_rcg_ops, -- .flags = CLK_SET_PARENT_GATE, -+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -969,7 +969,7 @@ static struct clk_branch gsbi7_qup_clk = - }, - .num_parents = 1, - .ops = &clk_branch_ops, -- .flags = CLK_SET_RATE_PARENT, -+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, - }, - }, - }; -@@ -1015,6 +1015,7 @@ static struct clk_branch gsbi4_h_clk = { - .hw.init = &(struct clk_init_data){ - .name = "gsbi4_h_clk", - .ops = &clk_branch_ops, -+ .flags = CLK_IGNORE_UNUSED, - }, - }, - }; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch deleted file mode 100644 index 22bd040d1bf..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-09-linux-next-clk-qcom-clk-rcg-add-clk_rcg_floor_ops-ops.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 33958ad3fc02aeb06a4634e59689a9559d968e1f Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:29 +0100 -Subject: [PATCH 09/14] clk: qcom: clk-rcg: add clk_rcg_floor_ops ops - -Add clk_rcg_floor_ops for clock that can't provide a stable freq and -require to use a floor freq to provide the requested frequency. - -Signed-off-by: Ansuel Smith -Reviewed-by: Bjorn Andersson -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-10-ansuelsmth@gmail.com ---- - drivers/clk/qcom/clk-rcg.c | 24 ++++++++++++++++++++++++ - drivers/clk/qcom/clk-rcg.h | 1 + - 2 files changed, 25 insertions(+) - ---- a/drivers/clk/qcom/clk-rcg.c -+++ b/drivers/clk/qcom/clk-rcg.c -@@ -526,6 +526,19 @@ static int clk_rcg_set_rate(struct clk_h - return __clk_rcg_set_rate(rcg, f); - } - -+static int clk_rcg_set_floor_rate(struct clk_hw *hw, unsigned long rate, -+ unsigned long parent_rate) -+{ -+ struct clk_rcg *rcg = to_clk_rcg(hw); -+ const struct freq_tbl *f; -+ -+ f = qcom_find_freq_floor(rcg->freq_tbl, rate); -+ if (!f) -+ return -EINVAL; -+ -+ return __clk_rcg_set_rate(rcg, f); -+} -+ - static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) - { -@@ -816,6 +829,17 @@ const struct clk_ops clk_rcg_ops = { - }; - EXPORT_SYMBOL_GPL(clk_rcg_ops); - -+const struct clk_ops clk_rcg_floor_ops = { -+ .enable = clk_enable_regmap, -+ .disable = clk_disable_regmap, -+ .get_parent = clk_rcg_get_parent, -+ .set_parent = clk_rcg_set_parent, -+ .recalc_rate = clk_rcg_recalc_rate, -+ .determine_rate = clk_rcg_determine_rate, -+ .set_rate = clk_rcg_set_floor_rate, -+}; -+EXPORT_SYMBOL_GPL(clk_rcg_floor_ops); -+ - const struct clk_ops clk_rcg_bypass_ops = { - .enable = clk_enable_regmap, - .disable = clk_disable_regmap, ---- a/drivers/clk/qcom/clk-rcg.h -+++ b/drivers/clk/qcom/clk-rcg.h -@@ -86,6 +86,7 @@ struct clk_rcg { - }; - - extern const struct clk_ops clk_rcg_ops; -+extern const struct clk_ops clk_rcg_floor_ops; - extern const struct clk_ops clk_rcg_bypass_ops; - extern const struct clk_ops clk_rcg_bypass2_ops; - extern const struct clk_ops clk_rcg_pixel_ops; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch deleted file mode 100644 index 3bb5e57c87a..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-10-linux-next-clk-qcom-gcc-ipq806x-add-additional-freq-for-sdc-tab.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 7e726f34c782b2ca28a29ca9870e34e4319d65bc Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:30 +0100 -Subject: [PATCH 10/14] clk: qcom: gcc-ipq806x: add additional freq for sdc - table - -Add additional freq supported for the sdc table. The ops are changed to -the floor_ops to handle a freq request of 52kHz where we need to provide -a freq of 51.2kHz instead for stability reason. - -Signed-off-by: Ansuel Smith -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-11-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -1292,6 +1292,7 @@ static const struct freq_tbl clk_tbl_sdc - { 20210000, P_PLL8, 1, 1, 19 }, - { 24000000, P_PLL8, 4, 1, 4 }, - { 48000000, P_PLL8, 4, 1, 2 }, -+ { 51200000, P_PLL8, 1, 2, 15 }, - { 64000000, P_PLL8, 3, 1, 2 }, - { 96000000, P_PLL8, 4, 0, 0 }, - { 192000000, P_PLL8, 2, 0, 0 }, -@@ -1325,7 +1326,7 @@ static struct clk_rcg sdc1_src = { - .name = "sdc1_src", - .parent_data = gcc_pxo_pll8, - .num_parents = ARRAY_SIZE(gcc_pxo_pll8), -- .ops = &clk_rcg_ops, -+ .ops = &clk_rcg_floor_ops, - }, - } - }; diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch deleted file mode 100644 index 858c6f78a52..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-11-linux-next-dt-bindings-clock-add-ipq8064-ce5-clk-define.patch +++ /dev/null @@ -1,39 +0,0 @@ -From b565d66403e3df303a058c0d8d00d0fc6aeb2ddc Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:31 +0100 -Subject: [PATCH 11/14] dt-bindings: clock: add ipq8064 ce5 clk define - -Add ipq8064 ce5 clk define needed for CryptoEngine in gcc driver. -Define CE5_SRC is not used so it's OK to change and we align it to -the QSDK naming. - -Signed-off-by: Ansuel Smith -Acked-by: Rob Herring -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-12-ansuelsmth@gmail.com ---- - include/dt-bindings/clock/qcom,gcc-ipq806x.h | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - ---- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h -+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h -@@ -240,7 +240,7 @@ - #define PLL14 232 - #define PLL14_VOTE 233 - #define PLL18 234 --#define CE5_SRC 235 -+#define CE5_A_CLK 235 - #define CE5_H_CLK 236 - #define CE5_CORE_CLK 237 - #define CE3_SLEEP_CLK 238 -@@ -283,5 +283,8 @@ - #define EBI2_AON_CLK 281 - #define NSSTCM_CLK_SRC 282 - #define NSSTCM_CLK 283 -+#define CE5_A_CLK_SRC 285 -+#define CE5_H_CLK_SRC 286 -+#define CE5_CORE_CLK_SRC 287 - - #endif diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch deleted file mode 100644 index 3ded707bf0c..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-12-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-clocks.patch +++ /dev/null @@ -1,304 +0,0 @@ -From b293510f3961b90dcab59965f57779be93ceda7c Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:32 +0100 -Subject: [PATCH 12/14] clk: qcom: gcc-ipq806x: add CryptoEngine clocks - -Add missing CryptoEngine clocks and pll11 required clock. - -Signed-off-by: Ansuel Smith -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-13-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 244 +++++++++++++++++++++++++++++++++ - 1 file changed, 244 insertions(+) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -256,6 +256,24 @@ static struct clk_pll pll18 = { - }, - }; - -+static struct clk_pll pll11 = { -+ .l_reg = 0x3184, -+ .m_reg = 0x3188, -+ .n_reg = 0x318c, -+ .config_reg = 0x3194, -+ .mode_reg = 0x3180, -+ .status_reg = 0x3198, -+ .status_bit = 16, -+ .clkr.hw.init = &(struct clk_init_data){ -+ .name = "pll11", -+ .parent_data = &(const struct clk_parent_data){ -+ .fw_name = "pxo", -+ }, -+ .num_parents = 1, -+ .ops = &clk_pll_ops, -+ }, -+}; -+ - enum { - P_PXO, - P_PLL8, -@@ -264,6 +282,7 @@ enum { - P_CXO, - P_PLL14, - P_PLL18, -+ P_PLL11, - }; - - static const struct parent_map gcc_pxo_pll8_map[] = { -@@ -331,6 +350,44 @@ static const struct clk_parent_data gcc_ - { .hw = &pll18.clkr.hw }, - }; - -+static const struct parent_map gcc_pxo_pll8_pll0_pll14_pll18_pll11_map[] = { -+ { P_PXO, 0 }, -+ { P_PLL8, 4 }, -+ { P_PLL0, 2 }, -+ { P_PLL14, 5 }, -+ { P_PLL18, 1 }, -+ { P_PLL11, 3 }, -+}; -+ -+static const struct clk_parent_data gcc_pxo_pll8_pll0_pll14_pll18_pll11[] = { -+ { .fw_name = "pxo" }, -+ { .hw = &pll8_vote.hw }, -+ { .hw = &pll0_vote.hw }, -+ { .hw = &pll14.clkr.hw }, -+ { .hw = &pll18.clkr.hw }, -+ { .hw = &pll11.clkr.hw }, -+ -+}; -+ -+static const struct parent_map gcc_pxo_pll3_pll0_pll14_pll18_pll11_map[] = { -+ { P_PXO, 0 }, -+ { P_PLL3, 6 }, -+ { P_PLL0, 2 }, -+ { P_PLL14, 5 }, -+ { P_PLL18, 1 }, -+ { P_PLL11, 3 }, -+}; -+ -+static const struct clk_parent_data gcc_pxo_pll3_pll0_pll14_pll18_pll11[] = { -+ { .fw_name = "pxo" }, -+ { .hw = &pll3.clkr.hw }, -+ { .hw = &pll0_vote.hw }, -+ { .hw = &pll14.clkr.hw }, -+ { .hw = &pll18.clkr.hw }, -+ { .hw = &pll11.clkr.hw }, -+ -+}; -+ - static struct freq_tbl clk_tbl_gsbi_uart[] = { - { 1843200, P_PLL8, 2, 6, 625 }, - { 3686400, P_PLL8, 2, 12, 625 }, -@@ -2824,6 +2881,186 @@ static struct clk_dyn_rcg ubi32_core2_sr - }, - }; - -+static const struct freq_tbl clk_tbl_ce5_core[] = { -+ { 150000000, P_PLL3, 8, 1, 1 }, -+ { 213200000, P_PLL11, 5, 1, 1 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg ce5_core_src = { -+ .ns_reg[0] = 0x36C4, -+ .ns_reg[1] = 0x36C8, -+ .bank_reg = 0x36C0, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll3_pll0_pll14_pll18_pll11_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_ce5_core, -+ .clkr = { -+ .enable_reg = 0x36C0, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_core_src", -+ .parent_data = gcc_pxo_pll3_pll0_pll14_pll18_pll11, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll3_pll0_pll14_pll18_pll11), -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch ce5_core_clk = { -+ .halt_reg = 0x2FDC, -+ .halt_bit = 5, -+ .hwcg_reg = 0x36CC, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x36CC, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_core_clk", -+ .parent_hws = (const struct clk_hw*[]){ -+ &ce5_core_src.clkr.hw, -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static const struct freq_tbl clk_tbl_ce5_a_clk[] = { -+ { 160000000, P_PLL0, 5, 1, 1 }, -+ { 213200000, P_PLL11, 5, 1, 1 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg ce5_a_clk_src = { -+ .ns_reg[0] = 0x3d84, -+ .ns_reg[1] = 0x3d88, -+ .bank_reg = 0x3d80, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_ce5_a_clk, -+ .clkr = { -+ .enable_reg = 0x3d80, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_a_clk_src", -+ .parent_data = gcc_pxo_pll8_pll0_pll14_pll18_pll11, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0_pll14_pll18_pll11), -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch ce5_a_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 12, -+ .hwcg_reg = 0x3d8c, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3d8c, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_a_clk", -+ .parent_hws = (const struct clk_hw*[]){ -+ &ce5_a_clk_src.clkr.hw, -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ -+static const struct freq_tbl clk_tbl_ce5_h_clk[] = { -+ { 160000000, P_PLL0, 5, 1, 1 }, -+ { 213200000, P_PLL11, 5, 1, 1 }, -+ { } -+}; -+ -+static struct clk_dyn_rcg ce5_h_clk_src = { -+ .ns_reg[0] = 0x3c64, -+ .ns_reg[1] = 0x3c68, -+ .bank_reg = 0x3c60, -+ .s[0] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, -+ }, -+ .s[1] = { -+ .src_sel_shift = 0, -+ .parent_map = gcc_pxo_pll8_pll0_pll14_pll18_pll11_map, -+ }, -+ .p[0] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .p[1] = { -+ .pre_div_shift = 3, -+ .pre_div_width = 4, -+ }, -+ .mux_sel_bit = 0, -+ .freq_tbl = clk_tbl_ce5_h_clk, -+ .clkr = { -+ .enable_reg = 0x3c60, -+ .enable_mask = BIT(1), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_h_clk_src", -+ .parent_data = gcc_pxo_pll8_pll0_pll14_pll18_pll11, -+ .num_parents = ARRAY_SIZE(gcc_pxo_pll8_pll0_pll14_pll18_pll11), -+ .ops = &clk_dyn_rcg_ops, -+ }, -+ }, -+}; -+ -+static struct clk_branch ce5_h_clk = { -+ .halt_reg = 0x3c20, -+ .halt_bit = 11, -+ .hwcg_reg = 0x3c6c, -+ .hwcg_bit = 6, -+ .clkr = { -+ .enable_reg = 0x3c6c, -+ .enable_mask = BIT(4), -+ .hw.init = &(struct clk_init_data){ -+ .name = "ce5_h_clk", -+ .parent_hws = (const struct clk_hw*[]){ -+ &ce5_h_clk_src.clkr.hw, -+ }, -+ .num_parents = 1, -+ .ops = &clk_branch_ops, -+ .flags = CLK_SET_RATE_PARENT, -+ }, -+ }, -+}; -+ - static struct clk_regmap *gcc_ipq806x_clks[] = { - [PLL0] = &pll0.clkr, - [PLL0_VOTE] = &pll0_vote, -@@ -2831,6 +3068,7 @@ static struct clk_regmap *gcc_ipq806x_cl - [PLL4_VOTE] = &pll4_vote, - [PLL8] = &pll8.clkr, - [PLL8_VOTE] = &pll8_vote, -+ [PLL11] = &pll11.clkr, - [PLL14] = &pll14.clkr, - [PLL14_VOTE] = &pll14_vote, - [PLL18] = &pll18.clkr, -@@ -2945,6 +3183,12 @@ static struct clk_regmap *gcc_ipq806x_cl - [PLL9] = &hfpll0.clkr, - [PLL10] = &hfpll1.clkr, - [PLL12] = &hfpll_l2.clkr, -+ [CE5_A_CLK_SRC] = &ce5_a_clk_src.clkr, -+ [CE5_A_CLK] = &ce5_a_clk.clkr, -+ [CE5_H_CLK_SRC] = &ce5_h_clk_src.clkr, -+ [CE5_H_CLK] = &ce5_h_clk.clkr, -+ [CE5_CORE_CLK_SRC] = &ce5_core_src.clkr, -+ [CE5_CORE_CLK] = &ce5_core_clk.clkr, - }; - - static const struct qcom_reset_map gcc_ipq806x_resets[] = { diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch deleted file mode 100644 index 5d05c2b3af3..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-13-linux-next-dt-bindings-reset-add-ipq8064-ce5-resets.patch +++ /dev/null @@ -1,29 +0,0 @@ -From f4a7e56f4956f0450b9f671ed93d45ffcc15aa62 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Tue, 18 Jan 2022 01:22:05 +0100 -Subject: [PATCH v6 13/15] dt-bindings: reset: add ipq8064 ce5 resets - -Add ipq8064 ce5 resets needed for CryptoEngine gcc driver. - -Signed-off-by: Ansuel Smith -Reviewed-by: Bjorn Andersson -Acked-by: Philipp Zabel -Acked-by: Rob Herring -Reviewed-by: Stephen Boyd ---- - include/dt-bindings/reset/qcom,gcc-ipq806x.h | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h -+++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h -@@ -163,5 +163,10 @@ - #define NSS_CAL_PRBS_RST_N_RESET 154 - #define NSS_LCKDT_RST_N_RESET 155 - #define NSS_SRDS_N_RESET 156 -+#define CRYPTO_ENG1_RESET 157 -+#define CRYPTO_ENG2_RESET 158 -+#define CRYPTO_ENG3_RESET 159 -+#define CRYPTO_ENG4_RESET 160 -+#define CRYPTO_AHB_RESET 161 - - #endif diff --git a/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch b/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch deleted file mode 100644 index a26f67e36e0..00000000000 --- a/target/linux/ipq806x/patches-6.1/100-v5.18-14-linux-next-clk-qcom-gcc-ipq806x-add-CryptoEngine-resets.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4f865bdcb44fb18951de94be5c2ec37a891a8d03 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:34 +0100 -Subject: [PATCH 14/14] clk: qcom: gcc-ipq806x: add CryptoEngine resets - -Add missing CryptoEngine resets. - -Signed-off-by: Ansuel Smith -Reviewed-by: Stephen Boyd -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-15-ansuelsmth@gmail.com ---- - drivers/clk/qcom/gcc-ipq806x.c | 5 +++++ - 1 file changed, 5 insertions(+) - ---- a/drivers/clk/qcom/gcc-ipq806x.c -+++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -3320,6 +3320,11 @@ static const struct qcom_reset_map gcc_i - [GMAC_CORE3_RESET] = { 0x3cfc, 0 }, - [GMAC_CORE4_RESET] = { 0x3d1c, 0 }, - [GMAC_AHB_RESET] = { 0x3e24, 0 }, -+ [CRYPTO_ENG1_RESET] = { 0x3e00, 0}, -+ [CRYPTO_ENG2_RESET] = { 0x3e04, 0}, -+ [CRYPTO_ENG3_RESET] = { 0x3e08, 0}, -+ [CRYPTO_ENG4_RESET] = { 0x3e0c, 0}, -+ [CRYPTO_AHB_RESET] = { 0x3e10, 0}, - [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 }, - [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 }, - [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 }, diff --git a/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch b/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch deleted file mode 100644 index bd492ca1ecd..00000000000 --- a/target/linux/ipq806x/patches-6.1/101-v6.0-01-net-ethernet-stmmac-add-missing-sgmii-configure-for-.patch +++ /dev/null @@ -1,151 +0,0 @@ -From 9ec092d2feb69045dd289845024301fb91c064ee Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Tue, 14 Jun 2022 13:22:27 +0200 -Subject: [PATCH 1/2] net: ethernet: stmmac: add missing sgmii configure for - ipq806x - -The different gmacid require different configuration based on the soc -and on the gmac id. Add these missing configuration taken from the -original driver. - -Signed-off-by: Christian 'Ansuel' Marangi -Link: https://lore.kernel.org/r/20220614112228.1998-1-ansuelsmth@gmail.com -Signed-off-by: Paolo Abeni ---- - drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 + - .../ethernet/stmicro/stmmac/dwmac-ipq806x.c | 93 +++++++++++++++---- - 2 files changed, 78 insertions(+), 16 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig -+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig -@@ -83,6 +83,7 @@ config DWMAC_IPQ806X - default ARCH_QCOM - depends on OF && (ARCH_QCOM || COMPILE_TEST) - select MFD_SYSCON -+ select QCOM_SOCINFO - help - Support for QCA IPQ806X DWMAC Ethernet. - ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -27,6 +27,8 @@ - #include - #include - #include -+#include -+#include - - #include "stmmac_platform.h" - -@@ -75,11 +77,20 @@ - #define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2) - #define QSGMII_PHY_TX_DRIVER_EN BIT(3) - #define QSGMII_PHY_QSGMII_EN BIT(7) --#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12 --#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18 --#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20 --#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22 --#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28 -+#define QSGMII_PHY_DEEMPHASIS_LVL_MASK GENMASK(11, 10) -+#define QSGMII_PHY_DEEMPHASIS_LVL(x) FIELD_PREP(QSGMII_PHY_DEEMPHASIS_LVL_MASK, (x)) -+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK GENMASK(14, 12) -+#define QSGMII_PHY_PHASE_LOOP_GAIN(x) FIELD_PREP(QSGMII_PHY_PHASE_LOOP_GAIN_MASK, (x)) -+#define QSGMII_PHY_RX_DC_BIAS_MASK GENMASK(19, 18) -+#define QSGMII_PHY_RX_DC_BIAS(x) FIELD_PREP(QSGMII_PHY_RX_DC_BIAS_MASK, (x)) -+#define QSGMII_PHY_RX_INPUT_EQU_MASK GENMASK(21, 20) -+#define QSGMII_PHY_RX_INPUT_EQU(x) FIELD_PREP(QSGMII_PHY_RX_INPUT_EQU_MASK, (x)) -+#define QSGMII_PHY_CDR_PI_SLEW_MASK GENMASK(23, 22) -+#define QSGMII_PHY_CDR_PI_SLEW(x) FIELD_PREP(QSGMII_PHY_CDR_PI_SLEW_MASK, (x)) -+#define QSGMII_PHY_TX_SLEW_MASK GENMASK(27, 26) -+#define QSGMII_PHY_TX_SLEW(x) FIELD_PREP(QSGMII_PHY_TX_SLEW_MASK, (x)) -+#define QSGMII_PHY_TX_DRV_AMP_MASK GENMASK(31, 28) -+#define QSGMII_PHY_TX_DRV_AMP(x) FIELD_PREP(QSGMII_PHY_TX_DRV_AMP_MASK, (x)) - - struct ipq806x_gmac { - struct platform_device *pdev; -@@ -242,6 +253,64 @@ static void ipq806x_gmac_fix_mac_speed(v - ipq806x_gmac_set_speed(gmac, speed); - } - -+static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = { -+ { -+ .revision = "1.*", -+ }, -+ { -+ /* sentinel */ -+ } -+}; -+ -+static int -+ipq806x_gmac_configure_qsgmii_params(struct ipq806x_gmac *gmac) -+{ -+ struct platform_device *pdev = gmac->pdev; -+ const struct soc_device_attribute *soc; -+ struct device *dev = &pdev->dev; -+ u32 qsgmii_param; -+ -+ switch (gmac->id) { -+ case 1: -+ soc = soc_device_match(ipq806x_gmac_soc_v1); -+ -+ if (soc) -+ qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xc) | -+ QSGMII_PHY_TX_SLEW(0x2) | -+ QSGMII_PHY_DEEMPHASIS_LVL(0x2); -+ else -+ qsgmii_param = QSGMII_PHY_TX_DRV_AMP(0xd) | -+ QSGMII_PHY_TX_SLEW(0x0) | -+ QSGMII_PHY_DEEMPHASIS_LVL(0x0); -+ -+ qsgmii_param |= QSGMII_PHY_RX_DC_BIAS(0x2); -+ break; -+ case 2: -+ case 3: -+ qsgmii_param = QSGMII_PHY_RX_DC_BIAS(0x3) | -+ QSGMII_PHY_TX_DRV_AMP(0xc); -+ break; -+ default: /* gmac 0 can't be set in SGMII mode */ -+ dev_err(dev, "gmac id %d can't be in SGMII mode", gmac->id); -+ return -EINVAL; -+ } -+ -+ /* Common params across all gmac id */ -+ qsgmii_param |= QSGMII_PHY_CDR_EN | -+ QSGMII_PHY_RX_FRONT_EN | -+ QSGMII_PHY_RX_SIGNAL_DETECT_EN | -+ QSGMII_PHY_TX_DRIVER_EN | -+ QSGMII_PHY_QSGMII_EN | -+ QSGMII_PHY_PHASE_LOOP_GAIN(0x4) | -+ QSGMII_PHY_RX_INPUT_EQU(0x1) | -+ QSGMII_PHY_CDR_PI_SLEW(0x2); -+ -+ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), -+ qsgmii_param); -+ -+ return 0; -+} -+ - static int ipq806x_gmac_probe(struct platform_device *pdev) - { - struct plat_stmmacenet_data *plat_dat; -@@ -328,17 +397,9 @@ static int ipq806x_gmac_probe(struct pla - regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); - - if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) { -- regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), -- QSGMII_PHY_CDR_EN | -- QSGMII_PHY_RX_FRONT_EN | -- QSGMII_PHY_RX_SIGNAL_DETECT_EN | -- QSGMII_PHY_TX_DRIVER_EN | -- QSGMII_PHY_QSGMII_EN | -- 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | -- 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET | -- 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | -- 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | -- 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET); -+ err = ipq806x_gmac_configure_qsgmii_params(gmac); -+ if (err) -+ goto err_remove_config_dt; - } - - plat_dat->has_gmac = true; diff --git a/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch b/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch deleted file mode 100644 index d444553452c..00000000000 --- a/target/linux/ipq806x/patches-6.1/101-v6.0-02-net-ethernet-stmmac-reset-force-speed-bit-for-ipq806.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 8bca458990dd8c6d001b2fb52063aa18e8ca7444 Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Tue, 14 Jun 2022 13:22:28 +0200 -Subject: [PATCH 2/2] net: ethernet: stmmac: reset force speed bit for ipq806x - -Some bootloader may set the force speed regs even if the actual -interface should use autonegotiation between PCS and PHY. -This cause the complete malfuction of the interface. - -To fix this correctly reset the force speed regs if a fixed-link is not -defined in the DTS. With a fixed-link node correctly configure the -forced speed regs to handle any misconfiguration by the bootloader. - -Reported-by: Mark Mentovai -Co-developed-by: Mark Mentovai -Signed-off-by: Mark Mentovai -Signed-off-by: Christian 'Ansuel' Marangi -Link: https://lore.kernel.org/r/20220614112228.1998-2-ansuelsmth@gmail.com -Signed-off-by: Paolo Abeni ---- - .../ethernet/stmicro/stmmac/dwmac-ipq806x.c | 64 +++++++++++++++++++ - 1 file changed, 64 insertions(+) - ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -66,6 +66,17 @@ - #define NSS_COMMON_CLK_DIV_SGMII_100 4 - #define NSS_COMMON_CLK_DIV_SGMII_10 49 - -+#define QSGMII_PCS_ALL_CH_CTL 0x80 -+#define QSGMII_PCS_CH_SPEED_FORCE BIT(1) -+#define QSGMII_PCS_CH_SPEED_10 0x0 -+#define QSGMII_PCS_CH_SPEED_100 BIT(2) -+#define QSGMII_PCS_CH_SPEED_1000 BIT(3) -+#define QSGMII_PCS_CH_SPEED_MASK (QSGMII_PCS_CH_SPEED_FORCE | \ -+ QSGMII_PCS_CH_SPEED_10 | \ -+ QSGMII_PCS_CH_SPEED_100 | \ -+ QSGMII_PCS_CH_SPEED_1000) -+#define QSGMII_PCS_CH_SPEED_SHIFT(x) ((x) * 4) -+ - #define QSGMII_PCS_CAL_LCKDT_CTL 0x120 - #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) - -@@ -253,6 +264,55 @@ static void ipq806x_gmac_fix_mac_speed(v - ipq806x_gmac_set_speed(gmac, speed); - } - -+static int -+ipq806x_gmac_configure_qsgmii_pcs_speed(struct ipq806x_gmac *gmac) -+{ -+ struct platform_device *pdev = gmac->pdev; -+ struct device *dev = &pdev->dev; -+ struct device_node *dn; -+ int link_speed; -+ int val = 0; -+ int ret; -+ -+ /* Some bootloader may apply wrong configuration and cause -+ * not functioning port. If fixed link is not set, -+ * reset the force speed bit. -+ */ -+ if (!of_phy_is_fixed_link(pdev->dev.of_node)) -+ goto write; -+ -+ dn = of_get_child_by_name(pdev->dev.of_node, "fixed-link"); -+ ret = of_property_read_u32(dn, "speed", &link_speed); -+ of_node_put(dn); -+ if (ret) { -+ dev_err(dev, "found fixed-link node with no speed"); -+ return ret; -+ } -+ -+ val = QSGMII_PCS_CH_SPEED_FORCE; -+ -+ switch (link_speed) { -+ case SPEED_1000: -+ val |= QSGMII_PCS_CH_SPEED_1000; -+ break; -+ case SPEED_100: -+ val |= QSGMII_PCS_CH_SPEED_100; -+ break; -+ case SPEED_10: -+ val |= QSGMII_PCS_CH_SPEED_10; -+ break; -+ } -+ -+write: -+ regmap_update_bits(gmac->qsgmii_csr, QSGMII_PCS_ALL_CH_CTL, -+ QSGMII_PCS_CH_SPEED_MASK << -+ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id), -+ val << -+ QSGMII_PCS_CH_SPEED_SHIFT(gmac->id)); -+ -+ return 0; -+} -+ - static const struct soc_device_attribute ipq806x_gmac_soc_v1[] = { - { - .revision = "1.*", -@@ -400,6 +460,10 @@ static int ipq806x_gmac_probe(struct pla - err = ipq806x_gmac_configure_qsgmii_params(gmac); - if (err) - goto err_remove_config_dt; -+ -+ err = ipq806x_gmac_configure_qsgmii_pcs_speed(gmac); -+ if (err) -+ goto err_remove_config_dt; - } - - plat_dat->has_gmac = true; diff --git a/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch b/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch deleted file mode 100644 index 2ce526b6ca7..00000000000 --- a/target/linux/ipq806x/patches-6.1/103-v5.19-ARM-dts-qcom-add-syscon-and-cxo-pxo-clock-to-gcc-nod.patch +++ /dev/null @@ -1,48 +0,0 @@ -From a5ba119455c77a07e05f2fe0af446c8bf43d1a00 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 26 Feb 2022 14:52:35 +0100 -Subject: [PATCH] ARM: dts: qcom: add syscon and cxo/pxo clock to gcc node for - ipq8064 - -Add syscon compatible required for tsens driver to correctly probe driver -and access the reg. Also add cxo and pxo tag and declare them as gcc clock -now requires them for the ipq8064 gcc driver that has now been modernized. - -Signed-off-by: Ansuel Smith -Reviewed-by: Bjorn Andersson -Reviewed-by: Stephen Boyd -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220226135235.10051-16-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -298,13 +298,13 @@ - }; - - clocks { -- cxo_board { -+ cxo_board: cxo_board { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; - }; - -- pxo_board { -+ pxo_board: pxo_board { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; -@@ -736,7 +736,9 @@ - }; - - gcc: clock-controller@900000 { -- compatible = "qcom,gcc-ipq8064"; -+ compatible = "qcom,gcc-ipq8064", "syscon"; -+ clocks = <&pxo_board>, <&cxo_board>; -+ clock-names = "pxo", "cxo"; - reg = <0x00900000 0x4000>; - #clock-cells = <1>; - #reset-cells = <1>; diff --git a/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch b/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch deleted file mode 100644 index d0bc34c07fa..00000000000 --- a/target/linux/ipq806x/patches-6.1/103-v6.0-01-ARM-dts-qcom-replace-gcc-PXO-with-pxo_board-fixed-cl.patch +++ /dev/null @@ -1,29 +0,0 @@ -From eb9e93937756a05787977875830c0dc482cb57e0 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 30 Apr 2022 07:51:17 +0200 -Subject: [PATCH] ARM: dts: qcom: replace gcc PXO with pxo_board fixed clock - -Replace gcc PXO phandle to pxo_board fixed clock declared in the dts. -gcc driver doesn't provide PXO_SRC as it's a fixed-clock. This cause a -kernel panic if any driver actually try to use it. - -Fixes: 40cf5c884a96 ("ARM: dts: qcom: add L2CC and RPM for IPQ8064") -Signed-off-by: Ansuel Smith -Reviewed-by: Dmitry Baryshkov -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220430055118.1947-2-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -784,7 +784,7 @@ - l2cc: clock-controller@2011000 { - compatible = "qcom,kpss-gcc", "syscon"; - reg = <0x2011000 0x1000>; -- clocks = <&gcc PLL8_VOTE>, <&gcc PXO_SRC>; -+ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; - clock-names = "pll8_vote", "pxo"; - clock-output-names = "acpu_l2_aux"; - }; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch deleted file mode 100644 index 5dad164e3c2..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-01-ARM-dts-qcom-ipq8064-add-multiple-missing-pin-defini.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 4af1defb305798d1a064a5ea0d0c9b30e5eee185 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:35 +0200 -Subject: [PATCH 1/8] ARM: dts: qcom: ipq8064: add multiple missing pin - definition - -Add missing definition for mdio0 pins used for gpio-bitbang driver,i2c4 -pins and rgmii2 pins for ipq8064. - -Drop i2c4_pins node from ipq8064-ap148 dts as it's now moved to ipq8064 -dtsi. - -Drop mdio0_pins node from ipq8064-rb3011 dts as it's now moved to -ipq8064 dtsi. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-2-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 6 ----- - arch/arm/boot/dts/qcom-ipq8064-rb3011.dts | 9 ------- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 32 +++++++++++++++++++++++ - 3 files changed, 32 insertions(+), 15 deletions(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts -+++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts -@@ -305,15 +305,6 @@ - }; - }; - -- mdio0_pins: mdio0_pins { -- mux { -- pins = "gpio0", "gpio1"; -- function = "gpio"; -- drive-strength = <8>; -- bias-disable; -- }; -- }; -- - mdio1_pins: mdio1_pins { - mux { - pins = "gpio10", "gpio11"; ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -382,6 +382,13 @@ - }; - }; - -+ i2c4_pins: i2c4-default { -+ pins = "gpio12", "gpio13"; -+ function = "gsbi4"; -+ drive-strength = <12>; -+ bias-disable; -+ }; -+ - spi_pins: spi_pins { - mux { - pins = "gpio18", "gpio19", "gpio21"; -@@ -424,6 +431,8 @@ - - pullups { - pins = "gpio39"; -+ function = "nand"; -+ drive-strength = <10>; - bias-pull-up; - }; - -@@ -431,9 +440,32 @@ - pins = "gpio40", "gpio41", "gpio42", - "gpio43", "gpio44", "gpio45", - "gpio46", "gpio47"; -+ function = "nand"; -+ drive-strength = <10>; - bias-bus-hold; - }; - }; -+ -+ mdio0_pins: mdio0-pins { -+ mux { -+ pins = "gpio0", "gpio1"; -+ function = "mdio"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ }; -+ -+ rgmii2_pins: rgmii2-pins { -+ mux { -+ pins = "gpio27", "gpio28", "gpio29", -+ "gpio30", "gpio31", "gpio32", -+ "gpio51", "gpio52", "gpio59", -+ "gpio60", "gpio61", "gpio62"; -+ function = "rgmii2"; -+ drive-strength = <8>; -+ bias-disable; -+ }; -+ }; - }; - - intc: interrupt-controller@2000000 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch deleted file mode 100644 index 1f4e288fb81..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-02-ARM-dts-qcom-ipq8064-add-gsbi6-missing-definition.patch +++ /dev/null @@ -1,67 +0,0 @@ -From d883a12a547b6d42e795ff3b5ac87cfd013b5423 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:36 +0200 -Subject: [PATCH 2/8] ARM: dts: qcom: ipq8064: add gsbi6 missing definition - -Add gsbi6 missing definition for ipq8064. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-3-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 43 +++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -663,6 +663,49 @@ - }; - }; - -+ gsbi6: gsbi@16500000 { -+ compatible = "qcom,gsbi-v1.0.0"; -+ reg = <0x16500000 0x100>; -+ cell-index = <6>; -+ clocks = <&gcc GSBI6_H_CLK>; -+ clock-names = "iface"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ syscon-tcsr = <&tcsr>; -+ -+ status = "disabled"; -+ -+ gsbi6_i2c: i2c@16580000 { -+ compatible = "qcom,i2c-qup-v1.1.1"; -+ reg = <0x16580000 0x1000>; -+ interrupts = ; -+ -+ clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>; -+ clock-names = "core", "iface"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ -+ gsbi6_spi: spi@16580000 { -+ compatible = "qcom,spi-qup-v1.1.1"; -+ reg = <0x16580000 0x1000>; -+ interrupts = ; -+ -+ clocks = <&gcc GSBI6_QUP_CLK>, <&gcc GSBI6_H_CLK>; -+ clock-names = "core", "iface"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ }; -+ - gsbi7: gsbi@16600000 { - status = "disabled"; - compatible = "qcom,gsbi-v1.0.0"; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch deleted file mode 100644 index dbba722caaf..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-03-ARM-dts-qcom-ipq8064-add-specific-dtsi-with-smb208-r.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 5c47a46d5e942ea6b041c8b7727b201817c1ff76 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:37 +0200 -Subject: [PATCH 3/8] ARM: dts: qcom: ipq8064: add specific dtsi with smb208 - rpm regulators - -Add specific ipq8064 dtsi with smb208 rpm regulators. - -Qcom advise to use this configuration but it's not mandatory and OEM -can decide to implement their own regulators. -smb208 regulators are used to scale CPU voltage, L2 cache voltage and -Ubi32 cores. - -There regulators are controlled by rpm and to correctly works gsbi4-i2c -require to be NEVER disabled or rpm will reject any regulator change -request. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-4-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi | 37 ++++++++++++++++++++++ - 1 file changed, 37 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi - ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-smb208.dtsi -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include "qcom-ipq8064.dtsi" -+ -+&rpm { -+ smb208_regulators: regulators { -+ compatible = "qcom,rpm-smb208-regulators"; -+ -+ smb208_s1a: s1a { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s1b: s1b { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2a: s2a { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2b: s2b { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ }; -+}; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch deleted file mode 100644 index 1a3185f500d..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-04-ARM-dts-qcom-ipq8064-add-missing-snps-dwmac-compatib.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0ce34e0c13e99c239cce6099f64b0e95697f36b1 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:38 +0200 -Subject: [PATCH 4/8] ARM: dts: qcom: ipq8064: add missing snps,dwmac - compatible for gmac - -Add missing snps,dwmac compatible for gmac ipq8064 dtsi. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Reviewed-by: Krzysztof Kozlowski -Reviewed-by: Konrad Dybcio -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-5-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1042,7 +1042,7 @@ - - gmac0: ethernet@37000000 { - device_type = "network"; -- compatible = "qcom,ipq806x-gmac"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; - reg = <0x37000000 0x200000>; - interrupts = ; - interrupt-names = "macirq"; -@@ -1066,7 +1066,7 @@ - - gmac1: ethernet@37200000 { - device_type = "network"; -- compatible = "qcom,ipq806x-gmac"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; - reg = <0x37200000 0x200000>; - interrupts = ; - interrupt-names = "macirq"; -@@ -1090,7 +1090,7 @@ - - gmac2: ethernet@37400000 { - device_type = "network"; -- compatible = "qcom,ipq806x-gmac"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; - reg = <0x37400000 0x200000>; - interrupts = ; - interrupt-names = "macirq"; -@@ -1114,7 +1114,7 @@ - - gmac3: ethernet@37600000 { - device_type = "network"; -- compatible = "qcom,ipq806x-gmac"; -+ compatible = "qcom,ipq806x-gmac", "snps,dwmac"; - reg = <0x37600000 0x200000>; - interrupts = ; - interrupt-names = "macirq"; diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch deleted file mode 100644 index 43dac4b7fa2..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-05-ARM-dts-qcom-ipq8064-disable-usb-phy-by-default.patch +++ /dev/null @@ -1,37 +0,0 @@ -From d63d3124c0a5cdbe8b91d81b922fe56b2462e1b9 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:39 +0200 -Subject: [PATCH 5/8] ARM: dts: qcom: ipq8064: disable usb phy by default - -Disable usb phy by default. When the usb phy were pushed, half of them -were flagged as disabled by mistake. -Correctly disable all usb phy and enable them only if a device actually -use them. - -Signed-off-by: Christian Marangi -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-6-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1188,6 +1188,8 @@ - clocks = <&gcc USB30_1_UTMI_CLK>; - clock-names = "ref"; - #phy-cells = <0>; -+ -+ status = "disabled"; - }; - - ss_phy_1: phy@110f8830 { -@@ -1196,6 +1198,8 @@ - clocks = <&gcc USB30_1_MASTER_CLK>; - clock-names = "ref"; - #phy-cells = <0>; -+ -+ status = "disabled"; - }; - - usb3_1: usb3@110f8800 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch deleted file mode 100644 index ca5e5aa3c4c..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-07-ARM-dts-qcom-ipq8064-fix-and-add-some-missing-gsbi-n.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 6c421a9c08286389bb331fe783e2625c9efcc187 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:41 +0200 -Subject: [PATCH 7/8] ARM: dts: qcom: ipq8064: fix and add some missing gsbi - node - -Add some tag for gsbi to make them usable for ipq8064 SoC. Add missing -gsbi7 i2c node and gsbi1 node. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-8-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 54 ++++++++++++++++++++++++++++- - 1 file changed, 53 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -539,6 +539,44 @@ - regulator; - }; - -+ gsbi1: gsbi@12440000 { -+ compatible = "qcom,gsbi-v1.0.0"; -+ reg = <0x12440000 0x100>; -+ cell-index = <1>; -+ clocks = <&gcc GSBI1_H_CLK>; -+ clock-names = "iface"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ syscon-tcsr = <&tcsr>; -+ -+ status = "disabled"; -+ -+ gsbi1_serial: serial@12450000 { -+ compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; -+ reg = <0x12450000 0x100>, -+ <0x12400000 0x03>; -+ interrupts = ; -+ clocks = <&gcc GSBI1_UART_CLK>, <&gcc GSBI1_H_CLK>; -+ clock-names = "core", "iface"; -+ -+ status = "disabled"; -+ }; -+ -+ gsbi1_i2c: i2c@12460000 { -+ compatible = "qcom,i2c-qup-v1.1.1"; -+ reg = <0x12460000 0x1000>; -+ interrupts = ; -+ clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>; -+ clock-names = "core", "iface"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ }; -+ }; -+ - gsbi2: gsbi@12480000 { - compatible = "qcom,gsbi-v1.0.0"; - cell-index = <2>; -@@ -562,7 +600,7 @@ - status = "disabled"; - }; - -- i2c@124a0000 { -+ gsbi2_i2c: i2c@124a0000 { - compatible = "qcom,i2c-qup-v1.1.1"; - reg = <0x124a0000 0x1000>; - interrupts = ; -@@ -727,6 +765,20 @@ - clock-names = "core", "iface"; - status = "disabled"; - }; -+ -+ gsbi7_i2c: i2c@16680000 { -+ compatible = "qcom,i2c-qup-v1.1.1"; -+ reg = <0x16680000 0x1000>; -+ interrupts = ; -+ -+ clocks = <&gcc GSBI7_QUP_CLK>, <&gcc GSBI7_H_CLK>; -+ clock-names = "core", "iface"; -+ -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ status = "disabled"; -+ }; - }; - - rng@1a500000 { diff --git a/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch b/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch deleted file mode 100644 index 463c3d4a658..00000000000 --- a/target/linux/ipq806x/patches-6.1/104-v6.0-08-ARM-dts-qcom-ipq8064-add-speedbin-efuse-nvmem-node.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 7f5aecdd4ffcc018f73171bc0e028cd4e3361acd Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 03:09:43 +0200 -Subject: [PATCH 8/8] ARM: dts: qcom: ipq8064: add speedbin efuse nvmem node - -Add speedbin efuse nvmem cell needed for the opp table for the CPU -freqs. - -Signed-off-by: Christian Marangi -Tested-by: Jonathan McDowell -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707010943.20857-10-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -854,6 +854,9 @@ - reg = <0x00700000 0x1000>; - #address-cells = <1>; - #size-cells = <1>; -+ speedbin_efuse: speedbin@c0 { -+ reg = <0xc0 0x4>; -+ }; - tsens_calib: calib@400 { - reg = <0x400 0xb>; - }; diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch deleted file mode 100644 index 2c6f6b10c48..00000000000 --- a/target/linux/ipq806x/patches-6.1/105-v6.0-01-hwspinlock-qcom-Add-support-for-mmio-usage-to-sfpb-m.patch +++ /dev/null @@ -1,71 +0,0 @@ -From cdab30b44518513003607ecfc8a22de3dbbb78ed Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 12:20:38 +0200 -Subject: [PATCH 1/1] hwspinlock: qcom: Add support for mmio usage to - sfpb-mutex - -Allow sfpb-mutex to use mmio in addition to syscon. - -Signed-off-by: Christian Marangi -Reviewed-by: Bjorn Andersson -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707102040.1859-1-ansuelsmth@gmail.com ---- - drivers/hwspinlock/qcom_hwspinlock.c | 28 +++++++++++++++++++++++----- - 1 file changed, 23 insertions(+), 5 deletions(-) - ---- a/drivers/hwspinlock/qcom_hwspinlock.c -+++ b/drivers/hwspinlock/qcom_hwspinlock.c -@@ -19,6 +19,11 @@ - #define QCOM_MUTEX_APPS_PROC_ID 1 - #define QCOM_MUTEX_NUM_LOCKS 32 - -+struct qcom_hwspinlock_of_data { -+ u32 offset; -+ u32 stride; -+}; -+ - static int qcom_hwspinlock_trylock(struct hwspinlock *lock) - { - struct regmap_field *field = lock->priv; -@@ -63,9 +68,20 @@ static const struct hwspinlock_ops qcom_ - .unlock = qcom_hwspinlock_unlock, - }; - -+static const struct qcom_hwspinlock_of_data of_sfpb_mutex = { -+ .offset = 0x4, -+ .stride = 0x4, -+}; -+ -+/* All modern platform has offset 0 and stride of 4k */ -+static const struct qcom_hwspinlock_of_data of_tcsr_mutex = { -+ .offset = 0, -+ .stride = 0x1000, -+}; -+ - static const struct of_device_id qcom_hwspinlock_of_match[] = { -- { .compatible = "qcom,sfpb-mutex" }, -- { .compatible = "qcom,tcsr-mutex" }, -+ { .compatible = "qcom,sfpb-mutex", .data = &of_sfpb_mutex }, -+ { .compatible = "qcom,tcsr-mutex", .data = &of_tcsr_mutex }, - { } - }; - MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match); -@@ -112,12 +128,14 @@ static const struct regmap_config tcsr_m - static struct regmap *qcom_hwspinlock_probe_mmio(struct platform_device *pdev, - u32 *offset, u32 *stride) - { -+ const struct qcom_hwspinlock_of_data *data; - struct device *dev = &pdev->dev; - void __iomem *base; - -- /* All modern platform has offset 0 and stride of 4k */ -- *offset = 0; -- *stride = 0x1000; -+ data = of_device_get_match_data(dev); -+ -+ *offset = data->offset; -+ *stride = data->stride; - - base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(base)) diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch deleted file mode 100644 index d8303442f7e..00000000000 --- a/target/linux/ipq806x/patches-6.1/105-v6.0-02-ARM-dts-qcom-ipq8064-add-missing-hwlock.patch +++ /dev/null @@ -1,31 +0,0 @@ -From fbe4be367b2169602f6a5949a20d2917b25714d4 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 12:20:39 +0200 -Subject: [PATCH 1/2] ARM: dts: qcom: ipq8064: add missing hwlock - -Add missing hwlock for ipq8064 dtsi provided by qcom,sfpb-mutex. - -Signed-off-by: Christian Marangi -Acked-by: Krzysztof Kozlowski -[bjorn: Moved the node inside /soc] -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707102040.1859-2-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1357,5 +1357,12 @@ - dma-names = "tx", "rx"; - }; - }; -+ -+ sfpb_mutex: hwlock@1200600 { -+ compatible = "qcom,sfpb-mutex"; -+ reg = <0x01200600 0x100>; -+ -+ #hwlock-cells = <1>; -+ }; - }; - }; diff --git a/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch b/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch deleted file mode 100644 index 8b91eeb5116..00000000000 --- a/target/linux/ipq806x/patches-6.1/105-v6.0-03-ARM-dts-qcom-ipq8064-add-missing-smem-compatible.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4fefb5434c4b735daf913abaef12431405368031 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 12:20:40 +0200 -Subject: [PATCH 2/2] ARM: dts: qcom: ipq8064: add missing smem compatible - -Add missing smem compatible and hwlocks phandle for ipq8064 dtsi -smem node. - -Signed-off-by: Christian Marangi -Acked-by: Krzysztof Kozlowski -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220707102040.1859-3-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-ipq8064.dtsi | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -292,8 +292,11 @@ - }; - - smem: smem@41000000 { -+ compatible = "qcom,smem"; - reg = <0x41000000 0x200000>; - no-map; -+ -+ hwlocks = <&sfpb_mutex 3>; - }; - }; - diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch deleted file mode 100644 index 8b20a550f6f..00000000000 --- a/target/linux/ipq806x/patches-6.1/106-v6.1-01-ARM-dts-qcom-ipq8064-add-v2-dtsi-variant.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 9f7097a8b1948533a6db1b53b5c0480cc75bbd16 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Mon, 18 Jul 2022 18:05:16 +0200 -Subject: [PATCH 1/3] ARM: dts: qcom: ipq8064: add v2 dtsi variant - -Add ipq8064-v2.0 dtsi variant that differ from original ipq8064 SoC for -some additional pcie, sata and usb configuration values, additional -reserved memory and serial output. - -Signed-off-by: Christian Marangi ---- - .../boot/dts/qcom-ipq8064-v2.0-smb208.dtsi | 37 ++++++++++ - arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi | 69 +++++++++++++++++++ - 2 files changed, 106 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi - create mode 100644 arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi - ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-v2.0-smb208.dtsi -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include "qcom-ipq8064-v2.0.dtsi" -+ -+&rpm { -+ smb208_regulators: regulators { -+ compatible = "qcom,rpm-smb208-regulators"; -+ -+ smb208_s1a: s1a { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s1b: s1b { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2a: s2a { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2b: s2b { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1250000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8064-v2.0.dtsi -@@ -0,0 +1,69 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include "qcom-ipq8064.dtsi" -+ -+/ { -+ model = "Qualcomm Technologies, Inc. IPQ8064-v2.0"; -+ -+ aliases { -+ serial0 = &gsbi4_serial; -+ }; -+ -+ chosen { -+ stdout-path = "serial0:115200n8"; -+ }; -+ -+ reserved-memory { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges; -+ -+ rsvd@41200000 { -+ reg = <0x41200000 0x300000>; -+ no-map; -+ }; -+ }; -+}; -+ -+&gsbi4 { -+ qcom,mode = ; -+ status = "okay"; -+ -+ serial@16340000 { -+ status = "okay"; -+ }; -+ /* -+ * The i2c device on gsbi4 should not be enabled. -+ * On ipq806x designs gsbi4 i2c is meant for exclusive -+ * RPM usage. Turning this on in kernel manifests as -+ * i2c failure for the RPM. -+ */ -+}; -+ -+&pcie0 { -+ compatible = "qcom,pcie-ipq8064-v2"; -+}; -+ -+&pcie1 { -+ compatible = "qcom,pcie-ipq8064-v2"; -+}; -+ -+&pcie2 { -+ compatible = "qcom,pcie-ipq8064-v2"; -+}; -+ -+&sata { -+ ports-implemented = <0x1>; -+}; -+ -+&ss_phy_0 { -+ qcom,rx-eq = <2>; -+ qcom,tx-deamp_3_5db = <32>; -+ qcom,mpll = <5>; -+}; -+ -+&ss_phy_1 { -+ qcom,rx-eq = <2>; -+ qcom,tx-deamp_3_5db = <32>; -+ qcom,mpll = <5>; -+}; diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch deleted file mode 100644 index fdff292480e..00000000000 --- a/target/linux/ipq806x/patches-6.1/106-v6.1-02-ARM-dts-qcom-ipq8064-add-ipq8062-variant.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 41d9fa8de7845bd92d9c963196fdfd7ea9232bb2 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Mon, 18 Jul 2022 18:07:26 +0200 -Subject: [PATCH 2/3] ARM: dts: qcom: ipq8064: add ipq8062 variant - -ipq8062 SoC is based on ipq8064-v2.0 with lower supported freq, lack of -usb port and a reduced voltage output with the smb208 regulators. - -Signed-off-by: Christian Marangi ---- - arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi | 37 ++++++++++++++++++++++ - arch/arm/boot/dts/qcom-ipq8062.dtsi | 8 +++++ - 2 files changed, 45 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi - create mode 100644 arch/arm/boot/dts/qcom-ipq8062.dtsi - ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8062-smb208.dtsi -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include "qcom-ipq8062.dtsi" -+ -+&rpm { -+ smb208_regulators: regulators { -+ compatible = "qcom,rpm-smb208-regulators"; -+ -+ smb208_s1a: s1a { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s1b: s1b { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2a: s2a { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2b: s2b { -+ regulator-min-microvolt = < 800000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8062.dtsi -@@ -0,0 +1,8 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+ -+#include "qcom-ipq8064-v2.0.dtsi" -+ -+/ { -+ model = "Qualcomm Technologies, Inc. IPQ8062"; -+ compatible = "qcom,ipq8062", "qcom,ipq8064"; -+}; diff --git a/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch b/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch deleted file mode 100644 index bccc577b91c..00000000000 --- a/target/linux/ipq806x/patches-6.1/106-v6.1-03-ARM-dts-qcom-ipq8064-add-ipq8065-variant.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 01e7aa3fe6f76f7960f2382038136235eee9c6cd Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Mon, 18 Jul 2022 18:09:35 +0200 -Subject: [PATCH 3/3] ARM: dts: qcom: ipq8064: add ipq8065 variant - -ipq8065 SoC is based on ipq8064-v2.0 with a more clocked CPU and -an increased voltage output with the smb208 regulators. - -Signed-off-by: Christian Marangi ---- - arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi | 37 ++++++++++++++++++++++ - arch/arm/boot/dts/qcom-ipq8065.dtsi | 8 +++++ - 2 files changed, 45 insertions(+) - create mode 100644 arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi - create mode 100644 arch/arm/boot/dts/qcom-ipq8065.dtsi - ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8065-smb208.dtsi -@@ -0,0 +1,37 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include "qcom-ipq8065.dtsi" -+ -+&rpm { -+ smb208_regulators: regulators { -+ compatible = "qcom,rpm-smb208-regulators"; -+ -+ smb208_s1a: s1a { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s1b: s1b { -+ regulator-min-microvolt = <1050000>; -+ regulator-max-microvolt = <1150000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2a: s2a { -+ regulator-min-microvolt = <775000>; -+ regulator-max-microvolt = <1275000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ -+ smb208_s2b: s2b { -+ regulator-min-microvolt = <775000>; -+ regulator-max-microvolt = <1275000>; -+ -+ qcom,switch-mode-frequency = <1200000>; -+ }; -+ }; -+}; ---- /dev/null -+++ b/arch/arm/boot/dts/qcom-ipq8065.dtsi -@@ -0,0 +1,8 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include "qcom-ipq8064-v2.0.dtsi" -+ -+/ { -+ model = "Qualcomm Technologies, Inc. IPQ8065"; -+ compatible = "qcom,ipq8065", "qcom,ipq8064"; -+}; diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch deleted file mode 100644 index 72e70b613c8..00000000000 --- a/target/linux/ipq806x/patches-6.1/109-v6.1-01-dt-bindings-clock-add-pcm-reset-for-ipq806x-lcc.patch +++ /dev/null @@ -1,29 +0,0 @@ -From fc7dc1d0c10e8e3d72b68ddae8a61c8aa02a62c1 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 15 Jun 2022 17:13:32 +0200 -Subject: [PATCH v4 1/3] dt-bindings: clock: add pcm reset for ipq806x lcc - -Add pcm reset define for ipq806x lcc. - -Signed-off-by: Christian Marangi -Reviewed-by: Dmitry Baryshkov -Acked-by: Rob Herring ---- -v3: - - Added review tag - - Added ack tag -v2: - - Fix Sob tag - - include/dt-bindings/clock/qcom,lcc-ipq806x.h | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/include/dt-bindings/clock/qcom,lcc-ipq806x.h -+++ b/include/dt-bindings/clock/qcom,lcc-ipq806x.h -@@ -19,4 +19,6 @@ - #define SPDIF_CLK 10 - #define AHBIX_CLK 11 - -+#define LCC_PCM_RESET 0 -+ - #endif diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch deleted file mode 100644 index 23936513064..00000000000 --- a/target/linux/ipq806x/patches-6.1/109-v6.1-02-clk-qcom-lcc-ipq806x-add-reset-definition.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 3587d768bdf4683a53244be1acca5d095044671f Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 15 Jun 2022 17:19:55 +0200 -Subject: [PATCH v4 2/3] clk: qcom: lcc-ipq806x: add reset definition - -Add reset definition for lcc-ipq806x. - -Signed-off-by: Christian Marangi -Reviewed-by: Dmitry Baryshkov ---- -v3: - - Added review tag -v2: - - Fix Sob tag - - drivers/clk/qcom/lcc-ipq806x.c | 7 +++++++ - 1 file changed, 7 insertions(+) - ---- a/drivers/clk/qcom/lcc-ipq806x.c -+++ b/drivers/clk/qcom/lcc-ipq806x.c -@@ -22,6 +22,7 @@ - #include "clk-branch.h" - #include "clk-regmap-divider.h" - #include "clk-regmap-mux.h" -+#include "reset.h" - - static struct clk_pll pll4 = { - .l_reg = 0x4, -@@ -405,6 +406,10 @@ static struct clk_regmap *lcc_ipq806x_cl - [AHBIX_CLK] = &ahbix_clk.clkr, - }; - -+static const struct qcom_reset_map lcc_ipq806x_resets[] = { -+ [LCC_PCM_RESET] = { 0x54, 13 }, -+}; -+ - static const struct regmap_config lcc_ipq806x_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, -@@ -417,6 +422,8 @@ static const struct qcom_cc_desc lcc_ipq - .config = &lcc_ipq806x_regmap_config, - .clks = lcc_ipq806x_clks, - .num_clks = ARRAY_SIZE(lcc_ipq806x_clks), -+ .resets = lcc_ipq806x_resets, -+ .num_resets = ARRAY_SIZE(lcc_ipq806x_resets), - }; - - static const struct of_device_id lcc_ipq806x_match_table[] = { diff --git a/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch b/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch deleted file mode 100644 index 905dc5bf40b..00000000000 --- a/target/linux/ipq806x/patches-6.1/109-v6.1-03-clk-qcom-lcc-ipq806x-convert-to-parent-data.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 92ef900a4a53b62e0dc32554eb088a422657606c Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Wed, 15 Jun 2022 17:35:13 +0200 -Subject: [PATCH v5 3/3] clk: qcom: lcc-ipq806x: convert to parent data - -Convert lcc-ipq806x driver to parent_data API. - -Signed-off-by: Christian Marangi ---- -v5: -- Fix the same compilation error (don't know what the hell happen - to my buildroot) -v4: -- Fix compilation error -v3: - - Inline pxo pll4 parent - - Change .name from pxo to pxo_board - - drivers/clk/qcom/lcc-ipq806x.c | 77 ++++++++++++++++++---------------- - 1 file changed, 42 insertions(+), 35 deletions(-) - ---- a/drivers/clk/qcom/lcc-ipq806x.c -+++ b/drivers/clk/qcom/lcc-ipq806x.c -@@ -34,7 +34,9 @@ static struct clk_pll pll4 = { - .status_bit = 16, - .clkr.hw.init = &(struct clk_init_data){ - .name = "pll4", -- .parent_names = (const char *[]){ "pxo" }, -+ .parent_data = &(const struct clk_parent_data) { -+ .fw_name = "pxo", .name = "pxo_board", -+ }, - .num_parents = 1, - .ops = &clk_pll_ops, - }, -@@ -64,9 +66,9 @@ static const struct parent_map lcc_pxo_p - { P_PLL4, 2 } - }; - --static const char * const lcc_pxo_pll4[] = { -- "pxo", -- "pll4_vote", -+static const struct clk_parent_data lcc_pxo_pll4[] = { -+ { .fw_name = "pxo", .name = "pxo" }, -+ { .fw_name = "pll4_vote", .name = "pll4_vote" }, - }; - - static struct freq_tbl clk_tbl_aif_mi2s[] = { -@@ -131,18 +133,14 @@ static struct clk_rcg mi2s_osr_src = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "mi2s_osr_src", -- .parent_names = lcc_pxo_pll4, -- .num_parents = 2, -+ .parent_data = lcc_pxo_pll4, -+ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, - }, - }; - --static const char * const lcc_mi2s_parents[] = { -- "mi2s_osr_src", --}; -- - static struct clk_branch mi2s_osr_clk = { - .halt_reg = 0x50, - .halt_bit = 1, -@@ -152,7 +150,9 @@ static struct clk_branch mi2s_osr_clk = - .enable_mask = BIT(17), - .hw.init = &(struct clk_init_data){ - .name = "mi2s_osr_clk", -- .parent_names = lcc_mi2s_parents, -+ .parent_hws = (const struct clk_hw*[]){ -+ &mi2s_osr_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -167,7 +167,9 @@ static struct clk_regmap_div mi2s_div_cl - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "mi2s_div_clk", -- .parent_names = lcc_mi2s_parents, -+ .parent_hws = (const struct clk_hw*[]){ -+ &mi2s_osr_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_regmap_div_ops, - }, -@@ -183,7 +185,9 @@ static struct clk_branch mi2s_bit_div_cl - .enable_mask = BIT(15), - .hw.init = &(struct clk_init_data){ - .name = "mi2s_bit_div_clk", -- .parent_names = (const char *[]){ "mi2s_div_clk" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &mi2s_div_clk.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -191,6 +195,10 @@ static struct clk_branch mi2s_bit_div_cl - }, - }; - -+static const struct clk_parent_data lcc_mi2s_bit_div_codec_clk[] = { -+ { .hw = &mi2s_bit_div_clk.clkr.hw, }, -+ { .fw_name = "mi2s_codec_clk", .name = "mi2s_codec_clk" }, -+}; - - static struct clk_regmap_mux mi2s_bit_clk = { - .reg = 0x48, -@@ -199,11 +207,8 @@ static struct clk_regmap_mux mi2s_bit_cl - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "mi2s_bit_clk", -- .parent_names = (const char *[]){ -- "mi2s_bit_div_clk", -- "mi2s_codec_clk", -- }, -- .num_parents = 2, -+ .parent_data = lcc_mi2s_bit_div_codec_clk, -+ .num_parents = ARRAY_SIZE(lcc_mi2s_bit_div_codec_clk), - .ops = &clk_regmap_mux_closest_ops, - .flags = CLK_SET_RATE_PARENT, - }, -@@ -245,8 +250,8 @@ static struct clk_rcg pcm_src = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "pcm_src", -- .parent_names = lcc_pxo_pll4, -- .num_parents = 2, -+ .parent_data = lcc_pxo_pll4, -+ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, -@@ -262,7 +267,9 @@ static struct clk_branch pcm_clk_out = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "pcm_clk_out", -- .parent_names = (const char *[]){ "pcm_src" }, -+ .parent_hws = (const struct clk_hw*[]){ -+ &pcm_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -270,6 +277,11 @@ static struct clk_branch pcm_clk_out = { - }, - }; - -+static const struct clk_parent_data lcc_pcm_clk_out_codec_clk[] = { -+ { .hw = &pcm_clk_out.clkr.hw, }, -+ { .fw_name = "pcm_codec_clk", .name = "pcm_codec_clk" }, -+}; -+ - static struct clk_regmap_mux pcm_clk = { - .reg = 0x54, - .shift = 10, -@@ -277,11 +289,8 @@ static struct clk_regmap_mux pcm_clk = { - .clkr = { - .hw.init = &(struct clk_init_data){ - .name = "pcm_clk", -- .parent_names = (const char *[]){ -- "pcm_clk_out", -- "pcm_codec_clk", -- }, -- .num_parents = 2, -+ .parent_data = lcc_pcm_clk_out_codec_clk, -+ .num_parents = ARRAY_SIZE(lcc_pcm_clk_out_codec_clk), - .ops = &clk_regmap_mux_closest_ops, - .flags = CLK_SET_RATE_PARENT, - }, -@@ -325,18 +334,14 @@ static struct clk_rcg spdif_src = { - .enable_mask = BIT(9), - .hw.init = &(struct clk_init_data){ - .name = "spdif_src", -- .parent_names = lcc_pxo_pll4, -- .num_parents = 2, -+ .parent_data = lcc_pxo_pll4, -+ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), - .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, - }, - }, - }; - --static const char * const lcc_spdif_parents[] = { -- "spdif_src", --}; -- - static struct clk_branch spdif_clk = { - .halt_reg = 0xd4, - .halt_bit = 1, -@@ -346,7 +351,9 @@ static struct clk_branch spdif_clk = { - .enable_mask = BIT(12), - .hw.init = &(struct clk_init_data){ - .name = "spdif_clk", -- .parent_names = lcc_spdif_parents, -+ .parent_hws = (const struct clk_hw*[]){ -+ &spdif_src.clkr.hw, -+ }, - .num_parents = 1, - .ops = &clk_branch_ops, - .flags = CLK_SET_RATE_PARENT, -@@ -384,8 +391,8 @@ static struct clk_rcg ahbix_clk = { - .enable_mask = BIT(11), - .hw.init = &(struct clk_init_data){ - .name = "ahbix", -- .parent_names = lcc_pxo_pll4, -- .num_parents = 2, -+ .parent_data = lcc_pxo_pll4, -+ .num_parents = ARRAY_SIZE(lcc_pxo_pll4), - .ops = &clk_rcg_lcc_ops, - }, - }, diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch deleted file mode 100644 index 6b7a68952ea..00000000000 --- a/target/linux/ipq806x/patches-6.1/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch +++ /dev/null @@ -1,113 +0,0 @@ -From 713472e53e6e53c985e283782b0fd76b8ecfd47e Mon Sep 17 00:00:00 2001 -From: Chanwoo Choi -Date: Mon, 1 Mar 2021 02:07:29 +0900 -Subject: [PATCH 1/5] PM / devfreq: Export devfreq_get_freq_range symbol within - devfreq - -In order to get frequency range within devfreq governors, -export devfreq_get_freq_range symbol within devfreq. - -Reviewed-by: Matthias Kaehlcke -Tested-by: Chen-Yu Tsai -Tested-by: Johnson Wang -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/devfreq.c | 20 ++++++++++++-------- - drivers/devfreq/governor.h | 2 ++ - 2 files changed, 14 insertions(+), 8 deletions(-) - ---- a/drivers/devfreq/devfreq.c -+++ b/drivers/devfreq/devfreq.c -@@ -112,16 +112,16 @@ static unsigned long find_available_max_ - } - - /** -- * get_freq_range() - Get the current freq range -+ * devfreq_get_freq_range() - Get the current freq range - * @devfreq: the devfreq instance - * @min_freq: the min frequency - * @max_freq: the max frequency - * - * This takes into consideration all constraints. - */ --static void get_freq_range(struct devfreq *devfreq, -- unsigned long *min_freq, -- unsigned long *max_freq) -+void devfreq_get_freq_range(struct devfreq *devfreq, -+ unsigned long *min_freq, -+ unsigned long *max_freq) - { - unsigned long *freq_table = devfreq->profile->freq_table; - s32 qos_min_freq, qos_max_freq; -@@ -158,6 +158,7 @@ static void get_freq_range(struct devfre - if (*min_freq > *max_freq) - *min_freq = *max_freq; - } -+EXPORT_SYMBOL(devfreq_get_freq_range); - - /** - * devfreq_get_freq_level() - Lookup freq_table for the frequency -@@ -418,7 +419,7 @@ int devfreq_update_target(struct devfreq - err = devfreq->governor->get_target_freq(devfreq, &freq); - if (err) - return err; -- get_freq_range(devfreq, &min_freq, &max_freq); -+ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); - - if (freq < min_freq) { - freq = min_freq; -@@ -784,6 +785,7 @@ struct devfreq *devfreq_add_device(struc - { - struct devfreq *devfreq; - struct devfreq_governor *governor; -+ unsigned long min_freq, max_freq; - int err = 0; - - if (!dev || !profile || !governor_name) { -@@ -848,6 +850,8 @@ struct devfreq *devfreq_add_device(struc - goto err_dev; - } - -+ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); -+ - devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); - devfreq->opp_table = dev_pm_opp_get_opp_table(dev); - if (IS_ERR(devfreq->opp_table)) -@@ -1559,7 +1563,7 @@ static ssize_t min_freq_show(struct devi - unsigned long min_freq, max_freq; - - mutex_lock(&df->lock); -- get_freq_range(df, &min_freq, &max_freq); -+ devfreq_get_freq_range(df, &min_freq, &max_freq); - mutex_unlock(&df->lock); - - return sprintf(buf, "%lu\n", min_freq); -@@ -1613,7 +1617,7 @@ static ssize_t max_freq_show(struct devi - unsigned long min_freq, max_freq; - - mutex_lock(&df->lock); -- get_freq_range(df, &min_freq, &max_freq); -+ devfreq_get_freq_range(df, &min_freq, &max_freq); - mutex_unlock(&df->lock); - - return sprintf(buf, "%lu\n", max_freq); -@@ -1927,7 +1931,7 @@ static int devfreq_summary_show(struct s - - mutex_lock(&devfreq->lock); - cur_freq = devfreq->previous_freq; -- get_freq_range(devfreq, &min_freq, &max_freq); -+ devfreq_get_freq_range(devfreq, &min_freq, &max_freq); - timer = devfreq->profile->timer; - - if (IS_SUPPORTED_ATTR(devfreq->governor->attrs, POLLING_INTERVAL)) ---- a/drivers/devfreq/governor.h -+++ b/drivers/devfreq/governor.h -@@ -86,6 +86,8 @@ int devfreq_remove_governor(struct devfr - - int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); - int devfreq_update_target(struct devfreq *devfreq, unsigned long freq); -+void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq, -+ unsigned long *max_freq); - - static inline int devfreq_update_stats(struct devfreq *df) - { diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch deleted file mode 100644 index 3dd61985b28..00000000000 --- a/target/linux/ipq806x/patches-6.1/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch +++ /dev/null @@ -1,461 +0,0 @@ -From a03dacb0316f74400846aaf144d6c73f4217ca08 Mon Sep 17 00:00:00 2001 -From: Saravana Kannan -Date: Tue, 2 Mar 2021 15:58:21 +0900 -Subject: [PATCH 2/5] PM / devfreq: Add cpu based scaling support to passive - governor - -Many CPU architectures have caches that can scale independent of the -CPUs. Frequency scaling of the caches is necessary to make sure that the -cache is not a performance bottleneck that leads to poor performance and -power. The same idea applies for RAM/DDR. - -To achieve this, this patch adds support for cpu based scaling to the -passive governor. This is accomplished by taking the current frequency -of each CPU frequency domain and then adjust the frequency of the cache -(or any devfreq device) based on the frequency of the CPUs. It listens -to CPU frequency transition notifiers to keep itself up to date on the -current CPU frequency. - -To decide the frequency of the device, the governor does one of the -following: -* Derives the optimal devfreq device opp from required-opps property of - the parent cpu opp_table. - -* Scales the device frequency in proportion to the CPU frequency. So, if - the CPUs are running at their max frequency, the device runs at its - max frequency. If the CPUs are running at their min frequency, the - device runs at its min frequency. It is interpolated for frequencies - in between. - -Tested-by: Chen-Yu Tsai -Tested-by: Johnson Wang -Signed-off-by: Saravana Kannan -[Sibi: Integrated cpu-freqmap governor into passive_governor] -Signed-off-by: Sibi Sankar -[Chanwoo: Fix conflict with latest code and cleanup code] -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/governor.h | 22 +++ - drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++++++++++-- - include/linux/devfreq.h | 17 +- - 3 files changed, 323 insertions(+), 14 deletions(-) - ---- a/drivers/devfreq/governor.h -+++ b/drivers/devfreq/governor.h -@@ -48,6 +48,28 @@ - #define DEVFREQ_GOV_ATTR_TIMER BIT(1) - - /** -+ * struct devfreq_cpu_data - Hold the per-cpu data -+ * @dev: reference to cpu device. -+ * @first_cpu: the cpumask of the first cpu of a policy. -+ * @opp_table: reference to cpu opp table. -+ * @cur_freq: the current frequency of the cpu. -+ * @min_freq: the min frequency of the cpu. -+ * @max_freq: the max frequency of the cpu. -+ * -+ * This structure stores the required cpu_data of a cpu. -+ * This is auto-populated by the governor. -+ */ -+struct devfreq_cpu_data { -+ struct device *dev; -+ unsigned int first_cpu; -+ -+ struct opp_table *opp_table; -+ unsigned int cur_freq; -+ unsigned int min_freq; -+ unsigned int max_freq; -+}; -+ -+/** - * struct devfreq_governor - Devfreq policy governor - * @node: list node - contains registered devfreq governors - * @name: Governor's name ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -8,11 +8,85 @@ - */ - - #include -+#include -+#include -+#include -+#include - #include - #include - #include "governor.h" - --static int devfreq_passive_get_target_freq(struct devfreq *devfreq, -+#define HZ_PER_KHZ 1000 -+ -+static unsigned long get_target_freq_by_required_opp(struct device *p_dev, -+ struct opp_table *p_opp_table, -+ struct opp_table *opp_table, -+ unsigned long *freq) -+{ -+ struct dev_pm_opp *opp = NULL, *p_opp = NULL; -+ unsigned long target_freq; -+ -+ if (!p_dev || !p_opp_table || !opp_table || !freq) -+ return 0; -+ -+ p_opp = devfreq_recommended_opp(p_dev, freq, 0); -+ if (IS_ERR(p_opp)) -+ return 0; -+ -+ opp = dev_pm_opp_xlate_required_opp(p_opp_table, opp_table, p_opp); -+ dev_pm_opp_put(p_opp); -+ -+ if (IS_ERR(opp)) -+ return 0; -+ -+ target_freq = dev_pm_opp_get_freq(opp); -+ dev_pm_opp_put(opp); -+ -+ return target_freq; -+} -+ -+static int get_target_freq_with_cpufreq(struct devfreq *devfreq, -+ unsigned long *target_freq) -+{ -+ struct devfreq_passive_data *p_data = -+ (struct devfreq_passive_data *)devfreq->data; -+ struct devfreq_cpu_data *parent_cpu_data; -+ unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent; -+ unsigned long dev_min, dev_max; -+ unsigned long freq = 0; -+ -+ for_each_online_cpu(cpu) { -+ parent_cpu_data = p_data->parent_cpu_data[cpu]; -+ if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu) -+ continue; -+ -+ /* Get target freq via required opps */ -+ cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ; -+ freq = get_target_freq_by_required_opp(parent_cpu_data->dev, -+ parent_cpu_data->opp_table, -+ devfreq->opp_table, &cpu_cur); -+ if (freq) { -+ *target_freq = max(freq, *target_freq); -+ continue; -+ } -+ -+ /* Use interpolation if required opps is not available */ -+ devfreq_get_freq_range(devfreq, &dev_min, &dev_max); -+ -+ cpu_min = parent_cpu_data->min_freq; -+ cpu_max = parent_cpu_data->max_freq; -+ cpu_cur = parent_cpu_data->cur_freq; -+ -+ cpu_percent = ((cpu_cur - cpu_min) * 100) / (cpu_max - cpu_min); -+ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); -+ -+ *target_freq = max(freq, *target_freq); -+ } -+ -+ return 0; -+} -+ -+static int get_target_freq_with_devfreq(struct devfreq *devfreq, - unsigned long *freq) - { - struct devfreq_passive_data *p_data -@@ -99,6 +173,181 @@ no_required_opp: - return 0; - } - -+static int devfreq_passive_get_target_freq(struct devfreq *devfreq, -+ unsigned long *freq) -+{ -+ struct devfreq_passive_data *p_data = -+ (struct devfreq_passive_data *)devfreq->data; -+ int ret; -+ -+ if (!p_data) -+ return -EINVAL; -+ -+ /* -+ * If the devfreq device with passive governor has the specific method -+ * to determine the next frequency, should use the get_target_freq() -+ * of struct devfreq_passive_data. -+ */ -+ if (p_data->get_target_freq) -+ return p_data->get_target_freq(devfreq, freq); -+ -+ switch (p_data->parent_type) { -+ case DEVFREQ_PARENT_DEV: -+ ret = get_target_freq_with_devfreq(devfreq, freq); -+ break; -+ case CPUFREQ_PARENT_DEV: -+ ret = get_target_freq_with_cpufreq(devfreq, freq); -+ break; -+ default: -+ ret = -EINVAL; -+ dev_err(&devfreq->dev, "Invalid parent type\n"); -+ break; -+ } -+ -+ return ret; -+} -+ -+static int cpufreq_passive_notifier_call(struct notifier_block *nb, -+ unsigned long event, void *ptr) -+{ -+ struct devfreq_passive_data *p_data = -+ container_of(nb, struct devfreq_passive_data, nb); -+ struct devfreq *devfreq = (struct devfreq *)p_data->this; -+ struct devfreq_cpu_data *parent_cpu_data; -+ struct cpufreq_freqs *freqs = ptr; -+ unsigned int cur_freq; -+ int ret; -+ -+ if (event != CPUFREQ_POSTCHANGE || !freqs || -+ !p_data->parent_cpu_data[freqs->policy->cpu]) -+ return 0; -+ -+ parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu]; -+ if (parent_cpu_data->cur_freq == freqs->new) -+ return 0; -+ -+ cur_freq = parent_cpu_data->cur_freq; -+ parent_cpu_data->cur_freq = freqs->new; -+ -+ mutex_lock(&devfreq->lock); -+ ret = devfreq_update_target(devfreq, freqs->new); -+ mutex_unlock(&devfreq->lock); -+ if (ret) { -+ parent_cpu_data->cur_freq = cur_freq; -+ dev_err(&devfreq->dev, "failed to update the frequency.\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq) -+{ -+ struct devfreq_passive_data *p_data -+ = (struct devfreq_passive_data *)devfreq->data; -+ struct devfreq_cpu_data *parent_cpu_data; -+ int cpu, ret; -+ -+ if (p_data->nb.notifier_call) { -+ ret = cpufreq_unregister_notifier(&p_data->nb, -+ CPUFREQ_TRANSITION_NOTIFIER); -+ if (ret < 0) -+ return ret; -+ } -+ -+ for_each_possible_cpu(cpu) { -+ parent_cpu_data = p_data->parent_cpu_data[cpu]; -+ if (!parent_cpu_data) -+ continue; -+ -+ if (parent_cpu_data->opp_table) -+ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); -+ kfree(parent_cpu_data); -+ } -+ -+ return 0; -+} -+ -+static int cpufreq_passive_register_notifier(struct devfreq *devfreq) -+{ -+ struct devfreq_passive_data *p_data -+ = (struct devfreq_passive_data *)devfreq->data; -+ struct device *dev = devfreq->dev.parent; -+ struct opp_table *opp_table = NULL; -+ struct devfreq_cpu_data *parent_cpu_data; -+ struct cpufreq_policy *policy; -+ struct device *cpu_dev; -+ unsigned int cpu; -+ int ret; -+ -+ p_data->nb.notifier_call = cpufreq_passive_notifier_call; -+ ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER); -+ if (ret) { -+ dev_err(dev, "failed to register cpufreq notifier\n"); -+ p_data->nb.notifier_call = NULL; -+ goto err; -+ } -+ -+ for_each_possible_cpu(cpu) { -+ if (p_data->parent_cpu_data[cpu]) -+ continue; -+ -+ policy = cpufreq_cpu_get(cpu); -+ if (!policy) { -+ ret = -EPROBE_DEFER; -+ goto err; -+ } -+ -+ parent_cpu_data = kzalloc(sizeof(*parent_cpu_data), -+ GFP_KERNEL); -+ if (!parent_cpu_data) { -+ ret = -ENOMEM; -+ goto err_put_policy; -+ } -+ -+ cpu_dev = get_cpu_device(cpu); -+ if (!cpu_dev) { -+ dev_err(dev, "failed to get cpu device\n"); -+ ret = -ENODEV; -+ goto err_free_cpu_data; -+ } -+ -+ opp_table = dev_pm_opp_get_opp_table(cpu_dev); -+ if (IS_ERR(opp_table)) { -+ dev_err(dev, "failed to get opp_table of cpu%d\n", cpu); -+ ret = PTR_ERR(opp_table); -+ goto err_free_cpu_data; -+ } -+ -+ parent_cpu_data->dev = cpu_dev; -+ parent_cpu_data->opp_table = opp_table; -+ parent_cpu_data->first_cpu = cpumask_first(policy->related_cpus); -+ parent_cpu_data->cur_freq = policy->cur; -+ parent_cpu_data->min_freq = policy->cpuinfo.min_freq; -+ parent_cpu_data->max_freq = policy->cpuinfo.max_freq; -+ -+ p_data->parent_cpu_data[cpu] = parent_cpu_data; -+ cpufreq_cpu_put(policy); -+ } -+ -+ mutex_lock(&devfreq->lock); -+ ret = devfreq_update_target(devfreq, 0L); -+ mutex_unlock(&devfreq->lock); -+ if (ret) -+ dev_err(dev, "failed to update the frequency\n"); -+ -+ return ret; -+ -+err_free_cpu_data: -+ kfree(parent_cpu_data); -+err_put_policy: -+ cpufreq_cpu_put(policy); -+err: -+ WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); -+ -+ return ret; -+} -+ - static int devfreq_passive_notifier_call(struct notifier_block *nb, - unsigned long event, void *ptr) - { -@@ -131,30 +380,55 @@ static int devfreq_passive_notifier_call - return NOTIFY_DONE; - } - --static int devfreq_passive_event_handler(struct devfreq *devfreq, -- unsigned int event, void *data) -+static int devfreq_passive_unregister_notifier(struct devfreq *devfreq) -+{ -+ struct devfreq_passive_data *p_data -+ = (struct devfreq_passive_data *)devfreq->data; -+ struct devfreq *parent = (struct devfreq *)p_data->parent; -+ struct notifier_block *nb = &p_data->nb; -+ -+ return devfreq_unregister_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER); -+} -+ -+static int devfreq_passive_register_notifier(struct devfreq *devfreq) - { - struct devfreq_passive_data *p_data - = (struct devfreq_passive_data *)devfreq->data; - struct devfreq *parent = (struct devfreq *)p_data->parent; - struct notifier_block *nb = &p_data->nb; -- int ret = 0; - - if (!parent) - return -EPROBE_DEFER; - -+ nb->notifier_call = devfreq_passive_notifier_call; -+ return devfreq_register_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER); -+} -+ -+static int devfreq_passive_event_handler(struct devfreq *devfreq, -+ unsigned int event, void *data) -+{ -+ struct devfreq_passive_data *p_data -+ = (struct devfreq_passive_data *)devfreq->data; -+ int ret = -EINVAL; -+ -+ if (!p_data) -+ return -EINVAL; -+ -+ if (!p_data->this) -+ p_data->this = devfreq; -+ - switch (event) { - case DEVFREQ_GOV_START: -- if (!p_data->this) -- p_data->this = devfreq; -- -- nb->notifier_call = devfreq_passive_notifier_call; -- ret = devfreq_register_notifier(parent, nb, -- DEVFREQ_TRANSITION_NOTIFIER); -+ if (p_data->parent_type == DEVFREQ_PARENT_DEV) -+ ret = devfreq_passive_register_notifier(devfreq); -+ else if (p_data->parent_type == CPUFREQ_PARENT_DEV) -+ ret = cpufreq_passive_register_notifier(devfreq); - break; - case DEVFREQ_GOV_STOP: -- WARN_ON(devfreq_unregister_notifier(parent, nb, -- DEVFREQ_TRANSITION_NOTIFIER)); -+ if (p_data->parent_type == DEVFREQ_PARENT_DEV) -+ WARN_ON(devfreq_passive_unregister_notifier(devfreq)); -+ else if (p_data->parent_type == CPUFREQ_PARENT_DEV) -+ WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); - break; - default: - break; ---- a/include/linux/devfreq.h -+++ b/include/linux/devfreq.h -@@ -38,6 +38,7 @@ enum devfreq_timer { - - struct devfreq; - struct devfreq_governor; -+struct devfreq_cpu_data; - struct thermal_cooling_device; - - /** -@@ -289,6 +290,11 @@ struct devfreq_simple_ondemand_data { - #endif - - #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE) -+enum devfreq_parent_dev_type { -+ DEVFREQ_PARENT_DEV, -+ CPUFREQ_PARENT_DEV, -+}; -+ - /** - * struct devfreq_passive_data - ``void *data`` fed to struct devfreq - * and devfreq_add_device -@@ -300,8 +306,11 @@ struct devfreq_simple_ondemand_data { - * using governors except for passive governor. - * If the devfreq device has the specific method to decide - * the next frequency, should use this callback. -- * @this: the devfreq instance of own device. -- * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list -+ * @parent_type: the parent type of the device. -+ * @this: the devfreq instance of own device. -+ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or -+ * CPUFREQ_TRANSITION_NOTIFIER list. -+ * @parent_cpu_data: the state min/max/current frequency of all online cpu's. - * - * The devfreq_passive_data have to set the devfreq instance of parent - * device with governors except for the passive governor. But, don't need to -@@ -315,9 +324,13 @@ struct devfreq_passive_data { - /* Optional callback to decide the next frequency of passvice device */ - int (*get_target_freq)(struct devfreq *this, unsigned long *freq); - -+ /* Should set the type of parent device */ -+ enum devfreq_parent_dev_type parent_type; -+ - /* For passive governor's internal use. Don't need to set them */ - struct devfreq *this; - struct notifier_block nb; -+ struct devfreq_cpu_data *parent_cpu_data[NR_CPUS]; - }; - #endif - diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch deleted file mode 100644 index cb10bd1b62c..00000000000 --- a/target/linux/ipq806x/patches-6.1/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch +++ /dev/null @@ -1,110 +0,0 @@ -From 05723e71234b60a1a47313ea1a889797ec648f1c Mon Sep 17 00:00:00 2001 -From: Chanwoo Choi -Date: Tue, 2 Mar 2021 17:22:50 +0900 -Subject: [PATCH 3/5] PM / devfreq: passive: Reduce duplicate code when - passive_devfreq case - -In order to keep the consistent coding style between passive_devfreq -and passive_cpufreq, use common code for handling required opp property. -Also remove the unneed conditional statement and unify the comment -of both passive_devfreq and passive_cpufreq when getting the target frequency. - -Tested-by: Chen-Yu Tsai -Tested-by: Johnson Wang -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/governor_passive.c | 66 ++++-------------------------- - 1 file changed, 8 insertions(+), 58 deletions(-) - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -93,65 +93,16 @@ static int get_target_freq_with_devfreq( - = (struct devfreq_passive_data *)devfreq->data; - struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent; - unsigned long child_freq = ULONG_MAX; -- struct dev_pm_opp *opp, *p_opp; - int i, count; - -- /* -- * If the devfreq device with passive governor has the specific method -- * to determine the next frequency, should use the get_target_freq() -- * of struct devfreq_passive_data. -- */ -- if (p_data->get_target_freq) -- return p_data->get_target_freq(devfreq, freq); -- -- /* -- * If the parent and passive devfreq device uses the OPP table, -- * get the next frequency by using the OPP table. -- */ -- -- /* -- * - parent devfreq device uses the governors except for passive. -- * - passive devfreq device uses the passive governor. -- * -- * Each devfreq has the OPP table. After deciding the new frequency -- * from the governor of parent devfreq device, the passive governor -- * need to get the index of new frequency on OPP table of parent -- * device. And then the index is used for getting the suitable -- * new frequency for passive devfreq device. -- */ -- if (!devfreq->profile || !devfreq->profile->freq_table -- || devfreq->profile->max_state <= 0) -- return -EINVAL; -- -- /* -- * The passive governor have to get the correct frequency from OPP -- * list of parent device. Because in this case, *freq is temporary -- * value which is decided by ondemand governor. -- */ -- if (devfreq->opp_table && parent_devfreq->opp_table) { -- p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent, -- freq, 0); -- if (IS_ERR(p_opp)) -- return PTR_ERR(p_opp); -- -- opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table, -- devfreq->opp_table, p_opp); -- dev_pm_opp_put(p_opp); -- -- if (IS_ERR(opp)) -- goto no_required_opp; -- -- *freq = dev_pm_opp_get_freq(opp); -- dev_pm_opp_put(opp); -- -- return 0; -- } -+ /* Get target freq via required opps */ -+ child_freq = get_target_freq_by_required_opp(parent_devfreq->dev.parent, -+ parent_devfreq->opp_table, -+ devfreq->opp_table, freq); -+ if (child_freq) -+ goto out; - --no_required_opp: -- /* -- * Get the OPP table's index of decided frequency by governor -- * of parent device. -- */ -+ /* Use interpolation if required opps is not available */ - for (i = 0; i < parent_devfreq->profile->max_state; i++) - if (parent_devfreq->profile->freq_table[i] == *freq) - break; -@@ -159,7 +110,6 @@ no_required_opp: - if (i == parent_devfreq->profile->max_state) - return -EINVAL; - -- /* Get the suitable frequency by using index of parent device. */ - if (i < devfreq->profile->max_state) { - child_freq = devfreq->profile->freq_table[i]; - } else { -@@ -167,7 +117,7 @@ no_required_opp: - child_freq = devfreq->profile->freq_table[count - 1]; - } - -- /* Return the suitable frequency for passive device. */ -+out: - *freq = child_freq; - - return 0; diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch deleted file mode 100644 index 9ef02d0ea35..00000000000 --- a/target/linux/ipq806x/patches-6.1/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch +++ /dev/null @@ -1,232 +0,0 @@ -From 26984d9d581e5049bd75091d2e789b9cc3ea12e0 Mon Sep 17 00:00:00 2001 -From: Chanwoo Choi -Date: Wed, 27 Apr 2022 03:49:19 +0900 -Subject: [PATCH 4/5] PM / devfreq: passive: Keep cpufreq_policy for possible - cpus - -The passive governor requires the cpu data to get the next target frequency -of devfreq device if depending on cpu. In order to reduce the unnecessary -memory data, keep cpufreq_policy data for possible cpus instead of NR_CPU. - -Tested-by: Chen-Yu Tsai -Tested-by: Johnson Wang -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/governor.h | 3 ++ - drivers/devfreq/governor_passive.c | 75 +++++++++++++++++++++++------- - include/linux/devfreq.h | 4 +- - 3 files changed, 64 insertions(+), 18 deletions(-) - ---- a/drivers/devfreq/governor.h -+++ b/drivers/devfreq/governor.h -@@ -49,6 +49,7 @@ - - /** - * struct devfreq_cpu_data - Hold the per-cpu data -+ * @node: list node - * @dev: reference to cpu device. - * @first_cpu: the cpumask of the first cpu of a policy. - * @opp_table: reference to cpu opp table. -@@ -60,6 +61,8 @@ - * This is auto-populated by the governor. - */ - struct devfreq_cpu_data { -+ struct list_head node; -+ - struct device *dev; - unsigned int first_cpu; - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -1,4 +1,4 @@ --// SPDX-License-Identifier: GPL-2.0-only -+ // SPDX-License-Identifier: GPL-2.0-only - /* - * linux/drivers/devfreq/governor_passive.c - * -@@ -18,6 +18,22 @@ - - #define HZ_PER_KHZ 1000 - -+static struct devfreq_cpu_data * -+get_parent_cpu_data(struct devfreq_passive_data *p_data, -+ struct cpufreq_policy *policy) -+{ -+ struct devfreq_cpu_data *parent_cpu_data; -+ -+ if (!p_data || !policy) -+ return NULL; -+ -+ list_for_each_entry(parent_cpu_data, &p_data->cpu_data_list, node) -+ if (parent_cpu_data->first_cpu == cpumask_first(policy->related_cpus)) -+ return parent_cpu_data; -+ -+ return NULL; -+} -+ - static unsigned long get_target_freq_by_required_opp(struct device *p_dev, - struct opp_table *p_opp_table, - struct opp_table *opp_table, -@@ -51,14 +67,24 @@ static int get_target_freq_with_cpufreq( - struct devfreq_passive_data *p_data = - (struct devfreq_passive_data *)devfreq->data; - struct devfreq_cpu_data *parent_cpu_data; -+ struct cpufreq_policy *policy; - unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent; - unsigned long dev_min, dev_max; - unsigned long freq = 0; -+ int ret = 0; - - for_each_online_cpu(cpu) { -- parent_cpu_data = p_data->parent_cpu_data[cpu]; -- if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu) -+ policy = cpufreq_cpu_get(cpu); -+ if (!policy) { -+ ret = -EINVAL; -+ continue; -+ } -+ -+ parent_cpu_data = get_parent_cpu_data(p_data, policy); -+ if (!parent_cpu_data) { -+ cpufreq_cpu_put(policy); - continue; -+ } - - /* Get target freq via required opps */ - cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ; -@@ -67,6 +93,7 @@ static int get_target_freq_with_cpufreq( - devfreq->opp_table, &cpu_cur); - if (freq) { - *target_freq = max(freq, *target_freq); -+ cpufreq_cpu_put(policy); - continue; - } - -@@ -81,9 +108,10 @@ static int get_target_freq_with_cpufreq( - freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); - - *target_freq = max(freq, *target_freq); -+ cpufreq_cpu_put(policy); - } - -- return 0; -+ return ret; - } - - static int get_target_freq_with_devfreq(struct devfreq *devfreq, -@@ -168,12 +196,11 @@ static int cpufreq_passive_notifier_call - unsigned int cur_freq; - int ret; - -- if (event != CPUFREQ_POSTCHANGE || !freqs || -- !p_data->parent_cpu_data[freqs->policy->cpu]) -+ if (event != CPUFREQ_POSTCHANGE || !freqs) - return 0; - -- parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu]; -- if (parent_cpu_data->cur_freq == freqs->new) -+ parent_cpu_data = get_parent_cpu_data(p_data, freqs->policy); -+ if (!parent_cpu_data || parent_cpu_data->cur_freq == freqs->new) - return 0; - - cur_freq = parent_cpu_data->cur_freq; -@@ -196,7 +223,7 @@ static int cpufreq_passive_unregister_no - struct devfreq_passive_data *p_data - = (struct devfreq_passive_data *)devfreq->data; - struct devfreq_cpu_data *parent_cpu_data; -- int cpu, ret; -+ int cpu, ret = 0; - - if (p_data->nb.notifier_call) { - ret = cpufreq_unregister_notifier(&p_data->nb, -@@ -206,16 +233,26 @@ static int cpufreq_passive_unregister_no - } - - for_each_possible_cpu(cpu) { -- parent_cpu_data = p_data->parent_cpu_data[cpu]; -- if (!parent_cpu_data) -+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -+ if (!policy) { -+ ret = -EINVAL; -+ continue; -+ } -+ -+ parent_cpu_data = get_parent_cpu_data(p_data, policy); -+ if (!parent_cpu_data) { -+ cpufreq_cpu_put(policy); - continue; -+ } - -+ list_del(&parent_cpu_data->node); - if (parent_cpu_data->opp_table) - dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); - kfree(parent_cpu_data); -+ cpufreq_cpu_put(policy); - } - -- return 0; -+ return ret; - } - - static int cpufreq_passive_register_notifier(struct devfreq *devfreq) -@@ -230,6 +267,9 @@ static int cpufreq_passive_register_noti - unsigned int cpu; - int ret; - -+ p_data->cpu_data_list -+ = (struct list_head)LIST_HEAD_INIT(p_data->cpu_data_list); -+ - p_data->nb.notifier_call = cpufreq_passive_notifier_call; - ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER); - if (ret) { -@@ -239,15 +279,18 @@ static int cpufreq_passive_register_noti - } - - for_each_possible_cpu(cpu) { -- if (p_data->parent_cpu_data[cpu]) -- continue; -- - policy = cpufreq_cpu_get(cpu); - if (!policy) { - ret = -EPROBE_DEFER; - goto err; - } - -+ parent_cpu_data = get_parent_cpu_data(p_data, policy); -+ if (parent_cpu_data) { -+ cpufreq_cpu_put(policy); -+ continue; -+ } -+ - parent_cpu_data = kzalloc(sizeof(*parent_cpu_data), - GFP_KERNEL); - if (!parent_cpu_data) { -@@ -276,7 +319,7 @@ static int cpufreq_passive_register_noti - parent_cpu_data->min_freq = policy->cpuinfo.min_freq; - parent_cpu_data->max_freq = policy->cpuinfo.max_freq; - -- p_data->parent_cpu_data[cpu] = parent_cpu_data; -+ list_add_tail(&parent_cpu_data->node, &p_data->cpu_data_list); - cpufreq_cpu_put(policy); - } - ---- a/include/linux/devfreq.h -+++ b/include/linux/devfreq.h -@@ -310,7 +310,7 @@ enum devfreq_parent_dev_type { - * @this: the devfreq instance of own device. - * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or - * CPUFREQ_TRANSITION_NOTIFIER list. -- * @parent_cpu_data: the state min/max/current frequency of all online cpu's. -+ * @cpu_data_list: the list of cpu frequency data for all cpufreq_policy. - * - * The devfreq_passive_data have to set the devfreq instance of parent - * device with governors except for the passive governor. But, don't need to -@@ -330,7 +330,7 @@ struct devfreq_passive_data { - /* For passive governor's internal use. Don't need to set them */ - struct devfreq *this; - struct notifier_block nb; -- struct devfreq_cpu_data *parent_cpu_data[NR_CPUS]; -+ struct list_head cpu_data_list; - }; - #endif - diff --git a/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch b/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch deleted file mode 100644 index 69160fd77a5..00000000000 --- a/target/linux/ipq806x/patches-6.1/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 42d2607d91c4ec37ea1970899c2d614824f3014b Mon Sep 17 00:00:00 2001 -From: Chanwoo Choi -Date: Thu, 19 May 2022 10:07:53 +0900 -Subject: [PATCH 5/5] PM / devfreq: passive: Return non-error when - not-supported event is required - -Each devfreq governor specifies the supported governor event -such as GOV_START and GOV_STOP. When not-supported event is required, -just return non-error. But, commit ce9a0d88d97a ("PM / devfreq: Add -cpu based scaling support to passive governor") returned the error -value. So that return non-error value when not-supported event is required. - -Fixes: ce9a0d88d97a ("PM / devfreq: Add cpu based scaling support to passive governor") -Reported-by: Marek Szyprowski -Signed-off-by: Chanwoo Choi -Signed-off-by: Rafael J. Wysocki ---- - drivers/devfreq/governor_passive.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -402,7 +402,7 @@ static int devfreq_passive_event_handler - { - struct devfreq_passive_data *p_data - = (struct devfreq_passive_data *)devfreq->data; -- int ret = -EINVAL; -+ int ret = 0; - - if (!p_data) - return -EINVAL; diff --git a/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch b/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch deleted file mode 100644 index 3d2bb2de05b..00000000000 --- a/target/linux/ipq806x/patches-6.1/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 82c66d2bbbeda9e493487e7413769087a0b46250 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Mon, 20 Jun 2022 00:29:39 +0200 -Subject: [PATCH 1/1] PM / devfreq: Fix kernel warning with cpufreq passive - register fail - -Remove cpufreq_passive_unregister_notifier from -cpufreq_passive_register_notifier in case of error as devfreq core -already call unregister on GOV_START fail. - -This fix the kernel always printing a WARN on governor PROBE_DEFER as -cpufreq_passive_unregister_notifier is called two times and return -error on the second call as the cpufreq is already unregistered. - -Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") -Signed-off-by: Christian Marangi -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/governor_passive.c | 1 - - 1 file changed, 1 deletion(-) - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -336,7 +336,6 @@ err_free_cpu_data: - err_put_policy: - cpufreq_cpu_put(policy); - err: -- WARN_ON(cpufreq_passive_unregister_notifier(devfreq)); - - return ret; - } diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch deleted file mode 100644 index 08834245486..00000000000 --- a/target/linux/ipq806x/patches-6.1/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 8953603eb5447be52f6fc3d8fcae1b3ce9899189 Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Mon, 6 Jun 2022 11:58:49 +0200 -Subject: [PATCH v4 1/4] PM / devfreq: Fix cpufreq passive unregister erroring - on PROBE_DEFER - -With the passive governor, the cpu based scaling can PROBE_DEFER due to -the fact that CPU policy are not ready. -The cpufreq passive unregister notifier is called both from the -GOV_START errors and for the GOV_STOP and assume the notifier is -successfully registred every time. With GOV_START failing it's wrong to -loop over each possible CPU since the register path has failed for -some CPU policy not ready. Change the logic and unregister the notifer -based on the current allocated parent_cpu_data list to correctly handle -errors and the governor unregister path. - -Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") -Signed-off-by: Christian 'Ansuel' Marangi ---- - drivers/devfreq/governor_passive.c | 39 +++++++++++++----------------- - 1 file changed, 17 insertions(+), 22 deletions(-) - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -34,6 +34,20 @@ get_parent_cpu_data(struct devfreq_passi - return NULL; - } - -+static void delete_parent_cpu_data(struct devfreq_passive_data *p_data) -+{ -+ struct devfreq_cpu_data *parent_cpu_data, *tmp; -+ -+ list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) { -+ list_del(&parent_cpu_data->node); -+ -+ if (parent_cpu_data->opp_table) -+ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); -+ -+ kfree(parent_cpu_data); -+ } -+} -+ - static unsigned long get_target_freq_by_required_opp(struct device *p_dev, - struct opp_table *p_opp_table, - struct opp_table *opp_table, -@@ -222,8 +236,7 @@ static int cpufreq_passive_unregister_no - { - struct devfreq_passive_data *p_data - = (struct devfreq_passive_data *)devfreq->data; -- struct devfreq_cpu_data *parent_cpu_data; -- int cpu, ret = 0; -+ int ret; - - if (p_data->nb.notifier_call) { - ret = cpufreq_unregister_notifier(&p_data->nb, -@@ -232,27 +245,9 @@ static int cpufreq_passive_unregister_no - return ret; - } - -- for_each_possible_cpu(cpu) { -- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); -- if (!policy) { -- ret = -EINVAL; -- continue; -- } -- -- parent_cpu_data = get_parent_cpu_data(p_data, policy); -- if (!parent_cpu_data) { -- cpufreq_cpu_put(policy); -- continue; -- } -- -- list_del(&parent_cpu_data->node); -- if (parent_cpu_data->opp_table) -- dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); -- kfree(parent_cpu_data); -- cpufreq_cpu_put(policy); -- } -+ delete_parent_cpu_data(p_data); - -- return ret; -+ return 0; - } - - static int cpufreq_passive_register_notifier(struct devfreq *devfreq) diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch deleted file mode 100644 index 867ea83e0c9..00000000000 --- a/target/linux/ipq806x/patches-6.1/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 57e00b40033a376de3f3cf0bb9bf7590d2dd679d Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Tue, 14 Jun 2022 13:06:59 +0200 -Subject: [PATCH 1/1] PM / devfreq: Fix kernel panic with cpu based scaling to - passive gov - -The cpufreq passive register notifier can PROBE_DEFER and the devfreq -struct is freed and then reallocaed on probe retry. -The current logic assume that the code can't PROBE_DEFER so the devfreq -struct in the this variable in devfreq_passive_data is assumed to be -(if already set) always correct. -This cause kernel panic as the code try to access the wrong address. -To correctly handle this, update the this variable in -devfreq_passive_data to the devfreq reallocated struct. - -Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") -Signed-off-by: Christian 'Ansuel' Marangi -Signed-off-by: Chanwoo Choi ---- - drivers/devfreq/governor_passive.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -401,8 +401,7 @@ static int devfreq_passive_event_handler - if (!p_data) - return -EINVAL; - -- if (!p_data->this) -- p_data->this = devfreq; -+ p_data->this = devfreq; - - switch (event) { - case DEVFREQ_GOV_START: diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch deleted file mode 100644 index 210f57bd7e6..00000000000 --- a/target/linux/ipq806x/patches-6.1/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch +++ /dev/null @@ -1,269 +0,0 @@ -From 46d05776a1a5dd8eb479e868f5ff4f4b97d68238 Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Mon, 6 Jun 2022 12:39:19 +0200 -Subject: [PATCH v4 3/4] PM / devfreq: Rework freq_table to be local to devfreq - struct - -Currently we reference the freq_table to the profile defined one and we -make changes on it. Devfreq never supported PROBE_DEFER before the cpu -based scaling support to the passive governor and assumed that a devfreq -device could only had error and be done with it. -Now that a device can PROBE_DEFER a rework to the freq_table logic is -required. - -If a device PROBE_DEFER on the GOV_START, the freq_table is already set -in the device profile struct and its init is skipped. This is due to the -fact that it's common for devs to declare this kind of struct static. -This cause the devfreq logic to find a freq table declared (freq_table -not NULL) with random data and poiting to the old addrs freed by devm. - -This problem CAN be solved by devs by clearing the freq_table in their -profile struct on driver exit path but it should not be trusted and it -looks to use a flawed logic. - -A better solution is to move the freq_table and max_state to the -devfreq struct and never change the profile struct. -This permit to correctly handle PROBE_DEFER since the devfreq struct is -reallocated and contains new values. -Also the profile struct should only be used to init the driver and should -not be used by the devfreq to write the freq_table if it's not provided -by the driver. - -Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") -Signed-off-by: Christian 'Ansuel' Marangi ---- - drivers/devfreq/devfreq.c | 71 ++++++++++++++---------------- - drivers/devfreq/governor_passive.c | 14 +++--- - include/linux/devfreq.h | 4 ++ - 3 files changed, 45 insertions(+), 44 deletions(-) - ---- a/drivers/devfreq/devfreq.c -+++ b/drivers/devfreq/devfreq.c -@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfr - unsigned long *min_freq, - unsigned long *max_freq) - { -- unsigned long *freq_table = devfreq->profile->freq_table; -+ unsigned long *freq_table = devfreq->freq_table; - s32 qos_min_freq, qos_max_freq; - - lockdep_assert_held(&devfreq->lock); -@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfr - * The devfreq drivers can initialize this in either ascending or - * descending order and devfreq core supports both. - */ -- if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) { -+ if (freq_table[0] < freq_table[devfreq->max_state - 1]) { - *min_freq = freq_table[0]; -- *max_freq = freq_table[devfreq->profile->max_state - 1]; -+ *max_freq = freq_table[devfreq->max_state - 1]; - } else { -- *min_freq = freq_table[devfreq->profile->max_state - 1]; -+ *min_freq = freq_table[devfreq->max_state - 1]; - *max_freq = freq_table[0]; - } - -@@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct - { - int lev; - -- for (lev = 0; lev < devfreq->profile->max_state; lev++) -- if (freq == devfreq->profile->freq_table[lev]) -+ for (lev = 0; lev < devfreq->max_state; lev++) -+ if (freq == devfreq->freq_table[lev]) - return lev; - - return -EINVAL; -@@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct - - static int set_freq_table(struct devfreq *devfreq) - { -- struct devfreq_dev_profile *profile = devfreq->profile; - struct dev_pm_opp *opp; - unsigned long freq; - int i, count; -@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq - if (count <= 0) - return -EINVAL; - -- profile->max_state = count; -- profile->freq_table = devm_kcalloc(devfreq->dev.parent, -- profile->max_state, -- sizeof(*profile->freq_table), -- GFP_KERNEL); -- if (!profile->freq_table) { -- profile->max_state = 0; -+ devfreq->max_state = count; -+ devfreq->freq_table = devm_kcalloc(devfreq->dev.parent, -+ devfreq->max_state, -+ sizeof(*devfreq->freq_table), -+ GFP_KERNEL); -+ if (!devfreq->freq_table) - return -ENOMEM; -- } - -- for (i = 0, freq = 0; i < profile->max_state; i++, freq++) { -+ for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) { - opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq); - if (IS_ERR(opp)) { -- devm_kfree(devfreq->dev.parent, profile->freq_table); -- profile->max_state = 0; -+ devm_kfree(devfreq->dev.parent, devfreq->freq_table); - return PTR_ERR(opp); - } - dev_pm_opp_put(opp); -- profile->freq_table[i] = freq; -+ devfreq->freq_table[i] = freq; - } - - return 0; -@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq - - if (lev != prev_lev) { - devfreq->stats.trans_table[ -- (prev_lev * devfreq->profile->max_state) + lev]++; -+ (prev_lev * devfreq->max_state) + lev]++; - devfreq->stats.total_trans++; - } - -@@ -834,6 +830,9 @@ struct devfreq *devfreq_add_device(struc - if (err < 0) - goto err_dev; - mutex_lock(&devfreq->lock); -+ } else { -+ devfreq->freq_table = devfreq->profile->freq_table; -+ devfreq->max_state = devfreq->profile->max_state; - } - - devfreq->scaling_min_freq = find_available_min_freq(devfreq); -@@ -869,8 +868,8 @@ struct devfreq *devfreq_add_device(struc - - devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev, - array3_size(sizeof(unsigned int), -- devfreq->profile->max_state, -- devfreq->profile->max_state), -+ devfreq->max_state, -+ devfreq->max_state), - GFP_KERNEL); - if (!devfreq->stats.trans_table) { - mutex_unlock(&devfreq->lock); -@@ -879,7 +878,7 @@ struct devfreq *devfreq_add_device(struc - } - - devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev, -- devfreq->profile->max_state, -+ devfreq->max_state, - sizeof(*devfreq->stats.time_in_state), - GFP_KERNEL); - if (!devfreq->stats.time_in_state) { -@@ -1637,9 +1636,9 @@ static ssize_t available_frequencies_sho - - mutex_lock(&df->lock); - -- for (i = 0; i < df->profile->max_state; i++) -+ for (i = 0; i < df->max_state; i++) - count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), -- "%lu ", df->profile->freq_table[i]); -+ "%lu ", df->freq_table[i]); - - mutex_unlock(&df->lock); - /* Truncate the trailing space */ -@@ -1662,7 +1661,7 @@ static ssize_t trans_stat_show(struct de - - if (!df->profile) - return -EINVAL; -- max_state = df->profile->max_state; -+ max_state = df->max_state; - - if (max_state == 0) - return sprintf(buf, "Not Supported.\n"); -@@ -1679,19 +1678,17 @@ static ssize_t trans_stat_show(struct de - len += sprintf(buf + len, " :"); - for (i = 0; i < max_state; i++) - len += sprintf(buf + len, "%10lu", -- df->profile->freq_table[i]); -+ df->freq_table[i]); - - len += sprintf(buf + len, " time(ms)\n"); - - for (i = 0; i < max_state; i++) { -- if (df->profile->freq_table[i] -- == df->previous_freq) { -+ if (df->freq_table[i] == df->previous_freq) - len += sprintf(buf + len, "*"); -- } else { -+ else - len += sprintf(buf + len, " "); -- } -- len += sprintf(buf + len, "%10lu:", -- df->profile->freq_table[i]); -+ -+ len += sprintf(buf + len, "%10lu:", df->freq_table[i]); - for (j = 0; j < max_state; j++) - len += sprintf(buf + len, "%10u", - df->stats.trans_table[(i * max_state) + j]); -@@ -1715,7 +1712,7 @@ static ssize_t trans_stat_store(struct d - if (!df->profile) - return -EINVAL; - -- if (df->profile->max_state == 0) -+ if (df->max_state == 0) - return count; - - err = kstrtoint(buf, 10, &value); -@@ -1723,11 +1720,11 @@ static ssize_t trans_stat_store(struct d - return -EINVAL; - - mutex_lock(&df->lock); -- memset(df->stats.time_in_state, 0, (df->profile->max_state * -+ memset(df->stats.time_in_state, 0, (df->max_state * - sizeof(*df->stats.time_in_state))); - memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int), -- df->profile->max_state, -- df->profile->max_state)); -+ df->max_state, -+ df->max_state)); - df->stats.total_trans = 0; - df->stats.last_update = get_jiffies_64(); - mutex_unlock(&df->lock); ---- a/drivers/devfreq/governor_passive.c -+++ b/drivers/devfreq/governor_passive.c -@@ -145,18 +145,18 @@ static int get_target_freq_with_devfreq( - goto out; - - /* Use interpolation if required opps is not available */ -- for (i = 0; i < parent_devfreq->profile->max_state; i++) -- if (parent_devfreq->profile->freq_table[i] == *freq) -+ for (i = 0; i < parent_devfreq->max_state; i++) -+ if (parent_devfreq->freq_table[i] == *freq) - break; - -- if (i == parent_devfreq->profile->max_state) -+ if (i == parent_devfreq->max_state) - return -EINVAL; - -- if (i < devfreq->profile->max_state) { -- child_freq = devfreq->profile->freq_table[i]; -+ if (i < devfreq->max_state) { -+ child_freq = devfreq->freq_table[i]; - } else { -- count = devfreq->profile->max_state; -- child_freq = devfreq->profile->freq_table[count - 1]; -+ count = devfreq->max_state; -+ child_freq = devfreq->freq_table[count - 1]; - } - - out: ---- a/include/linux/devfreq.h -+++ b/include/linux/devfreq.h -@@ -185,6 +185,10 @@ struct devfreq { - struct notifier_block nb; - struct delayed_work work; - -+ /* devfreq local freq_table */ -+ unsigned long *freq_table; -+ unsigned int max_state; -+ - unsigned long previous_freq; - struct devfreq_dev_status last_status; - diff --git a/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch b/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch deleted file mode 100644 index 591340c6f22..00000000000 --- a/target/linux/ipq806x/patches-6.1/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch +++ /dev/null @@ -1,28 +0,0 @@ -From eee9f767c41b03a2744d4b0f0c1a144e4ff41e78 Mon Sep 17 00:00:00 2001 -From: Christian 'Ansuel' Marangi -Date: Mon, 6 Jun 2022 13:01:02 +0200 -Subject: [PATCH v4 4/4] PM / devfreq: Mute warning on governor PROBE_DEFER - -Don't print warning when a governor PROBE_DEFER as it's not a real -GOV_START fail. - -Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor") -Signed-off-by: Christian 'Ansuel' Marangi ---- - drivers/devfreq/devfreq.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - ---- a/drivers/devfreq/devfreq.c -+++ b/drivers/devfreq/devfreq.c -@@ -930,8 +930,9 @@ struct devfreq *devfreq_add_device(struc - err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, - NULL); - if (err) { -- dev_err(dev, "%s: Unable to start governor for the device\n", -- __func__); -+ dev_err_probe(dev, err, -+ "%s: Unable to start governor for the device\n", -+ __func__); - goto err_init; - } - create_sysfs_files(devfreq, devfreq->governor); diff --git a/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch b/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch deleted file mode 100644 index c595b10dd74..00000000000 --- a/target/linux/ipq806x/patches-6.1/116-v6.0-01-mtd-nand-raw-qcom_nandc-reorder-qcom_nand_host-struc.patch +++ /dev/null @@ -1,268 +0,0 @@ -From b360514edb4743cbf86fc377699c75e98b1264c7 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 16 Jun 2022 02:18:33 +0200 -Subject: [PATCH 1/2] mtd: nand: raw: qcom_nandc: reorder qcom_nand_host struct - -Reorder structs in nandc driver to save holes. - -Signed-off-by: Christian Marangi -Reviewed-by: Manivannan Sadhasivam -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-2-ansuelsmth@gmail.com ---- - drivers/mtd/nand/raw/qcom_nandc.c | 107 +++++++++++++++++------------- - 1 file changed, 62 insertions(+), 45 deletions(-) - ---- a/drivers/mtd/nand/raw/qcom_nandc.c -+++ b/drivers/mtd/nand/raw/qcom_nandc.c -@@ -237,6 +237,9 @@ nandc_set_reg(chip, reg, \ - * @bam_ce - the array of BAM command elements - * @cmd_sgl - sgl for NAND BAM command pipe - * @data_sgl - sgl for NAND BAM consumer/producer pipe -+ * @last_data_desc - last DMA desc in data channel (tx/rx). -+ * @last_cmd_desc - last DMA desc in command channel. -+ * @txn_done - completion for NAND transfer. - * @bam_ce_pos - the index in bam_ce which is available for next sgl - * @bam_ce_start - the index in bam_ce which marks the start position ce - * for current sgl. It will be used for size calculation -@@ -249,14 +252,14 @@ nandc_set_reg(chip, reg, \ - * @rx_sgl_start - start index in data sgl for rx. - * @wait_second_completion - wait for second DMA desc completion before making - * the NAND transfer completion. -- * @txn_done - completion for NAND transfer. -- * @last_data_desc - last DMA desc in data channel (tx/rx). -- * @last_cmd_desc - last DMA desc in command channel. - */ - struct bam_transaction { - struct bam_cmd_element *bam_ce; - struct scatterlist *cmd_sgl; - struct scatterlist *data_sgl; -+ struct dma_async_tx_descriptor *last_data_desc; -+ struct dma_async_tx_descriptor *last_cmd_desc; -+ struct completion txn_done; - u32 bam_ce_pos; - u32 bam_ce_start; - u32 cmd_sgl_pos; -@@ -266,25 +269,23 @@ struct bam_transaction { - u32 rx_sgl_pos; - u32 rx_sgl_start; - bool wait_second_completion; -- struct completion txn_done; -- struct dma_async_tx_descriptor *last_data_desc; -- struct dma_async_tx_descriptor *last_cmd_desc; - }; - - /* - * This data type corresponds to the nand dma descriptor -+ * @dma_desc - low level DMA engine descriptor - * @list - list for desc_info -- * @dir - DMA transfer direction -+ * - * @adm_sgl - sgl which will be used for single sgl dma descriptor. Only used by - * ADM - * @bam_sgl - sgl which will be used for dma descriptor. Only used by BAM - * @sgl_cnt - number of SGL in bam_sgl. Only used by BAM -- * @dma_desc - low level DMA engine descriptor -+ * @dir - DMA transfer direction - */ - struct desc_info { -+ struct dma_async_tx_descriptor *dma_desc; - struct list_head node; - -- enum dma_data_direction dir; - union { - struct scatterlist adm_sgl; - struct { -@@ -292,7 +293,7 @@ struct desc_info { - int sgl_cnt; - }; - }; -- struct dma_async_tx_descriptor *dma_desc; -+ enum dma_data_direction dir; - }; - - /* -@@ -336,52 +337,64 @@ struct nandc_regs { - /* - * NAND controller data struct - * -- * @controller: base controller structure -- * @host_list: list containing all the chips attached to the -- * controller - * @dev: parent device -+ * - * @base: MMIO base -- * @base_phys: physical base address of controller registers -- * @base_dma: dma base address of controller registers -+ * - * @core_clk: controller clock - * @aon_clk: another controller clock - * -+ * @regs: a contiguous chunk of memory for DMA register -+ * writes. contains the register values to be -+ * written to controller -+ * -+ * @props: properties of current NAND controller, -+ * initialized via DT match data -+ * -+ * @controller: base controller structure -+ * @host_list: list containing all the chips attached to the -+ * controller -+ * - * @chan: dma channel - * @cmd_crci: ADM DMA CRCI for command flow control - * @data_crci: ADM DMA CRCI for data flow control -+ * - * @desc_list: DMA descriptor list (list of desc_infos) - * - * @data_buffer: our local DMA buffer for page read/writes, - * used when we can't use the buffer provided - * by upper layers directly -- * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf -- * functions - * @reg_read_buf: local buffer for reading back registers via DMA -+ * -+ * @base_phys: physical base address of controller registers -+ * @base_dma: dma base address of controller registers - * @reg_read_dma: contains dma address for register read buffer -- * @reg_read_pos: marker for data read in reg_read_buf - * -- * @regs: a contiguous chunk of memory for DMA register -- * writes. contains the register values to be -- * written to controller -- * @cmd1/vld: some fixed controller register values -- * @props: properties of current NAND controller, -- * initialized via DT match data -+ * @buf_size/count/start: markers for chip->legacy.read_buf/write_buf -+ * functions - * @max_cwperpage: maximum QPIC codewords required. calculated - * from all connected NAND devices pagesize -+ * -+ * @reg_read_pos: marker for data read in reg_read_buf -+ * -+ * @cmd1/vld: some fixed controller register values - */ - struct qcom_nand_controller { -- struct nand_controller controller; -- struct list_head host_list; -- - struct device *dev; - - void __iomem *base; -- phys_addr_t base_phys; -- dma_addr_t base_dma; - - struct clk *core_clk; - struct clk *aon_clk; - -+ struct nandc_regs *regs; -+ struct bam_transaction *bam_txn; -+ -+ const struct qcom_nandc_props *props; -+ -+ struct nand_controller controller; -+ struct list_head host_list; -+ - union { - /* will be used only by QPIC for BAM DMA */ - struct { -@@ -399,22 +412,22 @@ struct qcom_nand_controller { - }; - - struct list_head desc_list; -- struct bam_transaction *bam_txn; - - u8 *data_buffer; -+ __le32 *reg_read_buf; -+ -+ phys_addr_t base_phys; -+ dma_addr_t base_dma; -+ dma_addr_t reg_read_dma; -+ - int buf_size; - int buf_count; - int buf_start; - unsigned int max_cwperpage; - -- __le32 *reg_read_buf; -- dma_addr_t reg_read_dma; - int reg_read_pos; - -- struct nandc_regs *regs; -- - u32 cmd1, vld; -- const struct qcom_nandc_props *props; - }; - - /* -@@ -430,19 +443,21 @@ struct qcom_nand_controller { - * and reserved bytes - * @cw_data: the number of bytes within a codeword protected - * by ECC -- * @use_ecc: request the controller to use ECC for the -- * upcoming read/write -- * @bch_enabled: flag to tell whether BCH ECC mode is used - * @ecc_bytes_hw: ECC bytes used by controller hardware for this - * chip -- * @status: value to be returned if NAND_CMD_STATUS command -- * is executed -+ * - * @last_command: keeps track of last command on this chip. used - * for reading correct status - * - * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for - * ecc/non-ecc mode for the current nand flash - * device -+ * -+ * @status: value to be returned if NAND_CMD_STATUS command -+ * is executed -+ * @use_ecc: request the controller to use ECC for the -+ * upcoming read/write -+ * @bch_enabled: flag to tell whether BCH ECC mode is used - */ - struct qcom_nand_host { - struct nand_chip chip; -@@ -451,12 +466,10 @@ struct qcom_nand_host { - int cs; - int cw_size; - int cw_data; -- bool use_ecc; -- bool bch_enabled; - int ecc_bytes_hw; - int spare_bytes; - int bbm_size; -- u8 status; -+ - int last_command; - - u32 cfg0, cfg1; -@@ -465,23 +478,27 @@ struct qcom_nand_host { - u32 ecc_bch_cfg; - u32 clrflashstatus; - u32 clrreadstatus; -+ -+ u8 status; -+ bool use_ecc; -+ bool bch_enabled; - }; - - /* - * This data type corresponds to the NAND controller properties which varies - * among different NAND controllers. - * @ecc_modes - ecc mode for NAND -+ * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset - * @is_bam - whether NAND controller is using BAM - * @is_qpic - whether NAND CTRL is part of qpic IP - * @qpic_v2 - flag to indicate QPIC IP version 2 -- * @dev_cmd_reg_start - NAND_DEV_CMD_* registers starting offset - */ - struct qcom_nandc_props { - u32 ecc_modes; -+ u32 dev_cmd_reg_start; - bool is_bam; - bool is_qpic; - bool qpic_v2; -- u32 dev_cmd_reg_start; - }; - - /* Frees the BAM transaction memory */ diff --git a/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch b/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch deleted file mode 100644 index 2a661953044..00000000000 --- a/target/linux/ipq806x/patches-6.1/116-v6.0-02-mtd-nand-raw-qcom_nandc-add-support-for-unprotected-.patch +++ /dev/null @@ -1,406 +0,0 @@ -From 862bdedd7f4b8aebf00fdb422062e64896e97809 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 16 Jun 2022 02:18:34 +0200 -Subject: [PATCH 2/2] mtd: nand: raw: qcom_nandc: add support for unprotected - spare data pages - -IPQ8064 nand have special pages where a different layout scheme is used. -These special page are used by boot partition and on reading them -lots of warning are reported about wrong ECC data and if written to -results in broken data and not bootable device. - -The layout scheme used by these special page consist in using 512 bytes -as the codeword size (even for the last codeword) while writing to CFG0 -register. This forces the NAND controller to unprotect the 4 bytes of -spare data. - -Since the kernel is unaware of this different layout for these special -page, it does try to protect the spare data too during read/write and -warn about CRC errors. - -Add support for this by permitting the user to declare these special -pages in dts by declaring offset and size of the partition. The driver -internally will convert these value to nand pages. - -On user read/write the page is checked and if it's a boot page the -correct layout is used. - -Signed-off-by: Christian Marangi -Reviewed-by: Manivannan Sadhasivam -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20220616001835.24393-3-ansuelsmth@gmail.com ---- - drivers/mtd/nand/raw/qcom_nandc.c | 199 +++++++++++++++++++++++++++++- - 1 file changed, 194 insertions(+), 5 deletions(-) - ---- a/drivers/mtd/nand/raw/qcom_nandc.c -+++ b/drivers/mtd/nand/raw/qcom_nandc.c -@@ -79,8 +79,10 @@ - #define DISABLE_STATUS_AFTER_WRITE 4 - #define CW_PER_PAGE 6 - #define UD_SIZE_BYTES 9 -+#define UD_SIZE_BYTES_MASK GENMASK(18, 9) - #define ECC_PARITY_SIZE_BYTES_RS 19 - #define SPARE_SIZE_BYTES 23 -+#define SPARE_SIZE_BYTES_MASK GENMASK(26, 23) - #define NUM_ADDR_CYCLES 27 - #define STATUS_BFR_READ 30 - #define SET_RD_MODE_AFTER_STATUS 31 -@@ -101,6 +103,7 @@ - #define ECC_MODE 4 - #define ECC_PARITY_SIZE_BYTES_BCH 8 - #define ECC_NUM_DATA_BYTES 16 -+#define ECC_NUM_DATA_BYTES_MASK GENMASK(25, 16) - #define ECC_FORCE_CLK_OPEN 30 - - /* NAND_DEV_CMD1 bits */ -@@ -431,12 +434,31 @@ struct qcom_nand_controller { - }; - - /* -+ * NAND special boot partitions -+ * -+ * @page_offset: offset of the partition where spare data is not protected -+ * by ECC (value in pages) -+ * @page_offset: size of the partition where spare data is not protected -+ * by ECC (value in pages) -+ */ -+struct qcom_nand_boot_partition { -+ u32 page_offset; -+ u32 page_size; -+}; -+ -+/* - * NAND chip structure - * -+ * @boot_partitions: array of boot partitions where offset and size of the -+ * boot partitions are stored -+ * - * @chip: base NAND chip structure - * @node: list node to add itself to host_list in - * qcom_nand_controller - * -+ * @nr_boot_partitions: count of the boot partitions where spare data is not -+ * protected by ECC -+ * - * @cs: chip select value for this chip - * @cw_size: the number of bytes in a single step/codeword - * of a page, consisting of all data, ecc, spare -@@ -455,14 +477,20 @@ struct qcom_nand_controller { - * - * @status: value to be returned if NAND_CMD_STATUS command - * is executed -+ * @codeword_fixup: keep track of the current layout used by -+ * the driver for read/write operation. - * @use_ecc: request the controller to use ECC for the - * upcoming read/write - * @bch_enabled: flag to tell whether BCH ECC mode is used - */ - struct qcom_nand_host { -+ struct qcom_nand_boot_partition *boot_partitions; -+ - struct nand_chip chip; - struct list_head node; - -+ int nr_boot_partitions; -+ - int cs; - int cw_size; - int cw_data; -@@ -480,6 +508,7 @@ struct qcom_nand_host { - u32 clrreadstatus; - - u8 status; -+ bool codeword_fixup; - bool use_ecc; - bool bch_enabled; - }; -@@ -492,6 +521,7 @@ struct qcom_nand_host { - * @is_bam - whether NAND controller is using BAM - * @is_qpic - whether NAND CTRL is part of qpic IP - * @qpic_v2 - flag to indicate QPIC IP version 2 -+ * @use_codeword_fixup - whether NAND has different layout for boot partitions - */ - struct qcom_nandc_props { - u32 ecc_modes; -@@ -499,6 +529,7 @@ struct qcom_nandc_props { - bool is_bam; - bool is_qpic; - bool qpic_v2; -+ bool use_codeword_fixup; - }; - - /* Frees the BAM transaction memory */ -@@ -1708,7 +1739,7 @@ qcom_nandc_read_cw_raw(struct mtd_info * - data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); - oob_size1 = host->bbm_size; - -- if (qcom_nandc_is_last_cw(ecc, cw)) { -+ if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { - data_size2 = ecc->size - data_size1 - - ((ecc->steps - 1) * 4); - oob_size2 = (ecc->steps * 4) + host->ecc_bytes_hw + -@@ -1789,7 +1820,7 @@ check_for_erased_page(struct qcom_nand_h - } - - for_each_set_bit(cw, &uncorrectable_cws, ecc->steps) { -- if (qcom_nandc_is_last_cw(ecc, cw)) { -+ if (qcom_nandc_is_last_cw(ecc, cw) && !host->codeword_fixup) { - data_size = ecc->size - ((ecc->steps - 1) * 4); - oob_size = (ecc->steps * 4) + host->ecc_bytes_hw; - } else { -@@ -1947,7 +1978,7 @@ static int read_page_ecc(struct qcom_nan - for (i = 0; i < ecc->steps; i++) { - int data_size, oob_size; - -- if (qcom_nandc_is_last_cw(ecc, i)) { -+ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { - data_size = ecc->size - ((ecc->steps - 1) << 2); - oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + - host->spare_bytes; -@@ -2044,6 +2075,69 @@ static int copy_last_cw(struct qcom_nand - return ret; - } - -+static bool qcom_nandc_is_boot_partition(struct qcom_nand_host *host, int page) -+{ -+ struct qcom_nand_boot_partition *boot_partition; -+ u32 start, end; -+ int i; -+ -+ /* -+ * Since the frequent access will be to the non-boot partitions like rootfs, -+ * optimize the page check by: -+ * -+ * 1. Checking if the page lies after the last boot partition. -+ * 2. Checking from the boot partition end. -+ */ -+ -+ /* First check the last boot partition */ -+ boot_partition = &host->boot_partitions[host->nr_boot_partitions - 1]; -+ start = boot_partition->page_offset; -+ end = start + boot_partition->page_size; -+ -+ /* Page is after the last boot partition end. This is NOT a boot partition */ -+ if (page > end) -+ return false; -+ -+ /* Actually check if it's a boot partition */ -+ if (page < end && page >= start) -+ return true; -+ -+ /* Check the other boot partitions starting from the second-last partition */ -+ for (i = host->nr_boot_partitions - 2; i >= 0; i--) { -+ boot_partition = &host->boot_partitions[i]; -+ start = boot_partition->page_offset; -+ end = start + boot_partition->page_size; -+ -+ if (page < end && page >= start) -+ return true; -+ } -+ -+ return false; -+} -+ -+static void qcom_nandc_codeword_fixup(struct qcom_nand_host *host, int page) -+{ -+ bool codeword_fixup = qcom_nandc_is_boot_partition(host, page); -+ -+ /* Skip conf write if we are already in the correct mode */ -+ if (codeword_fixup == host->codeword_fixup) -+ return; -+ -+ host->codeword_fixup = codeword_fixup; -+ -+ host->cw_data = codeword_fixup ? 512 : 516; -+ host->spare_bytes = host->cw_size - host->ecc_bytes_hw - -+ host->bbm_size - host->cw_data; -+ -+ host->cfg0 &= ~(SPARE_SIZE_BYTES_MASK | UD_SIZE_BYTES_MASK); -+ host->cfg0 |= host->spare_bytes << SPARE_SIZE_BYTES | -+ host->cw_data << UD_SIZE_BYTES; -+ -+ host->ecc_bch_cfg &= ~ECC_NUM_DATA_BYTES_MASK; -+ host->ecc_bch_cfg |= host->cw_data << ECC_NUM_DATA_BYTES; -+ host->ecc_buf_cfg = (host->cw_data - 1) << NUM_STEPS; -+} -+ - /* implements ecc->read_page() */ - static int qcom_nandc_read_page(struct nand_chip *chip, uint8_t *buf, - int oob_required, int page) -@@ -2052,6 +2146,9 @@ static int qcom_nandc_read_page(struct n - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - u8 *data_buf, *oob_buf = NULL; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - nand_read_page_op(chip, page, 0, NULL, 0); - data_buf = buf; - oob_buf = oob_required ? chip->oob_poi : NULL; -@@ -2071,6 +2168,9 @@ static int qcom_nandc_read_page_raw(stru - int cw, ret; - u8 *data_buf = buf, *oob_buf = chip->oob_poi; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - for (cw = 0; cw < ecc->steps; cw++) { - ret = qcom_nandc_read_cw_raw(mtd, chip, data_buf, oob_buf, - page, cw); -@@ -2091,6 +2191,9 @@ static int qcom_nandc_read_oob(struct na - struct qcom_nand_controller *nandc = get_qcom_nand_controller(chip); - struct nand_ecc_ctrl *ecc = &chip->ecc; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - clear_read_regs(nandc); - clear_bam_transaction(nandc); - -@@ -2111,6 +2214,9 @@ static int qcom_nandc_write_page(struct - u8 *data_buf, *oob_buf; - int i, ret; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - nand_prog_page_begin_op(chip, page, 0, NULL, 0); - - clear_read_regs(nandc); -@@ -2126,7 +2232,7 @@ static int qcom_nandc_write_page(struct - for (i = 0; i < ecc->steps; i++) { - int data_size, oob_size; - -- if (qcom_nandc_is_last_cw(ecc, i)) { -+ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { - data_size = ecc->size - ((ecc->steps - 1) << 2); - oob_size = (ecc->steps << 2) + host->ecc_bytes_hw + - host->spare_bytes; -@@ -2183,6 +2289,9 @@ static int qcom_nandc_write_page_raw(str - u8 *data_buf, *oob_buf; - int i, ret; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - nand_prog_page_begin_op(chip, page, 0, NULL, 0); - clear_read_regs(nandc); - clear_bam_transaction(nandc); -@@ -2201,7 +2310,7 @@ static int qcom_nandc_write_page_raw(str - data_size1 = mtd->writesize - host->cw_size * (ecc->steps - 1); - oob_size1 = host->bbm_size; - -- if (qcom_nandc_is_last_cw(ecc, i)) { -+ if (qcom_nandc_is_last_cw(ecc, i) && !host->codeword_fixup) { - data_size2 = ecc->size - data_size1 - - ((ecc->steps - 1) << 2); - oob_size2 = (ecc->steps << 2) + host->ecc_bytes_hw + -@@ -2261,6 +2370,9 @@ static int qcom_nandc_write_oob(struct n - int data_size, oob_size; - int ret; - -+ if (host->nr_boot_partitions) -+ qcom_nandc_codeword_fixup(host, page); -+ - host->use_ecc = true; - clear_bam_transaction(nandc); - -@@ -2922,6 +3034,74 @@ static int qcom_nandc_setup(struct qcom_ - - static const char * const probes[] = { "cmdlinepart", "ofpart", "qcomsmem", NULL }; - -+static int qcom_nand_host_parse_boot_partitions(struct qcom_nand_controller *nandc, -+ struct qcom_nand_host *host, -+ struct device_node *dn) -+{ -+ struct nand_chip *chip = &host->chip; -+ struct mtd_info *mtd = nand_to_mtd(chip); -+ struct qcom_nand_boot_partition *boot_partition; -+ struct device *dev = nandc->dev; -+ int partitions_count, i, j, ret; -+ -+ if (!of_find_property(dn, "qcom,boot-partitions", NULL)) -+ return 0; -+ -+ partitions_count = of_property_count_u32_elems(dn, "qcom,boot-partitions"); -+ if (partitions_count <= 0) { -+ dev_err(dev, "Error parsing boot partition\n"); -+ return partitions_count ? partitions_count : -EINVAL; -+ } -+ -+ host->nr_boot_partitions = partitions_count / 2; -+ host->boot_partitions = devm_kcalloc(dev, host->nr_boot_partitions, -+ sizeof(*host->boot_partitions), GFP_KERNEL); -+ if (!host->boot_partitions) { -+ host->nr_boot_partitions = 0; -+ return -ENOMEM; -+ } -+ -+ for (i = 0, j = 0; i < host->nr_boot_partitions; i++, j += 2) { -+ boot_partition = &host->boot_partitions[i]; -+ -+ ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j, -+ &boot_partition->page_offset); -+ if (ret) { -+ dev_err(dev, "Error parsing boot partition offset at index %d\n", i); -+ host->nr_boot_partitions = 0; -+ return ret; -+ } -+ -+ if (boot_partition->page_offset % mtd->writesize) { -+ dev_err(dev, "Boot partition offset not multiple of writesize at index %i\n", -+ i); -+ host->nr_boot_partitions = 0; -+ return -EINVAL; -+ } -+ /* Convert offset to nand pages */ -+ boot_partition->page_offset /= mtd->writesize; -+ -+ ret = of_property_read_u32_index(dn, "qcom,boot-partitions", j + 1, -+ &boot_partition->page_size); -+ if (ret) { -+ dev_err(dev, "Error parsing boot partition size at index %d\n", i); -+ host->nr_boot_partitions = 0; -+ return ret; -+ } -+ -+ if (boot_partition->page_size % mtd->writesize) { -+ dev_err(dev, "Boot partition size not multiple of writesize at index %i\n", -+ i); -+ host->nr_boot_partitions = 0; -+ return -EINVAL; -+ } -+ /* Convert size to nand pages */ -+ boot_partition->page_size /= mtd->writesize; -+ } -+ -+ return 0; -+} -+ - static int qcom_nand_host_init_and_register(struct qcom_nand_controller *nandc, - struct qcom_nand_host *host, - struct device_node *dn) -@@ -2979,6 +3159,14 @@ static int qcom_nand_host_init_and_regis - if (ret) - nand_cleanup(chip); - -+ if (nandc->props->use_codeword_fixup) { -+ ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn); -+ if (ret) { -+ nand_cleanup(chip); -+ return ret; -+ } -+ } -+ - return ret; - } - -@@ -3144,6 +3332,7 @@ static int qcom_nandc_remove(struct plat - static const struct qcom_nandc_props ipq806x_nandc_props = { - .ecc_modes = (ECC_RS_4BIT | ECC_BCH_8BIT), - .is_bam = false, -+ .use_codeword_fixup = true, - .dev_cmd_reg_start = 0x0, - }; - diff --git a/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch b/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch deleted file mode 100644 index 3008fff9b7f..00000000000 --- a/target/linux/ipq806x/patches-6.1/117-v6.0-01-clk-qcom-clk-hfpll-use-poll_timeout-macro.patch +++ /dev/null @@ -1,41 +0,0 @@ -From fcfbfe373d41b4728ffec075f8f91b6572a88c27 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 30 Apr 2022 07:44:56 +0200 -Subject: [PATCH 1/3] clk: qcom: clk-hfpll: use poll_timeout macro - -Use regmap_read_poll_timeout macro instead of do-while structure to tidy -things up. Also set a timeout to prevent any sort of system stall. - -Signed-off-by: Ansuel Smith -Reviewed-by: Dmitry Baryshkov -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220430054458.31321-2-ansuelsmth@gmail.com ---- - drivers/clk/qcom/clk-hfpll.c | 15 +++++++++------ - 1 file changed, 9 insertions(+), 6 deletions(-) - ---- a/drivers/clk/qcom/clk-hfpll.c -+++ b/drivers/clk/qcom/clk-hfpll.c -@@ -72,13 +72,16 @@ static void __clk_hfpll_enable(struct cl - regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N); - - /* Wait for PLL to lock. */ -- if (hd->status_reg) { -- do { -- regmap_read(regmap, hd->status_reg, &val); -- } while (!(val & BIT(hd->lock_bit))); -- } else { -+ if (hd->status_reg) -+ /* -+ * Busy wait. Should never timeout, we add a timeout to -+ * prevent any sort of stall. -+ */ -+ regmap_read_poll_timeout(regmap, hd->status_reg, val, -+ !(val & BIT(hd->lock_bit)), 0, -+ 100 * USEC_PER_MSEC); -+ else - udelay(60); -- } - - /* Enable PLL output. */ - regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL); diff --git a/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch b/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch deleted file mode 100644 index 4012e16f9bc..00000000000 --- a/target/linux/ipq806x/patches-6.1/117-v6.0-03-clk-qcom-clk-krait-add-apq-ipq8064-errata-workaround.patch +++ /dev/null @@ -1,86 +0,0 @@ -From 898d0d6483a9360f1968e0a900465c1fa152a4a9 Mon Sep 17 00:00:00 2001 -From: Ansuel Smith -Date: Sat, 30 Apr 2022 07:44:58 +0200 -Subject: [PATCH 3/3] clk: qcom: clk-krait: add apq/ipq8064 errata workaround - -Add apq/ipq8064 errata workaround where the sec_src clock gating needs to -be disabled during switching. krait-cc compatible is not enough to -handle this and limit this workaround to apq/ipq8064. We check machine -compatible to handle this. - -Signed-off-by: Ansuel Smith -Reviewed-by: Dmitry Baryshkov -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220430054458.31321-4-ansuelsmth@gmail.com ---- - drivers/clk/qcom/clk-krait.c | 16 ++++++++++++++++ - drivers/clk/qcom/clk-krait.h | 1 + - drivers/clk/qcom/krait-cc.c | 8 ++++++++ - 3 files changed, 25 insertions(+) - ---- a/drivers/clk/qcom/clk-krait.c -+++ b/drivers/clk/qcom/clk-krait.c -@@ -18,13 +18,23 @@ - static DEFINE_SPINLOCK(krait_clock_reg_lock); - - #define LPL_SHIFT 8 -+#define SECCLKAGD BIT(4) -+ - static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel) - { - unsigned long flags; - u32 regval; - - spin_lock_irqsave(&krait_clock_reg_lock, flags); -+ - regval = krait_get_l2_indirect_reg(mux->offset); -+ -+ /* apq/ipq8064 Errata: disable sec_src clock gating during switch. */ -+ if (mux->disable_sec_src_gating) { -+ regval |= SECCLKAGD; -+ krait_set_l2_indirect_reg(mux->offset, regval); -+ } -+ - regval &= ~(mux->mask << mux->shift); - regval |= (sel & mux->mask) << mux->shift; - if (mux->lpl) { -@@ -33,6 +43,12 @@ static void __krait_mux_set_sel(struct k - } - krait_set_l2_indirect_reg(mux->offset, regval); - -+ /* apq/ipq8064 Errata: re-enabled sec_src clock gating. */ -+ if (mux->disable_sec_src_gating) { -+ regval &= ~SECCLKAGD; -+ krait_set_l2_indirect_reg(mux->offset, regval); -+ } -+ - /* Wait for switch to complete. */ - mb(); - udelay(1); ---- a/drivers/clk/qcom/clk-krait.h -+++ b/drivers/clk/qcom/clk-krait.h -@@ -15,6 +15,7 @@ struct krait_mux_clk { - u8 safe_sel; - u8 old_index; - bool reparent; -+ bool disable_sec_src_gating; - - struct clk_hw hw; - struct notifier_block clk_nb; ---- a/drivers/clk/qcom/krait-cc.c -+++ b/drivers/clk/qcom/krait-cc.c -@@ -139,6 +139,14 @@ krait_add_sec_mux(struct device *dev, in - mux->hw.init = &init; - mux->safe_sel = 0; - -+ /* Checking for qcom,krait-cc-v1 or qcom,krait-cc-v2 is not -+ * enough to limit this to apq/ipq8064. Directly check machine -+ * compatible to correctly handle this errata. -+ */ -+ if (of_machine_is_compatible("qcom,ipq8064") || -+ of_machine_is_compatible("qcom,apq8064")) -+ mux->disable_sec_src_gating = true; -+ - init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s); - if (!init.name) - return -ENOMEM; diff --git a/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch b/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch deleted file mode 100644 index 8567d0802bc..00000000000 --- a/target/linux/ipq806x/patches-6.1/118-v6.1-03-clk-introduce-devm_-hw_register_mux_parent_data_tabl.patch +++ /dev/null @@ -1,46 +0,0 @@ -From e4cacac0cae3ce7399b70df3bce92eac03151624 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Tue, 12 Apr 2022 16:48:39 +0200 -Subject: [PATCH 3/4] clk: introduce (devm_)hw_register_mux_parent_data_table - API - -Introduce (devm_)hw_register_mux_parent_data_table new API. We have -basic support for clk_register_mux using parent_data but we lack any API -to provide a custom parent_map. Add these 2 new API to correctly handle -these special configuration instead of using the generic -__(devm_)clk_hw_register_mux API. - -Signed-off-by: Christian Marangi ---- - include/linux/clk-provider.h | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - ---- a/include/linux/clk-provider.h -+++ b/include/linux/clk-provider.h -@@ -955,12 +955,26 @@ struct clk *clk_register_mux_table(struc - __clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, NULL, \ - (parent_data), (flags), (reg), (shift), \ - BIT((width)) - 1, (clk_mux_flags), NULL, (lock)) -+#define clk_hw_register_mux_parent_data_table(dev, name, parent_data, \ -+ num_parents, flags, reg, shift, \ -+ width, clk_mux_flags, table, \ -+ lock) \ -+ __clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, NULL, \ -+ (parent_data), (flags), (reg), (shift), \ -+ BIT((width)) - 1, (clk_mux_flags), table, (lock)) - #define devm_clk_hw_register_mux(dev, name, parent_names, num_parents, flags, reg, \ - shift, width, clk_mux_flags, lock) \ - __devm_clk_hw_register_mux((dev), NULL, (name), (num_parents), \ - (parent_names), NULL, NULL, (flags), (reg), \ - (shift), BIT((width)) - 1, (clk_mux_flags), \ - NULL, (lock)) -+#define devm_clk_hw_register_mux_parent_data_table(dev, name, parent_data, \ -+ num_parents, flags, reg, shift, \ -+ width, clk_mux_flags, table, \ -+ lock) \ -+ __devm_clk_hw_register_mux((dev), NULL, (name), (num_parents), NULL, \ -+ NULL, (parent_data), (flags), (reg), (shift), \ -+ BIT((width)) - 1, (clk_mux_flags), table, (lock)) - - int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, - unsigned int val); diff --git a/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch b/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch deleted file mode 100644 index 6c5f5ea96b2..00000000000 --- a/target/linux/ipq806x/patches-6.1/118-v6.1-04-clk-qcom-kpss-xcc-convert-to-parent-data-API.patch +++ /dev/null @@ -1,70 +0,0 @@ -From d08c79b818767f24c3c9cbba585d8a3ec896c1a1 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 17 Feb 2022 22:43:34 +0100 -Subject: [PATCH 4/4] clk: qcom: kpss-xcc: convert to parent data API - -Convert the driver to parent data API. From the Documentation pll8_vote -and pxo should be declared in the DTS so fw_name can be used instead of -parent_names. Name is still used to save regression on old definition. - -Signed-off-by: Christian Marangi ---- - drivers/clk/qcom/kpss-xcc.c | 26 +++++++++----------------- - 1 file changed, 9 insertions(+), 17 deletions(-) - ---- a/drivers/clk/qcom/kpss-xcc.c -+++ b/drivers/clk/qcom/kpss-xcc.c -@@ -12,9 +12,9 @@ - #include - #include - --static const char *aux_parents[] = { -- "pll8_vote", -- "pxo", -+static const struct clk_parent_data aux_parents[] = { -+ { .name = "pll8_vote", .fw_name = "pll8_vote" }, -+ { .name = "pxo", .fw_name = "pxo" }, - }; - - static unsigned int aux_parent_map[] = { -@@ -32,9 +32,9 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_t - static int kpss_xcc_driver_probe(struct platform_device *pdev) - { - const struct of_device_id *id; -- struct clk *clk; - struct resource *res; - void __iomem *base; -+ struct clk_hw *hw; - const char *name; - - id = of_match_device(kpss_xcc_match_table, &pdev->dev); -@@ -57,24 +57,16 @@ static int kpss_xcc_driver_probe(struct - base += 0x28; - } - -- clk = clk_register_mux_table(&pdev->dev, name, aux_parents, -- ARRAY_SIZE(aux_parents), 0, base, 0, 0x3, -- 0, aux_parent_map, NULL); -+ hw = devm_clk_hw_register_mux_parent_data_table(&pdev->dev, name, aux_parents, -+ ARRAY_SIZE(aux_parents), 0, -+ base, 0, 0x3, -+ 0, aux_parent_map, NULL); - -- platform_set_drvdata(pdev, clk); -- -- return PTR_ERR_OR_ZERO(clk); --} -- --static int kpss_xcc_driver_remove(struct platform_device *pdev) --{ -- clk_unregister_mux(platform_get_drvdata(pdev)); -- return 0; -+ return PTR_ERR_OR_ZERO(hw); - } - - static struct platform_driver kpss_xcc_driver = { - .probe = kpss_xcc_driver_probe, -- .remove = kpss_xcc_driver_remove, - .driver = { - .name = "kpss-xcc", - .of_match_table = kpss_xcc_match_table, diff --git a/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch b/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch deleted file mode 100644 index f853b5d2f24..00000000000 --- a/target/linux/ipq806x/patches-6.1/119-v6.0-02-ARM-dts-qcom-add-rpmcc-missing-clocks-for-apq-ipq806.patch +++ /dev/null @@ -1,61 +0,0 @@ -From aa7fd3bb6017b343585e97a909f9b7d2fe174018 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 00:53:19 +0200 -Subject: [PATCH] ARM: dts: qcom: add rpmcc missing clocks for apq/ipq8064 and - msm8660 - -Add missing rpmcc pxo and cxo clock for apq8064, ipq8064 and -msm8660 dtsi. - -Signed-off-by: Christian Marangi -Reviewed-by: Dmitry Baryshkov -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220706225321.26215-3-ansuelsmth@gmail.com ---- - arch/arm/boot/dts/qcom-apq8064.dtsi | 2 ++ - arch/arm/boot/dts/qcom-ipq8064.dtsi | 2 ++ - arch/arm/boot/dts/qcom-msm8660.dtsi | 4 +++- - 3 files changed, 7 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/qcom-apq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi -@@ -862,6 +862,8 @@ - rpmcc: clock-controller { - compatible = "qcom,rpmcc-apq8064", "qcom,rpmcc"; - #clock-cells = <1>; -+ clocks = <&pxo_board>, <&cxo_board>; -+ clock-names = "pxo", "cxo"; - }; - - regulators { ---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi -+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1074,6 +1074,8 @@ - rpmcc: clock-controller { - compatible = "qcom,rpmcc-ipq806x", "qcom,rpmcc"; - #clock-cells = <1>; -+ clocks = <&pxo_board>; -+ clock-names = "pxo"; - }; - }; - ---- a/arch/arm/boot/dts/qcom-msm8660.dtsi -+++ b/arch/arm/boot/dts/qcom-msm8660.dtsi -@@ -56,7 +56,7 @@ - clock-frequency = <19200000>; - }; - -- pxo_board { -+ pxo_board: pxo_board { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <27000000>; -@@ -420,6 +420,8 @@ - rpmcc: clock-controller { - compatible = "qcom,rpmcc-msm8660", "qcom,rpmcc"; - #clock-cells = <1>; -+ clocks = <&pxo_board>; -+ clock-names = "pxo"; - }; - - pm8901-regulators { diff --git a/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch b/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch deleted file mode 100644 index 8481b636708..00000000000 --- a/target/linux/ipq806x/patches-6.1/119-v6.0-03-clk-qcom-clk-rpm-convert-to-parent_data-API.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 129d9cd9c25041f8b8681fd6e8584fa47c385f3b Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Thu, 7 Jul 2022 00:53:20 +0200 -Subject: [PATCH] clk: qcom: clk-rpm: convert to parent_data API - -Convert clk-rpm driver to parent_data API. -We keep the old pxo/cxo_board parent naming to keep compatibility with -old DT and we use the new pxo/cxo for new implementation where these -clock are defined in DTS. - -Signed-off-by: Christian Marangi -Signed-off-by: Bjorn Andersson -Link: https://lore.kernel.org/r/20220706225321.26215-4-ansuelsmth@gmail.com ---- - drivers/clk/qcom/clk-rpm.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - ---- a/drivers/clk/qcom/clk-rpm.c -+++ b/drivers/clk/qcom/clk-rpm.c -@@ -23,6 +23,14 @@ - #define QCOM_RPM_SCALING_ENABLE_ID 0x2 - #define QCOM_RPM_XO_MODE_ON 0x2 - -+static const struct clk_parent_data gcc_pxo[] = { -+ { .fw_name = "pxo", .name = "pxo_board" }, -+}; -+ -+static const struct clk_parent_data gcc_cxo[] = { -+ { .fw_name = "cxo", .name = "cxo_board" }, -+}; -+ - #define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ - static struct clk_rpm _platform##_##_active; \ - static struct clk_rpm _platform##_##_name = { \ -@@ -32,8 +40,8 @@ - .hw.init = &(struct clk_init_data){ \ - .ops = &clk_rpm_ops, \ - .name = #_name, \ -- .parent_names = (const char *[]){ "pxo_board" }, \ -- .num_parents = 1, \ -+ .parent_data = gcc_pxo, \ -+ .num_parents = ARRAY_SIZE(gcc_pxo), \ - }, \ - }; \ - static struct clk_rpm _platform##_##_active = { \ -@@ -44,8 +52,8 @@ - .hw.init = &(struct clk_init_data){ \ - .ops = &clk_rpm_ops, \ - .name = #_active, \ -- .parent_names = (const char *[]){ "pxo_board" }, \ -- .num_parents = 1, \ -+ .parent_data = gcc_pxo, \ -+ .num_parents = ARRAY_SIZE(gcc_pxo), \ - }, \ - } - -@@ -56,8 +64,8 @@ - .hw.init = &(struct clk_init_data){ \ - .ops = &clk_rpm_xo_ops, \ - .name = #_name, \ -- .parent_names = (const char *[]){ "cxo_board" }, \ -- .num_parents = 1, \ -+ .parent_data = gcc_cxo, \ -+ .num_parents = ARRAY_SIZE(gcc_cxo), \ - }, \ - } - -@@ -68,8 +76,8 @@ - .hw.init = &(struct clk_init_data){ \ - .ops = &clk_rpm_fixed_ops, \ - .name = #_name, \ -- .parent_names = (const char *[]){ "pxo" }, \ -- .num_parents = 1, \ -+ .parent_data = gcc_pxo, \ -+ .num_parents = ARRAY_SIZE(gcc_pxo), \ - }, \ - } - diff --git a/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch b/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch deleted file mode 100644 index 2e7e6833bb8..00000000000 --- a/target/linux/ipq806x/patches-6.1/130-6.1-mtd-rawnand-qcom-handle-ret-from-parse-with-codeword.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 7df140e84a75c89962feef659d686303d3ce75e5 Mon Sep 17 00:00:00 2001 -From: Christian Marangi -Date: Fri, 21 Oct 2022 18:53:04 +0200 -Subject: [PATCH] mtd: rawnand: qcom: handle ret from parse with codeword_fixup - -With use_codeword_fixup enabled, any return from -mtd_device_parse_register gets overwritten. Aside from the clear bug, this -is also problematic as a parser can EPROBE_DEFER and because this is not -correctly handled, the nand is never rescanned later in the bootup -process. - -An example of this problem is when smem requires additional time to be -probed and nandc use qcomsmempart as parser. Parser will return -EPROBE_DEFER but in the current code this ret gets overwritten by -qcom_nand_host_parse_boot_partitions and qcom_nand_host_init_and_register -return 0. - -Correctly handle the return code from mtd_device_parse_register so that -any error from this function is not ignored. - -Fixes: 862bdedd7f4b ("mtd: nand: raw: qcom_nandc: add support for unprotected spare data pages") -Cc: stable@vger.kernel.org # v6.0+ -Signed-off-by: Christian Marangi -Signed-off-by: Miquel Raynal -Link: https://lore.kernel.org/linux-mtd/20221021165304.19991-1-ansuelsmth@gmail.com ---- - drivers/mtd/nand/raw/qcom_nandc.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - ---- a/drivers/mtd/nand/raw/qcom_nandc.c -+++ b/drivers/mtd/nand/raw/qcom_nandc.c -@@ -3157,16 +3157,18 @@ static int qcom_nand_host_init_and_regis - - ret = mtd_device_parse_register(mtd, probes, NULL, NULL, 0); - if (ret) -- nand_cleanup(chip); -+ goto err; - - if (nandc->props->use_codeword_fixup) { - ret = qcom_nand_host_parse_boot_partitions(nandc, host, dn); -- if (ret) { -- nand_cleanup(chip); -- return ret; -- } -+ if (ret) -+ goto err; - } - -+ return 0; -+ -+err: -+ nand_cleanup(chip); - return ret; - } - From f92bf3ffbc0d7523aece48b26aa5939b9d82a347 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 18 Oct 2022 23:49:18 +0200 Subject: [PATCH 83/88] ipq806x: 6.1: replace ZRELADDR HACK patch with new version With 6.1 lots have changed and the platform for Makefile.boot got dropped. Replace the patch with a new version that is alligned to the new implementation. Signed-off-by: Christian Marangi --- ...RM-mach-qcom-fix-support-for-ipq806x.patch | 67 +++++++++++++++++++ ...arch-arm-force-ZRELADDR-on-arch-qcom.patch | 62 ----------------- 2 files changed, 67 insertions(+), 62 deletions(-) create mode 100644 target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch delete mode 100644 target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch diff --git a/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch b/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch new file mode 100644 index 00000000000..41c102e30a3 --- /dev/null +++ b/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch @@ -0,0 +1,67 @@ +From 9c896e9fc2ef1209e4a56d8c9fdd183847c2c814 Mon Sep 17 00:00:00 2001 +From: Christian Marangi +Date: Tue, 18 Oct 2022 22:02:46 +0200 +Subject: [PATCH] ARM: mach-qcom: fix support for ipq806x + +Add a specific config flag for Qcom IPQ806x as this SoC can't use +AUTO_ZRELADDR and require the PHYS_OFFSET set to 0x42000000. + +This is needed as some legacy board (or some wrongly configured +bootloader) pass the wrong memory map and doesn't exclude the first +~20MB of RAM reserved for the hardware network accellerators. + +With this change we can correctly support each board and prevent any +kind of misconfiguration done by the OEM. + +Signed-off-by: Christian Marangi +--- + arch/arm/Kconfig | 3 ++- + arch/arm/mach-qcom/Kconfig | 13 +++++++++++++ + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig +index 1af63e17b4ad..0818d35973ad 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -282,6 +282,7 @@ config PHYS_OFFSET + default 0x30000000 if ARCH_S3C24XX + default 0xa0000000 if ARCH_IOP32X || ARCH_PXA + default 0xc0000000 if ARCH_EP93XX || ARCH_SA1100 ++ default 0x42000000 if ARCH_IPQ806X + default 0 + help + Please provide the physical address corresponding to the +@@ -1701,7 +1702,7 @@ config CRASH_DUMP + + config AUTO_ZRELADDR + bool "Auto calculation of the decompressed kernel image address" if !ARCH_MULTIPLATFORM +- default !(ARCH_FOOTBRIDGE || ARCH_RPC || ARCH_SA1100) ++ default !(ARCH_FOOTBRIDGE || ARCH_RPC || ARCH_SA1100 || ARCH_IPQ806X) + help + ZRELADDR is the physical address where the decompressed kernel + image will be placed. If AUTO_ZRELADDR is selected, the address +diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig +index 12a812e61c16..b11b6e391ff0 100644 +--- a/arch/arm/mach-qcom/Kconfig ++++ b/arch/arm/mach-qcom/Kconfig +@@ -46,4 +46,17 @@ config ARCH_MDM9615 + bool "Enable support for MDM9615" + select CLKSRC_QCOM + ++config ARCH_IPQ806X ++ bool "Enable support for IPQ806x" ++ help ++ Enable support for the Qualcomm IPQ806x. ++ ++ IPQ806x require special PHYS_OFFSET and can't use AUTO_ZRELADDR. ++ The first ~20MB of RAM is reserved for the hardware network accelerators, ++ and the bootloader removes this section from the layout passed from the ++ ATAGS (when used by some bootloader doesn't even do that). ++ ++ To support every system and handle legacy systems, hardcode PHYS_OFFSET and ++ disable AUTO_ZRELADDR. ++ + endif +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch deleted file mode 100644 index 1860cef8003..00000000000 --- a/target/linux/ipq806x/patches-6.1/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch +++ /dev/null @@ -1,62 +0,0 @@ -From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari -Date: Wed, 29 Apr 2015 15:21:46 -0700 -Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom - -ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended -on most ARM architectures. This automatically calculate ZRELADDR by -masking PHYS_OFFSET with 0xf8000000. - -However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware -network accelerators, and the bootloader removes this section from the -layout passed from the ATAGS (when used). - -For newer bootloader, when DT is used, this is not a problem, we just -reserve this memory in the device tree. But if the bootloader doesn't -have DT support, then ATAGS have to be used. In this case, the ARM -decompressor will position the kernel in this low mem, which will not be -in the RAM section mapped by the bootloader, which means the kernel will -freeze in the middle of the boot process trying to map the memory. - -As a work around, this patch allows disabling AUTO_ZRELADDR when -ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders -which don't support device-tree, which is the case on certain early -IPQ806x based designs. - -Signed-off-by: Mathieu Olivari ---- - arch/arm/Kconfig | 2 +- - arch/arm/Makefile | 2 ++ - arch/arm/mach-qcom/Makefile.boot | 1 + - 3 files changed, 4 insertions(+), 1 deletion(-) - create mode 100644 arch/arm/mach-qcom/Makefile.boot - ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -317,7 +317,7 @@ config ARCH_MULTIPLATFORM - select ARCH_SELECT_MEMORY_MODEL - select ARM_HAS_SG_CHAIN - select ARM_PATCH_PHYS_VIRT -- select AUTO_ZRELADDR -+ select AUTO_ZRELADDR if !ARCH_QCOM - select TIMER_OF - select COMMON_CLK - select GENERIC_IRQ_MULTI_HANDLER ---- a/arch/arm/Makefile -+++ b/arch/arm/Makefile -@@ -237,9 +237,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac - else - MACHINE := - endif -+ifeq ($(CONFIG_ARCH_QCOM),) - ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y) - MACHINE := - endif -+endif - - machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) - platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y))) ---- /dev/null -+++ b/arch/arm/mach-qcom/Makefile.boot -@@ -0,0 +1 @@ -+zreladdr-y+= 0x42208000 From eb69d7a4ff8c4af3e978ac60a341f27a385266fb Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 01:09:53 +0200 Subject: [PATCH 84/88] ipq806x: 6.1: manually refresh kernel patches Refresh kernel patches for version 6.1. Signed-off-by: Christian Marangi --- ...Mangle-bootloader-s-kernel-arguments.patch | 4 +- ...add-saw-for-l2-cache-and-kraitcc-for.patch | 96 +++++++++---------- ...-L2-Krait-Cache-devfreq-scaling-driv.patch | 91 ++++++++---------- ...kpss-xcc-register-it-as-clk-provider.patch | 12 ++- ...c-use-devm-variant-for-clk-notifier-.patch | 7 +- ...t-cc-handle-qsb-clock-defined-in-DTS.patch | 13 ++- ...ait-cc-register-REAL-qsb-fixed-clock.patch | 7 +- ...ait-cc-drop-pr_info-and-use-dev_info.patch | 9 +- ...c-rework-mux-reset-logic-and-reset-h.patch | 12 ++- .../850-soc-add-qualcomm-syscon.patch | 2 +- .../900-arm-add-cmdline-override.patch | 6 +- 11 files changed, 140 insertions(+), 119 deletions(-) diff --git a/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch index df5d4811a88..7d681922959 100644 --- a/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch +++ b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -248,7 +248,7 @@ Signed-off-by: Adrian Panella } --- a/init/main.c +++ b/init/main.c -@@ -114,6 +114,10 @@ +@@ -113,6 +113,10 @@ #include @@ -259,7 +259,7 @@ Signed-off-by: Adrian Panella static int kernel_init(void *); extern void init_IRQ(void); -@@ -993,6 +997,18 @@ asmlinkage __visible void __init __no_sa +@@ -992,6 +996,18 @@ asmlinkage __visible void __init __no_sa pr_notice("Kernel command line: %s\n", saved_command_line); /* parameters may set static keys */ jump_label_init(); diff --git a/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch index 418d6b26ce7..0417572be02 100644 --- a/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch +++ b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch @@ -29,53 +29,7 @@ Tested-by: Jonathan McDowell cxo_board: cxo_board { compatible = "fixed-clock"; #clock-cells = <0>; -@@ -503,11 +509,19 @@ - acc0: clock-controller@2088000 { - compatible = "qcom,kpss-acc-v1"; - reg = <0x02088000 0x1000>, <0x02008000 0x1000>; -+ clock-output-names = "acpu0_aux"; -+ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; -+ clock-names = "pll8_vote", "pxo"; -+ #clock-cells = <0>; - }; - - acc1: clock-controller@2098000 { - compatible = "qcom,kpss-acc-v1"; - reg = <0x02098000 0x1000>, <0x02008000 0x1000>; -+ clock-output-names = "acpu1_aux"; -+ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; -+ clock-names = "pll8_vote", "pxo"; -+ #clock-cells = <0>; - }; - - adm_dma: dma-controller@18300000 { -@@ -531,17 +545,23 @@ - }; - - saw0: regulator@2089000 { -- compatible = "qcom,saw2"; -+ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; - reg = <0x02089000 0x1000>, <0x02009000 0x1000>; - regulator; - }; - - saw1: regulator@2099000 { -- compatible = "qcom,saw2"; -+ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; - reg = <0x02099000 0x1000>, <0x02009000 0x1000>; - regulator; - }; - -+ saw_l2: regulator@02012000 { -+ compatible = "qcom,saw2", "syscon"; -+ reg = <0x02012000 0x1000>; -+ regulator; -+ }; -+ - gsbi1: gsbi@12440000 { - compatible = "qcom,gsbi-v1.0.0"; - reg = <0x12440000 0x100>; -@@ -920,6 +940,17 @@ +@@ -490,6 +490,17 @@ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; clock-names = "pll8_vote", "pxo"; clock-output-names = "acpu_l2_aux"; @@ -92,4 +46,50 @@ Tested-by: Jonathan McDowell + #clock-cells = <1>; }; - lcc: clock-controller@28000000 { + acc0: clock-controller@2088000 { +@@ -503,17 +509,25 @@ + acc0: clock-controller@2088000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02088000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu0_aux"; ++ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; ++ clock-names = "pll8_vote", "pxo"; ++ #clock-cells = <0>; + }; + + saw0: regulator@2089000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02089000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + + acc1: clock-controller@2098000 { + compatible = "qcom,kpss-acc-v1"; + reg = <0x02098000 0x1000>, <0x02008000 0x1000>; ++ clock-output-names = "acpu1_aux"; ++ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; ++ clock-names = "pll8_vote", "pxo"; ++ #clock-cells = <0>; + }; + + saw1: regulator@2099000 { +@@ -531,11 +545,17 @@ + }; + + saw1: regulator@2099000 { +- compatible = "qcom,saw2"; ++ compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; + reg = <0x02099000 0x1000>, <0x02009000 0x1000>; + regulator; + }; + ++ saw_l2: regulator@02012000 { ++ compatible = "qcom,saw2", "syscon"; ++ reg = <0x02012000 0x1000>; ++ regulator; ++ }; ++ + nss_common: syscon@03000000 { + compatible = "syscon"; + reg = <0x03000000 0x0000FFFF>; diff --git a/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch index 85feb89148b..af90393e2d5 100644 --- a/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch +++ b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch @@ -51,7 +51,7 @@ Signed-off-by: Christian Marangi obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/ --- /dev/null +++ b/drivers/devfreq/krait-cache-devfreq.c -@@ -0,0 +1,188 @@ +@@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include @@ -71,28 +71,25 @@ Signed-off-by: Christian Marangi +struct krait_cache_data { + struct clk *clk; + unsigned long idle_freq; ++ int token; +}; + -+static int krait_cache_set_opp(struct dev_pm_set_opp_data *data) ++static int krait_cache_config_clk(struct device *dev, struct opp_table *opp_table, ++ struct dev_pm_opp *old_opp, struct dev_pm_opp *opp, ++ void *data, bool scaling_down) +{ -+ unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate; -+ struct dev_pm_opp_supply *supply = &data->new_opp.supplies[0]; -+ struct regulator *reg = data->regulators[0]; + struct krait_cache_data *kdata; -+ struct clk *clk = data->clk; ++ unsigned long old_freq, freq; + unsigned long idle_freq; ++ struct clk *clk; + int ret; + -+ kdata = dev_get_drvdata(data->dev); ++ kdata = dev_get_drvdata(dev); + idle_freq = kdata->idle_freq; ++ clk = kdata->clk; + -+ if (reg) { -+ ret = regulator_set_voltage_triplet(reg, supply->u_volt_min, -+ supply->u_volt, -+ supply->u_volt_max); -+ if (ret) -+ goto exit; -+ } ++ old_freq = dev_pm_opp_get_freq(old_opp); ++ freq = dev_pm_opp_get_freq(opp); + + /* + * Set to idle bin if switching from normal to high bin @@ -104,15 +101,10 @@ Signed-off-by: Christian Marangi + if (likely(freq != idle_freq && old_freq != idle_freq)) { + ret = clk_set_rate(clk, idle_freq); + if (ret) -+ goto exit; ++ return ret; + } + -+ ret = clk_set_rate(clk, freq); -+ if (ret) -+ goto exit; -+ -+exit: -+ return ret; ++ return clk_set_rate(clk, freq); +}; + +static int krait_cache_get_cur_freq(struct device *dev, unsigned long *freq) @@ -162,15 +154,13 @@ Signed-off-by: Christian Marangi + +static int krait_cache_probe(struct platform_device *pdev) +{ ++ struct dev_pm_opp_config config = { }; + struct device *dev = &pdev->dev; + struct krait_cache_data *data; -+ struct opp_table *table; + struct devfreq *devfreq; + struct dev_pm_opp *opp; + struct clk *clk; -+ int ret; -+ -+ krait_cache_devfreq_profile.freq_table = NULL; ++ int ret, token; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) @@ -180,44 +170,47 @@ Signed-off-by: Christian Marangi + if (IS_ERR(clk)) + return PTR_ERR(clk); + -+ table = dev_pm_opp_set_regulators(dev, (const char *[]){ "l2" }, 1); -+ if (IS_ERR(table)) { -+ ret = PTR_ERR(table); -+ dev_err_probe(dev, -EPROBE_DEFER, "failed to set regulators %d\n", ret); -+ return ret; -+ } ++ config.regulator_names = (const char *[]){ "l2", NULL }; ++ config.clk_names = (const char *[]){ "l2", NULL }; ++ config.config_clks = krait_cache_config_clk; + -+ ret = PTR_ERR_OR_ZERO( -+ dev_pm_opp_register_set_opp_helper(dev, krait_cache_set_opp)); ++ token = dev_pm_opp_set_config(dev, &config); ++ if (token < 0) ++ return token; ++ ++ ret = devm_pm_opp_of_add_table(dev); + if (ret) -+ return ret; ++ goto free_opp; + -+ ret = dev_pm_opp_of_add_table(dev); -+ if (ret) { -+ dev_err(dev, "failed to parse L2 freq thresholds\n"); -+ return ret; -+ } -+ -+ data->clk = clk; + opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq); ++ if (IS_ERR(opp)) { ++ ret = PTR_ERR(opp); ++ goto free_opp; ++ } + dev_pm_opp_put(opp); + ++ data->token = token; ++ data->clk = clk; + dev_set_drvdata(dev, data); -+ -+ devfreq = devm_devfreq_add_device(&pdev->dev, &krait_cache_devfreq_profile, ++ devfreq = devm_devfreq_add_device(dev, &krait_cache_devfreq_profile, + DEVFREQ_GOV_PASSIVE, &devfreq_gov_data); + if (IS_ERR(devfreq)) { -+ dev_pm_opp_remove_table(dev); -+ dev_pm_opp_put_regulators(table); -+ dev_pm_opp_unregister_set_opp_helper(table); ++ ret = PTR_ERR(devfreq); ++ goto free_opp; + } + -+ return PTR_ERR_OR_ZERO(devfreq); ++ return 0; ++ ++free_opp: ++ dev_pm_opp_clear_config(token); ++ return ret; +}; + +static int krait_cache_remove(struct platform_device *pdev) +{ -+ dev_pm_opp_remove_table(&pdev->dev); ++ struct krait_cache_data *data = dev_get_drvdata(&pdev->dev); ++ ++ dev_pm_opp_clear_config(data->token); + + return 0; +}; @@ -238,5 +231,5 @@ Signed-off-by: Christian Marangi +module_platform_driver(krait_cache_driver); + +MODULE_DESCRIPTION("Krait CPU Cache Scaling driver"); -+MODULE_AUTHOR("Christian 'Ansuel' Marangi "); ++MODULE_AUTHOR("Christian Marangi "); +MODULE_LICENSE("GPL v2"); diff --git a/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch index ace313663d5..41201544f65 100644 --- a/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch +++ b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch @@ -13,15 +13,16 @@ Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com drivers/clk/qcom/kpss-xcc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) +diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c +index b1b370274ec4..97358c98c6c9 100644 --- a/drivers/clk/qcom/kpss-xcc.c +++ b/drivers/clk/qcom/kpss-xcc.c -@@ -31,13 +31,14 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_t +@@ -31,12 +31,13 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_table); static int kpss_xcc_driver_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; const struct of_device_id *id; - struct resource *res; void __iomem *base; struct clk_hw *hw; const char *name; @@ -31,7 +32,7 @@ Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com if (!id) return -ENODEV; -@@ -47,7 +48,7 @@ static int kpss_xcc_driver_probe(struct +@@ -45,7 +46,7 @@ static int kpss_xcc_driver_probe(struct platform_device *pdev) return PTR_ERR(base); if (id->data) { @@ -40,7 +41,7 @@ Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com "clock-output-names", 0, &name)) return -ENODEV; -@@ -57,12 +58,16 @@ static int kpss_xcc_driver_probe(struct +@@ -55,12 +56,16 @@ static int kpss_xcc_driver_probe(struct platform_device *pdev) base += 0x28; } @@ -59,3 +60,6 @@ Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com } static struct platform_driver kpss_xcc_driver = { +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch index 65c1fc17f21..d3d1ea17f5a 100644 --- a/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch @@ -14,9 +14,11 @@ Link: https://lore.kernel.org/r/20221108215827.30475-1-ansuelsmth@gmail.com drivers/clk/qcom/krait-cc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) +diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c +index e91275663973..33a78b7de0bd 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -62,7 +62,7 @@ static int krait_notifier_register(struc +@@ -64,7 +64,7 @@ static int krait_notifier_register(struct device *dev, struct clk *clk, int ret = 0; mux->clk_nb.notifier_call = krait_notifier_cb; @@ -25,3 +27,6 @@ Link: https://lore.kernel.org/r/20221108215827.30475-1-ansuelsmth@gmail.com if (ret) dev_err(dev, "failed to register clock notifier: %d\n", ret); +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch index c30c245d0a5..a8bf748258f 100644 --- a/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch +++ b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch @@ -12,18 +12,20 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) +diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c +index 84f0048961f5..f1d64b16cac3 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -348,7 +348,7 @@ static int krait_cc_probe(struct platfor +@@ -305,7 +305,7 @@ static int krait_cc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct of_device_id *id; - unsigned long cur_rate, aux_rate; + unsigned long cur_rate, aux_rate, qsb_rate; int cpu; - struct clk_hw *mux, *l2_pri_mux; - struct clk *clk, **clks; -@@ -357,11 +357,19 @@ static int krait_cc_probe(struct platfor + struct clk *clk; + struct clk **clks; +@@ -315,11 +315,19 @@ static int krait_cc_probe(struct platform_device *pdev) if (!id) return -ENODEV; @@ -45,3 +47,6 @@ Signed-off-by: Christian Marangi if (!id->data) { clk = clk_register_fixed_factor(dev, "acpu_aux", "gpll0_vote", 0, 1, 2); +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch index e2f78f79fb1..da082759cf8 100644 --- a/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch +++ b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch @@ -14,6 +14,8 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) +diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c +index f1d64b16cac3..e91275663973 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -25,6 +25,8 @@ enum { @@ -25,7 +27,7 @@ Signed-off-by: Christian Marangi static unsigned int sec_mux_map[] = { 2, 0, -@@ -364,7 +366,7 @@ static int krait_cc_probe(struct platfor +@@ -322,7 +324,7 @@ static int krait_cc_probe(struct platform_device *pdev) */ clk = clk_get(dev, "qsb"); if (IS_ERR(clk)) @@ -34,3 +36,6 @@ Signed-off-by: Christian Marangi if (IS_ERR(clk)) return PTR_ERR(clk); +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch index d95a63fc44f..e25627d86f6 100644 --- a/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch +++ b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch @@ -10,10 +10,12 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) +diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c +index b71067a49ee7..e4fb3ff2b5b5 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -423,25 +423,25 @@ static int krait_cc_probe(struct platfor - cur_rate = clk_get_rate(clks[l2_mux]); +@@ -391,25 +391,25 @@ static int krait_cc_probe(struct platform_device *pdev) + cur_rate = clk_get_rate(l2_pri_mux_clk); aux_rate = 384000000; if (cur_rate < aux_rate) { - pr_info("L2 @ Undefined rate. Forcing new rate.\n"); @@ -42,3 +44,6 @@ Signed-off-by: Christian Marangi } of_clk_add_provider(dev->of_node, krait_of_get, clks); +-- +2.37.2 + diff --git a/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch index 8f88e069912..7a19c965c2d 100644 --- a/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch +++ b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch @@ -17,6 +17,8 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 50 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) +diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c +index 717eff44b6a4..90dee71e7c38 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -25,7 +25,9 @@ enum { @@ -30,16 +32,16 @@ Signed-off-by: Christian Marangi static unsigned int sec_mux_map[] = { 2, -@@ -350,7 +352,7 @@ static int krait_cc_probe(struct platfor +@@ -317,7 +319,7 @@ static int krait_cc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct of_device_id *id; - unsigned long cur_rate, aux_rate, qsb_rate; + unsigned long cur_rate, qsb_rate; int cpu; - struct clk_hw *mux, *l2_pri_mux; - struct clk *clk, **clks; -@@ -420,28 +422,29 @@ static int krait_cc_probe(struct platfor + struct clk *clk; + struct clk **clks; +@@ -397,28 +399,29 @@ static int krait_cc_probe(struct platform_device *pdev) * two different rates to force a HFPLL reinit under all * circumstances. */ @@ -86,3 +88,5 @@ Signed-off-by: Christian Marangi } of_clk_add_provider(dev->of_node, krait_of_get, clks); + + diff --git a/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch index 0d983410ec1..ec9027ae47b 100644 --- a/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch +++ b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch @@ -12,7 +12,7 @@ Subject: SoC: add qualcomm syscon obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig -@@ -192,6 +192,13 @@ config QCOM_SOCINFO +@@ -190,6 +190,13 @@ config QCOM_SOCINFO Say yes here to support the Qualcomm socinfo driver, providing information about the SoC to user space. diff --git a/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch index 23cec10f445..09022dca464 100644 --- a/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch +++ b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch @@ -19,7 +19,7 @@ +++ b/drivers/of/fdt.c @@ -1162,6 +1162,17 @@ int __init early_init_dt_scan_chosen(uns if (p != NULL && l > 0) - strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE)); + strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); + /* CONFIG_CMDLINE_OVERRIDE is used to fallback to a different + * device tree option of chosen/bootargs-override. This is @@ -29,9 +29,9 @@ +#ifdef CONFIG_CMDLINE_OVERRIDE + p = of_get_flat_dt_prop(node, "bootargs-override", &l); + if (p != NULL && l > 0) -+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE)); ++ strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE)); +#endif + + handle_cmdline: /* * CONFIG_CMDLINE is meant to be a default in case nothing else - * managed to set the command line, unless CONFIG_CMDLINE_FORCE From 64c204c5862426e806008dbff762d9404660355f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Mon, 22 May 2023 18:12:08 +0200 Subject: [PATCH 85/88] ipq806x: 6.1: refresh kernel patches Refresh ipq806x kernel patches with make target/linux/refresh. Signed-off-by: Christian Marangi --- ...0060-ARM-mach-qcom-fix-support-for-ipq806x.patch | 11 ++--------- ...neric-Mangle-bootloader-s-kernel-arguments.patch | 6 +++--- ...-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch | 10 ++-------- ...-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch | 2 +- ...om-fix-wrong-nad_pins-definition-for-ipq80.patch | 2 +- ...om-add-MDIO-dedicated-controller-node-for-.patch | 8 ++++---- ...om-tsens-init-debugfs-only-with-successful.patch | 4 ++-- ...-qcom-tsens-simplify-debugfs-init-function.patch | 4 ++-- ...om-Add-L2-Krait-Cache-devfreq-scaling-driv.patch | 10 +++++----- ...om-add-krait-cache-compatible-for-ipq806x-.patch | 6 +++--- ...-devfreq-add-ipq806x-fabric-scaling-driver.patch | 6 +++--- ...-dts-qcom-add-fab-scaling-node-for-ipq806x.patch | 4 ++-- ...-qcom-kpss-xcc-register-it-as-clk-provider.patch | 11 +++-------- ...rait-cc-use-devm-variant-for-clk-notifier-.patch | 7 +------ ...m-krait-cc-handle-qsb-clock-defined-in-DTS.patch | 13 ++++--------- ...com-krait-cc-register-REAL-qsb-fixed-clock.patch | 7 +------ ...com-krait-cc-drop-pr_info-and-use-dev_info.patch | 9 ++------- ...rait-cc-rework-mux-reset-logic-and-reset-h.patch | 12 ++++-------- ...m-gcc-ipq806x-remove-cc_register_board-for.patch | 2 +- ...com-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch | 2 +- .../patches-6.1/850-soc-add-qualcomm-syscon.patch | 12 ++++++------ .../patches-6.1/900-arm-add-cmdline-override.patch | 4 ++-- 22 files changed, 55 insertions(+), 97 deletions(-) diff --git a/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch b/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch index 41c102e30a3..384eee6215b 100644 --- a/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch +++ b/target/linux/ipq806x/patches-6.1/0060-ARM-mach-qcom-fix-support-for-ipq806x.patch @@ -19,11 +19,9 @@ Signed-off-by: Christian Marangi arch/arm/mach-qcom/Kconfig | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) -diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 1af63e17b4ad..0818d35973ad 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -282,6 +282,7 @@ config PHYS_OFFSET +@@ -283,6 +283,7 @@ config PHYS_OFFSET default 0x30000000 if ARCH_S3C24XX default 0xa0000000 if ARCH_IOP32X || ARCH_PXA default 0xc0000000 if ARCH_EP93XX || ARCH_SA1100 @@ -31,7 +29,7 @@ index 1af63e17b4ad..0818d35973ad 100644 default 0 help Please provide the physical address corresponding to the -@@ -1701,7 +1702,7 @@ config CRASH_DUMP +@@ -1702,7 +1703,7 @@ config CRASH_DUMP config AUTO_ZRELADDR bool "Auto calculation of the decompressed kernel image address" if !ARCH_MULTIPLATFORM @@ -40,8 +38,6 @@ index 1af63e17b4ad..0818d35973ad 100644 help ZRELADDR is the physical address where the decompressed kernel image will be placed. If AUTO_ZRELADDR is selected, the address -diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig -index 12a812e61c16..b11b6e391ff0 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -46,4 +46,17 @@ config ARCH_MDM9615 @@ -62,6 +58,3 @@ index 12a812e61c16..b11b6e391ff0 100644 + disable AUTO_ZRELADDR. + endif --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch index 7d681922959..e40b43b968d 100644 --- a/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch +++ b/target/linux/ipq806x/patches-6.1/0067-generic-Mangle-bootloader-s-kernel-arguments.patch @@ -22,7 +22,7 @@ Signed-off-by: Adrian Panella --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -1727,6 +1727,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN +@@ -1586,6 +1586,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN The command-line arguments provided by the boot loader will be appended to the the device tree bootargs property. @@ -248,7 +248,7 @@ Signed-off-by: Adrian Panella } --- a/init/main.c +++ b/init/main.c -@@ -113,6 +113,10 @@ +@@ -114,6 +114,10 @@ #include @@ -259,7 +259,7 @@ Signed-off-by: Adrian Panella static int kernel_init(void *); extern void init_IRQ(void); -@@ -992,6 +996,18 @@ asmlinkage __visible void __init __no_sa +@@ -994,6 +998,18 @@ asmlinkage __visible void __init __no_sa pr_notice("Kernel command line: %s\n", saved_command_line); /* parameters may set static keys */ jump_label_init(); diff --git a/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch index 0417572be02..0a594b26888 100644 --- a/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch +++ b/target/linux/ipq806x/patches-6.1/107-10-ARM-dts-qcom-add-saw-for-l2-cache-and-kraitcc-for.patch @@ -29,7 +29,7 @@ Tested-by: Jonathan McDowell cxo_board: cxo_board { compatible = "fixed-clock"; #clock-cells = <0>; -@@ -490,6 +490,17 @@ +@@ -575,15 +581,30 @@ clocks = <&gcc PLL8_VOTE>, <&pxo_board>; clock-names = "pll8_vote", "pxo"; clock-output-names = "acpu_l2_aux"; @@ -47,8 +47,6 @@ Tested-by: Jonathan McDowell }; acc0: clock-controller@2088000 { -@@ -503,17 +509,25 @@ - acc0: clock-controller@2088000 { compatible = "qcom,kpss-acc-v1"; reg = <0x02088000 0x1000>, <0x02008000 0x1000>; + clock-output-names = "acpu0_aux"; @@ -63,7 +61,7 @@ Tested-by: Jonathan McDowell reg = <0x02089000 0x1000>, <0x02009000 0x1000>; regulator; }; - +@@ -591,14 +612,24 @@ acc1: clock-controller@2098000 { compatible = "qcom,kpss-acc-v1"; reg = <0x02098000 0x1000>, <0x02008000 0x1000>; @@ -73,10 +71,6 @@ Tested-by: Jonathan McDowell + #clock-cells = <0>; }; - saw1: regulator@2099000 { -@@ -531,11 +545,17 @@ - }; - saw1: regulator@2099000 { - compatible = "qcom,saw2"; + compatible = "qcom,saw2", "qcom,apq8064-saw2-v1.1-cpu", "syscon"; diff --git a/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch b/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch index f3c8f18f1de..16e924b303d 100644 --- a/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch +++ b/target/linux/ipq806x/patches-6.1/107-13-ARM-dts-qcom-add-opp-table-for-cpu-and-l2-for-ipq.patch @@ -127,7 +127,7 @@ Tested-by: Jonathan McDowell + }; + thermal-zones { - tsens_tz_sensor0 { + sensor0-thermal { polling-delay-passive = <0>; --- a/arch/arm/boot/dts/qcom-ipq8065.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8065.dtsi diff --git a/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch b/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch index d3f821a6a0f..6be9334e7d7 100644 --- a/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch +++ b/target/linux/ipq806x/patches-6.1/108-01-ARM-dts-qcom-fix-wrong-nad_pins-definition-for-ipq80.patch @@ -12,7 +12,7 @@ Signed-off-by: Christian 'Ansuel' Marangi --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -559,12 +559,9 @@ +@@ -599,12 +599,9 @@ }; nand_pins: nand_pins { diff --git a/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch b/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch index 4a57fc0330b..a35bb3874fe 100644 --- a/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch +++ b/target/linux/ipq806x/patches-6.1/108-02-ARM-dts-qcom-add-MDIO-dedicated-controller-node-for-.patch @@ -15,7 +15,7 @@ Signed-off-by: Christian 'Ansuel' Marangi --- a/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts +++ b/arch/arm/boot/dts/qcom-ipq8064-rb3011.dts -@@ -24,73 +24,6 @@ +@@ -25,73 +25,6 @@ device_type = "memory"; }; @@ -89,7 +89,7 @@ Signed-off-by: Christian 'Ansuel' Marangi mdio1: mdio-1 { status = "okay"; compatible = "virtual,mdio-gpio"; -@@ -220,6 +153,73 @@ +@@ -222,6 +155,73 @@ status = "okay"; }; @@ -165,8 +165,8 @@ Signed-off-by: Christian 'Ansuel' Marangi --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1446,6 +1446,20 @@ - }; +@@ -476,6 +476,20 @@ + snps,blen = <16 0 0 0 0 0 0>; }; + mdio0: mdio@37000000 { diff --git a/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch b/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch index 4caa2a9560e..c9b20a02220 100644 --- a/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch +++ b/target/linux/ipq806x/patches-6.1/110-01-thermal-qcom-tsens-init-debugfs-only-with-successful.patch @@ -16,7 +16,7 @@ Acked-by: Thara Gopinath --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c -@@ -917,8 +917,6 @@ int __init init_common(struct tsens_priv +@@ -918,8 +918,6 @@ int __init init_common(struct tsens_priv if (tsens_version(priv) >= VER_0_1) tsens_enable_irq(priv); @@ -25,7 +25,7 @@ Acked-by: Thara Gopinath err_put_device: put_device(&op->dev); return ret; -@@ -1163,7 +1161,12 @@ static int tsens_probe(struct platform_d +@@ -1156,7 +1154,12 @@ static int tsens_probe(struct platform_d } } diff --git a/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch b/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch index add2ab45987..0fbc4bd8cad 100644 --- a/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch +++ b/target/linux/ipq806x/patches-6.1/110-02-thermal-qcom-tsens-simplify-debugfs-init-function.patch @@ -17,7 +17,7 @@ Reviewed-by: Thara Gopinath --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c -@@ -691,7 +691,7 @@ static int dbg_version_show(struct seq_f +@@ -692,7 +692,7 @@ static int dbg_version_show(struct seq_f return ret; seq_printf(s, "%d.%d.%d\n", maj_ver, min_ver, step_ver); } else { @@ -26,7 +26,7 @@ Reviewed-by: Thara Gopinath } return 0; -@@ -703,21 +703,17 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors); +@@ -704,21 +704,17 @@ DEFINE_SHOW_ATTRIBUTE(dbg_sensors); static void tsens_debug_init(struct platform_device *pdev) { struct tsens_priv *priv = platform_get_drvdata(pdev); diff --git a/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch index af90393e2d5..9de73288799 100644 --- a/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch +++ b/target/linux/ipq806x/patches-6.1/114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch @@ -21,9 +21,9 @@ Signed-off-by: Christian Marangi --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig -@@ -132,6 +132,17 @@ config ARM_RK3399_DMC_DEVFREQ - It sets the frequency for the memory controller and reads the usage counts - from hardware. +@@ -151,6 +151,17 @@ config ARM_SUN8I_A33_MBUS_DEVFREQ + This adds the DEVFREQ driver for the MBUS controller in some + Allwinner sun8i (A33 through H3) and sun50i (A64 and H5) SoCs. +config ARM_KRAIT_CACHE_DEVFREQ + tristate "Scaling support for Krait CPU Cache Devfreq" @@ -41,9 +41,9 @@ Signed-off-by: Christian Marangi endif # PM_DEVFREQ --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx - obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o +@@ -15,6 +15,7 @@ obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) + obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o + obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o +obj-$(CONFIG_ARM_KRAIT_CACHE_DEVFREQ) += krait-cache-devfreq.o diff --git a/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch b/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch index f42729fd509..3a6c2817933 100644 --- a/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch +++ b/target/linux/ipq806x/patches-6.1/114-02-ARM-dts-qcom-add-krait-cache-compatible-for-ipq806x-.patch @@ -31,9 +31,9 @@ Signed-off-by: Christian Marangi }; opp_table_l2: opp_table_l2 { -@@ -470,6 +460,16 @@ - ranges; - compatible = "simple-bus"; +@@ -1410,6 +1400,16 @@ + #reset-cells = <1>; + }; + L2: l2-cache { + compatible = "cache", "qcom,krait-cache"; diff --git a/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch b/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch index 340c58a0c18..c9cd3ebdf73 100644 --- a/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch +++ b/target/linux/ipq806x/patches-6.1/115-01-devfreq-add-ipq806x-fabric-scaling-driver.patch @@ -15,7 +15,7 @@ Signed-off-by: Christian Marangi --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig -@@ -143,6 +143,17 @@ config ARM_KRAIT_CACHE_DEVFREQ +@@ -162,6 +162,17 @@ config ARM_KRAIT_CACHE_DEVFREQ based on the max frequency across all core and the range set in the device dts. If provided this scale also the regulator attached to the l2 cache. @@ -35,8 +35,8 @@ Signed-off-by: Christian Marangi endif # PM_DEVFREQ --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile -@@ -14,6 +14,7 @@ obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += - obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o +@@ -16,6 +16,7 @@ obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += + obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o obj-$(CONFIG_ARM_KRAIT_CACHE_DEVFREQ) += krait-cache-devfreq.o +obj-$(CONFIG_ARM_IPQ806X_FAB_DEVFREQ) += ipq806x-fab-devfreq.o diff --git a/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch b/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch index f4de1dbb52c..a324b6facf3 100644 --- a/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch +++ b/target/linux/ipq806x/patches-6.1/115-02-ARM-dts-qcom-add-fab-scaling-node-for-ipq806x.patch @@ -30,9 +30,9 @@ Signed-off-by: Christian Marangi + }; + thermal-zones { - tsens_tz_sensor0 { + sensor0-thermal { polling-delay-passive = <0>; -@@ -470,6 +482,13 @@ +@@ -1410,6 +1422,13 @@ operating-points-v2 = <&opp_table_l2>; }; diff --git a/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch index 41201544f65..9395f1b241e 100644 --- a/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch +++ b/target/linux/ipq806x/patches-6.1/120-v6.2-clk-qcom-kpss-xcc-register-it-as-clk-provider.patch @@ -13,11 +13,9 @@ Link: https://lore.kernel.org/r/20221108211734.3707-1-ansuelsmth@gmail.com drivers/clk/qcom/kpss-xcc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) -diff --git a/drivers/clk/qcom/kpss-xcc.c b/drivers/clk/qcom/kpss-xcc.c -index b1b370274ec4..97358c98c6c9 100644 --- a/drivers/clk/qcom/kpss-xcc.c +++ b/drivers/clk/qcom/kpss-xcc.c -@@ -31,12 +31,13 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_table); +@@ -31,12 +31,13 @@ MODULE_DEVICE_TABLE(of, kpss_xcc_match_t static int kpss_xcc_driver_probe(struct platform_device *pdev) { @@ -32,7 +30,7 @@ index b1b370274ec4..97358c98c6c9 100644 if (!id) return -ENODEV; -@@ -45,7 +46,7 @@ static int kpss_xcc_driver_probe(struct platform_device *pdev) +@@ -45,7 +46,7 @@ static int kpss_xcc_driver_probe(struct return PTR_ERR(base); if (id->data) { @@ -41,7 +39,7 @@ index b1b370274ec4..97358c98c6c9 100644 "clock-output-names", 0, &name)) return -ENODEV; -@@ -55,12 +56,16 @@ static int kpss_xcc_driver_probe(struct platform_device *pdev) +@@ -55,12 +56,16 @@ static int kpss_xcc_driver_probe(struct base += 0x28; } @@ -60,6 +58,3 @@ index b1b370274ec4..97358c98c6c9 100644 } static struct platform_driver kpss_xcc_driver = { --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch index d3d1ea17f5a..65c1fc17f21 100644 --- a/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch +++ b/target/linux/ipq806x/patches-6.1/121-v6.2-01-clk-qcom-krait-cc-use-devm-variant-for-clk-notifier-.patch @@ -14,11 +14,9 @@ Link: https://lore.kernel.org/r/20221108215827.30475-1-ansuelsmth@gmail.com drivers/clk/qcom/krait-cc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c -index e91275663973..33a78b7de0bd 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -64,7 +64,7 @@ static int krait_notifier_register(struct device *dev, struct clk *clk, +@@ -62,7 +62,7 @@ static int krait_notifier_register(struc int ret = 0; mux->clk_nb.notifier_call = krait_notifier_cb; @@ -27,6 +25,3 @@ index e91275663973..33a78b7de0bd 100644 if (ret) dev_err(dev, "failed to register clock notifier: %d\n", ret); --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch index a8bf748258f..c30c245d0a5 100644 --- a/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch +++ b/target/linux/ipq806x/patches-6.1/122-01-clk-qcom-krait-cc-handle-qsb-clock-defined-in-DTS.patch @@ -12,20 +12,18 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) -diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c -index 84f0048961f5..f1d64b16cac3 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -305,7 +305,7 @@ static int krait_cc_probe(struct platform_device *pdev) +@@ -348,7 +348,7 @@ static int krait_cc_probe(struct platfor { struct device *dev = &pdev->dev; const struct of_device_id *id; - unsigned long cur_rate, aux_rate; + unsigned long cur_rate, aux_rate, qsb_rate; int cpu; - struct clk *clk; - struct clk **clks; -@@ -315,11 +315,19 @@ static int krait_cc_probe(struct platform_device *pdev) + struct clk_hw *mux, *l2_pri_mux; + struct clk *clk, **clks; +@@ -357,11 +357,19 @@ static int krait_cc_probe(struct platfor if (!id) return -ENODEV; @@ -47,6 +45,3 @@ index 84f0048961f5..f1d64b16cac3 100644 if (!id->data) { clk = clk_register_fixed_factor(dev, "acpu_aux", "gpll0_vote", 0, 1, 2); --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch index da082759cf8..e2f78f79fb1 100644 --- a/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch +++ b/target/linux/ipq806x/patches-6.1/122-02-clk-qcom-krait-cc-register-REAL-qsb-fixed-clock.patch @@ -14,8 +14,6 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) -diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c -index f1d64b16cac3..e91275663973 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -25,6 +25,8 @@ enum { @@ -27,7 +25,7 @@ index f1d64b16cac3..e91275663973 100644 static unsigned int sec_mux_map[] = { 2, 0, -@@ -322,7 +324,7 @@ static int krait_cc_probe(struct platform_device *pdev) +@@ -364,7 +366,7 @@ static int krait_cc_probe(struct platfor */ clk = clk_get(dev, "qsb"); if (IS_ERR(clk)) @@ -36,6 +34,3 @@ index f1d64b16cac3..e91275663973 100644 if (IS_ERR(clk)) return PTR_ERR(clk); --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch index e25627d86f6..d95a63fc44f 100644 --- a/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch +++ b/target/linux/ipq806x/patches-6.1/122-03-clk-qcom-krait-cc-drop-pr_info-and-use-dev_info.patch @@ -10,12 +10,10 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) -diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c -index b71067a49ee7..e4fb3ff2b5b5 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c -@@ -391,25 +391,25 @@ static int krait_cc_probe(struct platform_device *pdev) - cur_rate = clk_get_rate(l2_pri_mux_clk); +@@ -423,25 +423,25 @@ static int krait_cc_probe(struct platfor + cur_rate = clk_get_rate(clks[l2_mux]); aux_rate = 384000000; if (cur_rate < aux_rate) { - pr_info("L2 @ Undefined rate. Forcing new rate.\n"); @@ -44,6 +42,3 @@ index b71067a49ee7..e4fb3ff2b5b5 100644 } of_clk_add_provider(dev->of_node, krait_of_get, clks); --- -2.37.2 - diff --git a/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch index 7a19c965c2d..8f88e069912 100644 --- a/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch +++ b/target/linux/ipq806x/patches-6.1/122-04-clk-qcom-krait-cc-rework-mux-reset-logic-and-reset-h.patch @@ -17,8 +17,6 @@ Signed-off-by: Christian Marangi drivers/clk/qcom/krait-cc.c | 50 +++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 27 deletions(-) -diff --git a/drivers/clk/qcom/krait-cc.c b/drivers/clk/qcom/krait-cc.c -index 717eff44b6a4..90dee71e7c38 100644 --- a/drivers/clk/qcom/krait-cc.c +++ b/drivers/clk/qcom/krait-cc.c @@ -25,7 +25,9 @@ enum { @@ -32,16 +30,16 @@ index 717eff44b6a4..90dee71e7c38 100644 static unsigned int sec_mux_map[] = { 2, -@@ -317,7 +319,7 @@ static int krait_cc_probe(struct platform_device *pdev) +@@ -350,7 +352,7 @@ static int krait_cc_probe(struct platfor { struct device *dev = &pdev->dev; const struct of_device_id *id; - unsigned long cur_rate, aux_rate, qsb_rate; + unsigned long cur_rate, qsb_rate; int cpu; - struct clk *clk; - struct clk **clks; -@@ -397,28 +399,29 @@ static int krait_cc_probe(struct platform_device *pdev) + struct clk_hw *mux, *l2_pri_mux; + struct clk *clk, **clks; +@@ -420,28 +422,29 @@ static int krait_cc_probe(struct platfor * two different rates to force a HFPLL reinit under all * circumstances. */ @@ -88,5 +86,3 @@ index 717eff44b6a4..90dee71e7c38 100644 } of_clk_add_provider(dev->of_node, krait_of_get, clks); - - diff --git a/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch b/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch index 20e7440ace8..0df29a07877 100644 --- a/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch +++ b/target/linux/ipq806x/patches-6.1/123-clk-qcom-gcc-ipq806x-remove-cc_register_board-for.patch @@ -14,7 +14,7 @@ Signed-off-by: Christian Marangi --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c -@@ -3384,14 +3384,6 @@ static int gcc_ipq806x_probe(struct plat +@@ -3386,14 +3386,6 @@ static int gcc_ipq806x_probe(struct plat struct regmap *regmap; int ret; diff --git a/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch b/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch index 8493f380fe0..e5424210858 100644 --- a/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch +++ b/target/linux/ipq806x/patches-6.1/131-6.2-ARM-dts-qcom-ipq8064-disable-mmc-ddr-1_8v-for-sdcc1.patch @@ -18,7 +18,7 @@ Link: https://lore.kernel.org/r/20221024233817.27410-1-ansuelsmth@gmail.com --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi -@@ -1529,7 +1529,6 @@ +@@ -932,7 +932,6 @@ non-removable; cap-sd-highspeed; cap-mmc-highspeed; diff --git a/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch index ec9027ae47b..397c4481ab1 100644 --- a/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch +++ b/target/linux/ipq806x/patches-6.1/850-soc-add-qualcomm-syscon.patch @@ -2,9 +2,9 @@ From: Christian Lamparter Subject: SoC: add qualcomm syscon --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile -@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o - obj-$(CONFIG_QCOM_SMSM) += smsm.o - obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o +@@ -23,6 +23,7 @@ obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o + obj-$(CONFIG_QCOM_SPM) += spm.o + obj-$(CONFIG_QCOM_STATS) += qcom_stats.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_TCSR) += qcom_tcsr.o obj-$(CONFIG_QCOM_APR) += apr.o @@ -12,9 +12,9 @@ Subject: SoC: add qualcomm syscon obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig -@@ -190,6 +190,13 @@ config QCOM_SOCINFO - Say yes here to support the Qualcomm socinfo driver, providing - information about the SoC to user space. +@@ -213,6 +213,13 @@ config QCOM_STATS + various SoC level low power modes statistics and export to debugfs + interface. +config QCOM_TCSR + tristate "QCOM Top Control and Status Registers" diff --git a/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch index 09022dca464..6361cfcbd91 100644 --- a/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch +++ b/target/linux/ipq806x/patches-6.1/900-arm-add-cmdline-override.patch @@ -1,6 +1,6 @@ --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -1740,6 +1740,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL +@@ -1599,6 +1599,14 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGL endchoice @@ -17,7 +17,7 @@ default "" --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c -@@ -1162,6 +1162,17 @@ int __init early_init_dt_scan_chosen(uns +@@ -1187,6 +1187,17 @@ int __init early_init_dt_scan_chosen(cha if (p != NULL && l > 0) strlcat(cmdline, p, min_t(int, strlen(cmdline) + (int)l, COMMAND_LINE_SIZE)); From 33a9bce27813f9f67abdd0e9c422159c601d2705 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Thu, 20 Oct 2022 17:50:06 +0200 Subject: [PATCH 86/88] ipq806x: 6.1: refresh dts Refresh dts for kernel 6.1 support. Changes: - nbg6817 drop amba node and reference directly sdcc1. Signed-off-by: Christian Marangi --- .../files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts index 162b28d27fb..60a949f44e3 100644 --- a/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts +++ b/target/linux/ipq806x/files-6.1/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts @@ -321,10 +321,8 @@ }; }; -&amba { - sdcc1: sdcc@12400000 { - status = "okay"; - }; +&sdcc1 { + status = "okay"; }; &adm_dma { From b2d3131edff189c11ef918c87b0d273d87440bac Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 00:00:38 +0200 Subject: [PATCH 87/88] ipq806x: 6.1: refresh config and add missing symbols Refresh config for kernel 6.1 and add missing symbols Then sorted using: $ ./scripts/kconfig.pl '+' target/linux/ipq806x/config-6.1 /dev/null > target/linux/ipq806x/config-6.1-new $ mv target/linux/ipq806x/config-6.1-new target/linux/ipq806x/config-6.1 Signed-off-by: Christian Marangi --- target/linux/ipq806x/config-6.1 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/target/linux/ipq806x/config-6.1 b/target/linux/ipq806x/config-6.1 index 69e17cfa504..aae2f8a0b0f 100644 --- a/target/linux/ipq806x/config-6.1 +++ b/target/linux/ipq806x/config-6.1 @@ -3,11 +3,15 @@ CONFIG_ALIGNMENT_TRAP=y # CONFIG_APQ_MMCC_8084 is not set CONFIG_AR8216_PHY=y CONFIG_ARCH_32BIT_OFF_T=y +CONFIG_ARCH_FORCE_MAX_ORDER=11 CONFIG_ARCH_HIBERNATION_POSSIBLE=y # CONFIG_ARCH_IPQ40XX is not set +CONFIG_ARCH_IPQ806X=y CONFIG_ARCH_KEEP_MEMBLOCK=y # CONFIG_ARCH_MDM9615 is not set CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_ARCH_MSM8909 is not set +# CONFIG_ARCH_MSM8916 is not set CONFIG_ARCH_MSM8960=y CONFIG_ARCH_MSM8974=y CONFIG_ARCH_MSM8X60=y @@ -88,6 +92,7 @@ CONFIG_CPU_IDLE=y CONFIG_CPU_IDLE_GOV_LADDER=y CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_PABRT_V7=y CONFIG_CPU_PM=y CONFIG_CPU_RMAP=y @@ -253,10 +258,12 @@ CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MODULES_USE_ELF_REL=y CONFIG_MSM_GCC_8660=y +# CONFIG_MSM_GCC_8909 is not set # CONFIG_MSM_GCC_8916 is not set # CONFIG_MSM_GCC_8939 is not set # CONFIG_MSM_GCC_8960 is not set # CONFIG_MSM_GCC_8974 is not set +# CONFIG_MSM_GCC_8976 is not set # CONFIG_MSM_GCC_8994 is not set # CONFIG_MSM_GCC_8996 is not set # CONFIG_MSM_GCC_8998 is not set @@ -332,7 +339,9 @@ CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y CONFIG_PHYLINK=y +CONFIG_PHYS_OFFSET=0x42000000 # CONFIG_PHY_QCOM_APQ8064_SATA is not set +# CONFIG_PHY_QCOM_EDP is not set # CONFIG_PHY_QCOM_IPQ4019_USB is not set CONFIG_PHY_QCOM_IPQ806X_SATA=y # CONFIG_PHY_QCOM_IPQ806X_USB is not set @@ -353,6 +362,7 @@ CONFIG_PINCTRL_IPQ8064=y CONFIG_PINCTRL_MSM=y # CONFIG_PINCTRL_MSM8226 is not set # CONFIG_PINCTRL_MSM8660 is not set +# CONFIG_PINCTRL_MSM8909 is not set # CONFIG_PINCTRL_MSM8916 is not set # CONFIG_PINCTRL_MSM8960 is not set # CONFIG_PINCTRL_MSM8976 is not set @@ -365,6 +375,7 @@ CONFIG_PINCTRL_MSM=y # CONFIG_PINCTRL_SC7180 is not set # CONFIG_PINCTRL_SDM660 is not set # CONFIG_PINCTRL_SDM845 is not set +# CONFIG_PINCTRL_SDX65 is not set # CONFIG_PINCTRL_SM8150 is not set # CONFIG_PINCTRL_SM8250 is not set CONFIG_PM_DEVFREQ=y @@ -377,6 +388,8 @@ CONFIG_PPS=y CONFIG_PRINTK_TIME=y CONFIG_PTP_1588_CLOCK=y CONFIG_PTP_1588_CLOCK_OPTIONAL=y +# CONFIG_QCM_DISPCC_2290 is not set +# CONFIG_QCM_GCC_2290 is not set # CONFIG_QCOM_A53PLL is not set CONFIG_QCOM_ADM=y CONFIG_QCOM_BAM_DMA=y @@ -387,6 +400,7 @@ CONFIG_QCOM_CLK_RPM=y # CONFIG_QCOM_GENI_SE is not set CONFIG_QCOM_GSBI=y CONFIG_QCOM_HFPLL=y +# CONFIG_QCOM_ICC_BWMON is not set # CONFIG_QCOM_IOMMU is not set # CONFIG_QCOM_LLCC is not set # CONFIG_QCOM_OCMEM is not set @@ -399,6 +413,7 @@ CONFIG_QCOM_SCM=y CONFIG_QCOM_SMEM=y # CONFIG_QCOM_SMSM is not set CONFIG_QCOM_SOCINFO=y +# CONFIG_QCOM_STATS is not set CONFIG_QCOM_TCSR=y CONFIG_QCOM_TSENS=y CONFIG_QCOM_WDT=y @@ -426,10 +441,14 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_I2C_AND_SPI=y CONFIG_RTC_MC146818_LIB=y CONFIG_RWSEM_SPIN_ON_OWNER=y +# CONFIG_SC_CAMCC_7280 is not set # CONFIG_SC_DISPCC_7180 is not set # CONFIG_SC_GCC_7180 is not set +# CONFIG_SC_GCC_8280XP is not set # CONFIG_SC_GPUCC_7180 is not set +# CONFIG_SC_LPASSCC_7280 is not set # CONFIG_SC_LPASS_CORECC_7180 is not set +# CONFIG_SC_LPASS_CORECC_7280 is not set # CONFIG_SC_MSS_7180 is not set # CONFIG_SC_VIDEOCC_7180 is not set # CONFIG_SDM_CAMCC_845 is not set @@ -439,6 +458,7 @@ CONFIG_RWSEM_SPIN_ON_OWNER=y # CONFIG_SDM_GPUCC_845 is not set # CONFIG_SDM_LPASSCC_845 is not set # CONFIG_SDM_VIDEOCC_845 is not set +# CONFIG_SDX_GCC_65 is not set CONFIG_SERIAL_8250_FSL=y CONFIG_SERIAL_MCTRL_GPIO=y CONFIG_SERIAL_MSM=y @@ -446,10 +466,14 @@ CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SGL_ALLOC=y CONFIG_SMP=y CONFIG_SMP_ON_UP=y +# CONFIG_SM_CAMCC_8450 is not set # CONFIG_SM_GCC_8150 is not set # CONFIG_SM_GCC_8250 is not set +# CONFIG_SM_GCC_8450 is not set +# CONFIG_SM_GPUCC_6350 is not set # CONFIG_SM_GPUCC_8150 is not set # CONFIG_SM_GPUCC_8250 is not set +# CONFIG_SM_GPUCC_8350 is not set # CONFIG_SM_VIDEOCC_8150 is not set # CONFIG_SM_VIDEOCC_8250 is not set CONFIG_SOCK_RX_QUEUE_MAPPING=y From 4c4ba378969c19b66b96403434f176a84d25f3a1 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Wed, 19 Oct 2022 00:05:36 +0200 Subject: [PATCH 88/88] ipq806x: enable testing kernel version with 6.1 version Enable testing kernel version with 6.1 kernel version. Signed-off-by: Christian Marangi --- target/linux/ipq806x/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/target/linux/ipq806x/Makefile b/target/linux/ipq806x/Makefile index 057446f7557..81fda2964db 100644 --- a/target/linux/ipq806x/Makefile +++ b/target/linux/ipq806x/Makefile @@ -11,6 +11,7 @@ CPU_SUBTYPE:=neon-vfpv4 SUBTARGETS:=generic chromium KERNEL_PATCHVER:=5.15 +KERNEL_TESTING_PATCHVER:=6.1 KERNELNAME:=zImage Image dtbs